diff --git a/Chutzpah.NoVS.sln b/Chutzpah.NoVS.sln
index 31bcd0b2..e982a411 100644
--- a/Chutzpah.NoVS.sln
+++ b/Chutzpah.NoVS.sln
@@ -84,4 +84,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {370B87B0-118E-4F9A-A13C-8E4A9B222047}
+ EndGlobalSection
EndGlobal
diff --git a/Chutzpah/Chutzpah.csproj b/Chutzpah/Chutzpah.csproj
index cc4cc4f6..6b3b8d88 100644
--- a/Chutzpah/Chutzpah.csproj
+++ b/Chutzpah/Chutzpah.csproj
@@ -388,6 +388,9 @@
Always
+
+ Always
+
Always
@@ -397,6 +400,9 @@
Always
+
+ Always
+
Always
@@ -406,6 +412,9 @@
Always
+
+ Always
+
Always
@@ -433,6 +442,9 @@
Always
+
+ Always
+
Always
@@ -481,6 +493,24 @@
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
diff --git a/Chutzpah/ChutzpahJSRunners/Chrome/jasmineRunnerV3.js b/Chutzpah/ChutzpahJSRunners/Chrome/jasmineRunnerV3.js
new file mode 100644
index 00000000..de410c56
--- /dev/null
+++ b/Chutzpah/ChutzpahJSRunners/Chrome/jasmineRunnerV3.js
@@ -0,0 +1,22 @@
+///
+
+(async function () {
+
+ const functions = require('../jasmineFunctionsV3.js');
+ const chutzpahRunner = require('./chutzpahRunner.js');
+
+ try {
+ await chutzpahRunner.runner(
+ functions.onInitialized,
+ functions.onPageLoaded,
+ functions.isJasmineLoaded,
+ functions.onJasmineLoaded,
+ functions.isTestingDone);
+
+ } catch (e) {
+ throw new Error("Failed to run jasmineRunnerV3.js: " + e);
+ }
+})().catch(e => {
+ console.error(e);
+ process.exit(2);
+});
\ No newline at end of file
diff --git a/Chutzpah/ChutzpahJSRunners/JsDom/jasmineRunnerV3.js b/Chutzpah/ChutzpahJSRunners/JsDom/jasmineRunnerV3.js
new file mode 100644
index 00000000..de410c56
--- /dev/null
+++ b/Chutzpah/ChutzpahJSRunners/JsDom/jasmineRunnerV3.js
@@ -0,0 +1,22 @@
+///
+
+(async function () {
+
+ const functions = require('../jasmineFunctionsV3.js');
+ const chutzpahRunner = require('./chutzpahRunner.js');
+
+ try {
+ await chutzpahRunner.runner(
+ functions.onInitialized,
+ functions.onPageLoaded,
+ functions.isJasmineLoaded,
+ functions.onJasmineLoaded,
+ functions.isTestingDone);
+
+ } catch (e) {
+ throw new Error("Failed to run jasmineRunnerV3.js: " + e);
+ }
+})().catch(e => {
+ console.error(e);
+ process.exit(2);
+});
\ No newline at end of file
diff --git a/Chutzpah/ChutzpahJSRunners/jasmineFunctionsV3.js b/Chutzpah/ChutzpahJSRunners/jasmineFunctionsV3.js
new file mode 100644
index 00000000..eb5c057b
--- /dev/null
+++ b/Chutzpah/ChutzpahJSRunners/jasmineFunctionsV3.js
@@ -0,0 +1,163 @@
+var module = module || {};
+module.exports = module.exports || {};
+
+function onInitialized() {
+ console.log("!!_!! onInitialized Jasmine - v3");
+}
+
+function isTestingDone() {
+ console.log("!!_!! isTestingDone");
+ return window.chutzpah.isTestingFinished === true;
+}
+
+function isJasmineLoaded() {
+ console.log("!!_!! isJasmineLoaded");
+ return !!window.jasmine && !!window.jasmine.getEnv;
+}
+
+function onJasmineLoaded() {
+
+ console.log("!!_!! onJasmineLoaded");
+
+ function log(obj) {
+ console.log(JSON.stringify(obj));
+ }
+
+
+ var activeTestCase = null,
+ fileStartTime = null,
+ testStartTime = null,
+ suites = [];
+
+ window.chutzpah.isTestingFinished = false;
+ window.chutzpah.testCases = [];
+
+ function logCoverage() {
+ if (window._Chutzpah_covobj_name && window[window._Chutzpah_covobj_name]) {
+ log({ type: "CoverageObject", object: JSON.stringify(window[window._Chutzpah_covobj_name]) });
+ }
+ }
+
+ function recordStackTrace(stack) {
+ if (stack) {
+ // Truncate stack to 5 deep.
+ stack = stack.split('\n').slice(1, 6).join('\n');
+ }
+ return stack;
+ }
+
+
+ function ChutzpahJasmineReporter(options) {
+
+ var passedCount = 0;
+ var failedCount = 0;
+ var skippedCount = 0;
+
+ this.jasmineStarted = function () {
+
+ fileStartTime = new Date().getTime();
+
+ // Testing began
+ log({ type: "FileStart" });
+ };
+
+
+ this.jasmineDone = function () {
+ var timetaken = new Date().getTime() - fileStartTime;
+ logCoverage();
+ log({ type: "FileDone", timetaken: timetaken, passed: passedCount, failed: failedCount });
+ window.chutzpah.isTestingFinished = true;
+ };
+
+
+ this.suiteStarted = function (result) {
+ suites.push(result);
+ };
+
+ this.suiteDone = function (result) {
+ suites.pop();
+ };
+
+ this.specStarted = function (result) {
+ var currentSuiteName = suites.length > 0
+ ? suites[suites.length - 1].fullName
+ : null;
+
+ testStartTime = new Date().getTime();
+ var suiteName = currentSuiteName;
+ var specName = result.description;
+ var newTestCase = { moduleName: suiteName, testName: specName, testResults: [] };
+ window.chutzpah.testCases.push(newTestCase);
+ activeTestCase = newTestCase;
+ log({ type: "TestStart", testCase: activeTestCase });
+ };
+
+ this.specDone = function (result) {
+ if (result.status === "disabled") {
+ return;
+ }
+
+ if (result.status === "failed") {
+ failedCount++;
+ }
+ else if (result.status === "pending") {
+ skippedCount++;
+ activeTestCase.skipped = true;
+ }
+ else {
+ passedCount++;
+ }
+
+ var timetaken = new Date().getTime() - testStartTime;
+ activeTestCase.timetaken = timetaken;
+
+ for (var i = 0; i < result.failedExpectations.length; i++) {
+ var expectation = result.failedExpectations[i];
+
+ var testResult = {};
+ testResult.passed = false;
+ testResult.message = expectation.message;
+ testResult.stackTrace = recordStackTrace(expectation.stack);
+ activeTestCase.testResults.push(testResult);
+
+ }
+
+ // Log test case when done. This will get picked up by phantom and streamed to chutzpah.
+ log({ type: "TestDone", testCase: activeTestCase });
+
+
+ };
+
+ }
+
+ if (window.chutzpah.testMode) {
+ jasmine.getEnv().addReporter(new ChutzpahJasmineReporter());
+ }
+
+ if (window.chutzpah.testMode === 'discovery') {
+ // If discovery mode overwrite execute to not run the test
+ jasmine.getEnv().beforeAll = function () { };
+ jasmine.getEnv().afterAll = function () { };
+ jasmine.Spec.prototype.execute = function (onComplete) {
+ this.onStart(this);
+ this.resultCallback(this.result);
+ if (onComplete)
+ onComplete();
+ };
+ }
+
+}
+
+function onPageLoaded() {
+ console.log("!!_!! onPageLoaded");
+
+ if (!window.chutzpah.usingModuleLoader && window.chutzpah.autoStart !== false) {
+ (window.chutzpah.start || window.initializeJasmine)();
+ }
+}
+
+module.exports.onInitialized = onInitialized;
+module.exports.isTestingDone = isTestingDone;
+module.exports.isJasmineLoaded = isJasmineLoaded;
+module.exports.onJasmineLoaded = onJasmineLoaded;
+module.exports.onPageLoaded = onPageLoaded;
\ No newline at end of file
diff --git a/Chutzpah/ChutzpahTestHarnessFiles/Coverage/blanket_jasmine_v3.js b/Chutzpah/ChutzpahTestHarnessFiles/Coverage/blanket_jasmine_v3.js
new file mode 100644
index 00000000..36ef004e
--- /dev/null
+++ b/Chutzpah/ChutzpahTestHarnessFiles/Coverage/blanket_jasmine_v3.js
@@ -0,0 +1,5791 @@
+/*! blanket - v1.2.1 */
+
+(function (define) {
+ (function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.acorn = f() } })(function () {
+ var define, module, exports; return (function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = "MODULE_NOT_FOUND", f } var l = n[o] = { exports: {} }; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++) s(r[o]); return s })({
+ 1: [function (_dereq_, module, exports) {
+
+
+ // The main exported interface (under `self.acorn` when in the
+ // browser) is a `parse` function that takes a code string and
+ // returns an abstract syntax tree as specified by [Mozilla parser
+ // API][api].
+ //
+ // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
+
+ "use strict";
+
+ exports.parse = parse;
+
+ // This function tries to parse a single expression at a given
+ // offset in a string. Useful for parsing mixed-language formats
+ // that embed JavaScript expressions.
+
+ exports.parseExpressionAt = parseExpressionAt;
+
+ // Acorn is organized as a tokenizer and a recursive-descent parser.
+ // The `tokenize` export provides an interface to the tokenizer.
+
+ exports.tokenizer = tokenizer;
+ exports.__esModule = true;
+ // Acorn is a tiny, fast JavaScript parser written in JavaScript.
+ //
+ // Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and
+ // various contributors and released under an MIT license.
+ //
+ // Git repositories for Acorn are available at
+ //
+ // http://marijnhaverbeke.nl/git/acorn
+ // https://github.com/marijnh/acorn.git
+ //
+ // Please use the [github bug tracker][ghbt] to report issues.
+ //
+ // [ghbt]: https://github.com/marijnh/acorn/issues
+ //
+ // This file defines the main parser interface. The library also comes
+ // with a [error-tolerant parser][dammit] and an
+ // [abstract syntax tree walker][walk], defined in other files.
+ //
+ // [dammit]: acorn_loose.js
+ // [walk]: util/walk.js
+
+ var _state = _dereq_("./state");
+
+ var Parser = _state.Parser;
+
+ var _options = _dereq_("./options");
+
+ var getOptions = _options.getOptions;
+
+ _dereq_("./parseutil");
+
+ _dereq_("./statement");
+
+ _dereq_("./lval");
+
+ _dereq_("./expression");
+
+ exports.Parser = _state.Parser;
+ exports.plugins = _state.plugins;
+ exports.defaultOptions = _options.defaultOptions;
+
+ var _location = _dereq_("./location");
+
+ exports.SourceLocation = _location.SourceLocation;
+ exports.getLineInfo = _location.getLineInfo;
+ exports.Node = _dereq_("./node").Node;
+
+ var _tokentype = _dereq_("./tokentype");
+
+ exports.TokenType = _tokentype.TokenType;
+ exports.tokTypes = _tokentype.types;
+
+ var _tokencontext = _dereq_("./tokencontext");
+
+ exports.TokContext = _tokencontext.TokContext;
+ exports.tokContexts = _tokencontext.types;
+
+ var _identifier = _dereq_("./identifier");
+
+ exports.isIdentifierChar = _identifier.isIdentifierChar;
+ exports.isIdentifierStart = _identifier.isIdentifierStart;
+ exports.Token = _dereq_("./tokenize").Token;
+
+ var _whitespace = _dereq_("./whitespace");
+
+ exports.isNewLine = _whitespace.isNewLine;
+ exports.lineBreak = _whitespace.lineBreak;
+ exports.lineBreakG = _whitespace.lineBreakG;
+ var version = "1.2.2"; exports.version = version;
+
+ function parse(input, options) {
+ var p = parser(options, input);
+ var startPos = p.pos,
+ startLoc = p.options.locations && p.curPosition();
+ p.nextToken();
+ return p.parseTopLevel(p.options.program || p.startNodeAt(startPos, startLoc));
+ }
+
+ function parseExpressionAt(input, pos, options) {
+ var p = parser(options, input, pos);
+ p.nextToken();
+ return p.parseExpression();
+ }
+
+ function tokenizer(input, options) {
+ return parser(options, input);
+ }
+
+ function parser(options, input) {
+ return new Parser(getOptions(options), String(input));
+ }
+
+ }, { "./expression": 6, "./identifier": 7, "./location": 8, "./lval": 9, "./node": 10, "./options": 11, "./parseutil": 12, "./state": 13, "./statement": 14, "./tokencontext": 15, "./tokenize": 16, "./tokentype": 17, "./whitespace": 19 }], 2: [function (_dereq_, module, exports) {
+ if (typeof Object.create === 'function') {
+ // implementation from standard node.js 'util' module
+ module.exports = function inherits(ctor, superCtor) {
+ ctor.super_ = superCtor
+ ctor.prototype = Object.create(superCtor.prototype, {
+ constructor: {
+ value: ctor,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ };
+ } else {
+ // old school shim for old browsers
+ module.exports = function inherits(ctor, superCtor) {
+ ctor.super_ = superCtor
+ var TempCtor = function () { }
+ TempCtor.prototype = superCtor.prototype
+ ctor.prototype = new TempCtor()
+ ctor.prototype.constructor = ctor
+ }
+ }
+
+ }, {}], 3: [function (_dereq_, module, exports) {
+ // shim for using process in browser
+
+ var process = module.exports = {};
+ var queue = [];
+ var draining = false;
+
+ function drainQueue() {
+ if (draining) {
+ return;
+ }
+ draining = true;
+ var currentQueue;
+ var len = queue.length;
+ while (len) {
+ currentQueue = queue;
+ queue = [];
+ var i = -1;
+ while (++i < len) {
+ currentQueue[i]();
+ }
+ len = queue.length;
+ }
+ draining = false;
+ }
+ process.nextTick = function (fun) {
+ queue.push(fun);
+ if (!draining) {
+ setTimeout(drainQueue, 0);
+ }
+ };
+
+ process.title = 'browser';
+ process.browser = true;
+ process.env = {};
+ process.argv = [];
+ process.version = ''; // empty string to avoid regexp issues
+ process.versions = {};
+
+ function noop() { }
+
+ process.on = noop;
+ process.addListener = noop;
+ process.once = noop;
+ process.off = noop;
+ process.removeListener = noop;
+ process.removeAllListeners = noop;
+ process.emit = noop;
+
+ process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+ };
+
+ // TODO(shtylman)
+ process.cwd = function () { return '/' };
+ process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+ };
+ process.umask = function () { return 0; };
+
+ }, {}], 4: [function (_dereq_, module, exports) {
+ module.exports = function isBuffer(arg) {
+ return arg && typeof arg === 'object'
+ && typeof arg.copy === 'function'
+ && typeof arg.fill === 'function'
+ && typeof arg.readUInt8 === 'function';
+ }
+ }, {}], 5: [function (_dereq_, module, exports) {
+ (function (process, global) {
+ // Copyright Joyent, Inc. and other Node contributors.
+ //
+ // Permission is hereby granted, free of charge, to any person obtaining a
+ // copy of this software and associated documentation files (the
+ // "Software"), to deal in the Software without restriction, including
+ // without limitation the rights to use, copy, modify, merge, publish,
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
+ // persons to whom the Software is furnished to do so, subject to the
+ // following conditions:
+ //
+ // The above copyright notice and this permission notice shall be included
+ // in all copies or substantial portions of the Software.
+ //
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ var formatRegExp = /%[sdj%]/g;
+ exports.format = function (f) {
+ if (!isString(f)) {
+ var objects = [];
+ for (var i = 0; i < arguments.length; i++) {
+ objects.push(inspect(arguments[i]));
+ }
+ return objects.join(' ');
+ }
+
+ var i = 1;
+ var args = arguments;
+ var len = args.length;
+ var str = String(f).replace(formatRegExp, function (x) {
+ if (x === '%%') return '%';
+ if (i >= len) return x;
+ switch (x) {
+ case '%s': return String(args[i++]);
+ case '%d': return Number(args[i++]);
+ case '%j':
+ try {
+ return JSON.stringify(args[i++]);
+ } catch (_) {
+ return '[Circular]';
+ }
+ default:
+ return x;
+ }
+ });
+ for (var x = args[i]; i < len; x = args[++i]) {
+ if (isNull(x) || !isObject(x)) {
+ str += ' ' + x;
+ } else {
+ str += ' ' + inspect(x);
+ }
+ }
+ return str;
+ };
+
+
+ // Mark that a method should not be used.
+ // Returns a modified function which warns once by default.
+ // If --no-deprecation is set, then it is a no-op.
+ exports.deprecate = function (fn, msg) {
+ // Allow for deprecating things in the process of starting up.
+ if (isUndefined(global.process)) {
+ return function () {
+ return exports.deprecate(fn, msg).apply(this, arguments);
+ };
+ }
+
+ if (process.noDeprecation === true) {
+ return fn;
+ }
+
+ var warned = false;
+ function deprecated() {
+ if (!warned) {
+ if (process.throwDeprecation) {
+ throw new Error(msg);
+ } else if (process.traceDeprecation) {
+ console.trace(msg);
+ } else {
+ console.error(msg);
+ }
+ warned = true;
+ }
+ return fn.apply(this, arguments);
+ }
+
+ return deprecated;
+ };
+
+
+ var debugs = {};
+ var debugEnviron;
+ exports.debuglog = function (set) {
+ if (isUndefined(debugEnviron))
+ debugEnviron = process.env.NODE_DEBUG || '';
+ set = set.toUpperCase();
+ if (!debugs[set]) {
+ if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
+ var pid = process.pid;
+ debugs[set] = function () {
+ var msg = exports.format.apply(exports, arguments);
+ console.error('%s %d: %s', set, pid, msg);
+ };
+ } else {
+ debugs[set] = function () { };
+ }
+ }
+ return debugs[set];
+ };
+
+
+ /**
+ * Echos the value of a value. Trys to print the value out
+ * in the best way possible given the different types.
+ *
+ * @param {Object} obj The object to print out.
+ * @param {Object} opts Optional options object that alters the output.
+ */
+ /* legacy: obj, showHidden, depth, colors*/
+ function inspect(obj, opts) {
+ // default options
+ var ctx = {
+ seen: [],
+ stylize: stylizeNoColor
+ };
+ // legacy...
+ if (arguments.length >= 3) ctx.depth = arguments[2];
+ if (arguments.length >= 4) ctx.colors = arguments[3];
+ if (isBoolean(opts)) {
+ // legacy...
+ ctx.showHidden = opts;
+ } else if (opts) {
+ // got an "options" object
+ exports._extend(ctx, opts);
+ }
+ // set default options
+ if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+ if (isUndefined(ctx.depth)) ctx.depth = 2;
+ if (isUndefined(ctx.colors)) ctx.colors = false;
+ if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+ if (ctx.colors) ctx.stylize = stylizeWithColor;
+ return formatValue(ctx, obj, ctx.depth);
+ }
+ exports.inspect = inspect;
+
+
+ // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+ inspect.colors = {
+ 'bold': [1, 22],
+ 'italic': [3, 23],
+ 'underline': [4, 24],
+ 'inverse': [7, 27],
+ 'white': [37, 39],
+ 'grey': [90, 39],
+ 'black': [30, 39],
+ 'blue': [34, 39],
+ 'cyan': [36, 39],
+ 'green': [32, 39],
+ 'magenta': [35, 39],
+ 'red': [31, 39],
+ 'yellow': [33, 39]
+ };
+
+ // Don't use 'blue' not visible on cmd.exe
+ inspect.styles = {
+ 'special': 'cyan',
+ 'number': 'yellow',
+ 'boolean': 'yellow',
+ 'undefined': 'grey',
+ 'null': 'bold',
+ 'string': 'green',
+ 'date': 'magenta',
+ // "name": intentionally not styling
+ 'regexp': 'red'
+ };
+
+
+ function stylizeWithColor(str, styleType) {
+ var style = inspect.styles[styleType];
+
+ if (style) {
+ return '\u001b[' + inspect.colors[style][0] + 'm' + str +
+ '\u001b[' + inspect.colors[style][1] + 'm';
+ } else {
+ return str;
+ }
+ }
+
+
+ function stylizeNoColor(str, styleType) {
+ return str;
+ }
+
+
+ function arrayToHash(array) {
+ var hash = {};
+
+ array.forEach(function (val, idx) {
+ hash[val] = true;
+ });
+
+ return hash;
+ }
+
+
+ function formatValue(ctx, value, recurseTimes) {
+ // Provide a hook for user-specified inspect functions.
+ // Check that value is an object with an inspect function on it
+ if (ctx.customInspect &&
+ value &&
+ isFunction(value.inspect) &&
+ // Filter out the util module, it's inspect function is special
+ value.inspect !== exports.inspect &&
+ // Also filter out any prototype objects using the circular check.
+ !(value.constructor && value.constructor.prototype === value)) {
+ var ret = value.inspect(recurseTimes, ctx);
+ if (!isString(ret)) {
+ ret = formatValue(ctx, ret, recurseTimes);
+ }
+ return ret;
+ }
+
+ // Primitive types cannot have properties
+ var primitive = formatPrimitive(ctx, value);
+ if (primitive) {
+ return primitive;
+ }
+
+ // Look up the keys of the object.
+ var keys = Object.keys(value);
+ var visibleKeys = arrayToHash(keys);
+
+ if (ctx.showHidden) {
+ keys = Object.getOwnPropertyNames(value);
+ }
+
+ // IE doesn't make error fields non-enumerable
+ // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
+ if (isError(value)
+ && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
+ return formatError(value);
+ }
+
+ // Some type of object without properties can be shortcutted.
+ if (keys.length === 0) {
+ if (isFunction(value)) {
+ var name = value.name ? ': ' + value.name : '';
+ return ctx.stylize('[Function' + name + ']', 'special');
+ }
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ }
+ if (isDate(value)) {
+ return ctx.stylize(Date.prototype.toString.call(value), 'date');
+ }
+ if (isError(value)) {
+ return formatError(value);
+ }
+ }
+
+ var base = '', array = false, braces = ['{', '}'];
+
+ // Make Array say that they are Array
+ if (isArray(value)) {
+ array = true;
+ braces = ['[', ']'];
+ }
+
+ // Make functions say that they are functions
+ if (isFunction(value)) {
+ var n = value.name ? ': ' + value.name : '';
+ base = ' [Function' + n + ']';
+ }
+
+ // Make RegExps say that they are RegExps
+ if (isRegExp(value)) {
+ base = ' ' + RegExp.prototype.toString.call(value);
+ }
+
+ // Make dates with properties first say the date
+ if (isDate(value)) {
+ base = ' ' + Date.prototype.toUTCString.call(value);
+ }
+
+ // Make error with message first say the error
+ if (isError(value)) {
+ base = ' ' + formatError(value);
+ }
+
+ if (keys.length === 0 && (!array || value.length == 0)) {
+ return braces[0] + base + braces[1];
+ }
+
+ if (recurseTimes < 0) {
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ } else {
+ return ctx.stylize('[Object]', 'special');
+ }
+ }
+
+ ctx.seen.push(value);
+
+ var output;
+ if (array) {
+ output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+ } else {
+ output = keys.map(function (key) {
+ return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+ });
+ }
+
+ ctx.seen.pop();
+
+ return reduceToSingleString(output, base, braces);
+ }
+
+
+ function formatPrimitive(ctx, value) {
+ if (isUndefined(value))
+ return ctx.stylize('undefined', 'undefined');
+ if (isString(value)) {
+ var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+ .replace(/'/g, "\\'")
+ .replace(/\\"/g, '"') + '\'';
+ return ctx.stylize(simple, 'string');
+ }
+ if (isNumber(value))
+ return ctx.stylize('' + value, 'number');
+ if (isBoolean(value))
+ return ctx.stylize('' + value, 'boolean');
+ // For some reason typeof null is "object", so special case here.
+ if (isNull(value))
+ return ctx.stylize('null', 'null');
+ }
+
+
+ function formatError(value) {
+ return '[' + Error.prototype.toString.call(value) + ']';
+ }
+
+
+ function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+ var output = [];
+ for (var i = 0, l = value.length; i < l; ++i) {
+ if (hasOwnProperty(value, String(i))) {
+ output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+ String(i), true));
+ } else {
+ output.push('');
+ }
+ }
+ keys.forEach(function (key) {
+ if (!key.match(/^\d+$/)) {
+ output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+ key, true));
+ }
+ });
+ return output;
+ }
+
+
+ function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+ var name, str, desc;
+ desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+ if (desc.get) {
+ if (desc.set) {
+ str = ctx.stylize('[Getter/Setter]', 'special');
+ } else {
+ str = ctx.stylize('[Getter]', 'special');
+ }
+ } else {
+ if (desc.set) {
+ str = ctx.stylize('[Setter]', 'special');
+ }
+ }
+ if (!hasOwnProperty(visibleKeys, key)) {
+ name = '[' + key + ']';
+ }
+ if (!str) {
+ if (ctx.seen.indexOf(desc.value) < 0) {
+ if (isNull(recurseTimes)) {
+ str = formatValue(ctx, desc.value, null);
+ } else {
+ str = formatValue(ctx, desc.value, recurseTimes - 1);
+ }
+ if (str.indexOf('\n') > -1) {
+ if (array) {
+ str = str.split('\n').map(function (line) {
+ return ' ' + line;
+ }).join('\n').substr(2);
+ } else {
+ str = '\n' + str.split('\n').map(function (line) {
+ return ' ' + line;
+ }).join('\n');
+ }
+ }
+ } else {
+ str = ctx.stylize('[Circular]', 'special');
+ }
+ }
+ if (isUndefined(name)) {
+ if (array && key.match(/^\d+$/)) {
+ return str;
+ }
+ name = JSON.stringify('' + key);
+ if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+ name = name.substr(1, name.length - 2);
+ name = ctx.stylize(name, 'name');
+ } else {
+ name = name.replace(/'/g, "\\'")
+ .replace(/\\"/g, '"')
+ .replace(/(^"|"$)/g, "'");
+ name = ctx.stylize(name, 'string');
+ }
+ }
+
+ return name + ': ' + str;
+ }
+
+
+ function reduceToSingleString(output, base, braces) {
+ var numLinesEst = 0;
+ var length = output.reduce(function (prev, cur) {
+ numLinesEst++;
+ if (cur.indexOf('\n') >= 0) numLinesEst++;
+ return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+ }, 0);
+
+ if (length > 60) {
+ return braces[0] +
+ (base === '' ? '' : base + '\n ') +
+ ' ' +
+ output.join(',\n ') +
+ ' ' +
+ braces[1];
+ }
+
+ return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+ }
+
+
+ // NOTE: These type checking functions intentionally don't use `instanceof`
+ // because it is fragile and can be easily faked with `Object.create()`.
+ function isArray(ar) {
+ return Array.isArray(ar);
+ }
+ exports.isArray = isArray;
+
+ function isBoolean(arg) {
+ return typeof arg === 'boolean';
+ }
+ exports.isBoolean = isBoolean;
+
+ function isNull(arg) {
+ return arg === null;
+ }
+ exports.isNull = isNull;
+
+ function isNullOrUndefined(arg) {
+ return arg == null;
+ }
+ exports.isNullOrUndefined = isNullOrUndefined;
+
+ function isNumber(arg) {
+ return typeof arg === 'number';
+ }
+ exports.isNumber = isNumber;
+
+ function isString(arg) {
+ return typeof arg === 'string';
+ }
+ exports.isString = isString;
+
+ function isSymbol(arg) {
+ return typeof arg === 'symbol';
+ }
+ exports.isSymbol = isSymbol;
+
+ function isUndefined(arg) {
+ return arg === void 0;
+ }
+ exports.isUndefined = isUndefined;
+
+ function isRegExp(re) {
+ return isObject(re) && objectToString(re) === '[object RegExp]';
+ }
+ exports.isRegExp = isRegExp;
+
+ function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
+ }
+ exports.isObject = isObject;
+
+ function isDate(d) {
+ return isObject(d) && objectToString(d) === '[object Date]';
+ }
+ exports.isDate = isDate;
+
+ function isError(e) {
+ return isObject(e) &&
+ (objectToString(e) === '[object Error]' || e instanceof Error);
+ }
+ exports.isError = isError;
+
+ function isFunction(arg) {
+ return typeof arg === 'function';
+ }
+ exports.isFunction = isFunction;
+
+ function isPrimitive(arg) {
+ return arg === null ||
+ typeof arg === 'boolean' ||
+ typeof arg === 'number' ||
+ typeof arg === 'string' ||
+ typeof arg === 'symbol' || // ES6 symbol
+ typeof arg === 'undefined';
+ }
+ exports.isPrimitive = isPrimitive;
+
+ exports.isBuffer = _dereq_('./support/isBuffer');
+
+ function objectToString(o) {
+ return Object.prototype.toString.call(o);
+ }
+
+
+ function pad(n) {
+ return n < 10 ? '0' + n.toString(10) : n.toString(10);
+ }
+
+
+ var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+ 'Oct', 'Nov', 'Dec'];
+
+ // 26 Feb 16:19:34
+ function timestamp() {
+ var d = new Date();
+ var time = [pad(d.getHours()),
+ pad(d.getMinutes()),
+ pad(d.getSeconds())].join(':');
+ return [d.getDate(), months[d.getMonth()], time].join(' ');
+ }
+
+
+ // log is just a thin wrapper to console.log that prepends a timestamp
+ exports.log = function () {
+ console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
+ };
+
+
+ /**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
+ * during bootstrapping this function needs to be rewritten using some native
+ * functions as prototype setup using normal JavaScript does not work as
+ * expected during bootstrapping (see mirror.js in r114903).
+ *
+ * @param {function} ctor Constructor function which needs to inherit the
+ * prototype.
+ * @param {function} superCtor Constructor function to inherit prototype from.
+ */
+ exports.inherits = _dereq_('inherits');
+
+ exports._extend = function (origin, add) {
+ // Don't do anything if add isn't an object
+ if (!add || !isObject(add)) return origin;
+
+ var keys = Object.keys(add);
+ var i = keys.length;
+ while (i--) {
+ origin[keys[i]] = add[keys[i]];
+ }
+ return origin;
+ };
+
+ function hasOwnProperty(obj, prop) {
+ return Object.prototype.hasOwnProperty.call(obj, prop);
+ }
+
+ }).call(this, _dereq_('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+ }, { "./support/isBuffer": 4, "_process": 3, "inherits": 2 }], 6: [function (_dereq_, module, exports) {
+ // A recursive descent parser operates by defining functions for all
+ // syntactic elements, and recursively calling those, each function
+ // advancing the input stream and returning an AST node. Precedence
+ // of constructs (for example, the fact that `!x[1]` means `!(x[1])`
+ // instead of `(!x)[1]` is handled by the fact that the parser
+ // function that parses unary prefix operators is called first, and
+ // in turn calls the function that parses `[]` subscripts — that
+ // way, it'll receive the node for `x[1]` already parsed, and wraps
+ // *that* in the unary operator node.
+ //
+ // Acorn uses an [operator precedence parser][opp] to handle binary
+ // operator precedence, because it is much more compact than using
+ // the technique outlined above, which uses different, nesting
+ // functions to specify precedence, for all of the ten binary
+ // precedence levels that JavaScript defines.
+ //
+ // [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
+
+ "use strict";
+
+ var tt = _dereq_("./tokentype").types;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var reservedWords = _dereq_("./identifier").reservedWords;
+
+ var has = _dereq_("./util").has;
+
+ var pp = Parser.prototype;
+
+ // Check if property name clashes with already added.
+ // Object/class getters and setters are not allowed to clash —
+ // either with each other or with an init property — and in
+ // strict mode, init properties are also not allowed to be repeated.
+
+ pp.checkPropClash = function (prop, propHash) {
+ if (this.options.ecmaVersion >= 6) return;
+ var key = prop.key,
+ name = undefined;
+ switch (key.type) {
+ case "Identifier":
+ name = key.name; break;
+ case "Literal":
+ name = String(key.value); break;
+ default:
+ return;
+ }
+ var kind = prop.kind || "init",
+ other = undefined;
+ if (has(propHash, name)) {
+ other = propHash[name];
+ var isGetSet = kind !== "init";
+ if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) this.raise(key.start, "Redefinition of property");
+ } else {
+ other = propHash[name] = {
+ init: false,
+ get: false,
+ set: false
+ };
+ }
+ other[kind] = true;
+ };
+
+ // ### Expression parsing
+
+ // These nest, from the most general expression type at the top to
+ // 'atomic', nondivisible expression types at the bottom. Most of
+ // the functions will simply let the function(s) below them parse,
+ // and, *if* the syntactic construct they handle is present, wrap
+ // the AST node that the inner parser gave them in another node.
+
+ // Parse a full expression. The optional arguments are used to
+ // forbid the `in` operator (in for loops initalization expressions)
+ // and provide reference for storing '=' operator inside shorthand
+ // property assignment in contexts where both object expression
+ // and object pattern might appear (so it's possible to raise
+ // delayed syntax error at correct position).
+
+ pp.parseExpression = function (noIn, refShorthandDefaultPos) {
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ var expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);
+ if (this.type === tt.comma) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.expressions = [expr];
+ while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos));
+ return this.finishNode(node, "SequenceExpression");
+ }
+ return expr;
+ };
+
+ // Parse an assignment expression. This includes applications of
+ // operators like `+=`.
+
+ pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) {
+ if (this.type == tt._yield && this.inGenerator) return this.parseYield();
+
+ var failOnShorthandAssign = undefined;
+ if (!refShorthandDefaultPos) {
+ refShorthandDefaultPos = { start: 0 };
+ failOnShorthandAssign = true;
+ } else {
+ failOnShorthandAssign = false;
+ }
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ if (this.type == tt.parenL || this.type == tt.name) this.potentialArrowAt = this.start;
+ var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos);
+ if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc);
+ if (this.type.isAssign) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.operator = this.value;
+ node.left = this.type === tt.eq ? this.toAssignable(left) : left;
+ refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly
+ this.checkLVal(left);
+ this.next();
+ node.right = this.parseMaybeAssign(noIn);
+ return this.finishNode(node, "AssignmentExpression");
+ } else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
+ this.unexpected(refShorthandDefaultPos.start);
+ }
+ return left;
+ };
+
+ // Parse a ternary conditional (`?:`) operator.
+
+ pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) {
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ var expr = this.parseExprOps(noIn, refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
+ if (this.eat(tt.question)) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.test = expr;
+ node.consequent = this.parseMaybeAssign();
+ this.expect(tt.colon);
+ node.alternate = this.parseMaybeAssign(noIn);
+ return this.finishNode(node, "ConditionalExpression");
+ }
+ return expr;
+ };
+
+ // Start the precedence parser.
+
+ pp.parseExprOps = function (noIn, refShorthandDefaultPos) {
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ var expr = this.parseMaybeUnary(refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
+ return this.parseExprOp(expr, startPos, startLoc, -1, noIn);
+ };
+
+ // Parse binary operators with the operator precedence parsing
+ // algorithm. `left` is the left-hand side of the operator.
+ // `minPrec` provides context that allows the function to stop and
+ // defer further parser to one of its callers when it encounters an
+ // operator that has a lower precedence than the set it is parsing.
+
+ pp.parseExprOp = function (left, leftStartPos, leftStartLoc, minPrec, noIn) {
+ var prec = this.type.binop;
+ if (Array.isArray(leftStartPos)) {
+ if (this.options.locations && noIn === undefined) {
+ // shift arguments to left by one
+ noIn = minPrec;
+ minPrec = leftStartLoc;
+ // flatten leftStartPos
+ leftStartLoc = leftStartPos[1];
+ leftStartPos = leftStartPos[0];
+ }
+ }
+ if (prec != null && (!noIn || this.type !== tt._in)) {
+ if (prec > minPrec) {
+ var node = this.startNodeAt(leftStartPos, leftStartLoc);
+ node.left = left;
+ node.operator = this.value;
+ var op = this.type;
+ this.next();
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn);
+ this.finishNode(node, op === tt.logicalOR || op === tt.logicalAND ? "LogicalExpression" : "BinaryExpression");
+ return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn);
+ }
+ }
+ return left;
+ };
+
+ // Parse unary operators, both prefix and postfix.
+
+ pp.parseMaybeUnary = function (refShorthandDefaultPos) {
+ if (this.type.prefix) {
+ var node = this.startNode(),
+ update = this.type === tt.incDec;
+ node.operator = this.value;
+ node.prefix = true;
+ this.next();
+ node.argument = this.parseMaybeUnary();
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
+ if (update) this.checkLVal(node.argument); else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") this.raise(node.start, "Deleting local variable in strict mode");
+ return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
+ }
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ var expr = this.parseExprSubscripts(refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
+ while (this.type.postfix && !this.canInsertSemicolon()) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.operator = this.value;
+ node.prefix = false;
+ node.argument = expr;
+ this.checkLVal(expr);
+ this.next();
+ expr = this.finishNode(node, "UpdateExpression");
+ }
+ return expr;
+ };
+
+ // Parse call, dot, and `[]`-subscript expressions.
+
+ pp.parseExprSubscripts = function (refShorthandDefaultPos) {
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ var expr = this.parseExprAtom(refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
+ return this.parseSubscripts(expr, startPos, startLoc);
+ };
+
+ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
+ if (Array.isArray(startPos)) {
+ if (this.options.locations && noCalls === undefined) {
+ // shift arguments to left by one
+ noCalls = startLoc;
+ // flatten startPos
+ startLoc = startPos[1];
+ startPos = startPos[0];
+ }
+ }
+ for (; ;) {
+ if (this.eat(tt.dot)) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.object = base;
+ node.property = this.parseIdent(true);
+ node.computed = false;
+ base = this.finishNode(node, "MemberExpression");
+ } else if (this.eat(tt.bracketL)) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.object = base;
+ node.property = this.parseExpression();
+ node.computed = true;
+ this.expect(tt.bracketR);
+ base = this.finishNode(node, "MemberExpression");
+ } else if (!noCalls && this.eat(tt.parenL)) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.callee = base;
+ node.arguments = this.parseExprList(tt.parenR, false);
+ base = this.finishNode(node, "CallExpression");
+ } else if (this.type === tt.backQuote) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.tag = base;
+ node.quasi = this.parseTemplate();
+ base = this.finishNode(node, "TaggedTemplateExpression");
+ } else {
+ return base;
+ }
+ }
+ };
+
+ // Parse an atomic expression — either a single token that is an
+ // expression, an expression started by a keyword like `function` or
+ // `new`, or an expression wrapped in punctuation like `()`, `[]`,
+ // or `{}`.
+
+ pp.parseExprAtom = function (refShorthandDefaultPos) {
+ var node = undefined,
+ canBeArrow = this.potentialArrowAt == this.start;
+ switch (this.type) {
+ case tt._this:
+ case tt._super:
+ var type = this.type === tt._this ? "ThisExpression" : "Super";
+ node = this.startNode();
+ this.next();
+ return this.finishNode(node, type);
+
+ case tt._yield:
+ if (this.inGenerator) this.unexpected();
+
+ case tt.name:
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ var id = this.parseIdent(this.type !== tt.name);
+ if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]);
+ return id;
+
+ case tt.regexp:
+ var value = this.value;
+ node = this.parseLiteral(value.value);
+ node.regex = { pattern: value.pattern, flags: value.flags };
+ return node;
+
+ case tt.num: case tt.string:
+ return this.parseLiteral(this.value);
+
+ case tt._null: case tt._true: case tt._false:
+ node = this.startNode();
+ node.value = this.type === tt._null ? null : this.type === tt._true;
+ node.raw = this.type.keyword;
+ this.next();
+ return this.finishNode(node, "Literal");
+
+ case tt.parenL:
+ return this.parseParenAndDistinguishExpression(canBeArrow);
+
+ case tt.bracketL:
+ node = this.startNode();
+ this.next();
+ // check whether this is array comprehension or regular array
+ if (this.options.ecmaVersion >= 7 && this.type === tt._for) {
+ return this.parseComprehension(node, false);
+ }
+ node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos);
+ return this.finishNode(node, "ArrayExpression");
+
+ case tt.braceL:
+ return this.parseObj(false, refShorthandDefaultPos);
+
+ case tt._function:
+ node = this.startNode();
+ this.next();
+ return this.parseFunction(node, false);
+
+ case tt._class:
+ return this.parseClass(this.startNode(), false);
+
+ case tt._new:
+ return this.parseNew();
+
+ case tt.backQuote:
+ return this.parseTemplate();
+
+ default:
+ this.unexpected();
+ }
+ };
+
+ pp.parseLiteral = function (value) {
+ var node = this.startNode();
+ node.value = value;
+ node.raw = this.input.slice(this.start, this.end);
+ this.next();
+ return this.finishNode(node, "Literal");
+ };
+
+ pp.parseParenExpression = function () {
+ this.expect(tt.parenL);
+ var val = this.parseExpression();
+ this.expect(tt.parenR);
+ return val;
+ };
+
+ pp.parseParenAndDistinguishExpression = function (canBeArrow) {
+ var startPos = this.start,
+ startLoc = this.startLoc,
+ val = undefined;
+ if (this.options.ecmaVersion >= 6) {
+ this.next();
+
+ if (this.options.ecmaVersion >= 7 && this.type === tt._for) {
+ return this.parseComprehension(this.startNodeAt(startPos, startLoc), true);
+ }
+
+ var innerStartPos = this.start,
+ innerStartLoc = this.startLoc;
+ var exprList = [],
+ first = true;
+ var refShorthandDefaultPos = { start: 0 },
+ spreadStart = undefined,
+ innerParenStart = undefined;
+ while (this.type !== tt.parenR) {
+ first ? first = false : this.expect(tt.comma);
+ if (this.type === tt.ellipsis) {
+ spreadStart = this.start;
+ exprList.push(this.parseParenItem(this.parseRest()));
+ break;
+ } else {
+ if (this.type === tt.parenL && !innerParenStart) {
+ innerParenStart = this.start;
+ }
+ exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem));
+ }
+ }
+ var innerEndPos = this.start,
+ innerEndLoc = this.startLoc;
+ this.expect(tt.parenR);
+
+ if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
+ if (innerParenStart) this.unexpected(innerParenStart);
+ return this.parseParenArrowList(startPos, startLoc, exprList);
+ }
+
+ if (!exprList.length) this.unexpected(this.lastTokStart);
+ if (spreadStart) this.unexpected(spreadStart);
+ if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
+
+ if (exprList.length > 1) {
+ val = this.startNodeAt(innerStartPos, innerStartLoc);
+ val.expressions = exprList;
+ this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc);
+ } else {
+ val = exprList[0];
+ }
+ } else {
+ val = this.parseParenExpression();
+ }
+
+ if (this.options.preserveParens) {
+ var par = this.startNodeAt(startPos, startLoc);
+ par.expression = val;
+ return this.finishNode(par, "ParenthesizedExpression");
+ } else {
+ return val;
+ }
+ };
+
+ pp.parseParenItem = function (item) {
+ return item;
+ };
+
+ pp.parseParenArrowList = function (startPos, startLoc, exprList) {
+ return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList);
+ };
+
+ // New's precedence is slightly tricky. It must allow its argument
+ // to be a `[]` or dot subscript expression, but not a call — at
+ // least, not without wrapping it in parentheses. Thus, it uses the
+
+ var empty = [];
+
+ pp.parseNew = function () {
+ var node = this.startNode();
+ var meta = this.parseIdent(true);
+ if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {
+ node.meta = meta;
+ node.property = this.parseIdent(true);
+ if (node.property.name !== "target") this.raise(node.property.start, "The only valid meta property for new is new.target");
+ return this.finishNode(node, "MetaProperty");
+ }
+ var startPos = this.start,
+ startLoc = this.startLoc;
+ node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true);
+ if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false); else node.arguments = empty;
+ return this.finishNode(node, "NewExpression");
+ };
+
+ // Parse template expression.
+
+ pp.parseTemplateElement = function () {
+ var elem = this.startNode();
+ elem.value = {
+ raw: this.input.slice(this.start, this.end),
+ cooked: this.value
+ };
+ this.next();
+ elem.tail = this.type === tt.backQuote;
+ return this.finishNode(elem, "TemplateElement");
+ };
+
+ pp.parseTemplate = function () {
+ var node = this.startNode();
+ this.next();
+ node.expressions = [];
+ var curElt = this.parseTemplateElement();
+ node.quasis = [curElt];
+ while (!curElt.tail) {
+ this.expect(tt.dollarBraceL);
+ node.expressions.push(this.parseExpression());
+ this.expect(tt.braceR);
+ node.quasis.push(curElt = this.parseTemplateElement());
+ }
+ this.next();
+ return this.finishNode(node, "TemplateLiteral");
+ };
+
+ // Parse an object literal or binding pattern.
+
+ pp.parseObj = function (isPattern, refShorthandDefaultPos) {
+ var node = this.startNode(),
+ first = true,
+ propHash = {};
+ node.properties = [];
+ this.next();
+ while (!this.eat(tt.braceR)) {
+ if (!first) {
+ this.expect(tt.comma);
+ if (this.afterTrailingComma(tt.braceR)) break;
+ } else first = false;
+
+ var prop = this.startNode(),
+ isGenerator = undefined,
+ startPos = undefined,
+ startLoc = undefined;
+ if (this.options.ecmaVersion >= 6) {
+ prop.method = false;
+ prop.shorthand = false;
+ if (isPattern || refShorthandDefaultPos) {
+ startPos = this.start;
+ startLoc = this.startLoc;
+ }
+ if (!isPattern) isGenerator = this.eat(tt.star);
+ }
+ this.parsePropertyName(prop);
+ this.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos);
+ this.checkPropClash(prop, propHash);
+ node.properties.push(this.finishNode(prop, "Property"));
+ }
+ return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
+ };
+
+ pp.parsePropertyValue = function (prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos) {
+ if (this.eat(tt.colon)) {
+ prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos);
+ prop.kind = "init";
+ } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {
+ if (isPattern) this.unexpected();
+ prop.kind = "init";
+ prop.method = true;
+ prop.value = this.parseMethod(isGenerator);
+ } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type != tt.comma && this.type != tt.braceR)) {
+ if (isGenerator || isPattern) this.unexpected();
+ prop.kind = prop.key.name;
+ this.parsePropertyName(prop);
+ prop.value = this.parseMethod(false);
+ } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
+ prop.kind = "init";
+ if (isPattern) {
+ if (this.isKeyword(prop.key.name) || this.strict && (reservedWords.strictBind(prop.key.name) || reservedWords.strict(prop.key.name)) || !this.options.allowReserved && this.isReservedWord(prop.key.name)) this.raise(prop.key.start, "Binding " + prop.key.name);
+ prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key);
+ } else if (this.type === tt.eq && refShorthandDefaultPos) {
+ if (!refShorthandDefaultPos.start) refShorthandDefaultPos.start = this.start;
+ prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key);
+ } else {
+ prop.value = prop.key;
+ }
+ prop.shorthand = true;
+ } else this.unexpected();
+ };
+
+ pp.parsePropertyName = function (prop) {
+ if (this.options.ecmaVersion >= 6) {
+ if (this.eat(tt.bracketL)) {
+ prop.computed = true;
+ prop.key = this.parseMaybeAssign();
+ this.expect(tt.bracketR);
+ return prop.key;
+ } else {
+ prop.computed = false;
+ }
+ }
+ return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true);
+ };
+
+ // Initialize empty function node.
+
+ pp.initFunction = function (node) {
+ node.id = null;
+ if (this.options.ecmaVersion >= 6) {
+ node.generator = false;
+ node.expression = false;
+ }
+ };
+
+ // Parse object or class method.
+
+ pp.parseMethod = function (isGenerator) {
+ var node = this.startNode();
+ this.initFunction(node);
+ this.expect(tt.parenL);
+ node.params = this.parseBindingList(tt.parenR, false, false);
+ var allowExpressionBody = undefined;
+ if (this.options.ecmaVersion >= 6) {
+ node.generator = isGenerator;
+ allowExpressionBody = true;
+ } else {
+ allowExpressionBody = false;
+ }
+ this.parseFunctionBody(node, allowExpressionBody);
+ return this.finishNode(node, "FunctionExpression");
+ };
+
+ // Parse arrow function expression with given parameters.
+
+ pp.parseArrowExpression = function (node, params) {
+ this.initFunction(node);
+ node.params = this.toAssignableList(params, true);
+ this.parseFunctionBody(node, true);
+ return this.finishNode(node, "ArrowFunctionExpression");
+ };
+
+ // Parse function body and check parameters.
+
+ pp.parseFunctionBody = function (node, allowExpression) {
+ var isExpression = allowExpression && this.type !== tt.braceL;
+
+ if (isExpression) {
+ node.body = this.parseMaybeAssign();
+ node.expression = true;
+ } else {
+ // Start a new scope with regard to labels and the `inFunction`
+ // flag (restore them to their old value afterwards).
+ var oldInFunc = this.inFunction,
+ oldInGen = this.inGenerator,
+ oldLabels = this.labels;
+ this.inFunction = true; this.inGenerator = node.generator; this.labels = [];
+ node.body = this.parseBlock(true);
+ node.expression = false;
+ this.inFunction = oldInFunc; this.inGenerator = oldInGen; this.labels = oldLabels;
+ }
+
+ // If this is a strict mode function, verify that argument names
+ // are not repeated, and it does not try to bind the words `eval`
+ // or `arguments`.
+ if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) {
+ var nameHash = {},
+ oldStrict = this.strict;
+ this.strict = true;
+ if (node.id) this.checkLVal(node.id, true);
+ for (var i = 0; i < node.params.length; i++) {
+ this.checkLVal(node.params[i], true, nameHash);
+ } this.strict = oldStrict;
+ }
+ };
+
+ // Parses a comma-separated list of expressions, and returns them as
+ // an array. `close` is the token type that ends the list, and
+ // `allowEmpty` can be turned on to allow subsequent commas with
+ // nothing in between them to be parsed as `null` (which is needed
+ // for array literals).
+
+ pp.parseExprList = function (close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) {
+ var elts = [],
+ first = true;
+ while (!this.eat(close)) {
+ if (!first) {
+ this.expect(tt.comma);
+ if (allowTrailingComma && this.afterTrailingComma(close)) break;
+ } else first = false;
+
+ if (allowEmpty && this.type === tt.comma) {
+ elts.push(null);
+ } else {
+ if (this.type === tt.ellipsis) elts.push(this.parseSpread(refShorthandDefaultPos)); else elts.push(this.parseMaybeAssign(false, refShorthandDefaultPos));
+ }
+ }
+ return elts;
+ };
+
+ // Parse the next token as an identifier. If `liberal` is true (used
+ // when parsing properties), it will also convert keywords into
+ // identifiers.
+
+ pp.parseIdent = function (liberal) {
+ var node = this.startNode();
+ if (liberal && this.options.allowReserved == "never") liberal = false;
+ if (this.type === tt.name) {
+ if (!liberal && (!this.options.allowReserved && this.isReservedWord(this.value) || this.strict && reservedWords.strict(this.value) && (this.options.ecmaVersion >= 6 || this.input.slice(this.start, this.end).indexOf("\\") == -1))) this.raise(this.start, "The keyword '" + this.value + "' is reserved");
+ node.name = this.value;
+ } else if (liberal && this.type.keyword) {
+ node.name = this.type.keyword;
+ } else {
+ this.unexpected();
+ }
+ this.next();
+ return this.finishNode(node, "Identifier");
+ };
+
+ // Parses yield expression inside generator.
+
+ pp.parseYield = function () {
+ var node = this.startNode();
+ this.next();
+ if (this.type == tt.semi || this.canInsertSemicolon() || this.type != tt.star && !this.type.startsExpr) {
+ node.delegate = false;
+ node.argument = null;
+ } else {
+ node.delegate = this.eat(tt.star);
+ node.argument = this.parseMaybeAssign();
+ }
+ return this.finishNode(node, "YieldExpression");
+ };
+
+ // Parses array and generator comprehensions.
+
+ pp.parseComprehension = function (node, isGenerator) {
+ node.blocks = [];
+ while (this.type === tt._for) {
+ var block = this.startNode();
+ this.next();
+ this.expect(tt.parenL);
+ block.left = this.parseBindingAtom();
+ this.checkLVal(block.left, true);
+ this.expectContextual("of");
+ block.right = this.parseExpression();
+ this.expect(tt.parenR);
+ node.blocks.push(this.finishNode(block, "ComprehensionBlock"));
+ }
+ node.filter = this.eat(tt._if) ? this.parseParenExpression() : null;
+ node.body = this.parseExpression();
+ this.expect(isGenerator ? tt.parenR : tt.bracketR);
+ node.generator = isGenerator;
+ return this.finishNode(node, "ComprehensionExpression");
+ };
+
+ }, { "./identifier": 7, "./state": 13, "./tokentype": 17, "./util": 18 }], 7: [function (_dereq_, module, exports) {
+
+
+ // Test whether a given character code starts an identifier.
+
+ "use strict";
+
+ exports.isIdentifierStart = isIdentifierStart;
+
+ // Test whether a given character is part of an identifier.
+
+ exports.isIdentifierChar = isIdentifierChar;
+ exports.__esModule = true;
+ // This is a trick taken from Esprima. It turns out that, on
+ // non-Chrome browsers, to check whether a string is in a set, a
+ // predicate containing a big ugly `switch` statement is faster than
+ // a regular expression, and on Chrome the two are about on par.
+ // This function uses `eval` (non-lexical) to produce such a
+ // predicate from a space-separated string of words.
+ //
+ // It starts by sorting the words by length.
+
+ function makePredicate(words) {
+ words = words.split(" ");
+ var f = "",
+ cats = [];
+ out: for (var i = 0; i < words.length; ++i) {
+ for (var j = 0; j < cats.length; ++j) {
+ if (cats[j][0].length == words[i].length) {
+ cats[j].push(words[i]);
+ continue out;
+ }
+ } cats.push([words[i]]);
+ }
+ function compareTo(arr) {
+ if (arr.length == 1) {
+ return f += "return str === " + JSON.stringify(arr[0]) + ";";
+ } f += "switch(str){";
+ for (var i = 0; i < arr.length; ++i) {
+ f += "case " + JSON.stringify(arr[i]) + ":";
+ } f += "return true}return false;";
+ }
+
+ // When there are more than three length categories, an outer
+ // switch first dispatches on the lengths, to save on comparisons.
+
+ if (cats.length > 3) {
+ cats.sort(function (a, b) {
+ return b.length - a.length;
+ });
+ f += "switch(str.length){";
+ for (var i = 0; i < cats.length; ++i) {
+ var cat = cats[i];
+ f += "case " + cat[0].length + ":";
+ compareTo(cat);
+ }
+ f += "}"
+
+ // Otherwise, simply generate a flat `switch` statement.
+
+ ;
+ } else {
+ compareTo(words);
+ }
+ return new Function("str", f);
+ }
+
+ // Reserved word lists for various dialects of the language
+
+ var reservedWords = {
+ 3: makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"),
+ 5: makePredicate("class enum extends super const export import"),
+ 6: makePredicate("enum await"),
+ strict: makePredicate("implements interface let package private protected public static yield"),
+ strictBind: makePredicate("eval arguments")
+ };
+
+ exports.reservedWords = reservedWords;
+ // And the keywords
+
+ var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this";
+
+ var keywords = {
+ 5: makePredicate(ecma5AndLessKeywords),
+ 6: makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super")
+ };
+
+ exports.keywords = keywords;
+ // ## Character categories
+
+ // Big ugly regular expressions that match characters in the
+ // whitespace, identifier, and identifier-start categories. These
+ // are only applied when a character is found to actually have a
+ // code point above 128.
+ // Generated by `tools/generate-identifier-regex.js`.
+
+ var nonASCIIidentifierStartChars = "ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢲऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞭꞰꞱꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭟꭤꭥꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ";
+ var nonASCIIidentifierChars = "·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఃా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ංඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ູົຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏ᦰ-ᧀᧈᧉ᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷼-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-꣄꣐-꣙꣠-꣱꤀-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︭︳︴﹍-﹏0-9_";
+
+ var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
+ var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
+
+ nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
+
+ // These are a run-length and offset encoded representation of the
+ // >0xffff code points that are a valid part of identifiers. The
+ // offset starts at 0x10000, and each pair of numbers represents an
+ // offset to the next range, and then a size of the range. They were
+ // generated by tools/generate-identifier-regex.js
+ var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 99, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 98, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 955, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 38, 17, 2, 24, 133, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 32, 4, 287, 47, 21, 1, 2, 0, 185, 46, 82, 47, 21, 0, 60, 42, 502, 63, 32, 0, 449, 56, 1288, 920, 104, 110, 2962, 1070, 13266, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67, 12, 16481, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 1340, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 16355, 541];
+ var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 16, 9, 83, 11, 168, 11, 6, 9, 8, 2, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 316, 19, 13, 9, 214, 6, 3, 8, 112, 16, 16, 9, 82, 12, 9, 9, 535, 9, 20855, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 4305, 6, 792618, 239];
+
+ // This has a complexity linear to the value of the code. The
+ // assumption is that looking up astral identifier characters is
+ // rare.
+ function isInAstralSet(code, set) {
+ var pos = 65536;
+ for (var i = 0; i < set.length; i += 2) {
+ pos += set[i];
+ if (pos > code) {
+ return false;
+ } pos += set[i + 1];
+ if (pos >= code) {
+ return true;
+ }
+ }
+ }
+ function isIdentifierStart(code, astral) {
+ if (code < 65) {
+ return code === 36;
+ } if (code < 91) {
+ return true;
+ } if (code < 97) {
+ return code === 95;
+ } if (code < 123) {
+ return true;
+ } if (code <= 65535) {
+ return code >= 170 && nonASCIIidentifierStart.test(String.fromCharCode(code));
+ } if (astral === false) {
+ return false;
+ } return isInAstralSet(code, astralIdentifierStartCodes);
+ }
+
+ function isIdentifierChar(code, astral) {
+ if (code < 48) {
+ return code === 36;
+ } if (code < 58) {
+ return true;
+ } if (code < 65) {
+ return false;
+ } if (code < 91) {
+ return true;
+ } if (code < 97) {
+ return code === 95;
+ } if (code < 123) {
+ return true;
+ } if (code <= 65535) {
+ return code >= 170 && nonASCIIidentifier.test(String.fromCharCode(code));
+ } if (astral === false) {
+ return false;
+ } return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
+ }
+
+ }, {}], 8: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
+
+ // The `getLineInfo` function is mostly useful when the
+ // `locations` option is off (for performance reasons) and you
+ // want to find the line/column position for a given character
+ // offset. `input` should be the code string that the offset refers
+ // into.
+
+ exports.getLineInfo = getLineInfo;
+ exports.__esModule = true;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var lineBreakG = _dereq_("./whitespace").lineBreakG;
+
+ var deprecate = _dereq_("util").deprecate;
+
+ // These are used when `options.locations` is on, for the
+ // `startLoc` and `endLoc` properties.
+
+ var Position = exports.Position = (function () {
+ function Position(line, col) {
+ _classCallCheck(this, Position);
+
+ this.line = line;
+ this.column = col;
+ }
+
+ Position.prototype.offset = function offset(n) {
+ return new Position(this.line, this.column + n);
+ };
+
+ return Position;
+ })();
+
+ var SourceLocation = exports.SourceLocation = function SourceLocation(p, start, end) {
+ _classCallCheck(this, SourceLocation);
+
+ this.start = start;
+ this.end = end;
+ if (p.sourceFile !== null) this.source = p.sourceFile;
+ };
+
+ function getLineInfo(input, offset) {
+ for (var line = 1, cur = 0; ;) {
+ lineBreakG.lastIndex = cur;
+ var match = lineBreakG.exec(input);
+ if (match && match.index < offset) {
+ ++line;
+ cur = match.index + match[0].length;
+ } else {
+ return new Position(line, offset - cur);
+ }
+ }
+ }
+
+ var pp = Parser.prototype;
+
+ // This function is used to raise exceptions on parse errors. It
+ // takes an offset integer (into the current `input`) to indicate
+ // the location of the error, attaches the position to the end
+ // of the error message, and then raises a `SyntaxError` with that
+ // message.
+
+ pp.raise = function (pos, message) {
+ var loc = getLineInfo(this.input, pos);
+ message += " (" + loc.line + ":" + loc.column + ")";
+ var err = new SyntaxError(message);
+ err.pos = pos; err.loc = loc; err.raisedAt = this.pos;
+ throw err;
+ };
+
+ pp.curPosition = function () {
+ return new Position(this.curLine, this.pos - this.lineStart);
+ };
+
+ pp.markPosition = function () {
+ return this.options.locations ? [this.start, this.startLoc] : this.start;
+ };
+
+ }, { "./state": 13, "./whitespace": 19, "util": 5 }], 9: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var tt = _dereq_("./tokentype").types;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var reservedWords = _dereq_("./identifier").reservedWords;
+
+ var has = _dereq_("./util").has;
+
+ var pp = Parser.prototype;
+
+ // Convert existing expression atom to assignable pattern
+ // if possible.
+
+ pp.toAssignable = function (node, isBinding) {
+ if (this.options.ecmaVersion >= 6 && node) {
+ switch (node.type) {
+ case "Identifier":
+ case "ObjectPattern":
+ case "ArrayPattern":
+ case "AssignmentPattern":
+ break;
+
+ case "ObjectExpression":
+ node.type = "ObjectPattern";
+ for (var i = 0; i < node.properties.length; i++) {
+ var prop = node.properties[i];
+ if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter");
+ this.toAssignable(prop.value, isBinding);
+ }
+ break;
+
+ case "ArrayExpression":
+ node.type = "ArrayPattern";
+ this.toAssignableList(node.elements, isBinding);
+ break;
+
+ case "AssignmentExpression":
+ if (node.operator === "=") {
+ node.type = "AssignmentPattern";
+ } else {
+ this.raise(node.left.end, "Only '=' operator can be used for specifying default value.");
+ }
+ break;
+
+ case "ParenthesizedExpression":
+ node.expression = this.toAssignable(node.expression, isBinding);
+ break;
+
+ case "MemberExpression":
+ if (!isBinding) break;
+
+ default:
+ this.raise(node.start, "Assigning to rvalue");
+ }
+ }
+ return node;
+ };
+
+ // Convert list of expression atoms to binding list.
+
+ pp.toAssignableList = function (exprList, isBinding) {
+ var end = exprList.length;
+ if (end) {
+ var last = exprList[end - 1];
+ if (last && last.type == "RestElement") {
+ --end;
+ } else if (last && last.type == "SpreadElement") {
+ last.type = "RestElement";
+ var arg = last.argument;
+ this.toAssignable(arg, isBinding);
+ if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") this.unexpected(arg.start);
+ --end;
+ }
+ }
+ for (var i = 0; i < end; i++) {
+ var elt = exprList[i];
+ if (elt) this.toAssignable(elt, isBinding);
+ }
+ return exprList;
+ };
+
+ // Parses spread element.
+
+ pp.parseSpread = function (refShorthandDefaultPos) {
+ var node = this.startNode();
+ this.next();
+ node.argument = this.parseMaybeAssign(refShorthandDefaultPos);
+ return this.finishNode(node, "SpreadElement");
+ };
+
+ pp.parseRest = function () {
+ var node = this.startNode();
+ this.next();
+ node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected();
+ return this.finishNode(node, "RestElement");
+ };
+
+ // Parses lvalue (assignable) atom.
+
+ pp.parseBindingAtom = function () {
+ if (this.options.ecmaVersion < 6) return this.parseIdent();
+ switch (this.type) {
+ case tt.name:
+ return this.parseIdent();
+
+ case tt.bracketL:
+ var node = this.startNode();
+ this.next();
+ node.elements = this.parseBindingList(tt.bracketR, true, true);
+ return this.finishNode(node, "ArrayPattern");
+
+ case tt.braceL:
+ return this.parseObj(true);
+
+ default:
+ this.unexpected();
+ }
+ };
+
+ pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) {
+ var elts = [],
+ first = true;
+ while (!this.eat(close)) {
+ if (first) first = false; else this.expect(tt.comma);
+ if (allowEmpty && this.type === tt.comma) {
+ elts.push(null);
+ } else if (allowTrailingComma && this.afterTrailingComma(close)) {
+ break;
+ } else if (this.type === tt.ellipsis) {
+ var rest = this.parseRest();
+ this.parseBindingListItem(rest);
+ elts.push(rest);
+ this.expect(close);
+ break;
+ } else {
+ var elem = this.parseMaybeDefault(this.start, this.startLoc);
+ this.parseBindingListItem(elem);
+ elts.push(elem);
+ }
+ }
+ return elts;
+ };
+
+ pp.parseBindingListItem = function (param) {
+ return param;
+ };
+
+ // Parses assignment pattern around given atom if possible.
+
+ pp.parseMaybeDefault = function (startPos, startLoc, left) {
+ if (Array.isArray(startPos)) {
+ if (this.options.locations && noCalls === undefined) {
+ // shift arguments to left by one
+ left = startLoc;
+ // flatten startPos
+ startLoc = startPos[1];
+ startPos = startPos[0];
+ }
+ }
+ left = left || this.parseBindingAtom();
+ if (!this.eat(tt.eq)) return left;
+ var node = this.startNodeAt(startPos, startLoc);
+ node.operator = "=";
+ node.left = left;
+ node.right = this.parseMaybeAssign();
+ return this.finishNode(node, "AssignmentPattern");
+ };
+
+ // Verify that a node is an lval — something that can be assigned
+ // to.
+
+ pp.checkLVal = function (expr, isBinding, checkClashes) {
+ switch (expr.type) {
+ case "Identifier":
+ if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name))) this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode");
+ if (checkClashes) {
+ if (has(checkClashes, expr.name)) this.raise(expr.start, "Argument name clash in strict mode");
+ checkClashes[expr.name] = true;
+ }
+ break;
+
+ case "MemberExpression":
+ if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression");
+ break;
+
+ case "ObjectPattern":
+ for (var i = 0; i < expr.properties.length; i++) {
+ this.checkLVal(expr.properties[i].value, isBinding, checkClashes);
+ } break;
+
+ case "ArrayPattern":
+ for (var i = 0; i < expr.elements.length; i++) {
+ var elem = expr.elements[i];
+ if (elem) this.checkLVal(elem, isBinding, checkClashes);
+ }
+ break;
+
+ case "AssignmentPattern":
+ this.checkLVal(expr.left, isBinding, checkClashes);
+ break;
+
+ case "RestElement":
+ this.checkLVal(expr.argument, isBinding, checkClashes);
+ break;
+
+ case "ParenthesizedExpression":
+ this.checkLVal(expr.expression, isBinding, checkClashes);
+ break;
+
+ default:
+ this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue");
+ }
+ };
+
+ }, { "./identifier": 7, "./state": 13, "./tokentype": 17, "./util": 18 }], 10: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
+
+ exports.__esModule = true;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var SourceLocation = _dereq_("./location").SourceLocation;
+
+ // Start an AST node, attaching a start offset.
+
+ var pp = Parser.prototype;
+
+ var Node = exports.Node = function Node() {
+ _classCallCheck(this, Node);
+ };
+
+ pp.startNode = function () {
+ var node = new Node();
+ node.start = this.start;
+ if (this.options.locations) node.loc = new SourceLocation(this, this.startLoc);
+ if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile;
+ if (this.options.ranges) node.range = [this.start, 0];
+ return node;
+ };
+
+ pp.startNodeAt = function (pos, loc) {
+ var node = new Node();
+ if (Array.isArray(pos)) {
+ if (this.options.locations && loc === undefined) {
+ // flatten pos
+ loc = pos[1];
+ pos = pos[0];
+ }
+ }
+ node.start = pos;
+ if (this.options.locations) node.loc = new SourceLocation(this, loc);
+ if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile;
+ if (this.options.ranges) node.range = [pos, 0];
+ return node;
+ };
+
+ // Finish an AST node, adding `type` and `end` properties.
+
+ pp.finishNode = function (node, type) {
+ node.type = type;
+ node.end = this.lastTokEnd;
+ if (this.options.locations) node.loc.end = this.lastTokEndLoc;
+ if (this.options.ranges) node.range[1] = this.lastTokEnd;
+ return node;
+ };
+
+ // Finish node at given position
+
+ pp.finishNodeAt = function (node, type, pos, loc) {
+ node.type = type;
+ if (Array.isArray(pos)) {
+ if (this.options.locations && loc === undefined) {
+ // flatten pos
+ loc = pos[1];
+ pos = pos[0];
+ }
+ }
+ node.end = pos;
+ if (this.options.locations) node.loc.end = loc;
+ if (this.options.ranges) node.range[1] = pos;
+ return node;
+ };
+
+ }, { "./location": 8, "./state": 13 }], 11: [function (_dereq_, module, exports) {
+
+
+ // Interpret and default an options object
+
+ "use strict";
+
+ exports.getOptions = getOptions;
+ exports.__esModule = true;
+
+ var _util = _dereq_("./util");
+
+ var has = _util.has;
+ var isArray = _util.isArray;
+
+ var SourceLocation = _dereq_("./location").SourceLocation;
+
+ // A second optional argument can be given to further configure
+ // the parser process. These options are recognized:
+
+ var defaultOptions = {
+ // `ecmaVersion` indicates the ECMAScript version to parse. Must
+ // be either 3, or 5, or 6. This influences support for strict
+ // mode, the set of reserved words, support for getters and
+ // setters and other features.
+ ecmaVersion: 5,
+ // Source type ("script" or "module") for different semantics
+ sourceType: "script",
+ // `onInsertedSemicolon` can be a callback that will be called
+ // when a semicolon is automatically inserted. It will be passed
+ // th position of the comma as an offset, and if `locations` is
+ // enabled, it is given the location as a `{line, column}` object
+ // as second argument.
+ onInsertedSemicolon: null,
+ // `onTrailingComma` is similar to `onInsertedSemicolon`, but for
+ // trailing commas.
+ onTrailingComma: null,
+ // By default, reserved words are not enforced. Disable
+ // `allowReserved` to enforce them. When this option has the
+ // value "never", reserved words and keywords can also not be
+ // used as property names.
+ allowReserved: true,
+ // When enabled, a return at the top level is not considered an
+ // error.
+ allowReturnOutsideFunction: false,
+ // When enabled, import/export statements are not constrained to
+ // appearing at the top of the program.
+ allowImportExportEverywhere: false,
+ // When enabled, hashbang directive in the beginning of file
+ // is allowed and treated as a line comment.
+ allowHashBang: false,
+ // When `locations` is on, `loc` properties holding objects with
+ // `start` and `end` properties in `{line, column}` form (with
+ // line being 1-based and column 0-based) will be attached to the
+ // nodes.
+ locations: false,
+ // A function can be passed as `onToken` option, which will
+ // cause Acorn to call that function with object in the same
+ // format as tokenize() returns. Note that you are not
+ // allowed to call the parser from the callback—that will
+ // corrupt its internal state.
+ onToken: null,
+ // A function can be passed as `onComment` option, which will
+ // cause Acorn to call that function with `(block, text, start,
+ // end)` parameters whenever a comment is skipped. `block` is a
+ // boolean indicating whether this is a block (`/* */`) comment,
+ // `text` is the content of the comment, and `start` and `end` are
+ // character offsets that denote the start and end of the comment.
+ // When the `locations` option is on, two more parameters are
+ // passed, the full `{line, column}` locations of the start and
+ // end of the comments. Note that you are not allowed to call the
+ // parser from the callback—that will corrupt its internal state.
+ onComment: null,
+ // Nodes have their start and end characters offsets recorded in
+ // `start` and `end` properties (directly on the node, rather than
+ // the `loc` object, which holds line/column data. To also add a
+ // [semi-standardized][range] `range` property holding a `[start,
+ // end]` array with the same numbers, set the `ranges` option to
+ // `true`.
+ //
+ // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
+ ranges: false,
+ // It is possible to parse multiple files into a single AST by
+ // passing the tree produced by parsing the first file as
+ // `program` option in subsequent parses. This will add the
+ // toplevel forms of the parsed file to the `Program` (top) node
+ // of an existing parse tree.
+ program: null,
+ // When `locations` is on, you can pass this to record the source
+ // file in every node's `loc` object.
+ sourceFile: null,
+ // This value, if given, is stored in every node, whether
+ // `locations` is on or off.
+ directSourceFile: null,
+ // When enabled, parenthesized expressions are represented by
+ // (non-standard) ParenthesizedExpression nodes
+ preserveParens: false,
+ plugins: {}
+ }; exports.defaultOptions = defaultOptions;
+
+ function getOptions(opts) {
+ var options = {};
+ for (var opt in defaultOptions) {
+ options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt];
+ } if (isArray(options.onToken)) {
+ (function () {
+ var tokens = options.onToken;
+ options.onToken = function (token) {
+ return tokens.push(token);
+ };
+ })();
+ }
+ if (isArray(options.onComment)) options.onComment = pushComment(options, options.onComment);
+
+ return options;
+ }
+
+ function pushComment(options, array) {
+ return function (block, text, start, end, startLoc, endLoc) {
+ var comment = {
+ type: block ? "Block" : "Line",
+ value: text,
+ start: start,
+ end: end
+ };
+ if (options.locations) comment.loc = new SourceLocation(this, startLoc, endLoc);
+ if (options.ranges) comment.range = [start, end];
+ array.push(comment);
+ };
+ }
+
+ }, { "./location": 8, "./util": 18 }], 12: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var tt = _dereq_("./tokentype").types;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var lineBreak = _dereq_("./whitespace").lineBreak;
+
+ var pp = Parser.prototype;
+
+ // ## Parser utilities
+
+ // Test whether a statement node is the string literal `"use strict"`.
+
+ pp.isUseStrict = function (stmt) {
+ return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && stmt.expression.type === "Literal" && stmt.expression.value === "use strict";
+ };
+
+ // Predicate that tests whether the next token is of the given
+ // type, and if yes, consumes it as a side effect.
+
+ pp.eat = function (type) {
+ if (this.type === type) {
+ this.next();
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ // Tests whether parsed token is a contextual keyword.
+
+ pp.isContextual = function (name) {
+ return this.type === tt.name && this.value === name;
+ };
+
+ // Consumes contextual keyword if possible.
+
+ pp.eatContextual = function (name) {
+ return this.value === name && this.eat(tt.name);
+ };
+
+ // Asserts that following token is given contextual keyword.
+
+ pp.expectContextual = function (name) {
+ if (!this.eatContextual(name)) this.unexpected();
+ };
+
+ // Test whether a semicolon can be inserted at the current position.
+
+ pp.canInsertSemicolon = function () {
+ return this.type === tt.eof || this.type === tt.braceR || lineBreak.test(this.input.slice(this.lastTokEnd, this.start));
+ };
+
+ pp.insertSemicolon = function () {
+ if (this.canInsertSemicolon()) {
+ if (this.options.onInsertedSemicolon) this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc);
+ return true;
+ }
+ };
+
+ // Consume a semicolon, or, failing that, see if we are allowed to
+ // pretend that there is a semicolon at this position.
+
+ pp.semicolon = function () {
+ if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected();
+ };
+
+ pp.afterTrailingComma = function (tokType) {
+ if (this.type == tokType) {
+ if (this.options.onTrailingComma) this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc);
+ this.next();
+ return true;
+ }
+ };
+
+ // Expect a token of a given type. If found, consume it, otherwise,
+ // raise an unexpected token error.
+
+ pp.expect = function (type) {
+ this.eat(type) || this.unexpected();
+ };
+
+ // Raise an unexpected token error.
+
+ pp.unexpected = function (pos) {
+ this.raise(pos != null ? pos : this.start, "Unexpected token");
+ };
+
+ }, { "./state": 13, "./tokentype": 17, "./whitespace": 19 }], 13: [function (_dereq_, module, exports) {
+ "use strict";
+
+ exports.Parser = Parser;
+ exports.__esModule = true;
+
+ var _identifier = _dereq_("./identifier");
+
+ var reservedWords = _identifier.reservedWords;
+ var keywords = _identifier.keywords;
+
+ var tt = _dereq_("./tokentype").types;
+
+ var lineBreak = _dereq_("./whitespace").lineBreak;
+
+ function Parser(options, input, startPos) {
+ this.options = options;
+ this.sourceFile = this.options.sourceFile || null;
+ this.isKeyword = keywords[this.options.ecmaVersion >= 6 ? 6 : 5];
+ this.isReservedWord = reservedWords[this.options.ecmaVersion];
+ this.input = input;
+
+ // Load plugins
+ this.loadPlugins(this.options.plugins);
+
+ // Set up token state
+
+ // The current position of the tokenizer in the input.
+ if (startPos) {
+ this.pos = startPos;
+ this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos));
+ this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length;
+ } else {
+ this.pos = this.lineStart = 0;
+ this.curLine = 1;
+ }
+
+ // Properties of the current token:
+ // Its type
+ this.type = tt.eof;
+ // For tokens that include more information than their type, the value
+ this.value = null;
+ // Its start and end offset
+ this.start = this.end = this.pos;
+ // And, if locations are used, the {line, column} object
+ // corresponding to those offsets
+ this.startLoc = this.endLoc = null;
+
+ // Position information for the previous token
+ this.lastTokEndLoc = this.lastTokStartLoc = null;
+ this.lastTokStart = this.lastTokEnd = this.pos;
+
+ // The context stack is used to superficially track syntactic
+ // context to predict whether a regular expression is allowed in a
+ // given position.
+ this.context = this.initialContext();
+ this.exprAllowed = true;
+
+ // Figure out if it's a module code.
+ this.strict = this.inModule = this.options.sourceType === "module";
+
+ // Used to signify the start of a potential arrow function
+ this.potentialArrowAt = -1;
+
+ // Flags to track whether we are in a function, a generator.
+ this.inFunction = this.inGenerator = false;
+ // Labels in scope.
+ this.labels = [];
+
+ // If enabled, skip leading hashbang line.
+ if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === "#!") this.skipLineComment(2);
+ }
+
+ Parser.prototype.extend = function (name, f) {
+ this[name] = f(this[name]);
+ };
+
+ // Registered plugins
+
+ var plugins = {};
+
+ exports.plugins = plugins;
+ Parser.prototype.loadPlugins = function (plugins) {
+ for (var _name in plugins) {
+ var plugin = exports.plugins[_name];
+ if (!plugin) throw new Error("Plugin '" + _name + "' not found");
+ plugin(this, plugins[_name]);
+ }
+ };
+
+ }, { "./identifier": 7, "./tokentype": 17, "./whitespace": 19 }], 14: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var tt = _dereq_("./tokentype").types;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var lineBreak = _dereq_("./whitespace").lineBreak;
+
+ var pp = Parser.prototype;
+
+ // ### Statement parsing
+
+ // Parse a program. Initializes the parser, reads any number of
+ // statements, and wraps them in a Program node. Optionally takes a
+ // `program` argument. If present, the statements will be appended
+ // to its body instead of creating a new node.
+
+ pp.parseTopLevel = function (node) {
+ var first = true;
+ if (!node.body) node.body = [];
+ while (this.type !== tt.eof) {
+ var stmt = this.parseStatement(true, true);
+ node.body.push(stmt);
+ if (first && this.isUseStrict(stmt)) this.setStrict(true);
+ first = false;
+ }
+ this.next();
+ if (this.options.ecmaVersion >= 6) {
+ node.sourceType = this.options.sourceType;
+ }
+ return this.finishNode(node, "Program");
+ };
+
+ var loopLabel = { kind: "loop" },
+ switchLabel = { kind: "switch" };
+
+ // Parse a single statement.
+ //
+ // If expecting a statement and finding a slash operator, parse a
+ // regular expression literal. This is to handle cases like
+ // `if (foo) /blah/.exec(foo)`, where looking at the previous token
+ // does not help.
+
+ pp.parseStatement = function (declaration, topLevel) {
+ var starttype = this.type,
+ node = this.startNode();
+
+ // Most types of statements are recognized by the keyword they
+ // start with. Many are trivial to parse, some require a bit of
+ // complexity.
+
+ switch (starttype) {
+ case tt._break: case tt._continue:
+ return this.parseBreakContinueStatement(node, starttype.keyword);
+ case tt._debugger:
+ return this.parseDebuggerStatement(node);
+ case tt._do:
+ return this.parseDoStatement(node);
+ case tt._for:
+ return this.parseForStatement(node);
+ case tt._function:
+ if (!declaration && this.options.ecmaVersion >= 6) this.unexpected();
+ return this.parseFunctionStatement(node);
+ case tt._class:
+ if (!declaration) this.unexpected();
+ return this.parseClass(node, true);
+ case tt._if:
+ return this.parseIfStatement(node);
+ case tt._return:
+ return this.parseReturnStatement(node);
+ case tt._switch:
+ return this.parseSwitchStatement(node);
+ case tt._throw:
+ return this.parseThrowStatement(node);
+ case tt._try:
+ return this.parseTryStatement(node);
+ case tt._let: case tt._const:
+ if (!declaration) this.unexpected(); // NOTE: falls through to _var
+ case tt._var:
+ return this.parseVarStatement(node, starttype);
+ case tt._while:
+ return this.parseWhileStatement(node);
+ case tt._with:
+ return this.parseWithStatement(node);
+ case tt.braceL:
+ return this.parseBlock();
+ case tt.semi:
+ return this.parseEmptyStatement(node);
+ case tt._export:
+ case tt._import:
+ if (!this.options.allowImportExportEverywhere) {
+ if (!topLevel) this.raise(this.start, "'import' and 'export' may only appear at the top level");
+ if (!this.inModule) this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'");
+ }
+ return starttype === tt._import ? this.parseImport(node) : this.parseExport(node);
+
+ // If the statement does not start with a statement keyword or a
+ // brace, it's an ExpressionStatement or LabeledStatement. We
+ // simply start parsing an expression, and afterwards, if the
+ // next token is a colon and the expression was a simple
+ // Identifier node, we switch to interpreting it as a label.
+ default:
+ var maybeName = this.value,
+ expr = this.parseExpression();
+ if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) return this.parseLabeledStatement(node, maybeName, expr); else return this.parseExpressionStatement(node, expr);
+ }
+ };
+
+ pp.parseBreakContinueStatement = function (node, keyword) {
+ var isBreak = keyword == "break";
+ this.next();
+ if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null; else if (this.type !== tt.name) this.unexpected(); else {
+ node.label = this.parseIdent();
+ this.semicolon();
+ }
+
+ // Verify that there is an actual destination to break or
+ // continue to.
+ for (var i = 0; i < this.labels.length; ++i) {
+ var lab = this.labels[i];
+ if (node.label == null || lab.name === node.label.name) {
+ if (lab.kind != null && (isBreak || lab.kind === "loop")) break;
+ if (node.label && isBreak) break;
+ }
+ }
+ if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword);
+ return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
+ };
+
+ pp.parseDebuggerStatement = function (node) {
+ this.next();
+ this.semicolon();
+ return this.finishNode(node, "DebuggerStatement");
+ };
+
+ pp.parseDoStatement = function (node) {
+ this.next();
+ this.labels.push(loopLabel);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ this.expect(tt._while);
+ node.test = this.parseParenExpression();
+ if (this.options.ecmaVersion >= 6) this.eat(tt.semi); else this.semicolon();
+ return this.finishNode(node, "DoWhileStatement");
+ };
+
+ // Disambiguating between a `for` and a `for`/`in` or `for`/`of`
+ // loop is non-trivial. Basically, we have to parse the init `var`
+ // statement or expression, disallowing the `in` operator (see
+ // the second parameter to `parseExpression`), and then check
+ // whether the next token is `in` or `of`. When there is no init
+ // part (semicolon immediately after the opening parenthesis), it
+ // is a regular `for` loop.
+
+ pp.parseForStatement = function (node) {
+ this.next();
+ this.labels.push(loopLabel);
+ this.expect(tt.parenL);
+ if (this.type === tt.semi) return this.parseFor(node, null);
+ if (this.type === tt._var || this.type === tt._let || this.type === tt._const) {
+ var _init = this.startNode(),
+ varKind = this.type;
+ this.next();
+ this.parseVar(_init, true, varKind);
+ this.finishNode(_init, "VariableDeclaration");
+ if ((this.type === tt._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) && _init.declarations.length === 1 && !(varKind !== tt._var && _init.declarations[0].init)) return this.parseForIn(node, _init);
+ return this.parseFor(node, _init);
+ }
+ var refShorthandDefaultPos = { start: 0 };
+ var init = this.parseExpression(true, refShorthandDefaultPos);
+ if (this.type === tt._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) {
+ this.toAssignable(init);
+ this.checkLVal(init);
+ return this.parseForIn(node, init);
+ } else if (refShorthandDefaultPos.start) {
+ this.unexpected(refShorthandDefaultPos.start);
+ }
+ return this.parseFor(node, init);
+ };
+
+ pp.parseFunctionStatement = function (node) {
+ this.next();
+ return this.parseFunction(node, true);
+ };
+
+ pp.parseIfStatement = function (node) {
+ this.next();
+ node.test = this.parseParenExpression();
+ node.consequent = this.parseStatement(false);
+ node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null;
+ return this.finishNode(node, "IfStatement");
+ };
+
+ pp.parseReturnStatement = function (node) {
+ if (!this.inFunction && !this.options.allowReturnOutsideFunction) this.raise(this.start, "'return' outside of function");
+ this.next();
+
+ // In `return` (and `break`/`continue`), the keywords with
+ // optional arguments, we eagerly look for a semicolon or the
+ // possibility to insert one.
+
+ if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null; else {
+ node.argument = this.parseExpression(); this.semicolon();
+ }
+ return this.finishNode(node, "ReturnStatement");
+ };
+
+ pp.parseSwitchStatement = function (node) {
+ this.next();
+ node.discriminant = this.parseParenExpression();
+ node.cases = [];
+ this.expect(tt.braceL);
+ this.labels.push(switchLabel);
+
+ // Statements under must be grouped (by label) in SwitchCase
+ // nodes. `cur` is used to keep the node that we are currently
+ // adding statements to.
+
+ for (var cur, sawDefault; this.type != tt.braceR;) {
+ if (this.type === tt._case || this.type === tt._default) {
+ var isCase = this.type === tt._case;
+ if (cur) this.finishNode(cur, "SwitchCase");
+ node.cases.push(cur = this.startNode());
+ cur.consequent = [];
+ this.next();
+ if (isCase) {
+ cur.test = this.parseExpression();
+ } else {
+ if (sawDefault) this.raise(this.lastTokStart, "Multiple default clauses");
+ sawDefault = true;
+ cur.test = null;
+ }
+ this.expect(tt.colon);
+ } else {
+ if (!cur) this.unexpected();
+ cur.consequent.push(this.parseStatement(true));
+ }
+ }
+ if (cur) this.finishNode(cur, "SwitchCase");
+ this.next(); // Closing brace
+ this.labels.pop();
+ return this.finishNode(node, "SwitchStatement");
+ };
+
+ pp.parseThrowStatement = function (node) {
+ this.next();
+ if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) this.raise(this.lastTokEnd, "Illegal newline after throw");
+ node.argument = this.parseExpression();
+ this.semicolon();
+ return this.finishNode(node, "ThrowStatement");
+ };
+
+ // Reused empty array added for node fields that are always empty.
+
+ var empty = [];
+
+ pp.parseTryStatement = function (node) {
+ this.next();
+ node.block = this.parseBlock();
+ node.handler = null;
+ if (this.type === tt._catch) {
+ var clause = this.startNode();
+ this.next();
+ this.expect(tt.parenL);
+ clause.param = this.parseBindingAtom();
+ this.checkLVal(clause.param, true);
+ this.expect(tt.parenR);
+ clause.guard = null;
+ clause.body = this.parseBlock();
+ node.handler = this.finishNode(clause, "CatchClause");
+ }
+ node.guardedHandlers = empty;
+ node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null;
+ if (!node.handler && !node.finalizer) this.raise(node.start, "Missing catch or finally clause");
+ return this.finishNode(node, "TryStatement");
+ };
+
+ pp.parseVarStatement = function (node, kind) {
+ this.next();
+ this.parseVar(node, false, kind);
+ this.semicolon();
+ return this.finishNode(node, "VariableDeclaration");
+ };
+
+ pp.parseWhileStatement = function (node) {
+ this.next();
+ node.test = this.parseParenExpression();
+ this.labels.push(loopLabel);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ return this.finishNode(node, "WhileStatement");
+ };
+
+ pp.parseWithStatement = function (node) {
+ if (this.strict) this.raise(this.start, "'with' in strict mode");
+ this.next();
+ node.object = this.parseParenExpression();
+ node.body = this.parseStatement(false);
+ return this.finishNode(node, "WithStatement");
+ };
+
+ pp.parseEmptyStatement = function (node) {
+ this.next();
+ return this.finishNode(node, "EmptyStatement");
+ };
+
+ pp.parseLabeledStatement = function (node, maybeName, expr) {
+ for (var i = 0; i < this.labels.length; ++i) {
+ if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared");
+ } var kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null;
+ this.labels.push({ name: maybeName, kind: kind });
+ node.body = this.parseStatement(true);
+ this.labels.pop();
+ node.label = expr;
+ return this.finishNode(node, "LabeledStatement");
+ };
+
+ pp.parseExpressionStatement = function (node, expr) {
+ node.expression = expr;
+ this.semicolon();
+ return this.finishNode(node, "ExpressionStatement");
+ };
+
+ // Parse a semicolon-enclosed block of statements, handling `"use
+ // strict"` declarations when `allowStrict` is true (used for
+ // function bodies).
+
+ pp.parseBlock = function (allowStrict) {
+ var node = this.startNode(),
+ first = true,
+ oldStrict = undefined;
+ node.body = [];
+ this.expect(tt.braceL);
+ while (!this.eat(tt.braceR)) {
+ var stmt = this.parseStatement(true);
+ node.body.push(stmt);
+ if (first && allowStrict && this.isUseStrict(stmt)) {
+ oldStrict = this.strict;
+ this.setStrict(this.strict = true);
+ }
+ first = false;
+ }
+ if (oldStrict === false) this.setStrict(false);
+ return this.finishNode(node, "BlockStatement");
+ };
+
+ // Parse a regular `for` loop. The disambiguation code in
+ // `parseStatement` will already have parsed the init statement or
+ // expression.
+
+ pp.parseFor = function (node, init) {
+ node.init = init;
+ this.expect(tt.semi);
+ node.test = this.type === tt.semi ? null : this.parseExpression();
+ this.expect(tt.semi);
+ node.update = this.type === tt.parenR ? null : this.parseExpression();
+ this.expect(tt.parenR);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ return this.finishNode(node, "ForStatement");
+ };
+
+ // Parse a `for`/`in` and `for`/`of` loop, which are almost
+ // same from parser's perspective.
+
+ pp.parseForIn = function (node, init) {
+ var type = this.type === tt._in ? "ForInStatement" : "ForOfStatement";
+ this.next();
+ node.left = init;
+ node.right = this.parseExpression();
+ this.expect(tt.parenR);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ return this.finishNode(node, type);
+ };
+
+ // Parse a list of variable declarations.
+
+ pp.parseVar = function (node, isFor, kind) {
+ node.declarations = [];
+ node.kind = kind.keyword;
+ for (; ;) {
+ var decl = this.startNode();
+ this.parseVarId(decl);
+ if (this.eat(tt.eq)) {
+ decl.init = this.parseMaybeAssign(isFor);
+ } else if (kind === tt._const && !(this.type === tt._in || this.options.ecmaVersion >= 6 && this.isContextual("of"))) {
+ this.unexpected();
+ } else if (decl.id.type != "Identifier" && !(isFor && (this.type === tt._in || this.isContextual("of")))) {
+ this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value");
+ } else {
+ decl.init = null;
+ }
+ node.declarations.push(this.finishNode(decl, "VariableDeclarator"));
+ if (!this.eat(tt.comma)) break;
+ }
+ return node;
+ };
+
+ pp.parseVarId = function (decl) {
+ decl.id = this.parseBindingAtom();
+ this.checkLVal(decl.id, true);
+ };
+
+ // Parse a function declaration or literal (depending on the
+ // `isStatement` parameter).
+
+ pp.parseFunction = function (node, isStatement, allowExpressionBody) {
+ this.initFunction(node);
+ if (this.options.ecmaVersion >= 6) node.generator = this.eat(tt.star);
+ if (isStatement || this.type === tt.name) node.id = this.parseIdent();
+ this.parseFunctionParams(node);
+ this.parseFunctionBody(node, allowExpressionBody);
+ return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
+ };
+
+ pp.parseFunctionParams = function (node) {
+ this.expect(tt.parenL);
+ node.params = this.parseBindingList(tt.parenR, false, false);
+ };
+
+ // Parse a class declaration or literal (depending on the
+ // `isStatement` parameter).
+
+ pp.parseClass = function (node, isStatement) {
+ this.next();
+ this.parseClassId(node, isStatement);
+ this.parseClassSuper(node);
+ var classBody = this.startNode();
+ var hadConstructor = false;
+ classBody.body = [];
+ this.expect(tt.braceL);
+ while (!this.eat(tt.braceR)) {
+ if (this.eat(tt.semi)) continue;
+ var method = this.startNode();
+ var isGenerator = this.eat(tt.star);
+ var isMaybeStatic = this.type === tt.name && this.value === "static";
+ this.parsePropertyName(method);
+ method["static"] = isMaybeStatic && this.type !== tt.parenL;
+ if (method["static"]) {
+ if (isGenerator) this.unexpected();
+ isGenerator = this.eat(tt.star);
+ this.parsePropertyName(method);
+ }
+ method.kind = "method";
+ if (!method.computed) {
+ var key = method.key;
+
+ var isGetSet = false;
+ if (!isGenerator && key.type === "Identifier" && this.type !== tt.parenL && (key.name === "get" || key.name === "set")) {
+ isGetSet = true;
+ method.kind = key.name;
+ key = this.parsePropertyName(method);
+ }
+ if (!method["static"] && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) {
+ if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class");
+ if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier");
+ if (isGenerator) this.raise(key.start, "Constructor can't be a generator");
+ method.kind = "constructor";
+ hadConstructor = true;
+ }
+ }
+ this.parseClassMethod(classBody, method, isGenerator);
+ }
+ node.body = this.finishNode(classBody, "ClassBody");
+ return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
+ };
+
+ pp.parseClassMethod = function (classBody, method, isGenerator) {
+ method.value = this.parseMethod(isGenerator);
+ classBody.body.push(this.finishNode(method, "MethodDefinition"));
+ };
+
+ pp.parseClassId = function (node, isStatement) {
+ node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null;
+ };
+
+ pp.parseClassSuper = function (node) {
+ node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null;
+ };
+
+ // Parses module export declaration.
+
+ pp.parseExport = function (node) {
+ this.next();
+ // export * from '...'
+ if (this.eat(tt.star)) {
+ this.expectContextual("from");
+ node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
+ this.semicolon();
+ return this.finishNode(node, "ExportAllDeclaration");
+ }
+ if (this.eat(tt._default)) {
+ // export default ...
+ var expr = this.parseMaybeAssign();
+ var needsSemi = true;
+ if (expr.type == "FunctionExpression" || expr.type == "ClassExpression") {
+ needsSemi = false;
+ if (expr.id) {
+ expr.type = expr.type == "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration";
+ }
+ }
+ node.declaration = expr;
+ if (needsSemi) this.semicolon();
+ return this.finishNode(node, "ExportDefaultDeclaration");
+ }
+ // export var|const|let|function|class ...
+ if (this.shouldParseExportStatement()) {
+ node.declaration = this.parseStatement(true);
+ node.specifiers = [];
+ node.source = null;
+ } else {
+ // export { x, y as z } [from '...']
+ node.declaration = null;
+ node.specifiers = this.parseExportSpecifiers();
+ if (this.eatContextual("from")) {
+ node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
+ } else {
+ node.source = null;
+ }
+ this.semicolon();
+ }
+ return this.finishNode(node, "ExportNamedDeclaration");
+ };
+
+ pp.shouldParseExportStatement = function () {
+ return this.type.keyword;
+ };
+
+ // Parses a comma-separated list of module exports.
+
+ pp.parseExportSpecifiers = function () {
+ var nodes = [],
+ first = true;
+ // export { x, y as z } [from '...']
+ this.expect(tt.braceL);
+ while (!this.eat(tt.braceR)) {
+ if (!first) {
+ this.expect(tt.comma);
+ if (this.afterTrailingComma(tt.braceR)) break;
+ } else first = false;
+
+ var node = this.startNode();
+ node.local = this.parseIdent(this.type === tt._default);
+ node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local;
+ nodes.push(this.finishNode(node, "ExportSpecifier"));
+ }
+ return nodes;
+ };
+
+ // Parses import declaration.
+
+ pp.parseImport = function (node) {
+ this.next();
+ // import '...'
+ if (this.type === tt.string) {
+ node.specifiers = empty;
+ node.source = this.parseExprAtom();
+ node.kind = "";
+ } else {
+ node.specifiers = this.parseImportSpecifiers();
+ this.expectContextual("from");
+ node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
+ }
+ this.semicolon();
+ return this.finishNode(node, "ImportDeclaration");
+ };
+
+ // Parses a comma-separated list of module imports.
+
+ pp.parseImportSpecifiers = function () {
+ var nodes = [],
+ first = true;
+ if (this.type === tt.name) {
+ // import defaultObj, { x, y as z } from '...'
+ var node = this.startNode();
+ node.local = this.parseIdent();
+ this.checkLVal(node.local, true);
+ nodes.push(this.finishNode(node, "ImportDefaultSpecifier"));
+ if (!this.eat(tt.comma)) return nodes;
+ }
+ if (this.type === tt.star) {
+ var node = this.startNode();
+ this.next();
+ this.expectContextual("as");
+ node.local = this.parseIdent();
+ this.checkLVal(node.local, true);
+ nodes.push(this.finishNode(node, "ImportNamespaceSpecifier"));
+ return nodes;
+ }
+ this.expect(tt.braceL);
+ while (!this.eat(tt.braceR)) {
+ if (!first) {
+ this.expect(tt.comma);
+ if (this.afterTrailingComma(tt.braceR)) break;
+ } else first = false;
+
+ var node = this.startNode();
+ node.imported = this.parseIdent(true);
+ node.local = this.eatContextual("as") ? this.parseIdent() : node.imported;
+ this.checkLVal(node.local, true);
+ nodes.push(this.finishNode(node, "ImportSpecifier"));
+ }
+ return nodes;
+ };
+
+ }, { "./state": 13, "./tokentype": 17, "./whitespace": 19 }], 15: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
+
+ exports.__esModule = true;
+ // The algorithm used to determine whether a regexp can appear at a
+ // given point in the program is loosely based on sweet.js' approach.
+ // See https://github.com/mozilla/sweet.js/wiki/design
+
+ var Parser = _dereq_("./state").Parser;
+
+ var tt = _dereq_("./tokentype").types;
+
+ var lineBreak = _dereq_("./whitespace").lineBreak;
+
+ var TokContext = exports.TokContext = function TokContext(token, isExpr, preserveSpace, override) {
+ _classCallCheck(this, TokContext);
+
+ this.token = token;
+ this.isExpr = isExpr;
+ this.preserveSpace = preserveSpace;
+ this.override = override;
+ };
+
+ var types = {
+ b_stat: new TokContext("{", false),
+ b_expr: new TokContext("{", true),
+ b_tmpl: new TokContext("${", true),
+ p_stat: new TokContext("(", false),
+ p_expr: new TokContext("(", true),
+ q_tmpl: new TokContext("`", true, true, function (p) {
+ return p.readTmplToken();
+ }),
+ f_expr: new TokContext("function", true)
+ };
+
+ exports.types = types;
+ var pp = Parser.prototype;
+
+ pp.initialContext = function () {
+ return [types.b_stat];
+ };
+
+ pp.braceIsBlock = function (prevType) {
+ var parent = undefined;
+ if (prevType === tt.colon && (parent = this.curContext()).token == "{") return !parent.isExpr;
+ if (prevType === tt._return) return lineBreak.test(this.input.slice(this.lastTokEnd, this.start));
+ if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof) return true;
+ if (prevType == tt.braceL) return this.curContext() === types.b_stat;
+ return !this.exprAllowed;
+ };
+
+ pp.updateContext = function (prevType) {
+ var update = undefined,
+ type = this.type;
+ if (type.keyword && prevType == tt.dot) this.exprAllowed = false; else if (update = type.updateContext) update.call(this, prevType); else this.exprAllowed = type.beforeExpr;
+ };
+
+ // Token-specific context update code
+
+ tt.parenR.updateContext = tt.braceR.updateContext = function () {
+ if (this.context.length == 1) {
+ this.exprAllowed = true;
+ return;
+ }
+ var out = this.context.pop();
+ if (out === types.b_stat && this.curContext() === types.f_expr) {
+ this.context.pop();
+ this.exprAllowed = false;
+ } else if (out === types.b_tmpl) {
+ this.exprAllowed = true;
+ } else {
+ this.exprAllowed = !out.isExpr;
+ }
+ };
+
+ tt.braceL.updateContext = function (prevType) {
+ this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr);
+ this.exprAllowed = true;
+ };
+
+ tt.dollarBraceL.updateContext = function () {
+ this.context.push(types.b_tmpl);
+ this.exprAllowed = true;
+ };
+
+ tt.parenL.updateContext = function (prevType) {
+ var statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while;
+ this.context.push(statementParens ? types.p_stat : types.p_expr);
+ this.exprAllowed = true;
+ };
+
+ tt.incDec.updateContext = function () { };
+
+ tt._function.updateContext = function () {
+ if (this.curContext() !== types.b_stat) this.context.push(types.f_expr);
+ this.exprAllowed = false;
+ };
+
+ tt.backQuote.updateContext = function () {
+ if (this.curContext() === types.q_tmpl) this.context.pop(); else this.context.push(types.q_tmpl);
+ this.exprAllowed = false;
+ };
+
+ // tokExprAllowed stays unchanged
+
+ }, { "./state": 13, "./tokentype": 17, "./whitespace": 19 }], 16: [function (_dereq_, module, exports) {
+ "use strict";
+
+ var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
+
+ exports.__esModule = true;
+
+ var _identifier = _dereq_("./identifier");
+
+ var isIdentifierStart = _identifier.isIdentifierStart;
+ var isIdentifierChar = _identifier.isIdentifierChar;
+
+ var _tokentype = _dereq_("./tokentype");
+
+ var tt = _tokentype.types;
+ var keywordTypes = _tokentype.keywords;
+
+ var Parser = _dereq_("./state").Parser;
+
+ var SourceLocation = _dereq_("./location").SourceLocation;
+
+ var _whitespace = _dereq_("./whitespace");
+
+ var lineBreak = _whitespace.lineBreak;
+ var lineBreakG = _whitespace.lineBreakG;
+ var isNewLine = _whitespace.isNewLine;
+ var nonASCIIwhitespace = _whitespace.nonASCIIwhitespace;
+
+ // Object type used to represent tokens. Note that normally, tokens
+ // simply exist as properties on the parser object. This is only
+ // used for the onToken callback and the external tokenizer.
+
+ var Token = exports.Token = function Token(p) {
+ _classCallCheck(this, Token);
+
+ this.type = p.type;
+ this.value = p.value;
+ this.start = p.start;
+ this.end = p.end;
+ if (p.options.locations) this.loc = new SourceLocation(p, p.startLoc, p.endLoc);
+ if (p.options.ranges) this.range = [p.start, p.end];
+ };
+
+ // ## Tokenizer
+
+ var pp = Parser.prototype;
+
+ // Are we running under Rhino?
+ var isRhino = typeof Packages !== "undefined";
+
+ // Move to the next token
+
+ pp.next = function () {
+ if (this.options.onToken) this.options.onToken(new Token(this));
+
+ this.lastTokEnd = this.end;
+ this.lastTokStart = this.start;
+ this.lastTokEndLoc = this.endLoc;
+ this.lastTokStartLoc = this.startLoc;
+ this.nextToken();
+ };
+
+ pp.getToken = function () {
+ this.next();
+ return new Token(this);
+ };
+
+ // If we're in an ES6 environment, make parsers iterable
+ if (typeof Symbol !== "undefined") pp[Symbol.iterator] = function () {
+ var self = this;
+ return {
+ next: function next() {
+ var token = self.getToken();
+ return {
+ done: token.type === tt.eof,
+ value: token
+ };
+ }
+ };
+ };
+
+ // Toggle strict mode. Re-reads the next number or string to please
+ // pedantic tests (`"use strict"; 010;` should fail).
+
+ pp.setStrict = function (strict) {
+ this.strict = strict;
+ if (this.type !== tt.num && this.type !== tt.string) return;
+ this.pos = this.start;
+ if (this.options.locations) {
+ while (this.pos < this.lineStart) {
+ this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1;
+ --this.curLine;
+ }
+ }
+ this.nextToken();
+ };
+
+ pp.curContext = function () {
+ return this.context[this.context.length - 1];
+ };
+
+ // Read a single token, updating the parser object's token-related
+ // properties.
+
+ pp.nextToken = function () {
+ var curContext = this.curContext();
+ if (!curContext || !curContext.preserveSpace) this.skipSpace();
+
+ this.start = this.pos;
+ if (this.options.locations) this.startLoc = this.curPosition();
+ if (this.pos >= this.input.length) return this.finishToken(tt.eof);
+
+ if (curContext.override) return curContext.override(this); else this.readToken(this.fullCharCodeAtPos());
+ };
+
+ pp.readToken = function (code) {
+ // Identifier or keyword. '\uXXXX' sequences are allowed in
+ // identifiers, so '\' also dispatches to that.
+ if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) return this.readWord();
+
+ return this.getTokenFromCode(code);
+ };
+
+ pp.fullCharCodeAtPos = function () {
+ var code = this.input.charCodeAt(this.pos);
+ if (code <= 55295 || code >= 57344) return code;
+ var next = this.input.charCodeAt(this.pos + 1);
+ return (code << 10) + next - 56613888;
+ };
+
+ pp.skipBlockComment = function () {
+ var startLoc = this.options.onComment && this.options.locations && this.curPosition();
+ var start = this.pos,
+ end = this.input.indexOf("*/", this.pos += 2);
+ if (end === -1) this.raise(this.pos - 2, "Unterminated comment");
+ this.pos = end + 2;
+ if (this.options.locations) {
+ lineBreakG.lastIndex = start;
+ var match = undefined;
+ while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) {
+ ++this.curLine;
+ this.lineStart = match.index + match[0].length;
+ }
+ }
+ if (this.options.onComment) this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.options.locations && this.curPosition());
+ };
+
+ pp.skipLineComment = function (startSkip) {
+ var start = this.pos;
+ var startLoc = this.options.onComment && this.options.locations && this.curPosition();
+ var ch = this.input.charCodeAt(this.pos += startSkip);
+ while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) {
+ ++this.pos;
+ ch = this.input.charCodeAt(this.pos);
+ }
+ if (this.options.onComment) this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.options.locations && this.curPosition());
+ };
+
+ // Called at the start of the parse and after every token. Skips
+ // whitespace and comments, and.
+
+ pp.skipSpace = function () {
+ while (this.pos < this.input.length) {
+ var ch = this.input.charCodeAt(this.pos);
+ if (ch === 32) {
+ // ' '
+ ++this.pos;
+ } else if (ch === 13) {
+ ++this.pos;
+ var next = this.input.charCodeAt(this.pos);
+ if (next === 10) {
+ ++this.pos;
+ }
+ if (this.options.locations) {
+ ++this.curLine;
+ this.lineStart = this.pos;
+ }
+ } else if (ch === 10 || ch === 8232 || ch === 8233) {
+ ++this.pos;
+ if (this.options.locations) {
+ ++this.curLine;
+ this.lineStart = this.pos;
+ }
+ } else if (ch > 8 && ch < 14) {
+ ++this.pos;
+ } else if (ch === 47) {
+ // '/'
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (next === 42) {
+ // '*'
+ this.skipBlockComment();
+ } else if (next === 47) {
+ // '/'
+ this.skipLineComment(2);
+ } else break;
+ } else if (ch === 160) {
+ // '\xa0'
+ ++this.pos;
+ } else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {
+ ++this.pos;
+ } else {
+ break;
+ }
+ }
+ };
+
+ // Called at the end of every token. Sets `end`, `val`, and
+ // maintains `context` and `exprAllowed`, and skips the space after
+ // the token, so that the next one's `start` will point at the
+ // right position.
+
+ pp.finishToken = function (type, val) {
+ this.end = this.pos;
+ if (this.options.locations) this.endLoc = this.curPosition();
+ var prevType = this.type;
+ this.type = type;
+ this.value = val;
+
+ this.updateContext(prevType);
+ };
+
+ // ### Token reading
+
+ // This is the function that is called to fetch the next token. It
+ // is somewhat obscure, because it works in character codes rather
+ // than characters, and because operator parsing has been inlined
+ // into it.
+ //
+ // All in the name of speed.
+ //
+ pp.readToken_dot = function () {
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (next >= 48 && next <= 57) return this.readNumber(true);
+ var next2 = this.input.charCodeAt(this.pos + 2);
+ if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) {
+ // 46 = dot '.'
+ this.pos += 3;
+ return this.finishToken(tt.ellipsis);
+ } else {
+ ++this.pos;
+ return this.finishToken(tt.dot);
+ }
+ };
+
+ pp.readToken_slash = function () {
+ // '/'
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (this.exprAllowed) {
+ ++this.pos; return this.readRegexp();
+ }
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(tt.slash, 1);
+ };
+
+ pp.readToken_mult_modulo = function (code) {
+ // '%*'
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(code === 42 ? tt.star : tt.modulo, 1);
+ };
+
+ pp.readToken_pipe_amp = function (code) {
+ // '|&'
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2);
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1);
+ };
+
+ pp.readToken_caret = function () {
+ // '^'
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(tt.bitwiseXOR, 1);
+ };
+
+ pp.readToken_plus_min = function (code) {
+ // '+-'
+ var next = this.input.charCodeAt(this.pos + 1);
+ if (next === code) {
+ if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 && lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) {
+ // A `-->` line comment
+ this.skipLineComment(3);
+ this.skipSpace();
+ return this.nextToken();
+ }
+ return this.finishOp(tt.incDec, 2);
+ }
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(tt.plusMin, 1);
+ };
+
+ pp.readToken_lt_gt = function (code) {
+ // '<>'
+ var next = this.input.charCodeAt(this.pos + 1);
+ var size = 1;
+ if (next === code) {
+ size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2;
+ if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1);
+ return this.finishOp(tt.bitShift, size);
+ }
+ if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) {
+ if (this.inModule) this.unexpected();
+ // `
+
+
+
+
+ Jasmine Spec Runner
+ @@TestFrameworkDependencies@@
+ @@CodeCoverageDependencies@@
+ @@ReferencedCSSFiles@@
+ @@ReferencedJSFiles@@
+ @@TestJSFile@@
+
+
+
+ @@TestHtmlTemplateFiles@@
+
+
diff --git a/Chutzpah/ChutzpahTestHarnessFiles/Jasmine/v3/jasmine.js b/Chutzpah/ChutzpahTestHarnessFiles/Jasmine/v3/jasmine.js
new file mode 100644
index 00000000..4875624e
--- /dev/null
+++ b/Chutzpah/ChutzpahTestHarnessFiles/Jasmine/v3/jasmine.js
@@ -0,0 +1,8218 @@
+/*
+Copyright (c) 2008-2019 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+// eslint-disable-next-line no-unused-vars
+var getJasmineRequireObj = (function(jasmineGlobal) {
+ var jasmineRequire;
+
+ if (
+ typeof module !== 'undefined' &&
+ module.exports &&
+ typeof exports !== 'undefined'
+ ) {
+ if (typeof global !== 'undefined') {
+ jasmineGlobal = global;
+ } else {
+ jasmineGlobal = {};
+ }
+ jasmineRequire = exports;
+ } else {
+ if (
+ typeof window !== 'undefined' &&
+ typeof window.toString === 'function' &&
+ window.toString() === '[object GjsGlobal]'
+ ) {
+ jasmineGlobal = window;
+ }
+ jasmineRequire = jasmineGlobal.jasmineRequire = {};
+ }
+
+ function getJasmineRequire() {
+ return jasmineRequire;
+ }
+
+ getJasmineRequire().core = function(jRequire) {
+ var j$ = {};
+
+ jRequire.base(j$, jasmineGlobal);
+ j$.util = jRequire.util(j$);
+ j$.errors = jRequire.errors();
+ j$.formatErrorMsg = jRequire.formatErrorMsg();
+ j$.Any = jRequire.Any(j$);
+ j$.Anything = jRequire.Anything(j$);
+ j$.CallTracker = jRequire.CallTracker(j$);
+ j$.MockDate = jRequire.MockDate();
+ j$.getClearStack = jRequire.clearStack(j$);
+ j$.Clock = jRequire.Clock();
+ j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
+ j$.Env = jRequire.Env(j$);
+ j$.StackTrace = jRequire.StackTrace(j$);
+ j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
+ j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
+ j$.Expector = jRequire.Expector(j$);
+ j$.Expectation = jRequire.Expectation(j$);
+ j$.buildExpectationResult = jRequire.buildExpectationResult();
+ j$.noopTimer = jRequire.noopTimer();
+ j$.JsApiReporter = jRequire.JsApiReporter(j$);
+ j$.matchersUtil = jRequire.matchersUtil(j$);
+ j$.ObjectContaining = jRequire.ObjectContaining(j$);
+ j$.ArrayContaining = jRequire.ArrayContaining(j$);
+ j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
+ j$.MapContaining = jRequire.MapContaining(j$);
+ j$.SetContaining = jRequire.SetContaining(j$);
+ j$.pp = jRequire.pp(j$);
+ j$.QueueRunner = jRequire.QueueRunner(j$);
+ j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
+ j$.Spec = jRequire.Spec(j$);
+ j$.Spy = jRequire.Spy(j$);
+ j$.SpyFactory = jRequire.SpyFactory(j$);
+ j$.SpyRegistry = jRequire.SpyRegistry(j$);
+ j$.SpyStrategy = jRequire.SpyStrategy(j$);
+ j$.StringMatching = jRequire.StringMatching(j$);
+ j$.UserContext = jRequire.UserContext(j$);
+ j$.Suite = jRequire.Suite(j$);
+ j$.Timer = jRequire.Timer();
+ j$.TreeProcessor = jRequire.TreeProcessor();
+ j$.version = jRequire.version();
+ j$.Order = jRequire.Order();
+ j$.DiffBuilder = jRequire.DiffBuilder(j$);
+ j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
+ j$.ObjectPath = jRequire.ObjectPath(j$);
+ j$.GlobalErrors = jRequire.GlobalErrors(j$);
+
+ j$.Truthy = jRequire.Truthy(j$);
+ j$.Falsy = jRequire.Falsy(j$);
+ j$.Empty = jRequire.Empty(j$);
+ j$.NotEmpty = jRequire.NotEmpty(j$);
+
+ j$.matchers = jRequire.requireMatchers(jRequire, j$);
+ j$.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$);
+
+ return j$;
+ };
+
+ return getJasmineRequire;
+})(this);
+
+getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
+ var availableMatchers = [
+ 'nothing',
+ 'toBe',
+ 'toBeCloseTo',
+ 'toBeDefined',
+ 'toBeInstanceOf',
+ 'toBeFalse',
+ 'toBeFalsy',
+ 'toBeGreaterThan',
+ 'toBeGreaterThanOrEqual',
+ 'toBeLessThan',
+ 'toBeLessThanOrEqual',
+ 'toBeNaN',
+ 'toBeNegativeInfinity',
+ 'toBeNull',
+ 'toBePositiveInfinity',
+ 'toBeTrue',
+ 'toBeTruthy',
+ 'toBeUndefined',
+ 'toContain',
+ 'toEqual',
+ 'toHaveBeenCalled',
+ 'toHaveBeenCalledBefore',
+ 'toHaveBeenCalledTimes',
+ 'toHaveBeenCalledWith',
+ 'toHaveClass',
+ 'toMatch',
+ 'toThrow',
+ 'toThrowError',
+ 'toThrowMatching'
+ ],
+ matchers = {};
+
+ for (var i = 0; i < availableMatchers.length; i++) {
+ var name = availableMatchers[i];
+ matchers[name] = jRequire[name](j$);
+ }
+
+ return matchers;
+};
+
+getJasmineRequireObj().base = function(j$, jasmineGlobal) {
+ j$.unimplementedMethod_ = function() {
+ throw new Error('unimplemented method');
+ };
+
+ /**
+ * Maximum object depth the pretty printer will print to.
+ * Set this to a lower value to speed up pretty printing if you have large objects.
+ * @name jasmine.MAX_PRETTY_PRINT_DEPTH
+ * @since 1.3.0
+ */
+ j$.MAX_PRETTY_PRINT_DEPTH = 8;
+ /**
+ * Maximum number of array elements to display when pretty printing objects.
+ * This will also limit the number of keys and values displayed for an object.
+ * Elements past this number will be ellipised.
+ * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
+ * @since 2.7.0
+ */
+ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
+ /**
+ * Maximum number of characters to display when pretty printing objects.
+ * Characters past this number will be ellipised.
+ * @name jasmine.MAX_PRETTY_PRINT_CHARS
+ * @since 2.9.0
+ */
+ j$.MAX_PRETTY_PRINT_CHARS = 1000;
+ /**
+ * Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
+ * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
+ * @since 1.3.0
+ */
+ j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+ j$.getGlobal = function() {
+ return jasmineGlobal;
+ };
+
+ /**
+ * Get the currently booted Jasmine Environment.
+ *
+ * @name jasmine.getEnv
+ * @since 1.3.0
+ * @function
+ * @return {Env}
+ */
+ j$.getEnv = function(options) {
+ var env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options));
+ //jasmine. singletons in here (setTimeout blah blah).
+ return env;
+ };
+
+ j$.isArray_ = function(value) {
+ return j$.isA_('Array', value);
+ };
+
+ j$.isObject_ = function(value) {
+ return (
+ !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value)
+ );
+ };
+
+ j$.isString_ = function(value) {
+ return j$.isA_('String', value);
+ };
+
+ j$.isNumber_ = function(value) {
+ return j$.isA_('Number', value);
+ };
+
+ j$.isFunction_ = function(value) {
+ return j$.isA_('Function', value);
+ };
+
+ j$.isAsyncFunction_ = function(value) {
+ return j$.isA_('AsyncFunction', value);
+ };
+
+ j$.isTypedArray_ = function(value) {
+ return (
+ j$.isA_('Float32Array', value) ||
+ j$.isA_('Float64Array', value) ||
+ j$.isA_('Int16Array', value) ||
+ j$.isA_('Int32Array', value) ||
+ j$.isA_('Int8Array', value) ||
+ j$.isA_('Uint16Array', value) ||
+ j$.isA_('Uint32Array', value) ||
+ j$.isA_('Uint8Array', value) ||
+ j$.isA_('Uint8ClampedArray', value)
+ );
+ };
+
+ j$.isA_ = function(typeName, value) {
+ return j$.getType_(value) === '[object ' + typeName + ']';
+ };
+
+ j$.isError_ = function(value) {
+ if (value instanceof Error) {
+ return true;
+ }
+ if (value && value.constructor && value.constructor.constructor) {
+ var valueGlobal = value.constructor.constructor('return this');
+ if (j$.isFunction_(valueGlobal)) {
+ valueGlobal = valueGlobal();
+ }
+
+ if (valueGlobal.Error && value instanceof valueGlobal.Error) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ j$.getType_ = function(value) {
+ return Object.prototype.toString.apply(value);
+ };
+
+ j$.isDomNode = function(obj) {
+ // Node is a function, because constructors
+ return typeof jasmineGlobal.Node !== 'undefined'
+ ? obj instanceof jasmineGlobal.Node
+ : obj !== null &&
+ typeof obj === 'object' &&
+ typeof obj.nodeType === 'number' &&
+ typeof obj.nodeName === 'string';
+ // return obj.nodeType > 0;
+ };
+
+ j$.isMap = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ typeof jasmineGlobal.Map !== 'undefined' &&
+ obj.constructor === jasmineGlobal.Map
+ );
+ };
+
+ j$.isSet = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ typeof jasmineGlobal.Set !== 'undefined' &&
+ obj.constructor === jasmineGlobal.Set
+ );
+ };
+
+ j$.isPromise = function(obj) {
+ return (
+ typeof jasmineGlobal.Promise !== 'undefined' &&
+ !!obj &&
+ obj.constructor === jasmineGlobal.Promise
+ );
+ };
+
+ j$.isPromiseLike = function(obj) {
+ return !!obj && j$.isFunction_(obj.then);
+ };
+
+ j$.fnNameFor = function(func) {
+ if (func.name) {
+ return func.name;
+ }
+
+ var matches =
+ func.toString().match(/^\s*function\s*(\w+)\s*\(/) ||
+ func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/);
+
+ return matches ? matches[1] : '';
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is an instance of the specified class/constructor.
+ * @name jasmine.any
+ * @since 1.3.0
+ * @function
+ * @param {Constructor} clazz - The constructor to check against.
+ */
+ j$.any = function(clazz) {
+ return new j$.Any(clazz);
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is not `null` and not `undefined`.
+ * @name jasmine.anything
+ * @since 2.2.0
+ * @function
+ */
+ j$.anything = function() {
+ return new j$.Anything();
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is `true` or anything truthy.
+ * @name jasmine.truthy
+ * @since 3.1.0
+ * @function
+ */
+ j$.truthy = function() {
+ return new j$.Truthy();
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
+ * @name jasmine.falsy
+ * @since 3.1.0
+ * @function
+ */
+ j$.falsy = function() {
+ return new j$.Falsy();
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is empty.
+ * @name jasmine.empty
+ * @since 3.1.0
+ * @function
+ */
+ j$.empty = function() {
+ return new j$.Empty();
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is not empty.
+ * @name jasmine.notEmpty
+ * @since 3.1.0
+ * @function
+ */
+ j$.notEmpty = function() {
+ return new j$.NotEmpty();
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared contains at least the keys and values.
+ * @name jasmine.objectContaining
+ * @since 1.3.0
+ * @function
+ * @param {Object} sample - The subset of properties that _must_ be in the actual.
+ */
+ j$.objectContaining = function(sample) {
+ return new j$.ObjectContaining(sample);
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
+ * @name jasmine.stringMatching
+ * @since 2.2.0
+ * @function
+ * @param {RegExp|String} expected
+ */
+ j$.stringMatching = function(expected) {
+ return new j$.StringMatching(expected);
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
+ * @name jasmine.arrayContaining
+ * @since 2.2.0
+ * @function
+ * @param {Array} sample
+ */
+ j$.arrayContaining = function(sample) {
+ return new j$.ArrayContaining(sample);
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
+ * @name jasmine.arrayWithExactContents
+ * @since 2.8.0
+ * @function
+ * @param {Array} sample
+ */
+ j$.arrayWithExactContents = function(sample) {
+ return new j$.ArrayWithExactContents(sample);
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if every key/value pair in the sample passes the deep equality comparison
+ * with at least one key/value pair in the actual value being compared
+ * @name jasmine.mapContaining
+ * @since 3.5.0
+ * @function
+ * @param {Map} sample - The subset of items that _must_ be in the actual.
+ */
+ j$.mapContaining = function(sample) {
+ return new j$.MapContaining(sample);
+ };
+
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if every item in the sample passes the deep equality comparison
+ * with at least one item in the actual value being compared
+ * @name jasmine.setContaining
+ * @since 3.5.0
+ * @function
+ * @param {Set} sample - The subset of items that _must_ be in the actual.
+ */
+ j$.setContaining = function(sample) {
+ return new j$.SetContaining(sample);
+ };
+
+ j$.isSpy = function(putativeSpy) {
+ if (!putativeSpy) {
+ return false;
+ }
+ return (
+ putativeSpy.and instanceof j$.SpyStrategy &&
+ putativeSpy.calls instanceof j$.CallTracker
+ );
+ };
+};
+
+getJasmineRequireObj().util = function(j$) {
+ var util = {};
+
+ util.inherit = function(childClass, parentClass) {
+ var Subclass = function() {};
+ Subclass.prototype = parentClass.prototype;
+ childClass.prototype = new Subclass();
+ };
+
+ util.htmlEscape = function(str) {
+ if (!str) {
+ return str;
+ }
+ return str
+ .replace(/&/g, '&')
+ .replace(//g, '>');
+ };
+
+ util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) {
+ arrayOfArgs.push(args[i]);
+ }
+ return arrayOfArgs;
+ };
+
+ util.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ util.arrayContains = function(array, search) {
+ var i = array.length;
+ while (i--) {
+ if (array[i] === search) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ util.clone = function(obj) {
+ if (Object.prototype.toString.apply(obj) === '[object Array]') {
+ return obj.slice();
+ }
+
+ var cloned = {};
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ cloned[prop] = obj[prop];
+ }
+ }
+
+ return cloned;
+ };
+
+ util.cloneArgs = function(args) {
+ var clonedArgs = [];
+ var argsAsArray = j$.util.argsToArray(args);
+ for (var i = 0; i < argsAsArray.length; i++) {
+ var str = Object.prototype.toString.apply(argsAsArray[i]),
+ primitives = /^\[object (Boolean|String|RegExp|Number)/;
+
+ // All falsey values are either primitives, `null`, or `undefined.
+ if (!argsAsArray[i] || str.match(primitives)) {
+ clonedArgs.push(argsAsArray[i]);
+ } else {
+ clonedArgs.push(j$.util.clone(argsAsArray[i]));
+ }
+ }
+ return clonedArgs;
+ };
+
+ util.getPropertyDescriptor = function(obj, methodName) {
+ var descriptor,
+ proto = obj;
+
+ do {
+ descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
+ proto = Object.getPrototypeOf(proto);
+ } while (!descriptor && proto);
+
+ return descriptor;
+ };
+
+ util.objectDifference = function(obj, toRemove) {
+ var diff = {};
+
+ for (var key in obj) {
+ if (util.has(obj, key) && !util.has(toRemove, key)) {
+ diff[key] = obj[key];
+ }
+ }
+
+ return diff;
+ };
+
+ util.has = function(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ };
+
+ util.errorWithStack = function errorWithStack() {
+ // Don't throw and catch if we don't have to, because it makes it harder
+ // for users to debug their code with exception breakpoints.
+ var error = new Error();
+
+ if (error.stack) {
+ return error;
+ }
+
+ // But some browsers (e.g. Phantom) only provide a stack trace if we throw.
+ try {
+ throw new Error();
+ } catch (e) {
+ return e;
+ }
+ };
+
+ function callerFile() {
+ var trace = new j$.StackTrace(util.errorWithStack());
+ return trace.frames[2].file;
+ }
+
+ util.jasmineFile = (function() {
+ var result;
+
+ return function() {
+ if (!result) {
+ result = callerFile();
+ }
+
+ return result;
+ };
+ })();
+
+ function StopIteration() {}
+ StopIteration.prototype = Object.create(Error.prototype);
+ StopIteration.prototype.constructor = StopIteration;
+
+ // useful for maps and sets since `forEach` is the only IE11-compatible way to iterate them
+ util.forEachBreakable = function(iterable, iteratee) {
+ function breakLoop() {
+ throw new StopIteration();
+ }
+
+ try {
+ iterable.forEach(function(value, key) {
+ iteratee(breakLoop, value, key, iterable);
+ });
+ } catch (error) {
+ if (!(error instanceof StopIteration)) throw error;
+ }
+ };
+
+ return util;
+};
+
+getJasmineRequireObj().Spec = function(j$) {
+ function Spec(attrs) {
+ this.expectationFactory = attrs.expectationFactory;
+ this.asyncExpectationFactory = attrs.asyncExpectationFactory;
+ this.resultCallback = attrs.resultCallback || function() {};
+ this.id = attrs.id;
+ this.description = attrs.description || '';
+ this.queueableFn = attrs.queueableFn;
+ this.beforeAndAfterFns =
+ attrs.beforeAndAfterFns ||
+ function() {
+ return { befores: [], afters: [] };
+ };
+ this.userContext =
+ attrs.userContext ||
+ function() {
+ return {};
+ };
+ this.onStart = attrs.onStart || function() {};
+ this.getSpecName =
+ attrs.getSpecName ||
+ function() {
+ return '';
+ };
+ this.expectationResultFactory =
+ attrs.expectationResultFactory || function() {};
+ this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
+ this.catchingExceptions =
+ attrs.catchingExceptions ||
+ function() {
+ return true;
+ };
+ this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
+ this.timer = attrs.timer || j$.noopTimer;
+
+ if (!this.queueableFn.fn) {
+ this.pend();
+ }
+
+ /**
+ * @typedef SpecResult
+ * @property {Int} id - The unique id of this spec.
+ * @property {String} description - The description passed to the {@link it} that created this spec.
+ * @property {String} fullName - The full description including all ancestors of this spec.
+ * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
+ * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
+ * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
+ * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
+ * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
+ * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
+ */
+ this.result = {
+ id: this.id,
+ description: this.description,
+ fullName: this.getFullName(),
+ failedExpectations: [],
+ passedExpectations: [],
+ deprecationWarnings: [],
+ pendingReason: '',
+ duration: null
+ };
+ }
+
+ Spec.prototype.addExpectationResult = function(passed, data, isError) {
+ var expectationResult = this.expectationResultFactory(data);
+ if (passed) {
+ this.result.passedExpectations.push(expectationResult);
+ } else {
+ this.result.failedExpectations.push(expectationResult);
+
+ if (this.throwOnExpectationFailure && !isError) {
+ throw new j$.errors.ExpectationFailed();
+ }
+ }
+ };
+
+ Spec.prototype.expect = function(actual) {
+ return this.expectationFactory(actual, this);
+ };
+
+ Spec.prototype.expectAsync = function(actual) {
+ return this.asyncExpectationFactory(actual, this);
+ };
+
+ Spec.prototype.execute = function(onComplete, excluded, failSpecWithNoExp) {
+ var self = this;
+
+ var onStart = {
+ fn: function(done) {
+ self.timer.start();
+ self.onStart(self, done);
+ }
+ };
+
+ var complete = {
+ fn: function(done) {
+ self.queueableFn.fn = null;
+ self.result.status = self.status(excluded, failSpecWithNoExp);
+ self.resultCallback(self.result, done);
+ }
+ };
+
+ var fns = this.beforeAndAfterFns();
+ var regularFns = fns.befores.concat(this.queueableFn);
+
+ var runnerConfig = {
+ isLeaf: true,
+ queueableFns: regularFns,
+ cleanupFns: fns.afters,
+ onException: function() {
+ self.onException.apply(self, arguments);
+ },
+ onComplete: function() {
+ self.result.duration = self.timer.elapsed();
+ onComplete(
+ self.result.status === 'failed' &&
+ new j$.StopExecutionError('spec failed')
+ );
+ },
+ userContext: this.userContext()
+ };
+
+ if (this.markedPending || excluded === true) {
+ runnerConfig.queueableFns = [];
+ runnerConfig.cleanupFns = [];
+ }
+
+ runnerConfig.queueableFns.unshift(onStart);
+ runnerConfig.cleanupFns.push(complete);
+
+ this.queueRunnerFactory(runnerConfig);
+ };
+
+ Spec.prototype.onException = function onException(e) {
+ if (Spec.isPendingSpecException(e)) {
+ this.pend(extractCustomPendingMessage(e));
+ return;
+ }
+
+ if (e instanceof j$.errors.ExpectationFailed) {
+ return;
+ }
+
+ this.addExpectationResult(
+ false,
+ {
+ matcherName: '',
+ passed: false,
+ expected: '',
+ actual: '',
+ error: e
+ },
+ true
+ );
+ };
+
+ Spec.prototype.pend = function(message) {
+ this.markedPending = true;
+ if (message) {
+ this.result.pendingReason = message;
+ }
+ };
+
+ Spec.prototype.getResult = function() {
+ this.result.status = this.status();
+ return this.result;
+ };
+
+ Spec.prototype.status = function(excluded, failSpecWithNoExpectations) {
+ if (excluded === true) {
+ return 'excluded';
+ }
+
+ if (this.markedPending) {
+ return 'pending';
+ }
+
+ if (
+ this.result.failedExpectations.length > 0 ||
+ (failSpecWithNoExpectations &&
+ this.result.failedExpectations.length +
+ this.result.passedExpectations.length ===
+ 0)
+ ) {
+ return 'failed';
+ }
+
+ return 'passed';
+ };
+
+ Spec.prototype.getFullName = function() {
+ return this.getSpecName(this);
+ };
+
+ Spec.prototype.addDeprecationWarning = function(deprecation) {
+ if (typeof deprecation === 'string') {
+ deprecation = { message: deprecation };
+ }
+ this.result.deprecationWarnings.push(
+ this.expectationResultFactory(deprecation)
+ );
+ };
+
+ var extractCustomPendingMessage = function(e) {
+ var fullMessage = e.toString(),
+ boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
+ boilerplateEnd =
+ boilerplateStart + Spec.pendingSpecExceptionMessage.length;
+
+ return fullMessage.substr(boilerplateEnd);
+ };
+
+ Spec.pendingSpecExceptionMessage = '=> marked Pending';
+
+ Spec.isPendingSpecException = function(e) {
+ return !!(
+ e &&
+ e.toString &&
+ e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1
+ );
+ };
+
+ return Spec;
+};
+
+if (typeof window == void 0 && typeof exports == 'object') {
+ /* globals exports */
+ exports.Spec = jasmineRequire.Spec;
+}
+
+/*jshint bitwise: false*/
+
+getJasmineRequireObj().Order = function() {
+ function Order(options) {
+ this.random = 'random' in options ? options.random : true;
+ var seed = (this.seed = options.seed || generateSeed());
+ this.sort = this.random ? randomOrder : naturalOrder;
+
+ function naturalOrder(items) {
+ return items;
+ }
+
+ function randomOrder(items) {
+ var copy = items.slice();
+ copy.sort(function(a, b) {
+ return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id);
+ });
+ return copy;
+ }
+
+ function generateSeed() {
+ return String(Math.random()).slice(-5);
+ }
+
+ // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
+ // used to get a different output when the key changes slightly.
+ // We use your return to sort the children randomly in a consistent way when
+ // used in conjunction with a seed
+
+ function jenkinsHash(key) {
+ var hash, i;
+ for (hash = i = 0; i < key.length; ++i) {
+ hash += key.charCodeAt(i);
+ hash += hash << 10;
+ hash ^= hash >> 6;
+ }
+ hash += hash << 3;
+ hash ^= hash >> 11;
+ hash += hash << 15;
+ return hash;
+ }
+ }
+
+ return Order;
+};
+
+getJasmineRequireObj().Env = function(j$) {
+ /**
+ * _Note:_ Do not construct this directly, Jasmine will make one during booting.
+ * @name Env
+ * @since 2.0.0
+ * @classdesc The Jasmine environment
+ * @constructor
+ */
+ function Env(options) {
+ options = options || {};
+
+ var self = this;
+ var global = options.global || j$.getGlobal();
+ var customPromise;
+
+ var totalSpecsDefined = 0;
+
+ var realSetTimeout = global.setTimeout;
+ var realClearTimeout = global.clearTimeout;
+ var clearStack = j$.getClearStack(global);
+ this.clock = new j$.Clock(
+ global,
+ function() {
+ return new j$.DelayedFunctionScheduler();
+ },
+ new j$.MockDate(global)
+ );
+
+ var runnableResources = {};
+
+ var currentSpec = null;
+ var currentlyExecutingSuites = [];
+ var currentDeclarationSuite = null;
+ var hasFailures = false;
+
+ /**
+ * This represents the available options to configure Jasmine.
+ * Options that are not provided will use their default values
+ * @interface Configuration
+ * @since 3.3.0
+ */
+ var config = {
+ /**
+ * Whether to randomize spec execution order
+ * @name Configuration#random
+ * @since 3.3.0
+ * @type Boolean
+ * @default true
+ */
+ random: true,
+ /**
+ * Seed to use as the basis of randomization.
+ * Null causes the seed to be determined randomly at the start of execution.
+ * @name Configuration#seed
+ * @since 3.3.0
+ * @type function
+ * @default null
+ */
+ seed: null,
+ /**
+ * Whether to stop execution of the suite after the first spec failure
+ * @name Configuration#failFast
+ * @since 3.3.0
+ * @type Boolean
+ * @default false
+ */
+ failFast: false,
+ /**
+ * Whether to fail the spec if it ran no expectations. By default
+ * a spec that ran no expectations is reported as passed. Setting this
+ * to true will report such spec as a failure.
+ * @name Configuration#failSpecWithNoExpectations
+ * @since 3.5.0
+ * @type Boolean
+ * @default false
+ */
+ failSpecWithNoExpectations: false,
+ /**
+ * Whether to cause specs to only have one expectation failure.
+ * @name Configuration#oneFailurePerSpec
+ * @since 3.3.0
+ * @type Boolean
+ * @default false
+ */
+ oneFailurePerSpec: false,
+ /**
+ * Function to use to filter specs
+ * @name Configuration#specFilter
+ * @since 3.3.0
+ * @type function
+ * @default true
+ */
+ specFilter: function() {
+ return true;
+ },
+ /**
+ * Whether or not reporters should hide disabled specs from their output.
+ * Currently only supported by Jasmine's HTMLReporter
+ * @name Configuration#hideDisabled
+ * @since 3.3.0
+ * @type Boolean
+ * @default false
+ */
+ hideDisabled: false,
+ /**
+ * Set to provide a custom promise library that Jasmine will use if it needs
+ * to create a promise. If not set, it will default to whatever global Promise
+ * library is available (if any).
+ * @name Configuration#Promise
+ * @since 3.5.0
+ * @type function
+ * @default undefined
+ */
+ Promise: undefined
+ };
+
+ var currentSuite = function() {
+ return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
+ };
+
+ var currentRunnable = function() {
+ return currentSpec || currentSuite();
+ };
+
+ var globalErrors = null;
+
+ var installGlobalErrors = function() {
+ if (globalErrors) {
+ return;
+ }
+
+ globalErrors = new j$.GlobalErrors();
+ globalErrors.install();
+ };
+
+ if (!options.suppressLoadErrors) {
+ installGlobalErrors();
+ globalErrors.pushListener(function(
+ message,
+ filename,
+ lineno,
+ colNo,
+ err
+ ) {
+ topSuite.result.failedExpectations.push({
+ passed: false,
+ globalErrorType: 'load',
+ message: message,
+ stack: err && err.stack,
+ filename: filename,
+ lineno: lineno
+ });
+ });
+ }
+
+ /**
+ * Configure your jasmine environment
+ * @name Env#configure
+ * @since 3.3.0
+ * @argument {Configuration} configuration
+ * @function
+ */
+ this.configure = function(configuration) {
+ if (configuration.specFilter) {
+ config.specFilter = configuration.specFilter;
+ }
+
+ if (configuration.hasOwnProperty('random')) {
+ config.random = !!configuration.random;
+ }
+
+ if (configuration.hasOwnProperty('seed')) {
+ config.seed = configuration.seed;
+ }
+
+ if (configuration.hasOwnProperty('failFast')) {
+ config.failFast = configuration.failFast;
+ }
+
+ if (configuration.hasOwnProperty('failSpecWithNoExpectations')) {
+ config.failSpecWithNoExpectations =
+ configuration.failSpecWithNoExpectations;
+ }
+
+ if (configuration.hasOwnProperty('oneFailurePerSpec')) {
+ config.oneFailurePerSpec = configuration.oneFailurePerSpec;
+ }
+
+ if (configuration.hasOwnProperty('hideDisabled')) {
+ config.hideDisabled = configuration.hideDisabled;
+ }
+
+ // Don't use hasOwnProperty to check for Promise existence because Promise
+ // can be initialized to undefined, either explicitly or by using the
+ // object returned from Env#configuration. In particular, Karma does this.
+ if (configuration.Promise) {
+ if (
+ typeof configuration.Promise.resolve === 'function' &&
+ typeof configuration.Promise.reject === 'function'
+ ) {
+ customPromise = configuration.Promise;
+ } else {
+ throw new Error(
+ 'Custom promise library missing `resolve`/`reject` functions'
+ );
+ }
+ }
+ };
+
+ /**
+ * Get the current configuration for your jasmine environment
+ * @name Env#configuration
+ * @since 3.3.0
+ * @function
+ * @returns {Configuration}
+ */
+ this.configuration = function() {
+ var result = {};
+ for (var property in config) {
+ result[property] = config[property];
+ }
+ return result;
+ };
+
+ Object.defineProperty(this, 'specFilter', {
+ get: function() {
+ self.deprecated(
+ 'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`'
+ );
+ return config.specFilter;
+ },
+ set: function(val) {
+ self.deprecated(
+ 'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`'
+ );
+ config.specFilter = val;
+ }
+ });
+
+ this.setDefaultSpyStrategy = function(defaultStrategyFn) {
+ if (!currentRunnable()) {
+ throw new Error(
+ 'Default spy strategy must be set in a before function or a spec'
+ );
+ }
+ runnableResources[
+ currentRunnable().id
+ ].defaultStrategyFn = defaultStrategyFn;
+ };
+
+ this.addSpyStrategy = function(name, fn) {
+ if (!currentRunnable()) {
+ throw new Error(
+ 'Custom spy strategies must be added in a before function or a spec'
+ );
+ }
+ runnableResources[currentRunnable().id].customSpyStrategies[name] = fn;
+ };
+
+ this.addCustomEqualityTester = function(tester) {
+ if (!currentRunnable()) {
+ throw new Error(
+ 'Custom Equalities must be added in a before function or a spec'
+ );
+ }
+ runnableResources[currentRunnable().id].customEqualityTesters.push(
+ tester
+ );
+ };
+
+ this.addMatchers = function(matchersToAdd) {
+ if (!currentRunnable()) {
+ throw new Error(
+ 'Matchers must be added in a before function or a spec'
+ );
+ }
+ var customMatchers =
+ runnableResources[currentRunnable().id].customMatchers;
+ for (var matcherName in matchersToAdd) {
+ customMatchers[matcherName] = matchersToAdd[matcherName];
+ }
+ };
+
+ this.addAsyncMatchers = function(matchersToAdd) {
+ if (!currentRunnable()) {
+ throw new Error(
+ 'Async Matchers must be added in a before function or a spec'
+ );
+ }
+ var customAsyncMatchers =
+ runnableResources[currentRunnable().id].customAsyncMatchers;
+ for (var matcherName in matchersToAdd) {
+ customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
+ }
+ };
+
+ j$.Expectation.addCoreMatchers(j$.matchers);
+ j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
+
+ var nextSpecId = 0;
+ var getNextSpecId = function() {
+ return 'spec' + nextSpecId++;
+ };
+
+ var nextSuiteId = 0;
+ var getNextSuiteId = function() {
+ return 'suite' + nextSuiteId++;
+ };
+
+ var expectationFactory = function(actual, spec) {
+ return j$.Expectation.factory({
+ util: j$.matchersUtil,
+ customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
+ customMatchers: runnableResources[spec.id].customMatchers,
+ actual: actual,
+ addExpectationResult: addExpectationResult
+ });
+
+ function addExpectationResult(passed, result) {
+ return spec.addExpectationResult(passed, result);
+ }
+ };
+
+ var asyncExpectationFactory = function(actual, spec) {
+ return j$.Expectation.asyncFactory({
+ util: j$.matchersUtil,
+ customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
+ customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers,
+ actual: actual,
+ addExpectationResult: addExpectationResult
+ });
+
+ function addExpectationResult(passed, result) {
+ return spec.addExpectationResult(passed, result);
+ }
+ };
+
+ var defaultResourcesForRunnable = function(id, parentRunnableId) {
+ var resources = {
+ spies: [],
+ customEqualityTesters: [],
+ customMatchers: {},
+ customAsyncMatchers: {},
+ customSpyStrategies: {},
+ defaultStrategyFn: undefined
+ };
+
+ if (runnableResources[parentRunnableId]) {
+ resources.customEqualityTesters = j$.util.clone(
+ runnableResources[parentRunnableId].customEqualityTesters
+ );
+ resources.customMatchers = j$.util.clone(
+ runnableResources[parentRunnableId].customMatchers
+ );
+ resources.customAsyncMatchers = j$.util.clone(
+ runnableResources[parentRunnableId].customAsyncMatchers
+ );
+ resources.defaultStrategyFn =
+ runnableResources[parentRunnableId].defaultStrategyFn;
+ }
+
+ runnableResources[id] = resources;
+ };
+
+ var clearResourcesForRunnable = function(id) {
+ spyRegistry.clearSpies();
+ delete runnableResources[id];
+ };
+
+ var beforeAndAfterFns = function(suite) {
+ return function() {
+ var befores = [],
+ afters = [];
+
+ while (suite) {
+ befores = befores.concat(suite.beforeFns);
+ afters = afters.concat(suite.afterFns);
+
+ suite = suite.parentSuite;
+ }
+
+ return {
+ befores: befores.reverse(),
+ afters: afters
+ };
+ };
+ };
+
+ var getSpecName = function(spec, suite) {
+ var fullName = [spec.description],
+ suiteFullName = suite.getFullName();
+
+ if (suiteFullName !== '') {
+ fullName.unshift(suiteFullName);
+ }
+ return fullName.join(' ');
+ };
+
+ // TODO: we may just be able to pass in the fn instead of wrapping here
+ var buildExpectationResult = j$.buildExpectationResult,
+ exceptionFormatter = new j$.ExceptionFormatter(),
+ expectationResultFactory = function(attrs) {
+ attrs.messageFormatter = exceptionFormatter.message;
+ attrs.stackFormatter = exceptionFormatter.stack;
+
+ return buildExpectationResult(attrs);
+ };
+
+ /**
+ * Sets whether Jasmine should throw an Error when an expectation fails.
+ * This causes a spec to only have one expectation failure.
+ * @name Env#throwOnExpectationFailure
+ * @since 2.3.0
+ * @function
+ * @param {Boolean} value Whether to throw when a expectation fails
+ * @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure}
+ */
+ this.throwOnExpectationFailure = function(value) {
+ this.deprecated(
+ 'Setting throwOnExpectationFailure directly on Env is deprecated and will be removed in a future version of Jasmine, please use the oneFailurePerSpec option in `configure`'
+ );
+ this.configure({ oneFailurePerSpec: !!value });
+ };
+
+ this.throwingExpectationFailures = function() {
+ this.deprecated(
+ 'Getting throwingExpectationFailures directly from Env is deprecated and will be removed in a future version of Jasmine, please check the oneFailurePerSpec option from `configuration`'
+ );
+ return config.oneFailurePerSpec;
+ };
+
+ /**
+ * Set whether to stop suite execution when a spec fails
+ * @name Env#stopOnSpecFailure
+ * @since 2.7.0
+ * @function
+ * @param {Boolean} value Whether to stop suite execution when a spec fails
+ * @deprecated Use the `failFast` option with {@link Env#configure}
+ */
+ this.stopOnSpecFailure = function(value) {
+ this.deprecated(
+ 'Setting stopOnSpecFailure directly is deprecated and will be removed in a future version of Jasmine, please use the failFast option in `configure`'
+ );
+ this.configure({ failFast: !!value });
+ };
+
+ this.stoppingOnSpecFailure = function() {
+ this.deprecated(
+ 'Getting stoppingOnSpecFailure directly from Env is deprecated and will be removed in a future version of Jasmine, please check the failFast option from `configuration`'
+ );
+ return config.failFast;
+ };
+
+ /**
+ * Set whether to randomize test execution order
+ * @name Env#randomizeTests
+ * @since 2.4.0
+ * @function
+ * @param {Boolean} value Whether to randomize execution order
+ * @deprecated Use the `random` option with {@link Env#configure}
+ */
+ this.randomizeTests = function(value) {
+ this.deprecated(
+ 'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`'
+ );
+ config.random = !!value;
+ };
+
+ this.randomTests = function() {
+ this.deprecated(
+ 'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`'
+ );
+ return config.random;
+ };
+
+ /**
+ * Set the random number seed for spec randomization
+ * @name Env#seed
+ * @since 2.4.0
+ * @function
+ * @param {Number} value The seed value
+ * @deprecated Use the `seed` option with {@link Env#configure}
+ */
+ this.seed = function(value) {
+ this.deprecated(
+ 'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`'
+ );
+ if (value) {
+ config.seed = value;
+ }
+ return config.seed;
+ };
+
+ this.hidingDisabled = function(value) {
+ this.deprecated(
+ 'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`'
+ );
+ return config.hideDisabled;
+ };
+
+ /**
+ * @name Env#hideDisabled
+ * @since 3.2.0
+ * @function
+ */
+ this.hideDisabled = function(value) {
+ this.deprecated(
+ 'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`'
+ );
+ config.hideDisabled = !!value;
+ };
+
+ this.deprecated = function(deprecation) {
+ var runnable = currentRunnable() || topSuite;
+ runnable.addDeprecationWarning(deprecation);
+ if (
+ typeof console !== 'undefined' &&
+ typeof console.error === 'function'
+ ) {
+ console.error('DEPRECATION:', deprecation);
+ }
+ };
+
+ var queueRunnerFactory = function(options, args) {
+ var failFast = false;
+ if (options.isLeaf) {
+ failFast = config.oneFailurePerSpec;
+ } else if (!options.isReporter) {
+ failFast = config.failFast;
+ }
+ options.clearStack = options.clearStack || clearStack;
+ options.timeout = {
+ setTimeout: realSetTimeout,
+ clearTimeout: realClearTimeout
+ };
+ options.fail = self.fail;
+ options.globalErrors = globalErrors;
+ options.completeOnFirstError = failFast;
+ options.onException =
+ options.onException ||
+ function(e) {
+ (currentRunnable() || topSuite).onException(e);
+ };
+ options.deprecated = self.deprecated;
+
+ new j$.QueueRunner(options).execute(args);
+ };
+
+ var topSuite = new j$.Suite({
+ env: this,
+ id: getNextSuiteId(),
+ description: 'Jasmine__TopLevel__Suite',
+ expectationFactory: expectationFactory,
+ asyncExpectationFactory: asyncExpectationFactory,
+ expectationResultFactory: expectationResultFactory
+ });
+ defaultResourcesForRunnable(topSuite.id);
+ currentDeclarationSuite = topSuite;
+
+ this.topSuite = function() {
+ return topSuite;
+ };
+
+ /**
+ * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
+ * @interface Reporter
+ * @see custom_reporter
+ */
+ var reporter = new j$.ReportDispatcher(
+ [
+ /**
+ * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
+ * @function
+ * @name Reporter#jasmineStarted
+ * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ * @see async
+ */
+ 'jasmineStarted',
+ /**
+ * When the entire suite has finished execution `jasmineDone` is called
+ * @function
+ * @name Reporter#jasmineDone
+ * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ * @see async
+ */
+ 'jasmineDone',
+ /**
+ * `suiteStarted` is invoked when a `describe` starts to run
+ * @function
+ * @name Reporter#suiteStarted
+ * @param {SuiteResult} result Information about the individual {@link describe} being run
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ * @see async
+ */
+ 'suiteStarted',
+ /**
+ * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
+ *
+ * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
+ * @function
+ * @name Reporter#suiteDone
+ * @param {SuiteResult} result
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ * @see async
+ */
+ 'suiteDone',
+ /**
+ * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
+ * @function
+ * @name Reporter#specStarted
+ * @param {SpecResult} result Information about the individual {@link it} being run
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ * @see async
+ */
+ 'specStarted',
+ /**
+ * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
+ *
+ * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
+ * @function
+ * @name Reporter#specDone
+ * @param {SpecResult} result
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ * @see async
+ */
+ 'specDone'
+ ],
+ queueRunnerFactory
+ );
+
+ this.execute = function(runnablesToRun) {
+ installGlobalErrors();
+
+ if (!runnablesToRun) {
+ if (focusedRunnables.length) {
+ runnablesToRun = focusedRunnables;
+ } else {
+ runnablesToRun = [topSuite.id];
+ }
+ }
+
+ var order = new j$.Order({
+ random: config.random,
+ seed: config.seed
+ });
+
+ var processor = new j$.TreeProcessor({
+ tree: topSuite,
+ runnableIds: runnablesToRun,
+ queueRunnerFactory: queueRunnerFactory,
+ failSpecWithNoExpectations: config.failSpecWithNoExpectations,
+ nodeStart: function(suite, next) {
+ currentlyExecutingSuites.push(suite);
+ defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
+ reporter.suiteStarted(suite.result, next);
+ suite.startTimer();
+ },
+ nodeComplete: function(suite, result, next) {
+ if (suite !== currentSuite()) {
+ throw new Error('Tried to complete the wrong suite');
+ }
+
+ clearResourcesForRunnable(suite.id);
+ currentlyExecutingSuites.pop();
+
+ if (result.status === 'failed') {
+ hasFailures = true;
+ }
+ suite.endTimer();
+ reporter.suiteDone(result, next);
+ },
+ orderChildren: function(node) {
+ return order.sort(node.children);
+ },
+ excludeNode: function(spec) {
+ return !config.specFilter(spec);
+ }
+ });
+
+ if (!processor.processTree().valid) {
+ throw new Error(
+ 'Invalid order: would cause a beforeAll or afterAll to be run multiple times'
+ );
+ }
+
+ var jasmineTimer = new j$.Timer();
+ jasmineTimer.start();
+
+ /**
+ * Information passed to the {@link Reporter#jasmineStarted} event.
+ * @typedef JasmineStartedInfo
+ * @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
+ * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
+ */
+ reporter.jasmineStarted(
+ {
+ totalSpecsDefined: totalSpecsDefined,
+ order: order
+ },
+ function() {
+ currentlyExecutingSuites.push(topSuite);
+
+ processor.execute(function() {
+ clearResourcesForRunnable(topSuite.id);
+ currentlyExecutingSuites.pop();
+ var overallStatus, incompleteReason;
+
+ if (hasFailures || topSuite.result.failedExpectations.length > 0) {
+ overallStatus = 'failed';
+ } else if (focusedRunnables.length > 0) {
+ overallStatus = 'incomplete';
+ incompleteReason = 'fit() or fdescribe() was found';
+ } else if (totalSpecsDefined === 0) {
+ overallStatus = 'incomplete';
+ incompleteReason = 'No specs found';
+ } else {
+ overallStatus = 'passed';
+ }
+
+ /**
+ * Information passed to the {@link Reporter#jasmineDone} event.
+ * @typedef JasmineDoneInfo
+ * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
+ * @property {Int} totalTime - The total time (in ms) that it took to execute the suite
+ * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
+ * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
+ * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
+ * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
+ */
+ reporter.jasmineDone(
+ {
+ overallStatus: overallStatus,
+ totalTime: jasmineTimer.elapsed(),
+ incompleteReason: incompleteReason,
+ order: order,
+ failedExpectations: topSuite.result.failedExpectations,
+ deprecationWarnings: topSuite.result.deprecationWarnings
+ },
+ function() {}
+ );
+ });
+ }
+ );
+ };
+
+ /**
+ * Add a custom reporter to the Jasmine environment.
+ * @name Env#addReporter
+ * @since 2.0.0
+ * @function
+ * @param {Reporter} reporterToAdd The reporter to be added.
+ * @see custom_reporter
+ */
+ this.addReporter = function(reporterToAdd) {
+ reporter.addReporter(reporterToAdd);
+ };
+
+ /**
+ * Provide a fallback reporter if no other reporters have been specified.
+ * @name Env#provideFallbackReporter
+ * @since 2.5.0
+ * @function
+ * @param {Reporter} reporterToAdd The reporter
+ * @see custom_reporter
+ */
+ this.provideFallbackReporter = function(reporterToAdd) {
+ reporter.provideFallbackReporter(reporterToAdd);
+ };
+
+ /**
+ * Clear all registered reporters
+ * @name Env#clearReporters
+ * @since 2.5.2
+ * @function
+ */
+ this.clearReporters = function() {
+ reporter.clearReporters();
+ };
+
+ var spyFactory = new j$.SpyFactory(
+ function getCustomStrategies() {
+ var runnable = currentRunnable();
+
+ if (runnable) {
+ return runnableResources[runnable.id].customSpyStrategies;
+ }
+
+ return {};
+ },
+ function getDefaultStrategyFn() {
+ var runnable = currentRunnable();
+
+ if (runnable) {
+ return runnableResources[runnable.id].defaultStrategyFn;
+ }
+
+ return undefined;
+ },
+ function getPromise() {
+ return customPromise || global.Promise;
+ }
+ );
+
+ var spyRegistry = new j$.SpyRegistry({
+ currentSpies: function() {
+ if (!currentRunnable()) {
+ throw new Error(
+ 'Spies must be created in a before function or a spec'
+ );
+ }
+ return runnableResources[currentRunnable().id].spies;
+ },
+ createSpy: function(name, originalFn) {
+ return self.createSpy(name, originalFn);
+ }
+ });
+
+ this.allowRespy = function(allow) {
+ spyRegistry.allowRespy(allow);
+ };
+
+ this.spyOn = function() {
+ return spyRegistry.spyOn.apply(spyRegistry, arguments);
+ };
+
+ this.spyOnProperty = function() {
+ return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
+ };
+
+ this.spyOnAllFunctions = function() {
+ return spyRegistry.spyOnAllFunctions.apply(spyRegistry, arguments);
+ };
+
+ this.createSpy = function(name, originalFn) {
+ if (arguments.length === 1 && j$.isFunction_(name)) {
+ originalFn = name;
+ name = originalFn.name;
+ }
+
+ return spyFactory.createSpy(name, originalFn);
+ };
+
+ this.createSpyObj = function(baseName, methodNames, propertyNames) {
+ return spyFactory.createSpyObj(baseName, methodNames, propertyNames);
+ };
+
+ var ensureIsFunction = function(fn, caller) {
+ if (!j$.isFunction_(fn)) {
+ throw new Error(
+ caller + ' expects a function argument; received ' + j$.getType_(fn)
+ );
+ }
+ };
+
+ var ensureIsFunctionOrAsync = function(fn, caller) {
+ if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
+ throw new Error(
+ caller + ' expects a function argument; received ' + j$.getType_(fn)
+ );
+ }
+ };
+
+ function ensureIsNotNested(method) {
+ var runnable = currentRunnable();
+ if (runnable !== null && runnable !== undefined) {
+ throw new Error(
+ "'" + method + "' should only be used in 'describe' function"
+ );
+ }
+ }
+
+ var suiteFactory = function(description) {
+ var suite = new j$.Suite({
+ env: self,
+ id: getNextSuiteId(),
+ description: description,
+ parentSuite: currentDeclarationSuite,
+ expectationFactory: expectationFactory,
+ asyncExpectationFactory: asyncExpectationFactory,
+ expectationResultFactory: expectationResultFactory,
+ throwOnExpectationFailure: config.oneFailurePerSpec
+ });
+
+ return suite;
+ };
+
+ this.describe = function(description, specDefinitions) {
+ ensureIsNotNested('describe');
+ ensureIsFunction(specDefinitions, 'describe');
+ var suite = suiteFactory(description);
+ if (specDefinitions.length > 0) {
+ throw new Error('describe does not expect any arguments');
+ }
+ if (currentDeclarationSuite.markedPending) {
+ suite.pend();
+ }
+ addSpecsToSuite(suite, specDefinitions);
+ return suite;
+ };
+
+ this.xdescribe = function(description, specDefinitions) {
+ ensureIsNotNested('xdescribe');
+ ensureIsFunction(specDefinitions, 'xdescribe');
+ var suite = suiteFactory(description);
+ suite.pend();
+ addSpecsToSuite(suite, specDefinitions);
+ return suite;
+ };
+
+ var focusedRunnables = [];
+
+ this.fdescribe = function(description, specDefinitions) {
+ ensureIsNotNested('fdescribe');
+ ensureIsFunction(specDefinitions, 'fdescribe');
+ var suite = suiteFactory(description);
+ suite.isFocused = true;
+
+ focusedRunnables.push(suite.id);
+ unfocusAncestor();
+ addSpecsToSuite(suite, specDefinitions);
+
+ return suite;
+ };
+
+ function addSpecsToSuite(suite, specDefinitions) {
+ var parentSuite = currentDeclarationSuite;
+ parentSuite.addChild(suite);
+ currentDeclarationSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch (e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ suite.onException(declarationError);
+ }
+
+ currentDeclarationSuite = parentSuite;
+ }
+
+ function findFocusedAncestor(suite) {
+ while (suite) {
+ if (suite.isFocused) {
+ return suite.id;
+ }
+ suite = suite.parentSuite;
+ }
+
+ return null;
+ }
+
+ function unfocusAncestor() {
+ var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
+ if (focusedAncestor) {
+ for (var i = 0; i < focusedRunnables.length; i++) {
+ if (focusedRunnables[i] === focusedAncestor) {
+ focusedRunnables.splice(i, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ var specFactory = function(description, fn, suite, timeout) {
+ totalSpecsDefined++;
+ var spec = new j$.Spec({
+ id: getNextSpecId(),
+ beforeAndAfterFns: beforeAndAfterFns(suite),
+ expectationFactory: expectationFactory,
+ asyncExpectationFactory: asyncExpectationFactory,
+ resultCallback: specResultCallback,
+ getSpecName: function(spec) {
+ return getSpecName(spec, suite);
+ },
+ onStart: specStarted,
+ description: description,
+ expectationResultFactory: expectationResultFactory,
+ queueRunnerFactory: queueRunnerFactory,
+ userContext: function() {
+ return suite.clonedSharedUserContext();
+ },
+ queueableFn: {
+ fn: fn,
+ timeout: timeout || 0
+ },
+ throwOnExpectationFailure: config.oneFailurePerSpec,
+ timer: new j$.Timer()
+ });
+ return spec;
+
+ function specResultCallback(result, next) {
+ clearResourcesForRunnable(spec.id);
+ currentSpec = null;
+
+ if (result.status === 'failed') {
+ hasFailures = true;
+ }
+
+ reporter.specDone(result, next);
+ }
+
+ function specStarted(spec, next) {
+ currentSpec = spec;
+ defaultResourcesForRunnable(spec.id, suite.id);
+ reporter.specStarted(spec.result, next);
+ }
+ };
+
+ this.it = function(description, fn, timeout) {
+ ensureIsNotNested('it');
+ // it() sometimes doesn't have a fn argument, so only check the type if
+ // it's given.
+ if (arguments.length > 1 && typeof fn !== 'undefined') {
+ ensureIsFunctionOrAsync(fn, 'it');
+ }
+ var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
+ if (currentDeclarationSuite.markedPending) {
+ spec.pend();
+ }
+ currentDeclarationSuite.addChild(spec);
+ return spec;
+ };
+
+ this.xit = function(description, fn, timeout) {
+ ensureIsNotNested('xit');
+ // xit(), like it(), doesn't always have a fn argument, so only check the
+ // type when needed.
+ if (arguments.length > 1 && typeof fn !== 'undefined') {
+ ensureIsFunctionOrAsync(fn, 'xit');
+ }
+ var spec = this.it.apply(this, arguments);
+ spec.pend('Temporarily disabled with xit');
+ return spec;
+ };
+
+ this.fit = function(description, fn, timeout) {
+ ensureIsNotNested('fit');
+ ensureIsFunctionOrAsync(fn, 'fit');
+ var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
+ currentDeclarationSuite.addChild(spec);
+ focusedRunnables.push(spec.id);
+ unfocusAncestor();
+ return spec;
+ };
+
+ this.expect = function(actual) {
+ if (!currentRunnable()) {
+ throw new Error(
+ "'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
+ );
+ }
+
+ return currentRunnable().expect(actual);
+ };
+
+ this.expectAsync = function(actual) {
+ if (!currentRunnable()) {
+ throw new Error(
+ "'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
+ );
+ }
+
+ return currentRunnable().expectAsync(actual);
+ };
+
+ this.beforeEach = function(beforeEachFunction, timeout) {
+ ensureIsNotNested('beforeEach');
+ ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
+ currentDeclarationSuite.beforeEach({
+ fn: beforeEachFunction,
+ timeout: timeout || 0
+ });
+ };
+
+ this.beforeAll = function(beforeAllFunction, timeout) {
+ ensureIsNotNested('beforeAll');
+ ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
+ currentDeclarationSuite.beforeAll({
+ fn: beforeAllFunction,
+ timeout: timeout || 0
+ });
+ };
+
+ this.afterEach = function(afterEachFunction, timeout) {
+ ensureIsNotNested('afterEach');
+ ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
+ afterEachFunction.isCleanup = true;
+ currentDeclarationSuite.afterEach({
+ fn: afterEachFunction,
+ timeout: timeout || 0
+ });
+ };
+
+ this.afterAll = function(afterAllFunction, timeout) {
+ ensureIsNotNested('afterAll');
+ ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
+ currentDeclarationSuite.afterAll({
+ fn: afterAllFunction,
+ timeout: timeout || 0
+ });
+ };
+
+ this.pending = function(message) {
+ var fullMessage = j$.Spec.pendingSpecExceptionMessage;
+ if (message) {
+ fullMessage += message;
+ }
+ throw fullMessage;
+ };
+
+ this.fail = function(error) {
+ if (!currentRunnable()) {
+ throw new Error(
+ "'fail' was used when there was no current spec, this could be because an asynchronous test timed out"
+ );
+ }
+
+ var message = 'Failed';
+ if (error) {
+ message += ': ';
+ if (error.message) {
+ message += error.message;
+ } else if (j$.isString_(error)) {
+ message += error;
+ } else {
+ // pretty print all kind of objects. This includes arrays.
+ message += j$.pp(error);
+ }
+ }
+
+ currentRunnable().addExpectationResult(false, {
+ matcherName: '',
+ passed: false,
+ expected: '',
+ actual: '',
+ message: message,
+ error: error && error.message ? error : null
+ });
+
+ if (config.oneFailurePerSpec) {
+ throw new Error(message);
+ }
+ };
+ }
+
+ return Env;
+};
+
+getJasmineRequireObj().JsApiReporter = function(j$) {
+ /**
+ * @name jsApiReporter
+ * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object.
+ * @class
+ * @hideconstructor
+ */
+ function JsApiReporter(options) {
+ var timer = options.timer || j$.noopTimer,
+ status = 'loaded';
+
+ this.started = false;
+ this.finished = false;
+ this.runDetails = {};
+
+ this.jasmineStarted = function() {
+ this.started = true;
+ status = 'started';
+ timer.start();
+ };
+
+ var executionTime;
+
+ this.jasmineDone = function(runDetails) {
+ this.finished = true;
+ this.runDetails = runDetails;
+ executionTime = timer.elapsed();
+ status = 'done';
+ };
+
+ /**
+ * Get the current status for the Jasmine environment.
+ * @name jsApiReporter#status
+ * @since 2.0.0
+ * @function
+ * @return {String} - One of `loaded`, `started`, or `done`
+ */
+ this.status = function() {
+ return status;
+ };
+
+ var suites = [],
+ suites_hash = {};
+
+ this.suiteStarted = function(result) {
+ suites_hash[result.id] = result;
+ };
+
+ this.suiteDone = function(result) {
+ storeSuite(result);
+ };
+
+ /**
+ * Get the results for a set of suites.
+ *
+ * Retrievable in slices for easier serialization.
+ * @name jsApiReporter#suiteResults
+ * @since 2.1.0
+ * @function
+ * @param {Number} index - The position in the suites list to start from.
+ * @param {Number} length - Maximum number of suite results to return.
+ * @return {SuiteResult[]}
+ */
+ this.suiteResults = function(index, length) {
+ return suites.slice(index, index + length);
+ };
+
+ function storeSuite(result) {
+ suites.push(result);
+ suites_hash[result.id] = result;
+ }
+
+ /**
+ * Get all of the suites in a single object, with their `id` as the key.
+ * @name jsApiReporter#suites
+ * @since 2.0.0
+ * @function
+ * @return {Object} - Map of suite id to {@link SuiteResult}
+ */
+ this.suites = function() {
+ return suites_hash;
+ };
+
+ var specs = [];
+
+ this.specDone = function(result) {
+ specs.push(result);
+ };
+
+ /**
+ * Get the results for a set of specs.
+ *
+ * Retrievable in slices for easier serialization.
+ * @name jsApiReporter#specResults
+ * @since 2.0.0
+ * @function
+ * @param {Number} index - The position in the specs list to start from.
+ * @param {Number} length - Maximum number of specs results to return.
+ * @return {SpecResult[]}
+ */
+ this.specResults = function(index, length) {
+ return specs.slice(index, index + length);
+ };
+
+ /**
+ * Get all spec results.
+ * @name jsApiReporter#specs
+ * @since 2.0.0
+ * @function
+ * @return {SpecResult[]}
+ */
+ this.specs = function() {
+ return specs;
+ };
+
+ /**
+ * Get the number of milliseconds it took for the full Jasmine suite to run.
+ * @name jsApiReporter#executionTime
+ * @since 2.0.0
+ * @function
+ * @return {Number}
+ */
+ this.executionTime = function() {
+ return executionTime;
+ };
+ }
+
+ return JsApiReporter;
+};
+
+getJasmineRequireObj().Any = function(j$) {
+
+ function Any(expectedObject) {
+ if (typeof expectedObject === 'undefined') {
+ throw new TypeError(
+ 'jasmine.any() expects to be passed a constructor function. ' +
+ 'Please pass one or use jasmine.anything() to match any object.'
+ );
+ }
+ this.expectedObject = expectedObject;
+ }
+
+ Any.prototype.asymmetricMatch = function(other) {
+ if (this.expectedObject == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedObject == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedObject == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedObject == Object) {
+ return other !== null && typeof other == 'object';
+ }
+
+ if (this.expectedObject == Boolean) {
+ return typeof other == 'boolean';
+ }
+
+ /* jshint -W122 */
+ /* global Symbol */
+ if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
+ return typeof other == 'symbol';
+ }
+ /* jshint +W122 */
+
+ return other instanceof this.expectedObject;
+ };
+
+ Any.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return Any;
+};
+
+getJasmineRequireObj().Anything = function(j$) {
+
+ function Anything() {}
+
+ Anything.prototype.asymmetricMatch = function(other) {
+ return !j$.util.isUndefined(other) && other !== null;
+ };
+
+ Anything.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return Anything;
+};
+
+getJasmineRequireObj().ArrayContaining = function(j$) {
+ function ArrayContaining(sample) {
+ this.sample = sample;
+ }
+
+ ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
+ if (!j$.isArray_(this.sample)) {
+ throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
+ }
+
+ // If the actual parameter is not an array, we can fail immediately, since it couldn't
+ // possibly be an "array containing" anything. However, we also want an empty sample
+ // array to match anything, so we need to double-check we aren't in that case
+ if (!j$.isArray_(other) && this.sample.length > 0) {
+ return false;
+ }
+
+ for (var i = 0; i < this.sample.length; i++) {
+ var item = this.sample[i];
+ if (!j$.matchersUtil.contains(other, item, customTesters)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ ArrayContaining.prototype.jasmineToString = function () {
+ return '';
+ };
+
+ return ArrayContaining;
+};
+
+getJasmineRequireObj().ArrayWithExactContents = function(j$) {
+
+ function ArrayWithExactContents(sample) {
+ this.sample = sample;
+ }
+
+ ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
+ if (!j$.isArray_(this.sample)) {
+ throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
+ }
+
+ if (this.sample.length !== other.length) {
+ return false;
+ }
+
+ for (var i = 0; i < this.sample.length; i++) {
+ var item = this.sample[i];
+ if (!j$.matchersUtil.contains(other, item, customTesters)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ ArrayWithExactContents.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return ArrayWithExactContents;
+};
+
+getJasmineRequireObj().Empty = function (j$) {
+
+ function Empty() {}
+
+ Empty.prototype.asymmetricMatch = function (other) {
+ if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
+ return other.length === 0;
+ }
+
+ if (j$.isMap(other) || j$.isSet(other)) {
+ return other.size === 0;
+ }
+
+ if (j$.isObject_(other)) {
+ return Object.keys(other).length === 0;
+ }
+ return false;
+ };
+
+ Empty.prototype.jasmineToString = function () {
+ return '';
+ };
+
+ return Empty;
+};
+
+getJasmineRequireObj().Falsy = function(j$) {
+
+ function Falsy() {}
+
+ Falsy.prototype.asymmetricMatch = function(other) {
+ return !other;
+ };
+
+ Falsy.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return Falsy;
+};
+
+getJasmineRequireObj().MapContaining = function(j$) {
+ function MapContaining(sample) {
+ if (!j$.isMap(sample)) {
+ throw new Error('You must provide a map to `mapContaining`, not ' + j$.pp(sample));
+ }
+
+ this.sample = sample;
+ }
+
+ MapContaining.prototype.asymmetricMatch = function(other, customTesters) {
+ if (!j$.isMap(other)) return false;
+
+ var hasAllMatches = true;
+ j$.util.forEachBreakable(this.sample, function(breakLoop, value, key) {
+ // for each key/value pair in `sample`
+ // there should be at least one pair in `other` whose key and value both match
+ var hasMatch = false;
+ j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
+ if (
+ j$.matchersUtil.equals(oKey, key, customTesters)
+ && j$.matchersUtil.equals(oValue, value, customTesters)
+ ) {
+ hasMatch = true;
+ oBreakLoop();
+ }
+ });
+ if (!hasMatch) {
+ hasAllMatches = false;
+ breakLoop();
+ }
+ });
+
+ return hasAllMatches;
+ };
+
+ MapContaining.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return MapContaining;
+};
+
+getJasmineRequireObj().NotEmpty = function (j$) {
+
+ function NotEmpty() {}
+
+ NotEmpty.prototype.asymmetricMatch = function (other) {
+ if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
+ return other.length !== 0;
+ }
+
+ if (j$.isMap(other) || j$.isSet(other)) {
+ return other.size !== 0;
+ }
+
+ if (j$.isObject_(other)) {
+ return Object.keys(other).length !== 0;
+ }
+
+ return false;
+ };
+
+ NotEmpty.prototype.jasmineToString = function () {
+ return '';
+ };
+
+ return NotEmpty;
+};
+
+getJasmineRequireObj().ObjectContaining = function(j$) {
+
+ function ObjectContaining(sample) {
+ this.sample = sample;
+ }
+
+ function getPrototype(obj) {
+ if (Object.getPrototypeOf) {
+ return Object.getPrototypeOf(obj);
+ }
+
+ if (obj.constructor.prototype == obj) {
+ return null;
+ }
+
+ return obj.constructor.prototype;
+ }
+
+ function hasProperty(obj, property) {
+ if (!obj) {
+ return false;
+ }
+
+ if (Object.prototype.hasOwnProperty.call(obj, property)) {
+ return true;
+ }
+
+ return hasProperty(getPrototype(obj), property);
+ }
+
+ ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
+ if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
+
+ for (var property in this.sample) {
+ if (!hasProperty(other, property) ||
+ !j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ ObjectContaining.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return ObjectContaining;
+};
+
+getJasmineRequireObj().SetContaining = function(j$) {
+ function SetContaining(sample) {
+ if (!j$.isSet(sample)) {
+ throw new Error('You must provide a set to `setContaining`, not ' + j$.pp(sample));
+ }
+
+ this.sample = sample;
+ }
+
+ SetContaining.prototype.asymmetricMatch = function(other, customTesters) {
+ if (!j$.isSet(other)) return false;
+
+ var hasAllMatches = true;
+ j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
+ // for each item in `sample` there should be at least one matching item in `other`
+ // (not using `j$.matchersUtil.contains` because it compares set members by reference,
+ // not by deep value equality)
+ var hasMatch = false;
+ j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
+ if (j$.matchersUtil.equals(oItem, item, customTesters)) {
+ hasMatch = true;
+ oBreakLoop();
+ }
+ });
+ if (!hasMatch) {
+ hasAllMatches = false;
+ breakLoop();
+ }
+ });
+
+ return hasAllMatches;
+ };
+
+ SetContaining.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return SetContaining;
+};
+
+getJasmineRequireObj().StringMatching = function(j$) {
+
+ function StringMatching(expected) {
+ if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
+ throw new Error('Expected is not a String or a RegExp');
+ }
+
+ this.regexp = new RegExp(expected);
+ }
+
+ StringMatching.prototype.asymmetricMatch = function(other) {
+ return this.regexp.test(other);
+ };
+
+ StringMatching.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return StringMatching;
+};
+
+getJasmineRequireObj().Truthy = function(j$) {
+
+ function Truthy() {}
+
+ Truthy.prototype.asymmetricMatch = function(other) {
+ return !!other;
+ };
+
+ Truthy.prototype.jasmineToString = function() {
+ return '';
+ };
+
+ return Truthy;
+};
+
+getJasmineRequireObj().CallTracker = function(j$) {
+ /**
+ * @namespace Spy#calls
+ * @since 2.0.0
+ */
+ function CallTracker() {
+ var calls = [];
+ var opts = {};
+
+ this.track = function(context) {
+ if (opts.cloneArgs) {
+ context.args = j$.util.cloneArgs(context.args);
+ }
+ calls.push(context);
+ };
+
+ /**
+ * Check whether this spy has been invoked.
+ * @name Spy#calls#any
+ * @since 2.0.0
+ * @function
+ * @return {Boolean}
+ */
+ this.any = function() {
+ return !!calls.length;
+ };
+
+ /**
+ * Get the number of invocations of this spy.
+ * @name Spy#calls#count
+ * @since 2.0.0
+ * @function
+ * @return {Integer}
+ */
+ this.count = function() {
+ return calls.length;
+ };
+
+ /**
+ * Get the arguments that were passed to a specific invocation of this spy.
+ * @name Spy#calls#argsFor
+ * @since 2.0.0
+ * @function
+ * @param {Integer} index The 0-based invocation index.
+ * @return {Array}
+ */
+ this.argsFor = function(index) {
+ var call = calls[index];
+ return call ? call.args : [];
+ };
+
+ /**
+ * Get the raw calls array for this spy.
+ * @name Spy#calls#all
+ * @since 2.0.0
+ * @function
+ * @return {Spy.callData[]}
+ */
+ this.all = function() {
+ return calls;
+ };
+
+ /**
+ * Get all of the arguments for each invocation of this spy in the order they were received.
+ * @name Spy#calls#allArgs
+ * @since 2.0.0
+ * @function
+ * @return {Array}
+ */
+ this.allArgs = function() {
+ var callArgs = [];
+ for (var i = 0; i < calls.length; i++) {
+ callArgs.push(calls[i].args);
+ }
+
+ return callArgs;
+ };
+
+ /**
+ * Get the first invocation of this spy.
+ * @name Spy#calls#first
+ * @since 2.0.0
+ * @function
+ * @return {ObjecSpy.callData}
+ */
+ this.first = function() {
+ return calls[0];
+ };
+
+ /**
+ * Get the most recent invocation of this spy.
+ * @name Spy#calls#mostRecent
+ * @since 2.0.0
+ * @function
+ * @return {ObjecSpy.callData}
+ */
+ this.mostRecent = function() {
+ return calls[calls.length - 1];
+ };
+
+ /**
+ * Reset this spy as if it has never been called.
+ * @name Spy#calls#reset
+ * @since 2.0.0
+ * @function
+ */
+ this.reset = function() {
+ calls = [];
+ };
+
+ /**
+ * Set this spy to do a shallow clone of arguments passed to each invocation.
+ * @name Spy#calls#saveArgumentsByValue
+ * @since 2.5.0
+ * @function
+ */
+ this.saveArgumentsByValue = function() {
+ opts.cloneArgs = true;
+ };
+ }
+
+ return CallTracker;
+};
+
+getJasmineRequireObj().clearStack = function(j$) {
+ var maxInlineCallCount = 10;
+
+ function messageChannelImpl(global, setTimeout) {
+ var channel = new global.MessageChannel(),
+ head = {},
+ tail = head;
+
+ var taskRunning = false;
+ channel.port1.onmessage = function() {
+ head = head.next;
+ var task = head.task;
+ delete head.task;
+
+ if (taskRunning) {
+ global.setTimeout(task, 0);
+ } else {
+ try {
+ taskRunning = true;
+ task();
+ } finally {
+ taskRunning = false;
+ }
+ }
+ };
+
+ var currentCallCount = 0;
+ return function clearStack(fn) {
+ currentCallCount++;
+
+ if (currentCallCount < maxInlineCallCount) {
+ tail = tail.next = { task: fn };
+ channel.port2.postMessage(0);
+ } else {
+ currentCallCount = 0;
+ setTimeout(fn);
+ }
+ };
+ }
+
+ function getClearStack(global) {
+ var currentCallCount = 0;
+ var realSetTimeout = global.setTimeout;
+ var setTimeoutImpl = function clearStack(fn) {
+ Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
+ };
+
+ if (j$.isFunction_(global.setImmediate)) {
+ var realSetImmediate = global.setImmediate;
+ return function(fn) {
+ currentCallCount++;
+
+ if (currentCallCount < maxInlineCallCount) {
+ realSetImmediate(fn);
+ } else {
+ currentCallCount = 0;
+
+ setTimeoutImpl(fn);
+ }
+ };
+ } else if (!j$.util.isUndefined(global.MessageChannel)) {
+ return messageChannelImpl(global, setTimeoutImpl);
+ } else {
+ return setTimeoutImpl;
+ }
+ }
+
+ return getClearStack;
+};
+
+getJasmineRequireObj().Clock = function() {
+ /* global process */
+ var NODE_JS =
+ typeof process !== 'undefined' &&
+ process.versions &&
+ typeof process.versions.node === 'string';
+
+ /**
+ * _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
+ * @class Clock
+ * @classdesc Jasmine's mock clock is used when testing time dependent code.
+ */
+ function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
+ var self = this,
+ realTimingFunctions = {
+ setTimeout: global.setTimeout,
+ clearTimeout: global.clearTimeout,
+ setInterval: global.setInterval,
+ clearInterval: global.clearInterval
+ },
+ fakeTimingFunctions = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval
+ },
+ installed = false,
+ delayedFunctionScheduler,
+ timer;
+
+ self.FakeTimeout = FakeTimeout;
+
+ /**
+ * Install the mock clock over the built-in methods.
+ * @name Clock#install
+ * @since 2.0.0
+ * @function
+ * @return {Clock}
+ */
+ self.install = function() {
+ if (!originalTimingFunctionsIntact()) {
+ throw new Error(
+ 'Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?'
+ );
+ }
+ replace(global, fakeTimingFunctions);
+ timer = fakeTimingFunctions;
+ delayedFunctionScheduler = delayedFunctionSchedulerFactory();
+ installed = true;
+
+ return self;
+ };
+
+ /**
+ * Uninstall the mock clock, returning the built-in methods to their places.
+ * @name Clock#uninstall
+ * @since 2.0.0
+ * @function
+ */
+ self.uninstall = function() {
+ delayedFunctionScheduler = null;
+ mockDate.uninstall();
+ replace(global, realTimingFunctions);
+
+ timer = realTimingFunctions;
+ installed = false;
+ };
+
+ /**
+ * Execute a function with a mocked Clock
+ *
+ * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
+ * @name Clock#withMock
+ * @since 2.3.0
+ * @function
+ * @param {Function} closure The function to be called.
+ */
+ self.withMock = function(closure) {
+ this.install();
+ try {
+ closure();
+ } finally {
+ this.uninstall();
+ }
+ };
+
+ /**
+ * Instruct the installed Clock to also mock the date returned by `new Date()`
+ * @name Clock#mockDate
+ * @since 2.1.0
+ * @function
+ * @param {Date} [initialDate=now] The `Date` to provide.
+ */
+ self.mockDate = function(initialDate) {
+ mockDate.install(initialDate);
+ };
+
+ self.setTimeout = function(fn, delay, params) {
+ return Function.prototype.apply.apply(timer.setTimeout, [
+ global,
+ arguments
+ ]);
+ };
+
+ self.setInterval = function(fn, delay, params) {
+ return Function.prototype.apply.apply(timer.setInterval, [
+ global,
+ arguments
+ ]);
+ };
+
+ self.clearTimeout = function(id) {
+ return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
+ };
+
+ self.clearInterval = function(id) {
+ return Function.prototype.call.apply(timer.clearInterval, [global, id]);
+ };
+
+ /**
+ * Tick the Clock forward, running any enqueued timeouts along the way
+ * @name Clock#tick
+ * @since 1.3.0
+ * @function
+ * @param {int} millis The number of milliseconds to tick.
+ */
+ self.tick = function(millis) {
+ if (installed) {
+ delayedFunctionScheduler.tick(millis, function(millis) {
+ mockDate.tick(millis);
+ });
+ } else {
+ throw new Error(
+ 'Mock clock is not installed, use jasmine.clock().install()'
+ );
+ }
+ };
+
+ return self;
+
+ function originalTimingFunctionsIntact() {
+ return (
+ global.setTimeout === realTimingFunctions.setTimeout &&
+ global.clearTimeout === realTimingFunctions.clearTimeout &&
+ global.setInterval === realTimingFunctions.setInterval &&
+ global.clearInterval === realTimingFunctions.clearInterval
+ );
+ }
+
+ function replace(dest, source) {
+ for (var prop in source) {
+ dest[prop] = source[prop];
+ }
+ }
+
+ function setTimeout(fn, delay) {
+ if (!NODE_JS) {
+ return delayedFunctionScheduler.scheduleFunction(
+ fn,
+ delay,
+ argSlice(arguments, 2)
+ );
+ }
+
+ var timeout = new FakeTimeout();
+
+ delayedFunctionScheduler.scheduleFunction(
+ fn,
+ delay,
+ argSlice(arguments, 2),
+ false,
+ timeout
+ );
+
+ return timeout;
+ }
+
+ function clearTimeout(id) {
+ return delayedFunctionScheduler.removeFunctionWithId(id);
+ }
+
+ function setInterval(fn, interval) {
+ if (!NODE_JS) {
+ return delayedFunctionScheduler.scheduleFunction(
+ fn,
+ interval,
+ argSlice(arguments, 2),
+ true
+ );
+ }
+
+ var timeout = new FakeTimeout();
+
+ delayedFunctionScheduler.scheduleFunction(
+ fn,
+ interval,
+ argSlice(arguments, 2),
+ true,
+ timeout
+ );
+
+ return timeout;
+ }
+
+ function clearInterval(id) {
+ return delayedFunctionScheduler.removeFunctionWithId(id);
+ }
+
+ function argSlice(argsObj, n) {
+ return Array.prototype.slice.call(argsObj, n);
+ }
+ }
+
+ /**
+ * Mocks Node.js Timeout class
+ */
+ function FakeTimeout() {}
+
+ FakeTimeout.prototype.ref = function() {
+ return this;
+ };
+
+ FakeTimeout.prototype.unref = function() {
+ return this;
+ };
+
+ return Clock;
+};
+
+getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
+ function DelayedFunctionScheduler() {
+ var self = this;
+ var scheduledLookup = [];
+ var scheduledFunctions = {};
+ var currentTime = 0;
+ var delayedFnCount = 0;
+ var deletedKeys = [];
+
+ self.tick = function(millis, tickDate) {
+ millis = millis || 0;
+ var endTime = currentTime + millis;
+
+ runScheduledFunctions(endTime, tickDate);
+ currentTime = endTime;
+ };
+
+ self.scheduleFunction = function(
+ funcToCall,
+ millis,
+ params,
+ recurring,
+ timeoutKey,
+ runAtMillis
+ ) {
+ var f;
+ if (typeof funcToCall === 'string') {
+ /* jshint evil: true */
+ f = function() {
+ return eval(funcToCall);
+ };
+ /* jshint evil: false */
+ } else {
+ f = funcToCall;
+ }
+
+ millis = millis || 0;
+ timeoutKey = timeoutKey || ++delayedFnCount;
+ runAtMillis = runAtMillis || currentTime + millis;
+
+ var funcToSchedule = {
+ runAtMillis: runAtMillis,
+ funcToCall: f,
+ recurring: recurring,
+ params: params,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+
+ if (runAtMillis in scheduledFunctions) {
+ scheduledFunctions[runAtMillis].push(funcToSchedule);
+ } else {
+ scheduledFunctions[runAtMillis] = [funcToSchedule];
+ scheduledLookup.push(runAtMillis);
+ scheduledLookup.sort(function(a, b) {
+ return a - b;
+ });
+ }
+
+ return timeoutKey;
+ };
+
+ self.removeFunctionWithId = function(timeoutKey) {
+ deletedKeys.push(timeoutKey);
+
+ for (var runAtMillis in scheduledFunctions) {
+ var funcs = scheduledFunctions[runAtMillis];
+ var i = indexOfFirstToPass(funcs, function(func) {
+ return func.timeoutKey === timeoutKey;
+ });
+
+ if (i > -1) {
+ if (funcs.length === 1) {
+ delete scheduledFunctions[runAtMillis];
+ deleteFromLookup(runAtMillis);
+ } else {
+ funcs.splice(i, 1);
+ }
+
+ // intervals get rescheduled when executed, so there's never more
+ // than a single scheduled function with a given timeoutKey
+ break;
+ }
+ }
+ };
+
+ return self;
+
+ function indexOfFirstToPass(array, testFn) {
+ var index = -1;
+
+ for (var i = 0; i < array.length; ++i) {
+ if (testFn(array[i])) {
+ index = i;
+ break;
+ }
+ }
+
+ return index;
+ }
+
+ function deleteFromLookup(key) {
+ var value = Number(key);
+ var i = indexOfFirstToPass(scheduledLookup, function(millis) {
+ return millis === value;
+ });
+
+ if (i > -1) {
+ scheduledLookup.splice(i, 1);
+ }
+ }
+
+ function reschedule(scheduledFn) {
+ self.scheduleFunction(
+ scheduledFn.funcToCall,
+ scheduledFn.millis,
+ scheduledFn.params,
+ true,
+ scheduledFn.timeoutKey,
+ scheduledFn.runAtMillis + scheduledFn.millis
+ );
+ }
+
+ function forEachFunction(funcsToRun, callback) {
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ callback(funcsToRun[i]);
+ }
+ }
+
+ function runScheduledFunctions(endTime, tickDate) {
+ tickDate = tickDate || function() {};
+ if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
+ tickDate(endTime - currentTime);
+ return;
+ }
+
+ do {
+ deletedKeys = [];
+ var newCurrentTime = scheduledLookup.shift();
+ tickDate(newCurrentTime - currentTime);
+
+ currentTime = newCurrentTime;
+
+ var funcsToRun = scheduledFunctions[currentTime];
+
+ delete scheduledFunctions[currentTime];
+
+ forEachFunction(funcsToRun, function(funcToRun) {
+ if (funcToRun.recurring) {
+ reschedule(funcToRun);
+ }
+ });
+
+ forEachFunction(funcsToRun, function(funcToRun) {
+ if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) {
+ // skip a timeoutKey deleted whilst we were running
+ return;
+ }
+ funcToRun.funcToCall.apply(null, funcToRun.params || []);
+ });
+ deletedKeys = [];
+ } while (
+ scheduledLookup.length > 0 &&
+ // checking first if we're out of time prevents setTimeout(0)
+ // scheduled in a funcToRun from forcing an extra iteration
+ currentTime !== endTime &&
+ scheduledLookup[0] <= endTime
+ );
+
+ // ran out of functions to call, but still time left on the clock
+ if (currentTime !== endTime) {
+ tickDate(endTime - currentTime);
+ }
+ }
+ }
+
+ return DelayedFunctionScheduler;
+};
+
+getJasmineRequireObj().errors = function() {
+ function ExpectationFailed() {}
+
+ ExpectationFailed.prototype = new Error();
+ ExpectationFailed.prototype.constructor = ExpectationFailed;
+
+ return {
+ ExpectationFailed: ExpectationFailed
+ };
+};
+
+getJasmineRequireObj().ExceptionFormatter = function(j$) {
+ var ignoredProperties = [
+ 'name',
+ 'message',
+ 'stack',
+ 'fileName',
+ 'sourceURL',
+ 'line',
+ 'lineNumber',
+ 'column',
+ 'description',
+ 'jasmineMessage'
+ ];
+
+ function ExceptionFormatter(options) {
+ var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile();
+ this.message = function(error) {
+ var message = '';
+
+ if (error.jasmineMessage) {
+ message += error.jasmineMessage;
+ } else if (error.name && error.message) {
+ message += error.name + ': ' + error.message;
+ } else if (error.message) {
+ message += error.message;
+ } else {
+ message += error.toString() + ' thrown';
+ }
+
+ if (error.fileName || error.sourceURL) {
+ message += ' in ' + (error.fileName || error.sourceURL);
+ }
+
+ if (error.line || error.lineNumber) {
+ message += ' (line ' + (error.line || error.lineNumber) + ')';
+ }
+
+ return message;
+ };
+
+ this.stack = function(error) {
+ if (!error || !error.stack) {
+ return null;
+ }
+
+ var stackTrace = new j$.StackTrace(error);
+ var lines = filterJasmine(stackTrace);
+ var result = '';
+
+ if (stackTrace.message) {
+ lines.unshift(stackTrace.message);
+ }
+
+ result += formatProperties(error);
+ result += lines.join('\n');
+
+ return result;
+ };
+
+ function filterJasmine(stackTrace) {
+ var result = [],
+ jasmineMarker =
+ stackTrace.style === 'webkit' ? '' : ' at ';
+
+ stackTrace.frames.forEach(function(frame) {
+ if (frame.file && frame.file !== jasmineFile) {
+ result.push(frame.raw);
+ } else if (result[result.length - 1] !== jasmineMarker) {
+ result.push(jasmineMarker);
+ }
+ });
+
+ return result;
+ }
+
+ function formatProperties(error) {
+ if (!(error instanceof Object)) {
+ return;
+ }
+
+ var result = {};
+ var empty = true;
+
+ for (var prop in error) {
+ if (j$.util.arrayContains(ignoredProperties, prop)) {
+ continue;
+ }
+ result[prop] = error[prop];
+ empty = false;
+ }
+
+ if (!empty) {
+ return 'error properties: ' + j$.pp(result) + '\n';
+ }
+
+ return '';
+ }
+ }
+
+ return ExceptionFormatter;
+};
+
+getJasmineRequireObj().Expectation = function(j$) {
+ /**
+ * Matchers that come with Jasmine out of the box.
+ * @namespace matchers
+ */
+ function Expectation(options) {
+ this.expector = new j$.Expector(options);
+
+ var customMatchers = options.customMatchers || {};
+ for (var matcherName in customMatchers) {
+ this[matcherName] = wrapSyncCompare(
+ matcherName,
+ customMatchers[matcherName]
+ );
+ }
+ }
+
+ /**
+ * Add some context for an {@link expect}
+ * @function
+ * @name matchers#withContext
+ * @since 3.3.0
+ * @param {String} message - Additional context to show when the matcher fails
+ * @return {matchers}
+ */
+ Expectation.prototype.withContext = function withContext(message) {
+ return addFilter(this, new ContextAddingFilter(message));
+ };
+
+ /**
+ * Invert the matcher following this {@link expect}
+ * @member
+ * @name matchers#not
+ * @since 1.3.0
+ * @type {matchers}
+ * @example
+ * expect(something).not.toBe(true);
+ */
+ Object.defineProperty(Expectation.prototype, 'not', {
+ get: function() {
+ return addFilter(this, syncNegatingFilter);
+ }
+ });
+
+ /**
+ * Asynchronous matchers.
+ * @namespace async-matchers
+ */
+ function AsyncExpectation(options) {
+ var global = options.global || j$.getGlobal();
+ this.expector = new j$.Expector(options);
+
+ if (!global.Promise) {
+ throw new Error(
+ 'expectAsync is unavailable because the environment does not support promises.'
+ );
+ }
+
+ var customAsyncMatchers = options.customAsyncMatchers || {};
+ for (var matcherName in customAsyncMatchers) {
+ this[matcherName] = wrapAsyncCompare(
+ matcherName,
+ customAsyncMatchers[matcherName]
+ );
+ }
+ }
+
+ /**
+ * Add some context for an {@link expectAsync}
+ * @function
+ * @name async-matchers#withContext
+ * @since 3.3.0
+ * @param {String} message - Additional context to show when the async matcher fails
+ * @return {async-matchers}
+ */
+ AsyncExpectation.prototype.withContext = function withContext(message) {
+ return addFilter(this, new ContextAddingFilter(message));
+ };
+
+ /**
+ * Invert the matcher following this {@link expectAsync}
+ * @member
+ * @name async-matchers#not
+ * @type {async-matchers}
+ * @example
+ * await expectAsync(myPromise).not.toBeResolved();
+ * @example
+ * return expectAsync(myPromise).not.toBeResolved();
+ */
+ Object.defineProperty(AsyncExpectation.prototype, 'not', {
+ get: function() {
+ return addFilter(this, asyncNegatingFilter);
+ }
+ });
+
+ function wrapSyncCompare(name, matcherFactory) {
+ return function() {
+ var result = this.expector.compare(name, matcherFactory, arguments);
+ this.expector.processResult(result);
+ };
+ }
+
+ function wrapAsyncCompare(name, matcherFactory) {
+ return function() {
+ var self = this;
+
+ // Capture the call stack here, before we go async, so that it will contain
+ // frames that are relevant to the user instead of just parts of Jasmine.
+ var errorForStack = j$.util.errorWithStack();
+
+ return this.expector
+ .compare(name, matcherFactory, arguments)
+ .then(function(result) {
+ self.expector.processResult(result, errorForStack);
+ });
+ };
+ }
+
+ function addCoreMatchers(prototype, matchers, wrapper) {
+ for (var matcherName in matchers) {
+ var matcher = matchers[matcherName];
+ prototype[matcherName] = wrapper(matcherName, matcher);
+ }
+ }
+
+ function addFilter(source, filter) {
+ var result = Object.create(source);
+ result.expector = source.expector.addFilter(filter);
+ return result;
+ }
+
+ function negatedFailureMessage(result, matcherName, args, util) {
+ if (result.message) {
+ if (j$.isFunction_(result.message)) {
+ return result.message();
+ } else {
+ return result.message;
+ }
+ }
+
+ args = args.slice();
+ args.unshift(true);
+ args.unshift(matcherName);
+ return util.buildFailureMessage.apply(null, args);
+ }
+
+ function negate(result) {
+ result.pass = !result.pass;
+ return result;
+ }
+
+ var syncNegatingFilter = {
+ selectComparisonFunc: function(matcher) {
+ function defaultNegativeCompare() {
+ return negate(matcher.compare.apply(null, arguments));
+ }
+
+ return matcher.negativeCompare || defaultNegativeCompare;
+ },
+ buildFailureMessage: negatedFailureMessage
+ };
+
+ var asyncNegatingFilter = {
+ selectComparisonFunc: function(matcher) {
+ function defaultNegativeCompare() {
+ return matcher.compare.apply(this, arguments).then(negate);
+ }
+
+ return matcher.negativeCompare || defaultNegativeCompare;
+ },
+ buildFailureMessage: negatedFailureMessage
+ };
+
+ function ContextAddingFilter(message) {
+ this.message = message;
+ }
+
+ ContextAddingFilter.prototype.modifyFailureMessage = function(msg) {
+ return this.message + ': ' + msg;
+ };
+
+ return {
+ factory: function(options) {
+ return new Expectation(options || {});
+ },
+ addCoreMatchers: function(matchers) {
+ addCoreMatchers(Expectation.prototype, matchers, wrapSyncCompare);
+ },
+ asyncFactory: function(options) {
+ return new AsyncExpectation(options || {});
+ },
+ addAsyncCoreMatchers: function(matchers) {
+ addCoreMatchers(AsyncExpectation.prototype, matchers, wrapAsyncCompare);
+ }
+ };
+};
+
+getJasmineRequireObj().ExpectationFilterChain = function() {
+ function ExpectationFilterChain(maybeFilter, prev) {
+ this.filter_ = maybeFilter;
+ this.prev_ = prev;
+ }
+
+ ExpectationFilterChain.prototype.addFilter = function(filter) {
+ return new ExpectationFilterChain(filter, this);
+ };
+
+ ExpectationFilterChain.prototype.selectComparisonFunc = function(matcher) {
+ return this.callFirst_('selectComparisonFunc', arguments).result;
+ };
+
+ ExpectationFilterChain.prototype.buildFailureMessage = function(
+ result,
+ matcherName,
+ args,
+ util
+ ) {
+ return this.callFirst_('buildFailureMessage', arguments).result;
+ };
+
+ ExpectationFilterChain.prototype.modifyFailureMessage = function(msg) {
+ var result = this.callFirst_('modifyFailureMessage', arguments).result;
+ return result || msg;
+ };
+
+ ExpectationFilterChain.prototype.callFirst_ = function(fname, args) {
+ var prevResult;
+
+ if (this.prev_) {
+ prevResult = this.prev_.callFirst_(fname, args);
+
+ if (prevResult.found) {
+ return prevResult;
+ }
+ }
+
+ if (this.filter_ && this.filter_[fname]) {
+ return {
+ found: true,
+ result: this.filter_[fname].apply(this.filter_, args)
+ };
+ }
+
+ return { found: false };
+ };
+
+ return ExpectationFilterChain;
+};
+
+//TODO: expectation result may make more sense as a presentation of an expectation.
+getJasmineRequireObj().buildExpectationResult = function() {
+ function buildExpectationResult(options) {
+ var messageFormatter = options.messageFormatter || function() {},
+ stackFormatter = options.stackFormatter || function() {};
+
+ /**
+ * @typedef Expectation
+ * @property {String} matcherName - The name of the matcher that was executed for this expectation.
+ * @property {String} message - The failure message for the expectation.
+ * @property {String} stack - The stack trace for the failure if available.
+ * @property {Boolean} passed - Whether the expectation passed or failed.
+ * @property {Object} expected - If the expectation failed, what was the expected value.
+ * @property {Object} actual - If the expectation failed, what actual value was produced.
+ */
+ var result = {
+ matcherName: options.matcherName,
+ message: message(),
+ stack: stack(),
+ passed: options.passed
+ };
+
+ if (!result.passed) {
+ result.expected = options.expected;
+ result.actual = options.actual;
+ }
+
+ return result;
+
+ function message() {
+ if (options.passed) {
+ return 'Passed.';
+ } else if (options.message) {
+ return options.message;
+ } else if (options.error) {
+ return messageFormatter(options.error);
+ }
+ return '';
+ }
+
+ function stack() {
+ if (options.passed) {
+ return '';
+ }
+
+ var error = options.error;
+ if (!error) {
+ if (options.errorForStack) {
+ error = options.errorForStack;
+ } else if (options.stack) {
+ error = options;
+ } else {
+ try {
+ throw new Error(message());
+ } catch (e) {
+ error = e;
+ }
+ }
+ }
+ return stackFormatter(error);
+ }
+ }
+
+ return buildExpectationResult;
+};
+
+getJasmineRequireObj().Expector = function(j$) {
+ function Expector(options) {
+ this.util = options.util || { buildFailureMessage: function() {} };
+ this.customEqualityTesters = options.customEqualityTesters || [];
+ this.actual = options.actual;
+ this.addExpectationResult = options.addExpectationResult || function() {};
+ this.filters = new j$.ExpectationFilterChain();
+ }
+
+ Expector.prototype.instantiateMatcher = function(
+ matcherName,
+ matcherFactory,
+ args
+ ) {
+ this.matcherName = matcherName;
+ this.args = Array.prototype.slice.call(args, 0);
+ this.expected = this.args.slice(0);
+
+ this.args.unshift(this.actual);
+
+ var matcher = matcherFactory(this.util, this.customEqualityTesters);
+ var comparisonFunc = this.filters.selectComparisonFunc(matcher);
+ return comparisonFunc || matcher.compare;
+ };
+
+ Expector.prototype.buildMessage = function(result) {
+ var self = this;
+
+ if (result.pass) {
+ return '';
+ }
+
+ var msg = this.filters.buildFailureMessage(
+ result,
+ this.matcherName,
+ this.args,
+ this.util,
+ defaultMessage
+ );
+ return this.filters.modifyFailureMessage(msg || defaultMessage());
+
+ function defaultMessage() {
+ if (!result.message) {
+ var args = self.args.slice();
+ args.unshift(false);
+ args.unshift(self.matcherName);
+ return self.util.buildFailureMessage.apply(null, args);
+ } else if (j$.isFunction_(result.message)) {
+ return result.message();
+ } else {
+ return result.message;
+ }
+ }
+ };
+
+ Expector.prototype.compare = function(matcherName, matcherFactory, args) {
+ var matcherCompare = this.instantiateMatcher(
+ matcherName,
+ matcherFactory,
+ args
+ );
+ return matcherCompare.apply(null, this.args);
+ };
+
+ Expector.prototype.addFilter = function(filter) {
+ var result = Object.create(this);
+ result.filters = this.filters.addFilter(filter);
+ return result;
+ };
+
+ Expector.prototype.processResult = function(result, errorForStack) {
+ var message = this.buildMessage(result);
+
+ if (this.expected.length === 1) {
+ this.expected = this.expected[0];
+ }
+
+ this.addExpectationResult(result.pass, {
+ matcherName: this.matcherName,
+ passed: result.pass,
+ message: message,
+ error: errorForStack ? undefined : result.error,
+ errorForStack: errorForStack || undefined,
+ actual: this.actual,
+ expected: this.expected // TODO: this may need to be arrayified/sliced
+ });
+ };
+
+ return Expector;
+};
+
+getJasmineRequireObj().formatErrorMsg = function() {
+ function generateErrorMsg(domain, usage) {
+ var usageDefinition = usage ? '\nUsage: ' + usage : '';
+
+ return function errorMsg(msg) {
+ return domain + ' : ' + msg + usageDefinition;
+ };
+ }
+
+ return generateErrorMsg;
+};
+
+getJasmineRequireObj().GlobalErrors = function(j$) {
+ function GlobalErrors(global) {
+ var handlers = [];
+ global = global || j$.getGlobal();
+
+ var onerror = function onerror() {
+ var handler = handlers[handlers.length - 1];
+
+ if (handler) {
+ handler.apply(null, Array.prototype.slice.call(arguments, 0));
+ } else {
+ throw arguments[0];
+ }
+ };
+
+ this.originalHandlers = {};
+ this.jasmineHandlers = {};
+ this.installOne_ = function installOne_(errorType, jasmineMessage) {
+ function taggedOnError(error) {
+ error.jasmineMessage = jasmineMessage + ': ' + error;
+
+ var handler = handlers[handlers.length - 1];
+
+ if (handler) {
+ handler(error);
+ } else {
+ throw error;
+ }
+ }
+
+ this.originalHandlers[errorType] = global.process.listeners(errorType);
+ this.jasmineHandlers[errorType] = taggedOnError;
+
+ global.process.removeAllListeners(errorType);
+ global.process.on(errorType, taggedOnError);
+
+ this.uninstall = function uninstall() {
+ var errorTypes = Object.keys(this.originalHandlers);
+ for (var iType = 0; iType < errorTypes.length; iType++) {
+ var errorType = errorTypes[iType];
+ global.process.removeListener(
+ errorType,
+ this.jasmineHandlers[errorType]
+ );
+ for (var i = 0; i < this.originalHandlers[errorType].length; i++) {
+ global.process.on(errorType, this.originalHandlers[errorType][i]);
+ }
+ delete this.originalHandlers[errorType];
+ delete this.jasmineHandlers[errorType];
+ }
+ };
+ };
+
+ this.install = function install() {
+ if (
+ global.process &&
+ global.process.listeners &&
+ j$.isFunction_(global.process.on)
+ ) {
+ this.installOne_('uncaughtException', 'Uncaught exception');
+ this.installOne_('unhandledRejection', 'Unhandled promise rejection');
+ } else {
+ var originalHandler = global.onerror;
+ global.onerror = onerror;
+
+ this.uninstall = function uninstall() {
+ global.onerror = originalHandler;
+ };
+ }
+ };
+
+ this.pushListener = function pushListener(listener) {
+ handlers.push(listener);
+ };
+
+ this.popListener = function popListener() {
+ handlers.pop();
+ };
+ }
+
+ return GlobalErrors;
+};
+
+getJasmineRequireObj().toBeRejected = function(j$) {
+ /**
+ * Expect a promise to be rejected.
+ * @function
+ * @async
+ * @name async-matchers#toBeRejected
+ * @since 3.1.0
+ * @example
+ * await expectAsync(aPromise).toBeRejected();
+ * @example
+ * return expectAsync(aPromise).toBeRejected();
+ */
+ return function toBeRejected(util) {
+ return {
+ compare: function(actual) {
+ if (!j$.isPromiseLike(actual)) {
+ throw new Error('Expected toBeRejected to be called on a promise.');
+ }
+ return actual.then(
+ function() { return {pass: false}; },
+ function() { return {pass: true}; }
+ );
+ }
+ };
+ };
+};
+
+getJasmineRequireObj().toBeRejectedWith = function(j$) {
+ /**
+ * Expect a promise to be rejected with a value equal to the expected, using deep equality comparison.
+ * @function
+ * @async
+ * @name async-matchers#toBeRejectedWith
+ * @since 3.3.0
+ * @param {Object} expected - Value that the promise is expected to be rejected with
+ * @example
+ * await expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
+ * @example
+ * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
+ */
+ return function toBeRejectedWith(util, customEqualityTesters) {
+ return {
+ compare: function(actualPromise, expectedValue) {
+ if (!j$.isPromiseLike(actualPromise)) {
+ throw new Error('Expected toBeRejectedWith to be called on a promise.');
+ }
+
+ function prefix(passed) {
+ return 'Expected a promise ' +
+ (passed ? 'not ' : '') +
+ 'to be rejected with ' + j$.pp(expectedValue);
+ }
+
+ return actualPromise.then(
+ function() {
+ return {
+ pass: false,
+ message: prefix(false) + ' but it was resolved.'
+ };
+ },
+ function(actualValue) {
+ if (util.equals(actualValue, expectedValue, customEqualityTesters)) {
+ return {
+ pass: true,
+ message: prefix(true) + '.'
+ };
+ } else {
+ return {
+ pass: false,
+ message: prefix(false) + ' but it was rejected with ' + j$.pp(actualValue) + '.'
+ };
+ }
+ }
+ );
+ }
+ };
+ };
+};
+
+getJasmineRequireObj().toBeRejectedWithError = function(j$) {
+ /**
+ * Expect a promise to be rejected with a value matched to the expected
+ * @function
+ * @async
+ * @name async-matchers#toBeRejectedWithError
+ * @since 3.5.0
+ * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
+ * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
+ * @example
+ * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, 'Error message');
+ * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, /Error message/);
+ * await expectAsync(aPromise).toBeRejectedWithError(MyCustomError);
+ * await expectAsync(aPromise).toBeRejectedWithError('Error message');
+ * return expectAsync(aPromise).toBeRejectedWithError(/Error message/);
+ */
+ return function toBeRejectedWithError() {
+ return {
+ compare: function(actualPromise, arg1, arg2) {
+ if (!j$.isPromiseLike(actualPromise)) {
+ throw new Error('Expected toBeRejectedWithError to be called on a promise.');
+ }
+
+ var expected = getExpectedFromArgs(arg1, arg2);
+
+ return actualPromise.then(
+ function() {
+ return {
+ pass: false,
+ message: 'Expected a promise to be rejected but it was resolved.'
+ };
+ },
+ function(actualValue) { return matchError(actualValue, expected); }
+ );
+ }
+ };
+ };
+
+ function matchError(actual, expected) {
+ if (!j$.isError_(actual)) {
+ return fail(expected, 'rejected with ' + j$.pp(actual));
+ }
+
+ if (!(actual instanceof expected.error)) {
+ return fail(expected, 'rejected with type ' + j$.fnNameFor(actual.constructor));
+ }
+
+ var actualMessage = actual.message;
+
+ if (actualMessage === expected.message || typeof expected.message === 'undefined') {
+ return pass(expected);
+ }
+
+ if (expected.message instanceof RegExp && expected.message.test(actualMessage)) {
+ return pass(expected);
+ }
+
+ return fail(expected, 'rejected with ' + j$.pp(actual));
+ }
+
+ function pass(expected) {
+ return {
+ pass: true,
+ message: 'Expected a promise not to be rejected with ' + expected.printValue + ', but it was.'
+ };
+ }
+
+ function fail(expected, message) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be rejected with ' + expected.printValue + ' but it was ' + message + '.'
+ };
+ }
+
+
+ function getExpectedFromArgs(arg1, arg2) {
+ var error, message;
+
+ if (isErrorConstructor(arg1)) {
+ error = arg1;
+ message = arg2;
+ } else {
+ error = Error;
+ message = arg1;
+ }
+
+ return {
+ error: error,
+ message: message,
+ printValue: j$.fnNameFor(error) + (typeof message === 'undefined' ? '' : ': ' + j$.pp(message))
+ };
+ }
+
+ function isErrorConstructor(value) {
+ return typeof value === 'function' && (value === Error || j$.isError_(value.prototype));
+ }
+};
+
+getJasmineRequireObj().toBeResolved = function(j$) {
+ /**
+ * Expect a promise to be resolved.
+ * @function
+ * @async
+ * @name async-matchers#toBeResolved
+ * @since 3.1.0
+ * @example
+ * await expectAsync(aPromise).toBeResolved();
+ * @example
+ * return expectAsync(aPromise).toBeResolved();
+ */
+ return function toBeResolved(util) {
+ return {
+ compare: function(actual) {
+ if (!j$.isPromiseLike(actual)) {
+ throw new Error('Expected toBeResolved to be called on a promise.');
+ }
+
+ return actual.then(
+ function() { return {pass: true}; },
+ function() { return {pass: false}; }
+ );
+ }
+ };
+ };
+};
+
+getJasmineRequireObj().toBeResolvedTo = function(j$) {
+ /**
+ * Expect a promise to be resolved to a value equal to the expected, using deep equality comparison.
+ * @function
+ * @async
+ * @name async-matchers#toBeResolvedTo
+ * @since 3.1.0
+ * @param {Object} expected - Value that the promise is expected to resolve to
+ * @example
+ * await expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
+ * @example
+ * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
+ */
+ return function toBeResolvedTo(util, customEqualityTesters) {
+ return {
+ compare: function(actualPromise, expectedValue) {
+ if (!j$.isPromiseLike(actualPromise)) {
+ throw new Error('Expected toBeResolvedTo to be called on a promise.');
+ }
+
+ function prefix(passed) {
+ return 'Expected a promise ' +
+ (passed ? 'not ' : '') +
+ 'to be resolved to ' + j$.pp(expectedValue);
+ }
+
+ return actualPromise.then(
+ function(actualValue) {
+ if (util.equals(actualValue, expectedValue, customEqualityTesters)) {
+ return {
+ pass: true,
+ message: prefix(true) + '.'
+ };
+ } else {
+ return {
+ pass: false,
+ message: prefix(false) + ' but it was resolved to ' + j$.pp(actualValue) + '.'
+ };
+ }
+ },
+ function() {
+ return {
+ pass: false,
+ message: prefix(false) + ' but it was rejected.'
+ };
+ }
+ );
+ }
+ };
+ };
+};
+
+getJasmineRequireObj().DiffBuilder = function(j$) {
+ return function DiffBuilder() {
+ var path = new j$.ObjectPath(),
+ mismatches = [];
+
+ return {
+ record: function (actual, expected, formatter) {
+ formatter = formatter || defaultFormatter;
+ mismatches.push(formatter(actual, expected, path));
+ },
+
+ getMessage: function () {
+ return mismatches.join('\n');
+ },
+
+ withPath: function (pathComponent, block) {
+ var oldPath = path;
+ path = path.add(pathComponent);
+ block();
+ path = oldPath;
+ }
+ };
+
+ function defaultFormatter (actual, expected, path) {
+ return 'Expected ' +
+ path + (path.depth() ? ' = ' : '') +
+ j$.pp(actual) +
+ ' to equal ' +
+ j$.pp(expected) +
+ '.';
+ }
+ };
+};
+
+getJasmineRequireObj().matchersUtil = function(j$) {
+ // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
+
+ return {
+ equals: equals,
+
+ contains: function(haystack, needle, customTesters) {
+ customTesters = customTesters || [];
+
+ if (j$.isSet(haystack)) {
+ return haystack.has(needle);
+ }
+
+ if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
+ (!!haystack && !haystack.indexOf))
+ {
+ for (var i = 0; i < haystack.length; i++) {
+ if (equals(haystack[i], needle, customTesters)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return !!haystack && haystack.indexOf(needle) >= 0;
+ },
+
+ buildFailureMessage: function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ matcherName = args[0],
+ isNot = args[1],
+ actual = args[2],
+ expected = args.slice(3),
+ englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+
+ var message = 'Expected ' +
+ j$.pp(actual) +
+ (isNot ? ' not ' : ' ') +
+ englishyPredicate;
+
+ if (expected.length > 0) {
+ for (var i = 0; i < expected.length; i++) {
+ if (i > 0) {
+ message += ',';
+ }
+ message += ' ' + j$.pp(expected[i]);
+ }
+ }
+
+ return message + '.';
+ }
+ };
+
+ function isAsymmetric(obj) {
+ return obj && j$.isA_('Function', obj.asymmetricMatch);
+ }
+
+ function asymmetricMatch(a, b, customTesters, diffBuilder) {
+ var asymmetricA = isAsymmetric(a),
+ asymmetricB = isAsymmetric(b),
+ result;
+
+ if (asymmetricA && asymmetricB) {
+ return undefined;
+ }
+
+ if (asymmetricA) {
+ result = a.asymmetricMatch(b, customTesters);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+
+ if (asymmetricB) {
+ result = b.asymmetricMatch(a, customTesters);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ }
+
+ function equals(a, b, customTesters, diffBuilder) {
+ customTesters = customTesters || [];
+ diffBuilder = diffBuilder || j$.NullDiffBuilder();
+
+ return eq(a, b, [], [], customTesters, diffBuilder);
+ }
+
+ // Equality function lovingly adapted from isEqual in
+ // [Underscore](http://underscorejs.org)
+ function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
+ var result = true, i;
+
+ var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
+ if (!j$.util.isUndefined(asymmetricResult)) {
+ return asymmetricResult;
+ }
+
+ for (i = 0; i < customTesters.length; i++) {
+ var customTesterResult = customTesters[i](a, b);
+ if (!j$.util.isUndefined(customTesterResult)) {
+ if (!customTesterResult) {
+ diffBuilder.record(a, b);
+ }
+ return customTesterResult;
+ }
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ result = a.message == b.message;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) {
+ result = a !== 0 || 1 / a == 1 / b;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ // A strict comparison is necessary because `null == undefined`.
+ if (a === null || b === null) {
+ result = a === b;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ var className = Object.prototype.toString.call(a);
+ if (className != Object.prototype.toString.call(b)) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ switch (className) {
+ // Strings, numbers, dates, and booleans are compared by value.
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ result = a == String(b);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+ // other numeric values.
+ result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ result = +a == +b;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ // RegExps are compared by their source patterns and flags.
+ case '[object RegExp]':
+ return a.source == b.source &&
+ a.global == b.global &&
+ a.multiline == b.multiline &&
+ a.ignoreCase == b.ignoreCase;
+ }
+ if (typeof a != 'object' || typeof b != 'object') {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ var aIsDomNode = j$.isDomNode(a);
+ var bIsDomNode = j$.isDomNode(b);
+ if (aIsDomNode && bIsDomNode) {
+ // At first try to use DOM3 method isEqualNode
+ result = a.isEqualNode(b);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ if (aIsDomNode || bIsDomNode) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ var aIsPromise = j$.isPromise(a);
+ var bIsPromise = j$.isPromise(b);
+ if (aIsPromise && bIsPromise) {
+ return a === b;
+ }
+
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] == a) { return bStack[length] == b; }
+ }
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+ var size = 0;
+ // Recursively compare objects and arrays.
+ // Compare array lengths to determine if a deep comparison is necessary.
+ if (className == '[object Array]') {
+ var aLength = a.length;
+ var bLength = b.length;
+
+ diffBuilder.withPath('length', function() {
+ if (aLength !== bLength) {
+ diffBuilder.record(aLength, bLength);
+ result = false;
+ }
+ });
+
+ for (i = 0; i < aLength || i < bLength; i++) {
+ diffBuilder.withPath(i, function() {
+ if (i >= bLength) {
+ diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
+ result = false;
+ } else {
+ result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
+ }
+ });
+ }
+ if (!result) {
+ return false;
+ }
+ } else if (j$.isMap(a) && j$.isMap(b)) {
+ if (a.size != b.size) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ var keysA = [];
+ var keysB = [];
+ a.forEach( function( valueA, keyA ) {
+ keysA.push( keyA );
+ });
+ b.forEach( function( valueB, keyB ) {
+ keysB.push( keyB );
+ });
+
+ // For both sets of keys, check they map to equal values in both maps.
+ // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys.
+ var mapKeys = [keysA, keysB];
+ var cmpKeys = [keysB, keysA];
+ var mapIter, mapKey, mapValueA, mapValueB;
+ var cmpIter, cmpKey;
+ for (i = 0; result && i < mapKeys.length; i++) {
+ mapIter = mapKeys[i];
+ cmpIter = cmpKeys[i];
+
+ for (var j = 0; result && j < mapIter.length; j++) {
+ mapKey = mapIter[j];
+ cmpKey = cmpIter[j];
+ mapValueA = a.get(mapKey);
+
+ // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
+ // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
+ // obj identity (that are otherwise equal) to not match.
+ if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
+ eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
+ mapValueB = b.get(cmpKey);
+ } else {
+ mapValueB = b.get(mapKey);
+ }
+ result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
+ }
+ }
+
+ if (!result) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ } else if (j$.isSet(a) && j$.isSet(b)) {
+ if (a.size != b.size) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ var valuesA = [];
+ a.forEach( function( valueA ) {
+ valuesA.push( valueA );
+ });
+ var valuesB = [];
+ b.forEach( function( valueB ) {
+ valuesB.push( valueB );
+ });
+
+ // For both sets, check they are all contained in the other set
+ var setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
+ var stackPairs = [[aStack, bStack], [bStack, aStack]];
+ var baseValues, baseValue, baseStack;
+ var otherValues, otherValue, otherStack;
+ var found;
+ var prevStackSize;
+ for (i = 0; result && i < setPairs.length; i++) {
+ baseValues = setPairs[i][0];
+ otherValues = setPairs[i][1];
+ baseStack = stackPairs[i][0];
+ otherStack = stackPairs[i][1];
+ // For each value in the base set...
+ for (var k = 0; result && k < baseValues.length; k++) {
+ baseValue = baseValues[k];
+ found = false;
+ // ... test that it is present in the other set
+ for (var l = 0; !found && l < otherValues.length; l++) {
+ otherValue = otherValues[l];
+ prevStackSize = baseStack.length;
+ // compare by value equality
+ found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
+ if (!found && prevStackSize !== baseStack.length) {
+ baseStack.splice(prevStackSize);
+ otherStack.splice(prevStackSize);
+ }
+ }
+ result = result && found;
+ }
+ }
+
+ if (!result) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ } else {
+
+ // Objects with different constructors are not equivalent, but `Object`s
+ // or `Array`s from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor &&
+ isFunction(aCtor) && isFunction(bCtor) &&
+ a instanceof aCtor && b instanceof bCtor &&
+ !(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
+
+ diffBuilder.record(a, b, constructorsAreDifferentFormatter);
+ return false;
+ }
+ }
+
+ // Deep compare objects.
+ var aKeys = keys(a, className == '[object Array]'), key;
+ size = aKeys.length;
+
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ if (keys(b, className == '[object Array]').length !== size) {
+ diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
+ return false;
+ }
+
+ for (i = 0; i < size; i++) {
+ key = aKeys[i];
+ // Deep compare each member
+ if (!j$.util.has(b, key)) {
+ diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
+ result = false;
+ continue;
+ }
+
+ diffBuilder.withPath(key, function() {
+ if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
+ result = false;
+ }
+ });
+ }
+
+ if (!result) {
+ return false;
+ }
+
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+
+ return result;
+ }
+
+ function keys(obj, isArray) {
+ var allKeys = Object.keys ? Object.keys(obj) :
+ (function(o) {
+ var keys = [];
+ for (var key in o) {
+ if (j$.util.has(o, key)) {
+ keys.push(key);
+ }
+ }
+ return keys;
+ })(obj);
+
+ if (!isArray) {
+ return allKeys;
+ }
+
+ if (allKeys.length === 0) {
+ return allKeys;
+ }
+
+ var extraKeys = [];
+ for (var i = 0; i < allKeys.length; i++) {
+ if (!/^[0-9]+$/.test(allKeys[i])) {
+ extraKeys.push(allKeys[i]);
+ }
+ }
+
+ return extraKeys;
+ }
+
+ function isFunction(obj) {
+ return typeof obj === 'function';
+ }
+
+ function objectKeysAreDifferentFormatter(actual, expected, path) {
+ var missingProperties = j$.util.objectDifference(expected, actual),
+ extraProperties = j$.util.objectDifference(actual, expected),
+ missingPropertiesMessage = formatKeyValuePairs(missingProperties),
+ extraPropertiesMessage = formatKeyValuePairs(extraProperties),
+ messages = [];
+
+ if (!path.depth()) {
+ path = 'object';
+ }
+
+ if (missingPropertiesMessage.length) {
+ messages.push('Expected ' + path + ' to have properties' + missingPropertiesMessage);
+ }
+
+ if (extraPropertiesMessage.length) {
+ messages.push('Expected ' + path + ' not to have properties' + extraPropertiesMessage);
+ }
+
+ return messages.join('\n');
+ }
+
+ function constructorsAreDifferentFormatter(actual, expected, path) {
+ if (!path.depth()) {
+ path = 'object';
+ }
+
+ return 'Expected ' +
+ path + ' to be a kind of ' +
+ j$.fnNameFor(expected.constructor) +
+ ', but was ' + j$.pp(actual) + '.';
+ }
+
+ function actualArrayIsLongerFormatter(actual, expected, path) {
+ return 'Unexpected ' +
+ path + (path.depth() ? ' = ' : '') +
+ j$.pp(actual) +
+ ' in array.';
+ }
+
+ function formatKeyValuePairs(obj) {
+ var formatted = '';
+ for (var key in obj) {
+ formatted += '\n ' + key + ': ' + j$.pp(obj[key]);
+ }
+ return formatted;
+ }
+};
+
+getJasmineRequireObj().nothing = function() {
+ /**
+ * {@link expect} nothing explicitly.
+ * @function
+ * @name matchers#nothing
+ * @since 2.8.0
+ * @example
+ * expect().nothing();
+ */
+ function nothing() {
+ return {
+ compare: function() {
+ return {
+ pass: true
+ };
+ }
+ };
+ }
+
+ return nothing;
+};
+
+getJasmineRequireObj().NullDiffBuilder = function(j$) {
+ return function() {
+ return {
+ withPath: function(_, block) {
+ block();
+ },
+ record: function() {}
+ };
+ };
+};
+
+getJasmineRequireObj().ObjectPath = function(j$) {
+ function ObjectPath(components) {
+ this.components = components || [];
+ }
+
+ ObjectPath.prototype.toString = function() {
+ if (this.components.length) {
+ return '$' + map(this.components, formatPropertyAccess).join('');
+ } else {
+ return '';
+ }
+ };
+
+ ObjectPath.prototype.add = function(component) {
+ return new ObjectPath(this.components.concat([component]));
+ };
+
+ ObjectPath.prototype.depth = function() {
+ return this.components.length;
+ };
+
+ function formatPropertyAccess(prop) {
+ if (typeof prop === 'number') {
+ return '[' + prop + ']';
+ }
+
+ if (isValidIdentifier(prop)) {
+ return '.' + prop;
+ }
+
+ return '[\'' + prop + '\']';
+ }
+
+ function map(array, fn) {
+ var results = [];
+ for (var i = 0; i < array.length; i++) {
+ results.push(fn(array[i]));
+ }
+ return results;
+ }
+
+ function isValidIdentifier(string) {
+ return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string);
+ }
+
+ return ObjectPath;
+};
+
+getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) {
+ var availableMatchers = [
+ 'toBeResolved',
+ 'toBeRejected',
+ 'toBeResolvedTo',
+ 'toBeRejectedWith',
+ 'toBeRejectedWithError'
+ ],
+ matchers = {};
+
+ for (var i = 0; i < availableMatchers.length; i++) {
+ var name = availableMatchers[i];
+ matchers[name] = jRequire[name](j$);
+ }
+
+ return matchers;
+};
+
+getJasmineRequireObj().toBe = function(j$) {
+ /**
+ * {@link expect} the actual value to be `===` to the expected value.
+ * @function
+ * @name matchers#toBe
+ * @since 1.3.0
+ * @param {Object} expected - The expected value to compare against.
+ * @example
+ * expect(thing).toBe(realThing);
+ */
+ function toBe(util) {
+ var tip = ' Tip: To check for deep equality, use .toEqual() instead of .toBe().';
+
+ return {
+ compare: function(actual, expected) {
+ var result = {
+ pass: actual === expected
+ };
+
+ if (typeof expected === 'object') {
+ result.message = util.buildFailureMessage('toBe', result.pass, actual, expected) + tip;
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBe;
+};
+
+getJasmineRequireObj().toBeCloseTo = function() {
+ /**
+ * {@link expect} the actual value to be within a specified precision of the expected value.
+ * @function
+ * @name matchers#toBeCloseTo
+ * @since 1.3.0
+ * @param {Object} expected - The expected value to compare against.
+ * @param {Number} [precision=2] - The number of decimal points to check.
+ * @example
+ * expect(number).toBeCloseTo(42.2, 3);
+ */
+ function toBeCloseTo() {
+ return {
+ compare: function(actual, expected, precision) {
+ if (precision !== 0) {
+ precision = precision || 2;
+ }
+
+ if (expected === null || actual === null) {
+ throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
+ 'expect(' + actual + ').toBeCloseTo(' + expected + ').'
+ );
+ }
+
+ var pow = Math.pow(10, precision + 1);
+ var delta = Math.abs(expected - actual);
+ var maxDelta = Math.pow(10, -precision) / 2;
+
+ return {
+ pass: Math.round(delta * pow) <= maxDelta * pow
+ };
+ }
+ };
+ }
+
+ return toBeCloseTo;
+};
+
+getJasmineRequireObj().toBeDefined = function() {
+ /**
+ * {@link expect} the actual value to be defined. (Not `undefined`)
+ * @function
+ * @name matchers#toBeDefined
+ * @since 1.3.0
+ * @example
+ * expect(result).toBeDefined();
+ */
+ function toBeDefined() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: (void 0 !== actual)
+ };
+ }
+ };
+ }
+
+ return toBeDefined;
+};
+
+getJasmineRequireObj().toBeFalse = function() {
+ /**
+ * {@link expect} the actual value to be `false`.
+ * @function
+ * @name matchers#toBeFalse
+ * @since 3.5.0
+ * @example
+ * expect(result).toBeFalse();
+ */
+ function toBeFalse() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: actual === false
+ };
+ }
+ };
+ }
+
+ return toBeFalse;
+};
+
+getJasmineRequireObj().toBeFalsy = function() {
+ /**
+ * {@link expect} the actual value to be falsy
+ * @function
+ * @name matchers#toBeFalsy
+ * @since 2.0.0
+ * @example
+ * expect(result).toBeFalsy();
+ */
+ function toBeFalsy() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: !actual
+ };
+ }
+ };
+ }
+
+ return toBeFalsy;
+};
+
+getJasmineRequireObj().toBeGreaterThan = function() {
+ /**
+ * {@link expect} the actual value to be greater than the expected value.
+ * @function
+ * @name matchers#toBeGreaterThan
+ * @since 2.0.0
+ * @param {Number} expected - The value to compare against.
+ * @example
+ * expect(result).toBeGreaterThan(3);
+ */
+ function toBeGreaterThan() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual > expected
+ };
+ }
+ };
+ }
+
+ return toBeGreaterThan;
+};
+
+
+getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
+ /**
+ * {@link expect} the actual value to be greater than or equal to the expected value.
+ * @function
+ * @name matchers#toBeGreaterThanOrEqual
+ * @since 2.0.0
+ * @param {Number} expected - The expected value to compare against.
+ * @example
+ * expect(result).toBeGreaterThanOrEqual(25);
+ */
+ function toBeGreaterThanOrEqual() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual >= expected
+ };
+ }
+ };
+ }
+
+ return toBeGreaterThanOrEqual;
+};
+
+getJasmineRequireObj().toBeInstanceOf = function(j$) {
+ var usageError = j$.formatErrorMsg('', 'expect(value).toBeInstanceOf()');
+
+ /**
+ * {@link expect} the actual to be an instance of the expected class
+ * @function
+ * @name matchers#toBeInstanceOf
+ * @since 3.5.0
+ * @param {Object} expected - The class or constructor function to check for
+ * @example
+ * expect('foo').toBeInstanceOf(String);
+ * expect(3).toBeInstanceOf(Number);
+ * expect(new Error()).toBeInstanceOf(Error);
+ */
+ function toBeInstanceOf(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : j$.pp(actual),
+ expectedType = expected ? j$.fnNameFor(expected) : j$.pp(expected),
+ expectedMatcher,
+ pass;
+
+ try {
+ expectedMatcher = new j$.Any(expected);
+ pass = expectedMatcher.asymmetricMatch(actual);
+ } catch (error) {
+ throw new Error(usageError('Expected value is not a constructor function'));
+ }
+
+ if (pass) {
+ return {
+ pass: true,
+ message: 'Expected instance of ' + actualType + ' not to be an instance of ' + expectedType
+ };
+ } else {
+ return {
+ pass: false,
+ message: 'Expected instance of ' + actualType + ' to be an instance of ' + expectedType
+ };
+ }
+ }
+ };
+ }
+
+ return toBeInstanceOf;
+};
+
+getJasmineRequireObj().toBeLessThan = function() {
+ /**
+ * {@link expect} the actual value to be less than the expected value.
+ * @function
+ * @name matchers#toBeLessThan
+ * @since 2.0.0
+ * @param {Number} expected - The expected value to compare against.
+ * @example
+ * expect(result).toBeLessThan(0);
+ */
+ function toBeLessThan() {
+ return {
+
+ compare: function(actual, expected) {
+ return {
+ pass: actual < expected
+ };
+ }
+ };
+ }
+
+ return toBeLessThan;
+};
+
+getJasmineRequireObj().toBeLessThanOrEqual = function() {
+ /**
+ * {@link expect} the actual value to be less than or equal to the expected value.
+ * @function
+ * @name matchers#toBeLessThanOrEqual
+ * @since 2.0.0
+ * @param {Number} expected - The expected value to compare against.
+ * @example
+ * expect(result).toBeLessThanOrEqual(123);
+ */
+ function toBeLessThanOrEqual() {
+ return {
+
+ compare: function(actual, expected) {
+ return {
+ pass: actual <= expected
+ };
+ }
+ };
+ }
+
+ return toBeLessThanOrEqual;
+};
+
+getJasmineRequireObj().toBeNaN = function(j$) {
+ /**
+ * {@link expect} the actual value to be `NaN` (Not a Number).
+ * @function
+ * @name matchers#toBeNaN
+ * @since 1.3.0
+ * @example
+ * expect(thing).toBeNaN();
+ */
+ function toBeNaN() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual !== actual)
+ };
+
+ if (result.pass) {
+ result.message = 'Expected actual not to be NaN.';
+ } else {
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBeNaN;
+};
+
+getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
+ /**
+ * {@link expect} the actual value to be `-Infinity` (-infinity).
+ * @function
+ * @name matchers#toBeNegativeInfinity
+ * @since 2.6.0
+ * @example
+ * expect(thing).toBeNegativeInfinity();
+ */
+ function toBeNegativeInfinity() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual === Number.NEGATIVE_INFINITY)
+ };
+
+ if (result.pass) {
+ result.message = 'Expected actual not to be -Infinity.';
+ } else {
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be -Infinity.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBeNegativeInfinity;
+};
+
+getJasmineRequireObj().toBeNull = function() {
+ /**
+ * {@link expect} the actual value to be `null`.
+ * @function
+ * @name matchers#toBeNull
+ * @since 1.3.0
+ * @example
+ * expect(result).toBeNull();
+ */
+ function toBeNull() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: actual === null
+ };
+ }
+ };
+ }
+
+ return toBeNull;
+};
+
+getJasmineRequireObj().toBePositiveInfinity = function(j$) {
+ /**
+ * {@link expect} the actual value to be `Infinity` (infinity).
+ * @function
+ * @name matchers#toBePositiveInfinity
+ * @since 2.6.0
+ * @example
+ * expect(thing).toBePositiveInfinity();
+ */
+ function toBePositiveInfinity() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual === Number.POSITIVE_INFINITY)
+ };
+
+ if (result.pass) {
+ result.message = 'Expected actual not to be Infinity.';
+ } else {
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be Infinity.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBePositiveInfinity;
+};
+
+getJasmineRequireObj().toBeTrue = function() {
+ /**
+ * {@link expect} the actual value to be `true`.
+ * @function
+ * @name matchers#toBeTrue
+ * @since 3.5.0
+ * @example
+ * expect(result).toBeTrue();
+ */
+ function toBeTrue() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: actual === true
+ };
+ }
+ };
+ }
+
+ return toBeTrue;
+};
+
+getJasmineRequireObj().toBeTruthy = function() {
+ /**
+ * {@link expect} the actual value to be truthy.
+ * @function
+ * @name matchers#toBeTruthy
+ * @since 2.0.0
+ * @example
+ * expect(thing).toBeTruthy();
+ */
+ function toBeTruthy() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: !!actual
+ };
+ }
+ };
+ }
+
+ return toBeTruthy;
+};
+
+getJasmineRequireObj().toBeUndefined = function() {
+ /**
+ * {@link expect} the actual value to be `undefined`.
+ * @function
+ * @name matchers#toBeUndefined
+ * @since 1.3.0
+ * @example
+ * expect(result).toBeUndefined():
+ */
+ function toBeUndefined() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: void 0 === actual
+ };
+ }
+ };
+ }
+
+ return toBeUndefined;
+};
+
+getJasmineRequireObj().toContain = function() {
+ /**
+ * {@link expect} the actual value to contain a specific value.
+ * @function
+ * @name matchers#toContain
+ * @since 2.0.0
+ * @param {Object} expected - The value to look for.
+ * @example
+ * expect(array).toContain(anElement);
+ * expect(string).toContain(substring);
+ */
+ function toContain(util, customEqualityTesters) {
+ customEqualityTesters = customEqualityTesters || [];
+
+ return {
+ compare: function(actual, expected) {
+
+ return {
+ pass: util.contains(actual, expected, customEqualityTesters)
+ };
+ }
+ };
+ }
+
+ return toContain;
+};
+
+getJasmineRequireObj().toEqual = function(j$) {
+ /**
+ * {@link expect} the actual value to be equal to the expected, using deep equality comparison.
+ * @function
+ * @name matchers#toEqual
+ * @since 1.3.0
+ * @param {Object} expected - Expected value
+ * @example
+ * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
+ */
+ function toEqual(util, customEqualityTesters) {
+ customEqualityTesters = customEqualityTesters || [];
+
+ return {
+ compare: function(actual, expected) {
+ var result = {
+ pass: false
+ },
+ diffBuilder = j$.DiffBuilder();
+
+ result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
+
+ // TODO: only set error message if test fails
+ result.message = diffBuilder.getMessage();
+
+ return result;
+ }
+ };
+ }
+
+ return toEqual;
+};
+
+getJasmineRequireObj().toHaveBeenCalled = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect().toHaveBeenCalled()');
+
+ /**
+ * {@link expect} the actual (a {@link Spy}) to have been called.
+ * @function
+ * @name matchers#toHaveBeenCalled
+ * @since 1.3.0
+ * @example
+ * expect(mySpy).toHaveBeenCalled();
+ * expect(mySpy).not.toHaveBeenCalled();
+ */
+ function toHaveBeenCalled() {
+ return {
+ compare: function(actual) {
+ var result = {};
+
+ if (!j$.isSpy(actual)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+ }
+
+ if (arguments.length > 1) {
+ throw new Error(getErrorMsg('Does not take arguments, use toHaveBeenCalledWith'));
+ }
+
+ result.pass = actual.calls.any();
+
+ result.message = result.pass ?
+ 'Expected spy ' + actual.and.identity + ' not to have been called.' :
+ 'Expected spy ' + actual.and.identity + ' to have been called.';
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalled;
+};
+
+getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect().toHaveBeenCalledBefore()');
+
+ /**
+ * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
+ * @function
+ * @name matchers#toHaveBeenCalledBefore
+ * @since 2.6.0
+ * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
+ * @example
+ * expect(mySpy).toHaveBeenCalledBefore(otherSpy);
+ */
+ function toHaveBeenCalledBefore() {
+ return {
+ compare: function(firstSpy, latterSpy) {
+ if (!j$.isSpy(firstSpy)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
+ }
+ if (!j$.isSpy(latterSpy)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
+ }
+
+ var result = { pass: false };
+
+ if (!firstSpy.calls.count()) {
+ result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called.';
+ return result;
+ }
+ if (!latterSpy.calls.count()) {
+ result.message = 'Expected spy ' + latterSpy.and.identity + ' to have been called.';
+ return result;
+ }
+
+ var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder;
+ var first2ndSpyCall = latterSpy.calls.first().invocationOrder;
+
+ result.pass = latest1stSpyCall < first2ndSpyCall;
+
+ if (result.pass) {
+ result.message = 'Expected spy ' + firstSpy.and.identity + ' to not have been called before spy ' + latterSpy.and.identity + ', but it was';
+ } else {
+ var first1stSpyCall = firstSpy.calls.first().invocationOrder;
+ var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
+
+ if(first1stSpyCall < first2ndSpyCall) {
+ result.message = 'Expected latest call to spy ' + firstSpy.and.identity + ' to have been called before first call to spy ' + latterSpy.and.identity + ' (no interleaved calls)';
+ } else if (latest2ndSpyCall > latest1stSpyCall) {
+ result.message = 'Expected first call to spy ' + latterSpy.and.identity + ' to have been called after latest call to spy ' + firstSpy.and.identity + ' (no interleaved calls)';
+ } else {
+ result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called before spy ' + latterSpy.and.identity;
+ }
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledBefore;
+};
+
+getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect().toHaveBeenCalledTimes()');
+
+ /**
+ * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
+ * @function
+ * @name matchers#toHaveBeenCalledTimes
+ * @since 2.4.0
+ * @param {Number} expected - The number of invocations to look for.
+ * @example
+ * expect(mySpy).toHaveBeenCalledTimes(3);
+ */
+ function toHaveBeenCalledTimes() {
+ return {
+ compare: function(actual, expected) {
+ if (!j$.isSpy(actual)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+ }
+
+ var args = Array.prototype.slice.call(arguments, 0),
+ result = { pass: false };
+
+ if (!j$.isNumber_(expected)) {
+ throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
+ }
+
+ actual = args[0];
+ var calls = actual.calls.count();
+ var timesMessage = expected === 1 ? 'once' : expected + ' times';
+ result.pass = calls === expected;
+ result.message = result.pass ?
+ 'Expected spy ' + actual.and.identity + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
+ 'Expected spy ' + actual.and.identity + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledTimes;
+};
+
+getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect().toHaveBeenCalledWith(...arguments)');
+
+ /**
+ * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
+ * @function
+ * @name matchers#toHaveBeenCalledWith
+ * @since 1.3.0
+ * @param {...Object} - The arguments to look for
+ * @example
+ * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
+ */
+ function toHaveBeenCalledWith(util, customEqualityTesters) {
+ return {
+ compare: function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ actual = args[0],
+ expectedArgs = args.slice(1),
+ result = { pass: false };
+
+ if (!j$.isSpy(actual)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+ }
+
+ if (!actual.calls.any()) {
+ result.message = function() {
+ return 'Expected spy ' + actual.and.identity + ' to have been called with:\n' +
+ ' ' + j$.pp(expectedArgs) +
+ '\nbut it was never called.';
+ };
+ return result;
+ }
+
+ if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
+ result.pass = true;
+ result.message = function() {
+ return 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' +
+ ' ' + j$.pp(expectedArgs) +
+ '\nbut it was.';
+ };
+ } else {
+ result.message = function() {
+ var prettyPrintedCalls = actual.calls.allArgs().map(function(argsForCall) {
+ return ' ' + j$.pp(argsForCall);
+ });
+
+ var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) {
+ var diffBuilder = new j$.DiffBuilder();
+ util.equals(argsForCall, expectedArgs, customEqualityTesters, diffBuilder);
+ return 'Call ' + callIx + ':\n' +
+ diffBuilder.getMessage().replace(/^/mg, ' ');
+ });
+
+ return 'Expected spy ' + actual.and.identity + ' to have been called with:\n' +
+ ' ' + j$.pp(expectedArgs) + '\n' + '' +
+ 'but actual calls were:\n' +
+ prettyPrintedCalls.join(',\n') + '.\n\n' +
+ diffs.join('\n');
+ };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledWith;
+};
+
+getJasmineRequireObj().toHaveClass = function(j$) {
+ /**
+ * {@link expect} the actual value to be a DOM element that has the expected class
+ * @function
+ * @name matchers#toHaveClass
+ * @since 3.0.0
+ * @param {Object} expected - The class name to test for
+ * @example
+ * var el = document.createElement('div');
+ * el.className = 'foo bar baz';
+ * expect(el).toHaveClass('bar');
+ */
+ function toHaveClass(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ if (!isElement(actual)) {
+ throw new Error(j$.pp(actual) + ' is not a DOM element');
+ }
+
+ return {
+ pass: actual.classList.contains(expected)
+ };
+ }
+ };
+ }
+
+ function isElement(maybeEl) {
+ return maybeEl &&
+ maybeEl.classList &&
+ j$.isFunction_(maybeEl.classList.contains);
+ }
+
+ return toHaveClass;
+};
+
+getJasmineRequireObj().toMatch = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect().toMatch( || )');
+
+ /**
+ * {@link expect} the actual value to match a regular expression
+ * @function
+ * @name matchers#toMatch
+ * @since 1.3.0
+ * @param {RegExp|String} expected - Value to look for in the string.
+ * @example
+ * expect("my string").toMatch(/string$/);
+ * expect("other string").toMatch("her");
+ */
+ function toMatch() {
+ return {
+ compare: function(actual, expected) {
+ if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
+ throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
+ }
+
+ var regexp = new RegExp(expected);
+
+ return {
+ pass: regexp.test(actual)
+ };
+ }
+ };
+ }
+
+ return toMatch;
+};
+
+getJasmineRequireObj().toThrow = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect(function() {}).toThrow()');
+
+ /**
+ * {@link expect} a function to `throw` something.
+ * @function
+ * @name matchers#toThrow
+ * @since 2.0.0
+ * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
+ * @example
+ * expect(function() { return 'things'; }).toThrow('foo');
+ * expect(function() { return 'stuff'; }).toThrow();
+ */
+ function toThrow(util) {
+ return {
+ compare: function(actual, expected) {
+ var result = { pass: false },
+ threw = false,
+ thrown;
+
+ if (typeof actual != 'function') {
+ throw new Error(getErrorMsg('Actual is not a Function'));
+ }
+
+ try {
+ actual();
+ } catch (e) {
+ threw = true;
+ thrown = e;
+ }
+
+ if (!threw) {
+ result.message = 'Expected function to throw an exception.';
+ return result;
+ }
+
+ if (arguments.length == 1) {
+ result.pass = true;
+ result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
+
+ return result;
+ }
+
+ if (util.equals(thrown, expected)) {
+ result.pass = true;
+ result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
+ } else {
+ result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toThrow;
+};
+
+getJasmineRequireObj().toThrowError = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('', 'expect(function() {}).toThrowError(, )');
+
+ /**
+ * {@link expect} a function to `throw` an `Error`.
+ * @function
+ * @name matchers#toThrowError
+ * @since 2.0.0
+ * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
+ * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
+ * @example
+ * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message');
+ * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/);
+ * expect(function() { return 'stuff'; }).toThrowError(MyCustomError);
+ * expect(function() { return 'other'; }).toThrowError(/foo/);
+ * expect(function() { return 'other'; }).toThrowError();
+ */
+ function toThrowError () {
+ return {
+ compare: function(actual) {
+ var errorMatcher = getMatcher.apply(null, arguments),
+ thrown;
+
+ if (typeof actual != 'function') {
+ throw new Error(getErrorMsg('Actual is not a Function'));
+ }
+
+ try {
+ actual();
+ return fail('Expected function to throw an Error.');
+ } catch (e) {
+ thrown = e;
+ }
+
+ if (!j$.isError_(thrown)) {
+ return fail(function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; });
+ }
+
+ return errorMatcher.match(thrown);
+ }
+ };
+
+ function getMatcher() {
+ var expected, errorType;
+
+ if (arguments[2]) {
+ errorType = arguments[1];
+ expected = arguments[2];
+ if (!isAnErrorType(errorType)) {
+ throw new Error(getErrorMsg('Expected error type is not an Error.'));
+ }
+
+ return exactMatcher(expected, errorType);
+ } else if (arguments[1]) {
+ expected = arguments[1];
+
+ if (isAnErrorType(arguments[1])) {
+ return exactMatcher(null, arguments[1]);
+ } else {
+ return exactMatcher(arguments[1], null);
+ }
+ } else {
+ return anyMatcher();
+ }
+ }
+
+ function anyMatcher() {
+ return {
+ match: function(error) {
+ return pass('Expected function not to throw an Error, but it threw ' + j$.fnNameFor(error) + '.');
+ }
+ };
+ }
+
+ function exactMatcher(expected, errorType) {
+ if (expected && !isStringOrRegExp(expected)) {
+ if (errorType) {
+ throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
+ } else {
+ throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));
+ }
+ }
+
+ function messageMatch(message) {
+ if (typeof expected == 'string') {
+ return expected == message;
+ } else {
+ return expected.test(message);
+ }
+ }
+
+ var errorTypeDescription = errorType ? j$.fnNameFor(errorType) : 'an exception';
+
+ function thrownDescription(thrown) {
+ var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
+ thrownMessage = '';
+
+ if (expected) {
+ thrownMessage = ' with message ' + j$.pp(thrown.message);
+ }
+
+ return thrownName + thrownMessage;
+ }
+
+ function messageDescription() {
+ if (expected === null) {
+ return '';
+ } else if (expected instanceof RegExp) {
+ return ' with a message matching ' + j$.pp(expected);
+ } else {
+ return ' with message ' + j$.pp(expected);
+ }
+ }
+
+ function matches(error) {
+ return (errorType === null || error instanceof errorType) &&
+ (expected === null || messageMatch(error.message));
+ }
+
+ return {
+ match: function(thrown) {
+ if (matches(thrown)) {
+ return pass(function() {
+ return 'Expected function not to throw ' + errorTypeDescription + messageDescription() + '.';
+ });
+ } else {
+ return fail(function() {
+ return 'Expected function to throw ' + errorTypeDescription + messageDescription() +
+ ', but it threw ' + thrownDescription(thrown) + '.';
+ });
+ }
+ }
+ };
+ }
+
+ function isStringOrRegExp(potential) {
+ return potential instanceof RegExp || (typeof potential == 'string');
+ }
+
+ function isAnErrorType(type) {
+ if (typeof type !== 'function') {
+ return false;
+ }
+
+ var Surrogate = function() {};
+ Surrogate.prototype = type.prototype;
+ return j$.isError_(new Surrogate());
+ }
+ }
+
+ function pass(message) {
+ return {
+ pass: true,
+ message: message
+ };
+ }
+
+ function fail(message) {
+ return {
+ pass: false,
+ message: message
+ };
+ }
+
+ return toThrowError;
+};
+
+getJasmineRequireObj().toThrowMatching = function(j$) {
+ var usageError = j$.formatErrorMsg('', 'expect(function() {}).toThrowMatching()');
+
+ /**
+ * {@link expect} a function to `throw` something matching a predicate.
+ * @function
+ * @name matchers#toThrowMatching
+ * @since 3.0.0
+ * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches.
+ * @example
+ * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; });
+ */
+ function toThrowMatching() {
+ return {
+ compare: function(actual, predicate) {
+ var thrown;
+
+ if (typeof actual !== 'function') {
+ throw new Error(usageError('Actual is not a Function'));
+ }
+
+ if (typeof predicate !== 'function') {
+ throw new Error(usageError('Predicate is not a Function'));
+ }
+
+ try {
+ actual();
+ return fail('Expected function to throw an exception.');
+ } catch (e) {
+ thrown = e;
+ }
+
+ if (predicate(thrown)) {
+ return pass('Expected function not to throw an exception matching a predicate.');
+ } else {
+ return fail(function() {
+ return 'Expected function to throw an exception matching a predicate, ' +
+ 'but it threw ' + thrownDescription(thrown) + '.';
+ });
+ }
+ }
+ };
+ }
+
+ function thrownDescription(thrown) {
+ if (thrown && thrown.constructor) {
+ return j$.fnNameFor(thrown.constructor) + ' with message ' +
+ j$.pp(thrown.message);
+ } else {
+ return j$.pp(thrown);
+ }
+ }
+
+ function pass(message) {
+ return {
+ pass: true,
+ message: message
+ };
+ }
+
+ function fail(message) {
+ return {
+ pass: false,
+ message: message
+ };
+ }
+
+ return toThrowMatching;
+};
+
+getJasmineRequireObj().MockDate = function() {
+ function MockDate(global) {
+ var self = this;
+ var currentTime = 0;
+
+ if (!global || !global.Date) {
+ self.install = function() {};
+ self.tick = function() {};
+ self.uninstall = function() {};
+ return self;
+ }
+
+ var GlobalDate = global.Date;
+
+ self.install = function(mockDate) {
+ if (mockDate instanceof GlobalDate) {
+ currentTime = mockDate.getTime();
+ } else {
+ currentTime = new GlobalDate().getTime();
+ }
+
+ global.Date = FakeDate;
+ };
+
+ self.tick = function(millis) {
+ millis = millis || 0;
+ currentTime = currentTime + millis;
+ };
+
+ self.uninstall = function() {
+ currentTime = 0;
+ global.Date = GlobalDate;
+ };
+
+ createDateProperties();
+
+ return self;
+
+ function FakeDate() {
+ switch (arguments.length) {
+ case 0:
+ return new GlobalDate(currentTime);
+ case 1:
+ return new GlobalDate(arguments[0]);
+ case 2:
+ return new GlobalDate(arguments[0], arguments[1]);
+ case 3:
+ return new GlobalDate(arguments[0], arguments[1], arguments[2]);
+ case 4:
+ return new GlobalDate(
+ arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3]
+ );
+ case 5:
+ return new GlobalDate(
+ arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3],
+ arguments[4]
+ );
+ case 6:
+ return new GlobalDate(
+ arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3],
+ arguments[4],
+ arguments[5]
+ );
+ default:
+ return new GlobalDate(
+ arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3],
+ arguments[4],
+ arguments[5],
+ arguments[6]
+ );
+ }
+ }
+
+ function createDateProperties() {
+ FakeDate.prototype = GlobalDate.prototype;
+
+ FakeDate.now = function() {
+ if (GlobalDate.now) {
+ return currentTime;
+ } else {
+ throw new Error('Browser does not support Date.now()');
+ }
+ };
+
+ FakeDate.toSource = GlobalDate.toSource;
+ FakeDate.toString = GlobalDate.toString;
+ FakeDate.parse = GlobalDate.parse;
+ FakeDate.UTC = GlobalDate.UTC;
+ }
+ }
+
+ return MockDate;
+};
+
+getJasmineRequireObj().pp = function(j$) {
+ function PrettyPrinter() {
+ this.ppNestLevel_ = 0;
+ this.seen = [];
+ this.length = 0;
+ this.stringParts = [];
+ }
+
+ function hasCustomToString(value) {
+ // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
+ // iframe, web worker)
+ try {
+ return (
+ j$.isFunction_(value.toString) &&
+ value.toString !== Object.prototype.toString &&
+ value.toString() !== Object.prototype.toString.call(value)
+ );
+ } catch (e) {
+ // The custom toString() threw.
+ return true;
+ }
+ }
+
+ PrettyPrinter.prototype.format = function(value) {
+ this.ppNestLevel_++;
+ try {
+ if (j$.util.isUndefined(value)) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === 0 && 1 / value === -Infinity) {
+ this.emitScalar('-0');
+ } else if (value === j$.getGlobal()) {
+ this.emitScalar('');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (j$.isSpy(value)) {
+ this.emitScalar('spy on ' + value.and.identity);
+ } else if (j$.isSpy(value.toString)) {
+ this.emitScalar('spy on ' + value.toString.and.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (j$.isDomNode(value)) {
+ if (value.tagName) {
+ this.emitDomElement(value);
+ } else {
+ this.emitScalar('HTMLNode');
+ }
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (j$.isSet(value)) {
+ this.emitSet(value);
+ } else if (j$.isMap(value)) {
+ this.emitMap(value);
+ } else if (j$.isTypedArray_(value)) {
+ this.emitTypedArray(value);
+ } else if (
+ value.toString &&
+ typeof value === 'object' &&
+ !j$.isArray_(value) &&
+ hasCustomToString(value)
+ ) {
+ try {
+ this.emitScalar(value.toString());
+ } catch (e) {
+ this.emitScalar('has-invalid-toString-method');
+ }
+ } else if (j$.util.arrayContains(this.seen, value)) {
+ this.emitScalar(
+ ''
+ );
+ } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
+ this.seen.push(value);
+ if (j$.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ this.seen.pop();
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } catch (e) {
+ if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
+ throw e;
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+ };
+
+ PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ var objKeys = keys(obj, j$.isArray_(obj));
+ var isGetter = function isGetter(prop) {};
+
+ if (obj.__lookupGetter__) {
+ isGetter = function isGetter(prop) {
+ var getter = obj.__lookupGetter__(prop);
+ return !j$.util.isUndefined(getter) && getter !== null;
+ };
+ }
+ var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+ for (var i = 0; i < length; i++) {
+ var property = objKeys[i];
+ fn(property, isGetter(property));
+ }
+
+ return objKeys.length > length;
+ };
+
+ PrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+ };
+
+ PrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+ };
+
+ PrettyPrinter.prototype.emitArray = function(array) {
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ this.append('Array');
+ return;
+ }
+ var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+ this.append('[ ');
+ for (var i = 0; i < length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ if (array.length > length) {
+ this.append(', ...');
+ }
+
+ var self = this;
+ var first = array.length === 0;
+ var truncated = this.iterateObject(array, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.formatProperty(array, property, isGetter);
+ });
+
+ if (truncated) {
+ this.append(', ...');
+ }
+
+ this.append(' ]');
+ };
+
+ PrettyPrinter.prototype.emitSet = function(set) {
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ this.append('Set');
+ return;
+ }
+ this.append('Set( ');
+ var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+ var i = 0;
+ set.forEach(function(value, key) {
+ if (i >= size) {
+ return;
+ }
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(value);
+
+ i++;
+ }, this);
+ if (set.size > size) {
+ this.append(', ...');
+ }
+ this.append(' )');
+ };
+
+ PrettyPrinter.prototype.emitMap = function(map) {
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ this.append('Map');
+ return;
+ }
+ this.append('Map( ');
+ var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+ var i = 0;
+ map.forEach(function(value, key) {
+ if (i >= size) {
+ return;
+ }
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format([key, value]);
+
+ i++;
+ }, this);
+ if (map.size > size) {
+ this.append(', ...');
+ }
+ this.append(' )');
+ };
+
+ PrettyPrinter.prototype.emitObject = function(obj) {
+ var ctor = obj.constructor,
+ constructorName;
+
+ constructorName =
+ typeof ctor === 'function' && obj instanceof ctor
+ ? j$.fnNameFor(obj.constructor)
+ : 'null';
+
+ this.append(constructorName);
+
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ return;
+ }
+
+ var self = this;
+ this.append('({ ');
+ var first = true;
+
+ var truncated = this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.formatProperty(obj, property, isGetter);
+ });
+
+ if (truncated) {
+ this.append(', ...');
+ }
+
+ this.append(' })');
+ };
+
+ PrettyPrinter.prototype.emitTypedArray = function(arr) {
+ var constructorName = j$.fnNameFor(arr.constructor),
+ limitedArray = Array.prototype.slice.call(
+ arr,
+ 0,
+ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
+ ),
+ itemsString = Array.prototype.join.call(limitedArray, ', ');
+
+ if (limitedArray.length !== arr.length) {
+ itemsString += ', ...';
+ }
+
+ this.append(constructorName + ' [ ' + itemsString + ' ]');
+ };
+
+ PrettyPrinter.prototype.emitDomElement = function(el) {
+ var tagName = el.tagName.toLowerCase(),
+ attrs = el.attributes,
+ i,
+ len = attrs.length,
+ out = '<' + tagName,
+ attr;
+
+ for (i = 0; i < len; i++) {
+ attr = attrs[i];
+ out += ' ' + attr.name;
+
+ if (attr.value !== '') {
+ out += '="' + attr.value + '"';
+ }
+ }
+
+ out += '>';
+
+ if (el.childElementCount !== 0 || el.textContent !== '') {
+ out += '...' + tagName + '>';
+ }
+
+ this.append(out);
+ };
+
+ PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
+ this.append(property);
+ this.append(': ');
+ if (isGetter) {
+ this.append('');
+ } else {
+ this.format(obj[property]);
+ }
+ };
+
+ PrettyPrinter.prototype.append = function(value) {
+ // This check protects us from the rare case where an object has overriden
+ // `toString()` with an invalid implementation (returning a non-string).
+ if (typeof value !== 'string') {
+ value = Object.prototype.toString.call(value);
+ }
+
+ var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
+ this.length += result.value.length;
+ this.stringParts.push(result.value);
+
+ if (result.truncated) {
+ throw new MaxCharsReachedError();
+ }
+ };
+
+ function truncate(s, maxlen) {
+ if (s.length <= maxlen) {
+ return { value: s, truncated: false };
+ }
+
+ s = s.substring(0, maxlen - 4) + ' ...';
+ return { value: s, truncated: true };
+ }
+
+ function MaxCharsReachedError() {
+ this.message =
+ 'Exceeded ' +
+ j$.MAX_PRETTY_PRINT_CHARS +
+ ' characters while pretty-printing a value';
+ }
+
+ MaxCharsReachedError.prototype = new Error();
+
+ function keys(obj, isArray) {
+ var allKeys = Object.keys
+ ? Object.keys(obj)
+ : (function(o) {
+ var keys = [];
+ for (var key in o) {
+ if (j$.util.has(o, key)) {
+ keys.push(key);
+ }
+ }
+ return keys;
+ })(obj);
+
+ if (!isArray) {
+ return allKeys;
+ }
+
+ if (allKeys.length === 0) {
+ return allKeys;
+ }
+
+ var extraKeys = [];
+ for (var i = 0; i < allKeys.length; i++) {
+ if (!/^[0-9]+$/.test(allKeys[i])) {
+ extraKeys.push(allKeys[i]);
+ }
+ }
+
+ return extraKeys;
+ }
+ return function(value) {
+ var prettyPrinter = new PrettyPrinter();
+ prettyPrinter.format(value);
+ return prettyPrinter.stringParts.join('');
+ };
+};
+
+getJasmineRequireObj().QueueRunner = function(j$) {
+ function StopExecutionError() {}
+ StopExecutionError.prototype = new Error();
+ j$.StopExecutionError = StopExecutionError;
+
+ function once(fn) {
+ var called = false;
+ return function(arg) {
+ if (!called) {
+ called = true;
+ // Direct call using single parameter, because cleanup/next does not need more
+ fn(arg);
+ }
+ return null;
+ };
+ }
+
+ function emptyFn() {}
+
+ function QueueRunner(attrs) {
+ var queueableFns = attrs.queueableFns || [];
+ this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
+ this.firstCleanupIx = queueableFns.length;
+ this.onComplete = attrs.onComplete || emptyFn;
+ this.clearStack =
+ attrs.clearStack ||
+ function(fn) {
+ fn();
+ };
+ this.onException = attrs.onException || emptyFn;
+ this.userContext = attrs.userContext || new j$.UserContext();
+ this.timeout = attrs.timeout || {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout
+ };
+ this.fail = attrs.fail || emptyFn;
+ this.globalErrors = attrs.globalErrors || {
+ pushListener: emptyFn,
+ popListener: emptyFn
+ };
+ this.completeOnFirstError = !!attrs.completeOnFirstError;
+ this.errored = false;
+
+ if (typeof this.onComplete !== 'function') {
+ throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
+ }
+ this.deprecated = attrs.deprecated;
+ }
+
+ QueueRunner.prototype.execute = function() {
+ var self = this;
+ this.handleFinalError = function(message, source, lineno, colno, error) {
+ // Older browsers would send the error as the first parameter. HTML5
+ // specifies the the five parameters above. The error instance should
+ // be preffered, otherwise the call stack would get lost.
+ self.onException(error || message);
+ };
+ this.globalErrors.pushListener(this.handleFinalError);
+ this.run(0);
+ };
+
+ QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
+ if (lastRanIndex < this.firstCleanupIx) {
+ this.run(this.firstCleanupIx);
+ } else {
+ this.run(lastRanIndex + 1);
+ }
+ };
+
+ QueueRunner.prototype.clearTimeout = function(timeoutId) {
+ Function.prototype.apply.apply(this.timeout.clearTimeout, [
+ j$.getGlobal(),
+ [timeoutId]
+ ]);
+ };
+
+ QueueRunner.prototype.setTimeout = function(fn, timeout) {
+ return Function.prototype.apply.apply(this.timeout.setTimeout, [
+ j$.getGlobal(),
+ [fn, timeout]
+ ]);
+ };
+
+ QueueRunner.prototype.attempt = function attempt(iterativeIndex) {
+ var self = this,
+ completedSynchronously = true,
+ handleError = function handleError(error) {
+ onException(error);
+ next(error);
+ },
+ cleanup = once(function cleanup() {
+ if (timeoutId !== void 0) {
+ self.clearTimeout(timeoutId);
+ }
+ self.globalErrors.popListener(handleError);
+ }),
+ next = once(function next(err) {
+ cleanup();
+
+ if (j$.isError_(err)) {
+ if (!(err instanceof StopExecutionError) && !err.jasmineMessage) {
+ self.fail(err);
+ }
+ self.errored = errored = true;
+ }
+
+ function runNext() {
+ if (self.completeOnFirstError && errored) {
+ self.skipToCleanup(iterativeIndex);
+ } else {
+ self.run(iterativeIndex + 1);
+ }
+ }
+
+ if (completedSynchronously) {
+ self.setTimeout(runNext);
+ } else {
+ runNext();
+ }
+ }),
+ errored = false,
+ queueableFn = self.queueableFns[iterativeIndex],
+ timeoutId;
+
+ next.fail = function nextFail() {
+ self.fail.apply(null, arguments);
+ self.errored = errored = true;
+ next();
+ };
+
+ self.globalErrors.pushListener(handleError);
+
+ if (queueableFn.timeout !== undefined) {
+ var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
+ timeoutId = self.setTimeout(function() {
+ var error = new Error(
+ 'Timeout - Async function did not complete within ' +
+ timeoutInterval +
+ 'ms ' +
+ (queueableFn.timeout
+ ? '(custom timeout)'
+ : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
+ );
+ onException(error);
+ next();
+ }, timeoutInterval);
+ }
+
+ try {
+ if (queueableFn.fn.length === 0) {
+ var maybeThenable = queueableFn.fn.call(self.userContext);
+
+ if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
+ maybeThenable.then(next, onPromiseRejection);
+ completedSynchronously = false;
+ return { completedSynchronously: false };
+ }
+ } else {
+ queueableFn.fn.call(self.userContext, next);
+ completedSynchronously = false;
+ return { completedSynchronously: false };
+ }
+ } catch (e) {
+ onException(e);
+ self.errored = errored = true;
+ }
+
+ cleanup();
+ return { completedSynchronously: true, errored: errored };
+
+ function onException(e) {
+ self.onException(e);
+ self.errored = errored = true;
+ }
+
+ function onPromiseRejection(e) {
+ onException(e);
+ next();
+ }
+ };
+
+ QueueRunner.prototype.run = function(recursiveIndex) {
+ var length = this.queueableFns.length,
+ self = this,
+ iterativeIndex;
+
+ for (
+ iterativeIndex = recursiveIndex;
+ iterativeIndex < length;
+ iterativeIndex++
+ ) {
+ var result = this.attempt(iterativeIndex);
+
+ if (!result.completedSynchronously) {
+ return;
+ }
+
+ self.errored = self.errored || result.errored;
+
+ if (this.completeOnFirstError && result.errored) {
+ this.skipToCleanup(iterativeIndex);
+ return;
+ }
+ }
+
+ this.clearStack(function() {
+ self.globalErrors.popListener(self.handleFinalError);
+ self.onComplete(self.errored && new StopExecutionError());
+ });
+ };
+
+ return QueueRunner;
+};
+
+getJasmineRequireObj().ReportDispatcher = function(j$) {
+ function ReportDispatcher(methods, queueRunnerFactory) {
+ var dispatchedMethods = methods || [];
+
+ for (var i = 0; i < dispatchedMethods.length; i++) {
+ var method = dispatchedMethods[i];
+ this[method] = (function(m) {
+ return function() {
+ dispatch(m, arguments);
+ };
+ })(method);
+ }
+
+ var reporters = [];
+ var fallbackReporter = null;
+
+ this.addReporter = function(reporter) {
+ reporters.push(reporter);
+ };
+
+ this.provideFallbackReporter = function(reporter) {
+ fallbackReporter = reporter;
+ };
+
+ this.clearReporters = function() {
+ reporters = [];
+ };
+
+ return this;
+
+ function dispatch(method, args) {
+ if (reporters.length === 0 && fallbackReporter !== null) {
+ reporters.push(fallbackReporter);
+ }
+ var onComplete = args[args.length - 1];
+ args = j$.util.argsToArray(args).splice(0, args.length - 1);
+ var fns = [];
+ for (var i = 0; i < reporters.length; i++) {
+ var reporter = reporters[i];
+ addFn(fns, reporter, method, args);
+ }
+
+ queueRunnerFactory({
+ queueableFns: fns,
+ onComplete: onComplete,
+ isReporter: true
+ });
+ }
+
+ function addFn(fns, reporter, method, args) {
+ var fn = reporter[method];
+ if (!fn) {
+ return;
+ }
+
+ var thisArgs = j$.util.cloneArgs(args);
+ if (fn.length <= 1) {
+ fns.push({
+ fn: function() {
+ return fn.apply(reporter, thisArgs);
+ }
+ });
+ } else {
+ fns.push({
+ fn: function(done) {
+ return fn.apply(reporter, thisArgs.concat([done]));
+ }
+ });
+ }
+ }
+ }
+
+ return ReportDispatcher;
+};
+
+getJasmineRequireObj().interface = function(jasmine, env) {
+ var jasmineInterface = {
+ /**
+ * Callback passed to parts of the Jasmine base interface.
+ *
+ * By default Jasmine assumes this function completes synchronously.
+ * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment.
+ * @callback implementationCallback
+ * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+ * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+ */
+
+ /**
+ * Create a group of specs (often called a suite).
+ *
+ * Calls to `describe` can be nested within other calls to compose your suite as a tree.
+ * @name describe
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {String} description Textual description of the group
+ * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
+ */
+ describe: function(description, specDefinitions) {
+ return env.describe(description, specDefinitions);
+ },
+
+ /**
+ * A temporarily disabled [`describe`]{@link describe}
+ *
+ * Specs within an `xdescribe` will be marked pending and not executed
+ * @name xdescribe
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {String} description Textual description of the group
+ * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
+ */
+ xdescribe: function(description, specDefinitions) {
+ return env.xdescribe(description, specDefinitions);
+ },
+
+ /**
+ * A focused [`describe`]{@link describe}
+ *
+ * If suites or specs are focused, only those that are focused will be executed
+ * @see fit
+ * @name fdescribe
+ * @since 2.1.0
+ * @function
+ * @global
+ * @param {String} description Textual description of the group
+ * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
+ */
+ fdescribe: function(description, specDefinitions) {
+ return env.fdescribe(description, specDefinitions);
+ },
+
+ /**
+ * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
+ *
+ * A spec whose expectations all succeed will be passing and a spec with any failures will fail.
+ * @name it
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {String} description Textual description of what this spec is checking
+ * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
+ * @see async
+ */
+ it: function() {
+ return env.it.apply(env, arguments);
+ },
+
+ /**
+ * A temporarily disabled [`it`]{@link it}
+ *
+ * The spec will report as `pending` and will not be executed.
+ * @name xit
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {String} description Textual description of what this spec is checking.
+ * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed.
+ */
+ xit: function() {
+ return env.xit.apply(env, arguments);
+ },
+
+ /**
+ * A focused [`it`]{@link it}
+ *
+ * If suites or specs are focused, only those that are focused will be executed.
+ * @name fit
+ * @since 2.1.0
+ * @function
+ * @global
+ * @param {String} description Textual description of what this spec is checking.
+ * @param {implementationCallback} testFunction Function that contains the code of your test.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
+ * @see async
+ */
+ fit: function() {
+ return env.fit.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared setup before each of the specs in the {@link describe} in which it is called.
+ * @name beforeEach
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {implementationCallback} [function] Function that contains the code to setup your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
+ * @see async
+ */
+ beforeEach: function() {
+ return env.beforeEach.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared teardown after each of the specs in the {@link describe} in which it is called.
+ * @name afterEach
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
+ * @see async
+ */
+ afterEach: function() {
+ return env.afterEach.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared setup once before all of the specs in the {@link describe} are run.
+ *
+ * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
+ * @name beforeAll
+ * @since 2.1.0
+ * @function
+ * @global
+ * @param {implementationCallback} [function] Function that contains the code to setup your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
+ * @see async
+ */
+ beforeAll: function() {
+ return env.beforeAll.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared teardown once after all of the specs in the {@link describe} are run.
+ *
+ * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
+ * @name afterAll
+ * @since 2.1.0
+ * @function
+ * @global
+ * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
+ * @see async
+ */
+ afterAll: function() {
+ return env.afterAll.apply(env, arguments);
+ },
+
+ /**
+ * Create an expectation for a spec.
+ * @name expect
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {Object} actual - Actual computed value to test expectations against.
+ * @return {matchers}
+ */
+ expect: function(actual) {
+ return env.expect(actual);
+ },
+
+ /**
+ * Create an asynchronous expectation for a spec. Note that the matchers
+ * that are provided by an asynchronous expectation all return promises
+ * which must be either returned from the spec or waited for using `await`
+ * in order for Jasmine to associate them with the correct spec.
+ * @name expectAsync
+ * @since 3.3.0
+ * @function
+ * @global
+ * @param {Object} actual - Actual computed value to test expectations against.
+ * @return {async-matchers}
+ * @example
+ * await expectAsync(somePromise).toBeResolved();
+ * @example
+ * return expectAsync(somePromise).toBeResolved();
+ */
+ expectAsync: function(actual) {
+ return env.expectAsync(actual);
+ },
+
+ /**
+ * Mark a spec as pending, expectation results will be ignored.
+ * @name pending
+ * @since 2.0.0
+ * @function
+ * @global
+ * @param {String} [message] - Reason the spec is pending.
+ */
+ pending: function() {
+ return env.pending.apply(env, arguments);
+ },
+
+ /**
+ * Explicitly mark a spec as failed.
+ * @name fail
+ * @since 2.1.0
+ * @function
+ * @global
+ * @param {String|Error} [error] - Reason for the failure.
+ */
+ fail: function() {
+ return env.fail.apply(env, arguments);
+ },
+
+ /**
+ * Install a spy onto an existing object.
+ * @name spyOn
+ * @since 1.3.0
+ * @function
+ * @global
+ * @param {Object} obj - The object upon which to install the {@link Spy}.
+ * @param {String} methodName - The name of the method to replace with a {@link Spy}.
+ * @returns {Spy}
+ */
+ spyOn: function(obj, methodName) {
+ return env.spyOn(obj, methodName);
+ },
+
+ /**
+ * Install a spy on a property installed with `Object.defineProperty` onto an existing object.
+ * @name spyOnProperty
+ * @since 2.6.0
+ * @function
+ * @global
+ * @param {Object} obj - The object upon which to install the {@link Spy}
+ * @param {String} propertyName - The name of the property to replace with a {@link Spy}.
+ * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on.
+ * @returns {Spy}
+ */
+ spyOnProperty: function(obj, methodName, accessType) {
+ return env.spyOnProperty(obj, methodName, accessType);
+ },
+
+ /**
+ * Installs spies on all writable and configurable properties of an object.
+ * @name spyOnAllFunctions
+ * @since 3.2.1
+ * @function
+ * @global
+ * @param {Object} obj - The object upon which to install the {@link Spy}s
+ * @returns {Object} the spied object
+ */
+ spyOnAllFunctions: function(obj) {
+ return env.spyOnAllFunctions(obj);
+ },
+
+ jsApiReporter: new jasmine.JsApiReporter({
+ timer: new jasmine.Timer()
+ }),
+
+ /**
+ * @namespace jasmine
+ */
+ jasmine: jasmine
+ };
+
+ /**
+ * Add a custom equality tester for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.addCustomEqualityTester
+ * @since 2.0.0
+ * @function
+ * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise.
+ * @see custom_equality
+ */
+ jasmine.addCustomEqualityTester = function(tester) {
+ env.addCustomEqualityTester(tester);
+ };
+
+ /**
+ * Add custom matchers for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.addMatchers
+ * @since 2.0.0
+ * @function
+ * @param {Object} matchers - Keys from this object will be the new matcher names.
+ * @see custom_matcher
+ */
+ jasmine.addMatchers = function(matchers) {
+ return env.addMatchers(matchers);
+ };
+
+ /**
+ * Add custom async matchers for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.addAsyncMatchers
+ * @since 3.5.0
+ * @function
+ * @param {Object} matchers - Keys from this object will be the new async matcher names.
+ * @see custom_matcher
+ */
+ jasmine.addAsyncMatchers = function(matchers) {
+ return env.addAsyncMatchers(matchers);
+ };
+
+ /**
+ * Get the currently booted mock {Clock} for this Jasmine environment.
+ * @name jasmine.clock
+ * @since 2.0.0
+ * @function
+ * @returns {Clock}
+ */
+ jasmine.clock = function() {
+ return env.clock;
+ };
+
+ /**
+ * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
+ * @name jasmine.createSpy
+ * @since 1.3.0
+ * @function
+ * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
+ * @param {Function} [originalFn] - Function to act as the real implementation.
+ * @return {Spy}
+ */
+ jasmine.createSpy = function(name, originalFn) {
+ return env.createSpy(name, originalFn);
+ };
+
+ /**
+ * Create an object with multiple {@link Spy}s as its members.
+ * @name jasmine.createSpyObj
+ * @since 1.3.0
+ * @function
+ * @param {String} [baseName] - Base name for the spies in the object.
+ * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
+ * @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}.
+ * @return {Object}
+ */
+ jasmine.createSpyObj = function(baseName, methodNames, propertyNames) {
+ return env.createSpyObj(baseName, methodNames, propertyNames);
+ };
+
+ /**
+ * Add a custom spy strategy for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.addSpyStrategy
+ * @since 3.5.0
+ * @function
+ * @param {String} name - The name of the strategy (i.e. what you call from `and`)
+ * @param {Function} factory - Factory function that returns the plan to be executed.
+ */
+ jasmine.addSpyStrategy = function(name, factory) {
+ return env.addSpyStrategy(name, factory);
+ };
+
+ /**
+ * Set the default spy strategy for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.setDefaultSpyStrategy
+ * @function
+ * @param {Function} defaultStrategyFn - a function that assigns a strategy
+ * @example
+ * beforeEach(function() {
+ * jasmine.setDefaultSpyStrategy(and => and.returnValue(true));
+ * });
+ */
+ jasmine.setDefaultSpyStrategy = function(defaultStrategyFn) {
+ return env.setDefaultSpyStrategy(defaultStrategyFn);
+ };
+
+ return jasmineInterface;
+};
+
+getJasmineRequireObj().Spy = function(j$) {
+ var nextOrder = (function() {
+ var order = 0;
+
+ return function() {
+ return order++;
+ };
+ })();
+
+ /**
+ * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
+ * @constructor
+ * @name Spy
+ */
+ function Spy(
+ name,
+ originalFn,
+ customStrategies,
+ defaultStrategyFn,
+ getPromise
+ ) {
+ var numArgs = typeof originalFn === 'function' ? originalFn.length : 0,
+ wrapper = makeFunc(numArgs, function() {
+ return spy.apply(this, Array.prototype.slice.call(arguments));
+ }),
+ strategyDispatcher = new SpyStrategyDispatcher({
+ name: name,
+ fn: originalFn,
+ getSpy: function() {
+ return wrapper;
+ },
+ customStrategies: customStrategies,
+ getPromise: getPromise
+ }),
+ callTracker = new j$.CallTracker(),
+ spy = function() {
+ /**
+ * @name Spy.callData
+ * @property {object} object - `this` context for the invocation.
+ * @property {number} invocationOrder - Order of the invocation.
+ * @property {Array} args - The arguments passed for this invocation.
+ */
+ var callData = {
+ object: this,
+ invocationOrder: nextOrder(),
+ args: Array.prototype.slice.apply(arguments)
+ };
+
+ callTracker.track(callData);
+ var returnValue = strategyDispatcher.exec(this, arguments);
+ callData.returnValue = returnValue;
+
+ return returnValue;
+ };
+
+ function makeFunc(length, fn) {
+ switch (length) {
+ case 1:
+ return function(a) {
+ return fn.apply(this, arguments);
+ };
+ case 2:
+ return function(a, b) {
+ return fn.apply(this, arguments);
+ };
+ case 3:
+ return function(a, b, c) {
+ return fn.apply(this, arguments);
+ };
+ case 4:
+ return function(a, b, c, d) {
+ return fn.apply(this, arguments);
+ };
+ case 5:
+ return function(a, b, c, d, e) {
+ return fn.apply(this, arguments);
+ };
+ case 6:
+ return function(a, b, c, d, e, f) {
+ return fn.apply(this, arguments);
+ };
+ case 7:
+ return function(a, b, c, d, e, f, g) {
+ return fn.apply(this, arguments);
+ };
+ case 8:
+ return function(a, b, c, d, e, f, g, h) {
+ return fn.apply(this, arguments);
+ };
+ case 9:
+ return function(a, b, c, d, e, f, g, h, i) {
+ return fn.apply(this, arguments);
+ };
+ default:
+ return function() {
+ return fn.apply(this, arguments);
+ };
+ }
+ }
+
+ for (var prop in originalFn) {
+ if (prop === 'and' || prop === 'calls') {
+ throw new Error(
+ "Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon"
+ );
+ }
+
+ wrapper[prop] = originalFn[prop];
+ }
+
+ /**
+ * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used
+ * whenever the spy is called with arguments that don't match any strategy
+ * created with {@link Spy#withArgs}.
+ * @name Spy#and
+ * @since 2.0.0
+ * @example
+ * spyOn(someObj, 'func').and.returnValue(42);
+ */
+ wrapper.and = strategyDispatcher.and;
+ /**
+ * Specifies a strategy to be used for calls to the spy that have the
+ * specified arguments.
+ * @name Spy#withArgs
+ * @since 3.0.0
+ * @function
+ * @param {...*} args - The arguments to match
+ * @type {SpyStrategy}
+ * @example
+ * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42);
+ * someObj.func(1, 2, 3); // returns 42
+ */
+ wrapper.withArgs = function() {
+ return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments);
+ };
+ wrapper.calls = callTracker;
+
+ if (defaultStrategyFn) {
+ defaultStrategyFn(wrapper.and);
+ }
+
+ return wrapper;
+ }
+
+ function SpyStrategyDispatcher(strategyArgs) {
+ var baseStrategy = new j$.SpyStrategy(strategyArgs);
+ var argsStrategies = new StrategyDict(function() {
+ return new j$.SpyStrategy(strategyArgs);
+ });
+
+ this.and = baseStrategy;
+
+ this.exec = function(spy, args) {
+ var strategy = argsStrategies.get(args);
+
+ if (!strategy) {
+ if (argsStrategies.any() && !baseStrategy.isConfigured()) {
+ throw new Error(
+ "Spy '" +
+ strategyArgs.name +
+ "' received a call with arguments " +
+ j$.pp(Array.prototype.slice.call(args)) +
+ ' but all configured strategies specify other arguments.'
+ );
+ } else {
+ strategy = baseStrategy;
+ }
+ }
+
+ return strategy.exec(spy, args);
+ };
+
+ this.withArgs = function() {
+ return { and: argsStrategies.getOrCreate(arguments) };
+ };
+ }
+
+ function StrategyDict(strategyFactory) {
+ this.strategies = [];
+ this.strategyFactory = strategyFactory;
+ }
+
+ StrategyDict.prototype.any = function() {
+ return this.strategies.length > 0;
+ };
+
+ StrategyDict.prototype.getOrCreate = function(args) {
+ var strategy = this.get(args);
+
+ if (!strategy) {
+ strategy = this.strategyFactory();
+ this.strategies.push({
+ args: args,
+ strategy: strategy
+ });
+ }
+
+ return strategy;
+ };
+
+ StrategyDict.prototype.get = function(args) {
+ var i;
+
+ for (i = 0; i < this.strategies.length; i++) {
+ if (j$.matchersUtil.equals(args, this.strategies[i].args)) {
+ return this.strategies[i].strategy;
+ }
+ }
+ };
+
+ return Spy;
+};
+
+getJasmineRequireObj().SpyFactory = function(j$) {
+ function SpyFactory(getCustomStrategies, getDefaultStrategyFn, getPromise) {
+ var self = this;
+
+ this.createSpy = function(name, originalFn) {
+ return j$.Spy(
+ name,
+ originalFn,
+ getCustomStrategies(),
+ getDefaultStrategyFn(),
+ getPromise
+ );
+ };
+
+ this.createSpyObj = function(baseName, methodNames, propertyNames) {
+ var baseNameIsCollection =
+ j$.isObject_(baseName) || j$.isArray_(baseName);
+
+ if (baseNameIsCollection) {
+ propertyNames = methodNames;
+ methodNames = baseName;
+ baseName = 'unknown';
+ }
+
+ var obj = {};
+ var spy, descriptor;
+
+ var methods = normalizeKeyValues(methodNames);
+ for (var i = 0; i < methods.length; i++) {
+ spy = obj[methods[i][0]] = self.createSpy(
+ baseName + '.' + methods[i][0]
+ );
+ if (methods[i].length > 1) {
+ spy.and.returnValue(methods[i][1]);
+ }
+ }
+
+ var properties = normalizeKeyValues(propertyNames);
+ for (var i = 0; i < properties.length; i++) {
+ descriptor = {
+ get: self.createSpy(baseName + '.' + properties[i][0] + '.get'),
+ set: self.createSpy(baseName + '.' + properties[i][0] + '.set')
+ };
+ if (properties[i].length > 1) {
+ descriptor.get.and.returnValue(properties[i][1]);
+ descriptor.set.and.returnValue(properties[i][1]);
+ }
+ Object.defineProperty(obj, properties[i][0], descriptor);
+ }
+
+ if (methods.length === 0 && properties.length === 0) {
+ throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
+ }
+
+ return obj;
+ };
+ }
+
+ function normalizeKeyValues(object) {
+ var result = [];
+ if (j$.isArray_(object)) {
+ for (var i = 0; i < object.length; i++) {
+ result.push([object[i]]);
+ }
+ } else if (j$.isObject_(object)) {
+ for (var key in object) {
+ if (object.hasOwnProperty(key)) {
+ result.push([key, object[key]]);
+ }
+ }
+ }
+ return result;
+ }
+
+ return SpyFactory;
+};
+
+getJasmineRequireObj().SpyRegistry = function(j$) {
+ var spyOnMsg = j$.formatErrorMsg('', 'spyOn(