UNPKG

@nfrasser/simple-html-tokenizer

Version:

Simple HTML Tokenizer is a lightweight JavaScript library that can be used to tokenize the kind of HTML normally found in templates.

1,469 lines (1,411 loc) 278 kB
/*! * QUnit 2.24.1 * https://qunitjs.com/ * * Copyright OpenJS Foundation and other contributors * Released under the MIT license * https://jquery.org/license */ (function () { 'use strict'; function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } // We don't use global-this-polyfill [1], because it modifies // the globals scope by default. QUnit must not affect the host context // as developers may test their project may be such a polyfill, and/or // they may intentionally test their project with and without certain // polyfills and we must not affect that. It also uses an obscure // mechanism that seems to sometimes causes a runtime error in older // browsers (specifically Safari and IE versions that support // Object.defineProperty but then report _T_ as undefined). // [1] https://github.com/ungap/global-this/blob/v0.4.4/esm/index.js // // Another way is `Function('return this')()`, but doing so relies // on eval which will cause a CSP error on some servers. // // Instead, simply check the four options that already exist // in all supported environments. function getGlobalThis() { if (typeof globalThis !== 'undefined') { // For SpiderMonkey, modern browsers, and recent Node.js // eslint-disable-next-line no-undef return globalThis; } if (typeof self !== 'undefined') { // For web workers // eslint-disable-next-line no-undef return self; } if (typeof window$1 !== 'undefined') { // For document context in browsers return window$1; } if (typeof global !== 'undefined') { // For Node.js // eslint-disable-next-line no-undef return global; } throw new Error('Unable to locate global object'); } // This avoids a simple `export const` assignment as that would lead Rollup // to change getGlobalThis and use the same (generated) variable name there. var g = getGlobalThis(); // These optional globals are undefined in one or more environments: // modern browser, old browser, Node.js, SpiderMonkey. // Calling code must check these for truthy-ness before use. var console$1 = g.console; var setTimeout$1 = g.setTimeout; var clearTimeout = g.clearTimeout; var process$1 = g.process; var window$1 = g.window; var document = window$1 && window$1.document; var navigator = window$1 && window$1.navigator; var localSessionStorage = function () { var x = 'qunit-test-string'; try { g.sessionStorage.setItem(x, x); g.sessionStorage.removeItem(x); return g.sessionStorage; } catch (e) { return undefined; } }(); // Basic fallback for ES6 Map // Support: IE 9-10, Safari 7, PhantomJS; Map is undefined // Support: iOS 8; `new Map(iterable)` is not supported // // Fallback for ES7 Map#keys // Support: IE 11; Map#keys is undefined var StringMap = typeof g.Map === 'function' && typeof g.Map.prototype.keys === 'function' && typeof g.Symbol === 'function' && _typeof(g.Symbol.iterator) === 'symbol' ? g.Map : function StringMap(input) { var _this = this; var store = Object.create(null); var hasOwn = Object.prototype.hasOwnProperty; this.has = function (strKey) { return hasOwn.call(store, strKey); }; this.get = function (strKey) { return store[strKey]; }; this.set = function (strKey, val) { if (!hasOwn.call(store, strKey)) { this.size++; } store[strKey] = val; return this; }; this.delete = function (strKey) { if (hasOwn.call(store, strKey)) { delete store[strKey]; this.size--; } }; this.forEach = function (callback) { for (var strKey in store) { callback(store[strKey], strKey); } }; this.keys = function () { return Object.keys(store); }; this.clear = function () { store = Object.create(null); this.size = 0; }; this.size = 0; if (input) { input.forEach(function (val, strKey) { _this.set(strKey, val); }); } }; // Basic fallback for ES6 Set // Support: IE 11, `new Set(iterable)` parameter not yet implemented // Test for Set#values() which came after Set(iterable). var StringSet = typeof g.Set === 'function' && typeof g.Set.prototype.values === 'function' ? g.Set : function (input) { var set = Object.create(null); if (Array.isArray(input)) { input.forEach(function (item) { set[item] = true; }); } return { add: function add(value) { set[value] = true; }, has: function has(value) { return value in set; }, get size() { return Object.keys(set).length; } }; }; var toString = Object.prototype.toString; var hasOwn$1 = Object.prototype.hasOwnProperty; var performance = { // eslint-disable-next-line compat/compat -- Checked now: window$1 && window$1.performance && window$1.performance.now ? window$1.performance.now.bind(window$1.performance) : Date.now }; // Returns a new Array with the elements that are in a but not in b function diff$1(a, b) { return a.filter(function (a) { return b.indexOf(a) === -1; }); } /** * Determines whether an element exists in a given array or not. * * @method inArray * @param {any} elem * @param {Array} array * @return {boolean} */ var inArray = Array.prototype.includes ? function (elem, array) { return array.includes(elem); } : function (elem, array) { return array.indexOf(elem) !== -1; }; /** * Recursively clone an object into a plain array or object, taking only the * own enumerable properties. * * @param {any} obj * @param {bool} [allowArray=true] * @return {Object|Array} */ function objectValues(obj) { var allowArray = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var vals = allowArray && is('array', obj) ? [] : {}; for (var key in obj) { if (hasOwn$1.call(obj, key)) { var val = obj[key]; vals[key] = val === Object(val) ? objectValues(val, allowArray) : val; } } return vals; } /** * Recursively clone an object into a plain object, taking only the * subset of own enumerable properties that exist a given model. * * @param {any} obj * @param {any} model * @return {Object} */ function objectValuesSubset(obj, model) { // Return primitive values unchanged to avoid false positives or confusing // results from assert.propContains(). // E.g. an actual null or false wrongly equaling an empty object, // or an actual string being reported as object not matching a partial object. if (obj !== Object(obj)) { return obj; } // Unlike objectValues(), subset arrays to a plain objects as well. // This enables subsetting [20, 30] with {1: 30}. var subset = {}; for (var key in model) { if (hasOwn$1.call(model, key) && hasOwn$1.call(obj, key)) { subset[key] = objectValuesSubset(obj[key], model[key]); } } return subset; } function extend(a, b, undefOnly) { for (var prop in b) { if (hasOwn$1.call(b, prop)) { if (b[prop] === undefined) { delete a[prop]; } else if (!(undefOnly && typeof a[prop] !== 'undefined')) { a[prop] = b[prop]; } } } return a; } function objectType(obj) { if (typeof obj === 'undefined') { return 'undefined'; } // Consider: typeof null === object if (obj === null) { return 'null'; } var match = toString.call(obj).match(/^\[object\s(.*)\]$/); var type = match && match[1]; switch (type) { case 'Number': if (isNaN(obj)) { return 'nan'; } return 'number'; case 'String': case 'Boolean': case 'Array': case 'Set': case 'Map': case 'Date': case 'RegExp': case 'Function': case 'Symbol': return type.toLowerCase(); default: return _typeof(obj); } } // Safe object type checking function is(type, obj) { return objectType(obj) === type; } // Based on Java's String.hashCode, a simple but not // rigorously collision resistant hashing function function generateHash(module, testName) { var str = module + '\x1C' + testName; var hash = 0; for (var i = 0; i < str.length; i++) { hash = (hash << 5) - hash + str.charCodeAt(i); hash |= 0; } // Convert the possibly negative integer hash code into an 8 character hex string, which isn't // strictly necessary but increases user understanding that the id is a SHA-like hash var hex = (0x100000000 + hash).toString(16); if (hex.length < 8) { hex = '0000000' + hex; } return hex.slice(-8); } /** * Converts an error into a simple string for comparisons. * * @param {Error|any} error * @return {string} */ function errorString(error) { // Use String() instead of toString() to handle non-object values like undefined or null. var resultErrorString = String(error); // If the error wasn't a subclass of Error but something like // an object literal with name and message properties... if (resultErrorString.slice(0, 7) === '[object') { // Based on https://es5.github.io/#x15.11.4.4 return (error.name || 'Error') + (error.message ? ": ".concat(error.message) : ''); } else { return resultErrorString; } } function escapeText(str) { if (!str) { return ''; } // Both single quotes and double quotes (for attributes) return ('' + str).replace(/['"<>&]/g, function (s) { switch (s) { case "'": return '&#039;'; case '"': return '&quot;'; case '<': return '&lt;'; case '>': return '&gt;'; case '&': return '&amp;'; } }); } var BOXABLE_TYPES = new StringSet(['boolean', 'number', 'string']); // Memory for previously seen containers (object, array, map, set). // Used for recursion detection, and to avoid repeated comparison. // // Elements are { a: val, b: val }. var memory = []; function useStrictEquality(a, b) { return a === b; } function useObjectValueEquality(a, b) { return a === b || a.valueOf() === b.valueOf(); } function compareConstructors(a, b) { // Comparing constructors is more strict than using `instanceof` return getConstructor(a) === getConstructor(b); } function getConstructor(obj) { var proto = Object.getPrototypeOf(obj); // If the obj prototype descends from a null constructor, treat it // as a null prototype. // Ref https://github.com/qunitjs/qunit/issues/851 // // Allow objects with no prototype, from Object.create(null), to be equivalent to // plain objects that have Object as their constructor. return !proto || proto.constructor === null ? Object : obj.constructor; } function getRegExpFlags(regexp) { return 'flags' in regexp ? regexp.flags : regexp.toString().match(/[gimuy]*$/)[0]; } // Specialised comparisons after entryTypeCallbacks.object, based on `objectType()` var objTypeCallbacks = { undefined: useStrictEquality, null: useStrictEquality, // Handle boxed boolean boolean: useObjectValueEquality, number: function number(a, b) { // Handle NaN and boxed number return a === b || a.valueOf() === b.valueOf() || isNaN(a.valueOf()) && isNaN(b.valueOf()); }, // Handle boxed string string: useObjectValueEquality, symbol: useStrictEquality, date: useObjectValueEquality, nan: function nan() { return true; }, regexp: function regexp(a, b) { return a.source === b.source && // Include flags in the comparison getRegExpFlags(a) === getRegExpFlags(b); }, // identical reference only function: useStrictEquality, array: function array(a, b) { if (a.length !== b.length) { // Safe and faster return false; } for (var i = 0; i < a.length; i++) { if (!typeEquiv(a[i], b[i])) { return false; } } return true; }, // Define sets a and b to be equivalent if for each element aVal in a, there // is some element bVal in b such that aVal and bVal are equivalent. Element // repetitions are not counted, so these are equivalent: // a = new Set( [ X={}, Y=[], Y ] ); // b = new Set( [ Y, X, X ] ); set: function set(a, b) { if (a.size !== b.size) { // This optimization has certain quirks because of the lack of // repetition counting. For instance, adding the same // (reference-identical) element to two equivalent sets can // make them non-equivalent. return false; } var outerEq = true; a.forEach(function (aVal) { // Short-circuit if the result is already known. (Using for...of // with a break clause would be cleaner here, but it would cause // a syntax error on older JavaScript implementations even if // Set is unused) if (!outerEq) { return; } var innerEq = false; b.forEach(function (bVal) { // Likewise, short-circuit if the result is already known if (innerEq) { return; } // Swap out the global memory, as nested typeEquiv() would clobber it var originalMemory = memory; memory = []; if (typeEquiv(bVal, aVal)) { innerEq = true; } // Restore memory = originalMemory; }); if (!innerEq) { outerEq = false; } }); return outerEq; }, // Define maps a and b to be equivalent if for each key-value pair (aKey, aVal) // in a, there is some key-value pair (bKey, bVal) in b such that // [ aKey, aVal ] and [ bKey, bVal ] are equivalent. Key repetitions are not // counted, so these are equivalent: // a = new Map( [ [ {}, 1 ], [ {}, 1 ], [ [], 1 ] ] ); // b = new Map( [ [ {}, 1 ], [ [], 1 ], [ [], 1 ] ] ); map: function map(a, b) { if (a.size !== b.size) { // This optimization has certain quirks because of the lack of // repetition counting. For instance, adding the same // (reference-identical) key-value pair to two equivalent maps // can make them non-equivalent. return false; } var outerEq = true; a.forEach(function (aVal, aKey) { // Short-circuit if the result is already known. (Using for...of // with a break clause would be cleaner here, but it would cause // a syntax error on older JavaScript implementations even if // Map is unused) if (!outerEq) { return; } var innerEq = false; b.forEach(function (bVal, bKey) { // Likewise, short-circuit if the result is already known if (innerEq) { return; } // Swap out the global memory, as nested typeEquiv() would clobber it var originalMemory = memory; memory = []; if (objTypeCallbacks.array([bVal, bKey], [aVal, aKey])) { innerEq = true; } // Restore memory = originalMemory; }); if (!innerEq) { outerEq = false; } }); return outerEq; } }; // Entry points from typeEquiv, based on `typeof` var entryTypeCallbacks = { undefined: useStrictEquality, null: useStrictEquality, boolean: useStrictEquality, number: function number(a, b) { // Handle NaN return a === b || isNaN(a) && isNaN(b); }, string: useStrictEquality, symbol: useStrictEquality, function: useStrictEquality, object: function object(a, b) { // Handle memory (skip recursion) if (memory.some(function (pair) { return pair.a === a && pair.b === b; })) { return true; } memory.push({ a: a, b: b }); var aObjType = objectType(a); var bObjType = objectType(b); if (aObjType !== 'object' || bObjType !== 'object') { // Handle literal `null` // Handle: Array, Map/Set, Date, Regxp/Function, boxed primitives return aObjType === bObjType && objTypeCallbacks[aObjType](a, b); } // NOTE: Literal null must not make it here as it would throw if (compareConstructors(a, b) === false) { return false; } var aProperties = []; var bProperties = []; // Be strict and go deep, no filtering with hasOwnProperty. for (var i in a) { // Collect a's properties aProperties.push(i); // Skip OOP methods that look the same if (a.constructor !== Object && typeof a.constructor !== 'undefined' && typeof a[i] === 'function' && typeof b[i] === 'function' && a[i].toString() === b[i].toString()) { continue; } if (!typeEquiv(a[i], b[i])) { return false; } } for (var _i in b) { // Collect b's properties bProperties.push(_i); } return objTypeCallbacks.array(aProperties.sort(), bProperties.sort()); } }; function typeEquiv(a, b) { // Optimization: Only perform type-specific comparison when pairs are not strictly equal. if (a === b) { return true; } var aType = _typeof(a); var bType = _typeof(b); if (aType !== bType) { // Support comparing primitive to boxed primitives // Try again after possibly unwrapping one return (aType === 'object' && BOXABLE_TYPES.has(objectType(a)) ? a.valueOf() : a) === (bType === 'object' && BOXABLE_TYPES.has(objectType(b)) ? b.valueOf() : b); } return entryTypeCallbacks[aType](a, b); } function innerEquiv(a, b) { var res = typeEquiv(a, b); // Release any retained objects and reset recursion detection for next call memory = []; return res; } /** * Test any two types of JavaScript values for equality. * * @author Philippe Rathé <prathe@gmail.com> * @author David Chan <david@troi.org> */ function equiv(a, b) { if (arguments.length === 2) { return a === b || innerEquiv(a, b); } // Given 0 or 1 arguments, just return true (nothing to compare). // Given (A,B,C,D) compare C,D then B,C then A,B. var i = arguments.length - 1; while (i > 0) { if (!innerEquiv(arguments[i - 1], arguments[i])) { return false; } i--; } return true; } /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ var config = { // HTML Reporter: Modify document.title when suite is done altertitle: true, // TODO: Move here from /src/core.js in QUnit 3. // autostart: true, // HTML Reporter: collapse every test except the first failing test // If false, all failing tests will be expanded collapse: true, countStepsAsOne: false, // TODO: Make explicit in QUnit 3. // current: undefined, // whether or not to fail when there are zero tests // defaults to `true` failOnZeroTests: true, // Select by pattern or case-insensitive substring match against "moduleName: testName" filter: undefined, // TODO: Make explicit in QUnit 3. // fixture: undefined, // Depth up-to which object will be dumped maxDepth: 5, // Select case-insensitive match of the module name module: undefined, // HTML Reporter: Select module/test by array of internal IDs moduleId: undefined, // By default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, reporters: {}, // When enabled, all tests must call expect() requireExpects: false, // By default, scroll to top of the page when suite is done scrolltop: true, // TODO: Make explicit in QUnit 3. // seed: undefined, // The storage module to use for reordering tests storage: localSessionStorage, testId: undefined, // The updateRate controls how often QUnit will yield the main thread // between tests. This is mainly for the benefit of the HTML Reporter, // so that the browser can visually paint DOM changes with test results. // This also helps avoid causing browsers to prompt a warning about // long-running scripts. // TODO: Move here from /src/core.js in QUnit 3. // updateRate: 1000, // HTML Reporter: List of URL parameters that are given visual controls urlConfig: [], // Internal: The first unnamed module // // By being defined as the intial value for currentModule, it is the // receptacle and implied parent for any global tests. It is as if we // called `QUnit.module( "" );` before any other tests were defined. // // If we reach begin() and no tests were put in it, we dequeue it as if it // never existed, and in that case never expose it to the events and // callbacks API. // // When global tests are defined, then this unnamed module will execute // as any other module, including moduleStart/moduleDone events etc. // // Since this module isn't explicitly created by the user, they have no // access to add hooks for it. The hooks object is defined to comply // with internal expectations of test.js, but they will be empty. // To apply hooks, place tests explicitly in a QUnit.module(), and use // its hooks accordingly. // // For global hooks that apply to all tests and all modules, use QUnit.hooks. // // NOTE: This is *not* a "global module". It is not an ancestor of all modules // and tests. It is merely the parent for any tests defined globally, // before the first QUnit.module(). As such, the events for this unnamed // module will fire as normal, right after its last test, and *not* at // the end of the test run. // // NOTE: This also should probably also not become a global module, unless // we keep it out of the public API. For example, it would likely not // improve the user interface and plugin behaviour if all modules became // wrapped between the start and end events of this module, and thus // needlessly add indentation, indirection, or other visible noise. // Unit tests for the callbacks API would detect that as a regression. currentModule: { name: '', tests: [], childModules: [], testsRun: 0, testsIgnored: 0, hooks: { before: [], beforeEach: [], afterEach: [], after: [] } }, // Internal: Exposed to make resets easier // Ref https://github.com/qunitjs/qunit/pull/1598 globalHooks: {}, // Internal: ProcessingQueue singleton, created in /src/core.js pq: null, // Internal: Created in /src/core.js // TODO: Move definitions here in QUnit 3.0. // started: 0, // Internal state _event_listeners: Object.create(null), _event_memory: {}, _deprecated_timeout_shown: false, _deprecated_countEachStep_shown: false, blocking: true, callbacks: {}, modules: [], queue: [], stats: { all: 0, bad: 0, testCount: 0 } }; function readFlatPreconfigBoolean(val, dest) { if (typeof val === 'boolean' || typeof val === 'string' && val !== '') { config[dest] = val === true || val === 'true'; } } function readFlatPreconfigNumber(val, dest) { if (typeof val === 'number' || typeof val === 'string' && /^[0-9]+$/.test(val)) { config[dest] = +val; } } function readFlatPreconfigString(val, dest) { if (typeof val === 'string' && val !== '') { config[dest] = val; } } function readFlatPreconfigStringOrBoolean(val, dest) { if (typeof val === 'boolean' || typeof val === 'string' && val !== '') { config[dest] = val; } } function readFlatPreconfigStringArray(val, dest) { if (typeof val === 'string' && val !== '') { config[dest] = [val]; } } function readFlatPreconfig(obj) { readFlatPreconfigBoolean(obj.qunit_config_altertitle, 'altertitle'); readFlatPreconfigBoolean(obj.qunit_config_autostart, 'autostart'); readFlatPreconfigBoolean(obj.qunit_config_collapse, 'collapse'); readFlatPreconfigBoolean(obj.qunit_config_failonzerotests, 'failOnZeroTests'); readFlatPreconfigString(obj.qunit_config_filter, 'filter'); readFlatPreconfigString(obj.qunit_config_fixture, 'fixture'); readFlatPreconfigBoolean(obj.qunit_config_hidepassed, 'hidepassed'); readFlatPreconfigNumber(obj.qunit_config_maxdepth, 'maxDepth'); readFlatPreconfigString(obj.qunit_config_module, 'module'); readFlatPreconfigStringArray(obj.qunit_config_moduleid, 'moduleId'); readFlatPreconfigBoolean(obj.qunit_config_noglobals, 'noglobals'); readFlatPreconfigBoolean(obj.qunit_config_notrycatch, 'notrycatch'); readFlatPreconfigBoolean(obj.qunit_config_reorder, 'reorder'); readFlatPreconfigBoolean(obj.qunit_config_requireexpects, 'requireExpects'); readFlatPreconfigBoolean(obj.qunit_config_scrolltop, 'scrolltop'); readFlatPreconfigStringOrBoolean(obj.qunit_config_seed, 'seed'); readFlatPreconfigStringArray(obj.qunit_config_testid, 'testId'); readFlatPreconfigNumber(obj.qunit_config_testtimeout, 'testTimeout'); var reporterKeys = { qunit_config_reporters_console: 'console', qunit_config_reporters_tap: 'tap' }; for (var key in reporterKeys) { var val = obj[key]; // Based on readFlatPreconfigBoolean if (typeof val === 'boolean' || typeof val === 'string' && val !== '') { var dest = reporterKeys[key]; config.reporters[dest] = val === true || val === 'true' || val === '1'; } } } if (process$1 && 'env' in process$1) { readFlatPreconfig(process$1.env); } readFlatPreconfig(g); // Apply a predefined QUnit.config object // // Ignore QUnit.config if it is a QUnit distribution instead of preconfig. // That means QUnit was loaded twice! (Use the same approach as export.js) var preConfig = g && g.QUnit && !g.QUnit.version && g.QUnit.config; if (preConfig) { extend(config, preConfig); } // Push a loose unnamed module to the modules collection config.modules.push(config.currentModule); if (config.seed === 'true' || config.seed === true) { // Generate a random seed // Length of `Math.random()` fraction, in base 36, may vary from 6-14. // Pad and take slice to a consistent 10-digit value. config.seed = (Math.random().toString(36) + '0000000000').slice(2, 12); } var dump = (function () { function quote(str) { return '"' + str.toString().replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'; } function literal(o) { return o + ''; } function join(pre, arr, post) { var s = dump.separator(); var inner = dump.indent(1); if (arr.join) { arr = arr.join(',' + s + inner); } if (!arr) { return pre + post; } var base = dump.indent(); return [pre, inner + arr, base + post].join(s); } function array(arr, stack) { if (dump.maxDepth && dump.depth > dump.maxDepth) { return '[object Array]'; } this.up(); var i = arr.length; var ret = new Array(i); while (i--) { ret[i] = this.parse(arr[i], undefined, stack); } this.down(); return join('[', ret, ']'); } function isArray(obj) { return ( // Native Arrays toString.call(obj) === '[object Array]' || // NodeList objects typeof obj.length === 'number' && obj.item !== undefined && (obj.length ? obj.item(0) === obj[0] : obj.item(0) === null && obj[0] === undefined) ); } var reName = /^function (\w+)/; var dump = { // The objType is used mostly internally, you can fix a (custom) type in advance parse: function parse(obj, objType, stack) { stack = stack || []; var objIndex = stack.indexOf(obj); if (objIndex !== -1) { return "recursion(".concat(objIndex - stack.length, ")"); } objType = objType || this.typeOf(obj); var parser = this.parsers[objType]; var parserType = _typeof(parser); if (parserType === 'function') { stack.push(obj); var res = parser.call(this, obj, stack); stack.pop(); return res; } if (parserType === 'string') { return parser; } return '[ERROR: Missing QUnit.dump formatter for type ' + objType + ']'; }, typeOf: function typeOf(obj) { var type; if (obj === null) { type = 'null'; } else if (typeof obj === 'undefined') { type = 'undefined'; } else if (is('regexp', obj)) { type = 'regexp'; } else if (is('date', obj)) { type = 'date'; } else if (is('function', obj)) { type = 'function'; } else if (obj.setInterval !== undefined && obj.document !== undefined && obj.nodeType === undefined) { type = 'window'; } else if (obj.nodeType === 9) { type = 'document'; } else if (obj.nodeType) { type = 'node'; } else if (isArray(obj)) { type = 'array'; } else if (obj.constructor === Error.prototype.constructor) { type = 'error'; } else { type = _typeof(obj); } return type; }, separator: function separator() { if (this.multiline) { return this.HTML ? '<br />' : '\n'; } else { return this.HTML ? '&#160;' : ' '; } }, // Extra can be a number, shortcut for increasing-calling-decreasing indent: function indent(extra) { if (!this.multiline) { return ''; } var chr = this.indentChar; if (this.HTML) { chr = chr.replace(/\t/g, ' ').replace(/ /g, '&#160;'); } return new Array(this.depth + (extra || 0)).join(chr); }, up: function up(a) { this.depth += a || 1; }, down: function down(a) { this.depth -= a || 1; }, setParser: function setParser(name, parser) { this.parsers[name] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, depth: 1, maxDepth: config.maxDepth, // This is the list of parsers, to modify them, use dump.setParser parsers: { window: '[Window]', document: '[Document]', error: function error(_error) { return 'Error("' + _error.message + '")'; }, // This has been unused since QUnit 1.0.0. // @todo Deprecate and remove. unknown: '[Unknown]', null: 'null', undefined: 'undefined', function: function _function(fn) { var ret = 'function'; // Functions never have name in IE var name = 'name' in fn ? fn.name : (reName.exec(fn) || [])[1]; if (name) { ret += ' ' + name; } ret += '('; ret = [ret, dump.parse(fn, 'functionArgs'), '){'].join(''); return join(ret, dump.parse(fn, 'functionCode'), '}'); }, array: array, nodelist: array, arguments: array, object: function object(map, stack) { var ret = []; if (dump.maxDepth && dump.depth > dump.maxDepth) { return '[object Object]'; } dump.up(); var keys = []; for (var key in map) { keys.push(key); } // Some properties are not always enumerable on Error objects. var nonEnumerableProperties = ['message', 'name']; for (var i in nonEnumerableProperties) { var _key = nonEnumerableProperties[i]; if (_key in map && !inArray(_key, keys)) { keys.push(_key); } } keys.sort(); for (var _i = 0; _i < keys.length; _i++) { var _key2 = keys[_i]; var val = map[_key2]; ret.push(dump.parse(_key2, 'key') + ': ' + dump.parse(val, undefined, stack)); } dump.down(); return join('{', ret, '}'); }, node: function node(_node) { var open = dump.HTML ? '&lt;' : '<'; var close = dump.HTML ? '&gt;' : '>'; var tag = _node.nodeName.toLowerCase(); var ret = open + tag; var attrs = _node.attributes; if (attrs) { for (var i = 0; i < attrs.length; i++) { var val = attrs[i].nodeValue; // IE6 includes all attributes in .attributes, even ones not explicitly // set. Those have values like undefined, null, 0, false, "" or // "inherit". if (val && val !== 'inherit') { ret += ' ' + attrs[i].nodeName + '=' + dump.parse(val, 'attribute'); } } } ret += close; // Show content of TextNode or CDATASection if (_node.nodeType === 3 || _node.nodeType === 4) { ret += _node.nodeValue; } return ret + open + '/' + tag + close; }, // Function calls it internally, it's the arguments part of the function functionArgs: function functionArgs(fn) { var l = fn.length; if (!l) { return ''; } var args = new Array(l); while (l--) { // 97 is 'a' args[l] = String.fromCharCode(97 + l); } return ' ' + args.join(', ') + ' '; }, // Object calls it internally, the key part of an item in a map key: quote, // Function calls it internally, it's the content of the function functionCode: '[code]', // Node calls it internally, it's a html attribute value attribute: quote, string: quote, date: quote, regexp: literal, number: literal, boolean: literal, symbol: function symbol(sym) { return sym.toString(); } }, // If true, entities are escaped ( <, >, \t, space and \n ) HTML: false, // Indentation unit indentChar: ' ', // If true, items in a collection, are separated by a \n, else just a space. multiline: true }; return dump; })(); // Support: IE 9 // Detect if the console object exists and no-op otherwise. // This allows support for IE 9, which doesn't have a console // object if the developer tools are not open. // Support: IE 9 // Function#bind is supported, but no console.log.bind(). // Support: SpiderMonkey (mozjs 68+) // The console object has a log method, but no warn method. var Logger = { warn: console$1 ? Function.prototype.bind.call(console$1.warn || console$1.log, console$1) : function () {} }; var SuiteReport = /*#__PURE__*/function () { function SuiteReport(name, parentSuite) { _classCallCheck(this, SuiteReport); this.name = name; this.fullName = parentSuite ? parentSuite.fullName.concat(name) : []; // When an "error" event is emitted from onUncaughtException(), the // "runEnd" event should report the status as failed. The "runEnd" event data // is tracked through this property (via the "runSuite" instance). this.globalFailureCount = 0; this.tests = []; this.childSuites = []; if (parentSuite) { parentSuite.pushChildSuite(this); } } return _createClass(SuiteReport, [{ key: "start", value: function start(recordTime) { if (recordTime) { this._startTime = performance.now(); } return { name: this.name, fullName: this.fullName.slice(), tests: this.tests.map(function (test) { return test.start(); }), childSuites: this.childSuites.map(function (suite) { return suite.start(); }), testCounts: { total: this.getTestCounts().total } }; } }, { key: "end", value: function end(recordTime) { if (recordTime) { this._endTime = performance.now(); } return { name: this.name, fullName: this.fullName.slice(), tests: this.tests.map(function (test) { return test.end(); }), childSuites: this.childSuites.map(function (suite) { return suite.end(); }), testCounts: this.getTestCounts(), runtime: this.getRuntime(), status: this.getStatus() }; } }, { key: "pushChildSuite", value: function pushChildSuite(suite) { this.childSuites.push(suite); } }, { key: "pushTest", value: function pushTest(test) { this.tests.push(test); } }, { key: "getRuntime", value: function getRuntime() { return Math.round(this._endTime - this._startTime); } }, { key: "getTestCounts", value: function getTestCounts() { var counts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 }; counts.failed += this.globalFailureCount; counts.total += this.globalFailureCount; counts = this.tests.reduce(function (counts, test) { if (test.valid) { counts[test.getStatus()]++; counts.total++; } return counts; }, counts); return this.childSuites.reduce(function (counts, suite) { return suite.getTestCounts(counts); }, counts); } }, { key: "getStatus", value: function getStatus() { var _this$getTestCounts = this.getTestCounts(), total = _this$getTestCounts.total, failed = _this$getTestCounts.failed, skipped = _this$getTestCounts.skipped, todo = _this$getTestCounts.todo; if (failed) { return 'failed'; } else { if (skipped === total) { return 'skipped'; } else if (todo === total) { return 'todo'; } else { return 'passed'; } } } }]); }(); var moduleStack = []; var runSuite = new SuiteReport(); function isParentModuleInQueue() { var modulesInQueue = config.modules.filter(function (module) { return !module.ignored; }).map(function (module) { return module.moduleId; }); return moduleStack.some(function (module) { return modulesInQueue.includes(module.moduleId); }); } function createModule(name, testEnvironment, modifiers) { var parentModule = moduleStack.length ? moduleStack.slice(-1)[0] : null; var moduleName = parentModule !== null ? [parentModule.name, name].join(' > ') : name; var parentSuite = parentModule ? parentModule.suiteReport : runSuite; var skip = parentModule !== null && parentModule.skip || modifiers.skip; var todo = parentModule !== null && parentModule.todo || modifiers.todo; var env = {}; if (parentModule) { extend(env, parentModule.testEnvironment); } extend(env, testEnvironment); var module = { name: moduleName, parentModule: parentModule, hooks: { before: [], beforeEach: [], afterEach: [], after: [] }, testEnvironment: env, tests: [], moduleId: generateHash(moduleName), testsRun: 0, testsIgnored: 0, childModules: [], suiteReport: new SuiteReport(name, parentSuite), // Initialised by test.js when the module start executing, // i.e. before the first test in this module (or a child). stats: null, // Pass along `skip` and `todo` properties from parent module, in case // there is one, to childs. And use own otherwise. // This property will be used to mark own tests and tests of child suites // as either `skipped` or `todo`. skip: skip, todo: skip ? false : todo, ignored: modifiers.ignored || false }; if (parentModule) { parentModule.childModules.push(module); } config.modules.push(module); return module; } function setHookFromEnvironment(hooks, environment, name) { var potentialHook = environment[name]; if (typeof potentialHook === 'function') { hooks[name].push(potentialHook); } delete environment[name]; } function makeSetHook(module, hookName) { return function setHook(callback) { if (config.currentModule !== module) { Logger.warn('The `' + hookName + '` hook was called inside the wrong module (`' + config.currentModule.name + '`). ' + 'Instead, use hooks provided by the callback to the containing module (`' + module.name + '`). ' + 'This will become an error in QUnit 3.0.'); } module.hooks[hookName].push(callback); }; } function processModule(name, options, scope) { var modifiers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; if (typeof options === 'function') { scope = options; options = undefined; } var module = createModule(name, options, modifiers); // Transfer any initial hooks from the options object to the 'hooks' object var testEnvironment = module.testEnvironment; var hooks = module.hooks; setHookFromEnvironment(hooks, testEnvironment, 'before'); setHookFromEnvironment(hooks, testEnvironment, 'beforeEach'); setHookFromEnvironment(hooks, testEnvironment, 'afterEach'); setHookFromEnvironment(hooks, testEnvironment, 'after'); var moduleFns = { before: makeSetHook(module, 'before'), beforeEach: makeSetHook(module, 'beforeEach'), afterEach: makeSetHook(module, 'afterEach'), after: makeSetHook(module, 'after') }; var prevModule = config.currentModule; config.currentModule = module; if (typeof scope === 'function') { moduleStack.push(module); try { var cbReturnValue = scope.call(module.testEnvironment, moduleFns); if (cbReturnValue && typeof cbReturnValue.then === 'function') { Logger.warn('Returning a promise from a module callback is not supported. ' + 'Instead, use hooks for async behavior. ' + 'This will become an error in QUnit 3.0.'); } } finally { // If the module closure threw an uncaught error during the load phase, // we let this bubble up to global error handlers. But, not until after // we teardown internal state to ensure correct module nesting. // Ref https://github.com/qunitjs/qunit/issues/1478. moduleStack.pop(); config.currentModule = module.parentModule || prevModule; } } } var focused$1 = false; // indicates that the "only" filter was used function module$1(name, options, scope) { var ignored = focused$1 && !isParentModuleInQueue(); processModule(name, options, scope, { ignored: ignored }); } module$1.only = function () { if (!focused$1) { // Upon the first module.only() call, // delete any and all previously registered modules and tests. config.modules.length = 0; config.queue.length = 0; // Ignore any tests declared after this block within the same // module parent. https://github.com/qunitjs/qunit/issues/1645 config.currentModule.ignored = true; } focused$1 = true; processModule.apply(void 0, arguments); }; module$1.skip = function (name, options, scope) { if (focused$1) { return; } processModule(name, options, scope, { skip: true }); }; module$1.if = function (name, condition, options, scope) { if (focused$1) { return; } processModule(name, options, scope, { skip: !condition }); }; module$1.todo = function (name, options, scope) { if (focused$1) { return; } processModule(name, options, scope, { todo: true }); }; // Stacktrace cleaner to focus on the path from error source to test suite. // // This should reduce a raw stack trace like this: // // > foo.broken()@/example/foo.js // > Bar@/example/bar.js // > @/test/bar.test.js // > @/lib/qunit.js:500:12 // > @/lib/qunit.js:100:28 // > @/lib/qunit.js:200:56 // > setTimeout@ // > @/dist/vendor.js // // and shorten it to show up until the end of the user's bar.test.js code. // // > foo.broken()@/example/foo.js // > Bar@/example/bar.js // > @/test/bar.test.js // // QUnit will obtain one example trace (once per process/pageload suffices), // strip off any :<line> and :<line>:<column>, and use that as match needle, // to the first QUnit-internal frames, and then stop at that point. // Any later frames, including those that are outside QUnit again, will be ommitted // as being uninteresting to the test, since QUnit will have either started or // resumed the test. This we also clean away browser built-ins, or other // vendor/bundler that may be higher up the stack. // // Stripping :<line>:<column> is not for prettyness, it is essential for the // match needle to work, since this sample trace will by definitin not be the // same line as e.g. the QUnit.test() call we're trying to identify. // // See also: // - https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function qunitFileName() { var error = new Error(); if (!error.stack) { // Copy of sourceFromStacktrace() to avoid circular dependency // Support: IE 9-11 try { throw error; } catch (e