UNPKG

p5.js-svg

Version:

The main goal of p5.SVG is to provide a SVG runtime for p5.js, so that we can draw using p5's powerful API in \<svg\>, save things to svg file and manipulating existing SVG file without rasterization.

1,651 lines (1,457 loc) 456 kB
(function () { 'use strict'; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn) { var module = { exports: {} }; return fn(module, module.exports), module.exports; } /*! * assertion-error * Copyright(c) 2013 Jake Luer <jake@qualiancy.com> * MIT Licensed */ /*! * Return a function that will copy properties from * one object to another excluding any originally * listed. Returned function will create a new `{}`. * * @param {String} excluded properties ... * @return {Function} */ function exclude () { var excludes = [].slice.call(arguments); function excludeProps (res, obj) { Object.keys(obj).forEach(function (key) { if (!~excludes.indexOf(key)) res[key] = obj[key]; }); } return function extendExclude () { var args = [].slice.call(arguments) , i = 0 , res = {}; for (; i < args.length; i++) { excludeProps(res, args[i]); } return res; }; } /*! * Primary Exports */ var assertionError = AssertionError; /** * ### AssertionError * * An extension of the JavaScript `Error` constructor for * assertion and validation scenarios. * * @param {String} message * @param {Object} properties to include (optional) * @param {callee} start stack function (optional) */ function AssertionError (message, _props, ssf) { var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') , props = extend(_props || {}); // default values this.message = message || 'Unspecified AssertionError'; this.showDiff = false; // copy from properties for (var key in props) { this[key] = props[key]; } // capture stack trace ssf = ssf || AssertionError; if (Error.captureStackTrace) { Error.captureStackTrace(this, ssf); } else { try { throw new Error(); } catch(e) { this.stack = e.stack; } } } /*! * Inherit from Error.prototype */ AssertionError.prototype = Object.create(Error.prototype); /*! * Statically set name */ AssertionError.prototype.name = 'AssertionError'; /*! * Ensure correct constructor */ AssertionError.prototype.constructor = AssertionError; /** * Allow errors to be converted to JSON for static transfer. * * @param {Boolean} include stack (default: `true`) * @return {Object} object that can be `JSON.stringify` */ AssertionError.prototype.toJSON = function (stack) { var extend = exclude('constructor', 'toJSON', 'stack') , props = extend({ name: this.name }, this); // include stack if exists and not turned off if (false !== stack && this.stack) { props.stack = this.stack; } return props; }; /* ! * Chai - pathval utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * @see https://github.com/logicalparadox/filtr * MIT Licensed */ /** * ### .hasProperty(object, name) * * This allows checking whether an object has own * or inherited from prototype chain named property. * * Basically does the same thing as the `in` * operator but works properly with null/undefined values * and other primitives. * * var obj = { * arr: ['a', 'b', 'c'] * , str: 'Hello' * } * * The following would be the results. * * hasProperty(obj, 'str'); // true * hasProperty(obj, 'constructor'); // true * hasProperty(obj, 'bar'); // false * * hasProperty(obj.str, 'length'); // true * hasProperty(obj.str, 1); // true * hasProperty(obj.str, 5); // false * * hasProperty(obj.arr, 'length'); // true * hasProperty(obj.arr, 2); // true * hasProperty(obj.arr, 3); // false * * @param {Object} object * @param {String|Symbol} name * @returns {Boolean} whether it exists * @namespace Utils * @name hasProperty * @api public */ function hasProperty$1(obj, name) { if (typeof obj === 'undefined' || obj === null) { return false; } // The `in` operator does not work with primitives. return name in Object(obj); } /* ! * ## parsePath(path) * * Helper function used to parse string object * paths. Use in conjunction with `internalGetPathValue`. * * var parsed = parsePath('myobject.property.subprop'); * * ### Paths: * * * Can be infinitely deep and nested. * * Arrays are also valid using the formal `myobject.document[3].property`. * * Literal dots and brackets (not delimiter) must be backslash-escaped. * * @param {String} path * @returns {Object} parsed * @api private */ function parsePath(path) { var str = path.replace(/([^\\])\[/g, '$1.['); var parts = str.match(/(\\\.|[^.]+?)+/g); return parts.map(function mapMatches(value) { if ( value === 'constructor' || value === '__proto__' || value === 'prototype' ) { return {}; } var regexp = /^\[(\d+)\]$/; var mArr = regexp.exec(value); var parsed = null; if (mArr) { parsed = { i: parseFloat(mArr[1]) }; } else { parsed = { p: value.replace(/\\([.[\]])/g, '$1') }; } return parsed; }); } /* ! * ## internalGetPathValue(obj, parsed[, pathDepth]) * * Helper companion function for `.parsePath` that returns * the value located at the parsed address. * * var value = getPathValue(obj, parsed); * * @param {Object} object to search against * @param {Object} parsed definition from `parsePath`. * @param {Number} depth (nesting level) of the property we want to retrieve * @returns {Object|Undefined} value * @api private */ function internalGetPathValue(obj, parsed, pathDepth) { var temporaryValue = obj; var res = null; pathDepth = typeof pathDepth === 'undefined' ? parsed.length : pathDepth; for (var i = 0; i < pathDepth; i++) { var part = parsed[i]; if (temporaryValue) { if (typeof part.p === 'undefined') { temporaryValue = temporaryValue[part.i]; } else { temporaryValue = temporaryValue[part.p]; } if (i === pathDepth - 1) { res = temporaryValue; } } } return res; } /* ! * ## internalSetPathValue(obj, value, parsed) * * Companion function for `parsePath` that sets * the value located at a parsed address. * * internalSetPathValue(obj, 'value', parsed); * * @param {Object} object to search and define on * @param {*} value to use upon set * @param {Object} parsed definition from `parsePath` * @api private */ function internalSetPathValue(obj, val, parsed) { var tempObj = obj; var pathDepth = parsed.length; var part = null; // Here we iterate through every part of the path for (var i = 0; i < pathDepth; i++) { var propName = null; var propVal = null; part = parsed[i]; // If it's the last part of the path, we set the 'propName' value with the property name if (i === pathDepth - 1) { propName = typeof part.p === 'undefined' ? part.i : part.p; // Now we set the property with the name held by 'propName' on object with the desired val tempObj[propName] = val; } else if (typeof part.p !== 'undefined' && tempObj[part.p]) { tempObj = tempObj[part.p]; } else if (typeof part.i !== 'undefined' && tempObj[part.i]) { tempObj = tempObj[part.i]; } else { // If the obj doesn't have the property we create one with that name to define it var next = parsed[i + 1]; // Here we set the name of the property which will be defined propName = typeof part.p === 'undefined' ? part.i : part.p; // Here we decide if this property will be an array or a new object propVal = typeof next.p === 'undefined' ? [] : {}; tempObj[propName] = propVal; tempObj = tempObj[propName]; } } } /** * ### .getPathInfo(object, path) * * This allows the retrieval of property info in an * object given a string path. * * The path info consists of an object with the * following properties: * * * parent - The parent object of the property referenced by `path` * * name - The name of the final property, a number if it was an array indexer * * value - The value of the property, if it exists, otherwise `undefined` * * exists - Whether the property exists or not * * @param {Object} object * @param {String} path * @returns {Object} info * @namespace Utils * @name getPathInfo * @api public */ function getPathInfo$1(obj, path) { var parsed = parsePath(path); var last = parsed[parsed.length - 1]; var info = { parent: parsed.length > 1 ? internalGetPathValue(obj, parsed, parsed.length - 1) : obj, name: last.p || last.i, value: internalGetPathValue(obj, parsed), }; info.exists = hasProperty$1(info.parent, info.name); return info; } /** * ### .getPathValue(object, path) * * This allows the retrieval of values in an * object given a string path. * * var obj = { * prop1: { * arr: ['a', 'b', 'c'] * , str: 'Hello' * } * , prop2: { * arr: [ { nested: 'Universe' } ] * , str: 'Hello again!' * } * } * * The following would be the results. * * getPathValue(obj, 'prop1.str'); // Hello * getPathValue(obj, 'prop1.att[2]'); // b * getPathValue(obj, 'prop2.arr[0].nested'); // Universe * * @param {Object} object * @param {String} path * @returns {Object} value or `undefined` * @namespace Utils * @name getPathValue * @api public */ function getPathValue(obj, path) { var info = getPathInfo$1(obj, path); return info.value; } /** * ### .setPathValue(object, path, value) * * Define the value in an object at a given string path. * * ```js * var obj = { * prop1: { * arr: ['a', 'b', 'c'] * , str: 'Hello' * } * , prop2: { * arr: [ { nested: 'Universe' } ] * , str: 'Hello again!' * } * }; * ``` * * The following would be acceptable. * * ```js * var properties = require('tea-properties'); * properties.set(obj, 'prop1.str', 'Hello Universe!'); * properties.set(obj, 'prop1.arr[2]', 'B'); * properties.set(obj, 'prop2.arr[0].nested.value', { hello: 'universe' }); * ``` * * @param {Object} object * @param {String} path * @param {Mixed} value * @api private */ function setPathValue(obj, path, val) { var parsed = parsePath(path); internalSetPathValue(obj, val, parsed); return obj; } var pathval = { hasProperty: hasProperty$1, getPathInfo: getPathInfo$1, getPathValue: getPathValue, setPathValue: setPathValue, }; /*! * Chai - flag utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .flag(object, key, [value]) * * Get or set a flag value on an object. If a * value is provided it will be set, else it will * return the currently set value or `undefined` if * the value is not set. * * utils.flag(this, 'foo', 'bar'); // setter * utils.flag(this, 'foo'); // getter, returns `bar` * * @param {Object} object constructed Assertion * @param {String} key * @param {Mixed} value (optional) * @namespace Utils * @name flag * @api private */ var flag$1 = function flag(obj, key, value) { var flags = obj.__flags || (obj.__flags = Object.create(null)); if (arguments.length === 3) { flags[key] = value; } else { return flags[key]; } }; /*! * Chai - test utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /*! * Module dependencies */ /** * ### .test(object, expression) * * Test and object for expression. * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments * @namespace Utils * @name test */ var test$2 = function test(obj, args) { var negate = flag$1(obj, 'negate') , expr = args[0]; return negate ? !expr : expr; }; var typeDetect = createCommonjsModule(function (module, exports) { (function (global, factory) { module.exports = factory() ; }(commonjsGlobal, (function () { /* ! * type-detect * Copyright(c) 2013 jake luer <jake@alogicalparadox.com> * MIT Licensed */ var promiseExists = typeof Promise === 'function'; /* eslint-disable no-undef */ var globalObject = typeof self === 'object' ? self : commonjsGlobal; // eslint-disable-line id-blacklist var symbolExists = typeof Symbol !== 'undefined'; var mapExists = typeof Map !== 'undefined'; var setExists = typeof Set !== 'undefined'; var weakMapExists = typeof WeakMap !== 'undefined'; var weakSetExists = typeof WeakSet !== 'undefined'; var dataViewExists = typeof DataView !== 'undefined'; var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined'; var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined'; var setEntriesExists = setExists && typeof Set.prototype.entries === 'function'; var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function'; var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries()); var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries()); var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function'; var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]()); var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function'; var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]()); var toStringLeftSliceLength = 8; var toStringRightSliceLength = -1; /** * ### typeOf (obj) * * Uses `Object.prototype.toString` to determine the type of an object, * normalising behaviour across engine versions & well optimised. * * @param {Mixed} object * @return {String} object type * @api public */ function typeDetect(obj) { /* ! Speed optimisation * Pre: * string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled) * boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled) * number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled) * undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled) * function x 2,556,769 ops/sec ±1.73% (77 runs sampled) * Post: * string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled) * boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled) * number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled) * undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled) * function x 31,296,870 ops/sec ±0.96% (83 runs sampled) */ var typeofObj = typeof obj; if (typeofObj !== 'object') { return typeofObj; } /* ! Speed optimisation * Pre: * null x 28,645,765 ops/sec ±1.17% (82 runs sampled) * Post: * null x 36,428,962 ops/sec ±1.37% (84 runs sampled) */ if (obj === null) { return 'null'; } /* ! Spec Conformance * Test: `Object.prototype.toString.call(window)`` * - Node === "[object global]" * - Chrome === "[object global]" * - Firefox === "[object Window]" * - PhantomJS === "[object Window]" * - Safari === "[object Window]" * - IE 11 === "[object Window]" * - IE Edge === "[object Window]" * Test: `Object.prototype.toString.call(this)`` * - Chrome Worker === "[object global]" * - Firefox Worker === "[object DedicatedWorkerGlobalScope]" * - Safari Worker === "[object DedicatedWorkerGlobalScope]" * - IE 11 Worker === "[object WorkerGlobalScope]" * - IE Edge Worker === "[object WorkerGlobalScope]" */ if (obj === globalObject) { return 'global'; } /* ! Speed optimisation * Pre: * array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled) * Post: * array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled) */ if ( Array.isArray(obj) && (symbolToStringTagExists === false || !(Symbol.toStringTag in obj)) ) { return 'Array'; } // Not caching existence of `window` and related properties due to potential // for `window` to be unset before tests in quasi-browser environments. if (typeof window === 'object' && window !== null) { /* ! Spec Conformance * (https://html.spec.whatwg.org/multipage/browsers.html#location) * WhatWG HTML$7.7.3 - The `Location` interface * Test: `Object.prototype.toString.call(window.location)`` * - IE <=11 === "[object Object]" * - IE Edge <=13 === "[object Object]" */ if (typeof window.location === 'object' && obj === window.location) { return 'Location'; } /* ! Spec Conformance * (https://html.spec.whatwg.org/#document) * WhatWG HTML$3.1.1 - The `Document` object * Note: Most browsers currently adher to the W3C DOM Level 2 spec * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268) * which suggests that browsers should use HTMLTableCellElement for * both TD and TH elements. WhatWG separates these. * WhatWG HTML states: * > For historical reasons, Window objects must also have a * > writable, configurable, non-enumerable property named * > HTMLDocument whose value is the Document interface object. * Test: `Object.prototype.toString.call(document)`` * - Chrome === "[object HTMLDocument]" * - Firefox === "[object HTMLDocument]" * - Safari === "[object HTMLDocument]" * - IE <=10 === "[object Document]" * - IE 11 === "[object HTMLDocument]" * - IE Edge <=13 === "[object HTMLDocument]" */ if (typeof window.document === 'object' && obj === window.document) { return 'Document'; } if (typeof window.navigator === 'object') { /* ! Spec Conformance * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray) * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray * Test: `Object.prototype.toString.call(navigator.mimeTypes)`` * - IE <=10 === "[object MSMimeTypesCollection]" */ if (typeof window.navigator.mimeTypes === 'object' && obj === window.navigator.mimeTypes) { return 'MimeTypeArray'; } /* ! Spec Conformance * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray) * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray * Test: `Object.prototype.toString.call(navigator.plugins)`` * - IE <=10 === "[object MSPluginsCollection]" */ if (typeof window.navigator.plugins === 'object' && obj === window.navigator.plugins) { return 'PluginArray'; } } if ((typeof window.HTMLElement === 'function' || typeof window.HTMLElement === 'object') && obj instanceof window.HTMLElement) { /* ! Spec Conformance * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray) * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement` * Test: `Object.prototype.toString.call(document.createElement('blockquote'))`` * - IE <=10 === "[object HTMLBlockElement]" */ if (obj.tagName === 'BLOCKQUOTE') { return 'HTMLQuoteElement'; } /* ! Spec Conformance * (https://html.spec.whatwg.org/#htmltabledatacellelement) * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement` * Note: Most browsers currently adher to the W3C DOM Level 2 spec * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075) * which suggests that browsers should use HTMLTableCellElement for * both TD and TH elements. WhatWG separates these. * Test: Object.prototype.toString.call(document.createElement('td')) * - Chrome === "[object HTMLTableCellElement]" * - Firefox === "[object HTMLTableCellElement]" * - Safari === "[object HTMLTableCellElement]" */ if (obj.tagName === 'TD') { return 'HTMLTableDataCellElement'; } /* ! Spec Conformance * (https://html.spec.whatwg.org/#htmltableheadercellelement) * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement` * Note: Most browsers currently adher to the W3C DOM Level 2 spec * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075) * which suggests that browsers should use HTMLTableCellElement for * both TD and TH elements. WhatWG separates these. * Test: Object.prototype.toString.call(document.createElement('th')) * - Chrome === "[object HTMLTableCellElement]" * - Firefox === "[object HTMLTableCellElement]" * - Safari === "[object HTMLTableCellElement]" */ if (obj.tagName === 'TH') { return 'HTMLTableHeaderCellElement'; } } } /* ! Speed optimisation * Pre: * Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled) * Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled) * Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled) * Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled) * Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled) * Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled) * Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled) * Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled) * Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled) * Post: * Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled) * Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled) * Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled) * Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled) * Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled) * Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled) * Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled) * Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled) * Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled) */ var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]); if (typeof stringTag === 'string') { return stringTag; } var objPrototype = Object.getPrototypeOf(obj); /* ! Speed optimisation * Pre: * regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled) * regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled) * Post: * regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled) * regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled) */ if (objPrototype === RegExp.prototype) { return 'RegExp'; } /* ! Speed optimisation * Pre: * date x 2,130,074 ops/sec ±4.42% (68 runs sampled) * Post: * date x 3,953,779 ops/sec ±1.35% (77 runs sampled) */ if (objPrototype === Date.prototype) { return 'Date'; } /* ! Spec Conformance * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag) * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise": * Test: `Object.prototype.toString.call(Promise.resolve())`` * - Chrome <=47 === "[object Object]" * - Edge <=20 === "[object Object]" * - Firefox 29-Latest === "[object Promise]" * - Safari 7.1-Latest === "[object Promise]" */ if (promiseExists && objPrototype === Promise.prototype) { return 'Promise'; } /* ! Speed optimisation * Pre: * set x 2,222,186 ops/sec ±1.31% (82 runs sampled) * Post: * set x 4,545,879 ops/sec ±1.13% (83 runs sampled) */ if (setExists && objPrototype === Set.prototype) { return 'Set'; } /* ! Speed optimisation * Pre: * map x 2,396,842 ops/sec ±1.59% (81 runs sampled) * Post: * map x 4,183,945 ops/sec ±6.59% (82 runs sampled) */ if (mapExists && objPrototype === Map.prototype) { return 'Map'; } /* ! Speed optimisation * Pre: * weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled) * Post: * weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled) */ if (weakSetExists && objPrototype === WeakSet.prototype) { return 'WeakSet'; } /* ! Speed optimisation * Pre: * weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled) * Post: * weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled) */ if (weakMapExists && objPrototype === WeakMap.prototype) { return 'WeakMap'; } /* ! Spec Conformance * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag) * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView": * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))`` * - Edge <=13 === "[object Object]" */ if (dataViewExists && objPrototype === DataView.prototype) { return 'DataView'; } /* ! Spec Conformance * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag) * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator": * Test: `Object.prototype.toString.call(new Map().entries())`` * - Edge <=13 === "[object Object]" */ if (mapExists && objPrototype === mapIteratorPrototype) { return 'Map Iterator'; } /* ! Spec Conformance * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag) * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator": * Test: `Object.prototype.toString.call(new Set().entries())`` * - Edge <=13 === "[object Object]" */ if (setExists && objPrototype === setIteratorPrototype) { return 'Set Iterator'; } /* ! Spec Conformance * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag) * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator": * Test: `Object.prototype.toString.call([][Symbol.iterator]())`` * - Edge <=13 === "[object Object]" */ if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) { return 'Array Iterator'; } /* ! Spec Conformance * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag) * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator": * Test: `Object.prototype.toString.call(''[Symbol.iterator]())`` * - Edge <=13 === "[object Object]" */ if (stringIteratorExists && objPrototype === stringIteratorPrototype) { return 'String Iterator'; } /* ! Speed optimisation * Pre: * object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled) * Post: * object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled) */ if (objPrototype === null) { return 'Object'; } return Object .prototype .toString .call(obj) .slice(toStringLeftSliceLength, toStringRightSliceLength); } return typeDetect; }))); }); /*! * Chai - expectTypes utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .expectTypes(obj, types) * * Ensures that the object being tested against is of a valid type. * * utils.expectTypes(this, ['array', 'object', 'string']); * * @param {Mixed} obj constructed Assertion * @param {Array} type A list of allowed types for this assertion * @namespace Utils * @name expectTypes * @api public */ var expectTypes$1 = function expectTypes(obj, types) { var flagMsg = flag$1(obj, 'message'); var ssfi = flag$1(obj, 'ssfi'); flagMsg = flagMsg ? flagMsg + ': ' : ''; obj = flag$1(obj, 'object'); types = types.map(function (t) { return t.toLowerCase(); }); types.sort(); // Transforms ['lorem', 'ipsum'] into 'a lorem, or an ipsum' var str = types.map(function (t, index) { var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a'; var or = types.length > 1 && index === types.length - 1 ? 'or ' : ''; return or + art + ' ' + t; }).join(', '); var objType = typeDetect(obj).toLowerCase(); if (!types.some(function (expected) { return objType === expected; })) { throw new assertionError( flagMsg + 'object tested must be ' + str + ', but ' + objType + ' given', undefined, ssfi ); } }; /*! * Chai - getActual utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .getActual(object, [actual]) * * Returns the `actual` value for an Assertion. * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments * @namespace Utils * @name getActual */ var getActual$1 = function getActual(obj, args) { return args.length > 4 ? args[4] : obj._obj; }; /* ! * Chai - getFuncName utility * Copyright(c) 2012-2016 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .getFuncName(constructorFn) * * Returns the name of a function. * When a non-function instance is passed, returns `null`. * This also includes a polyfill function if `aFunc.name` is not defined. * * @name getFuncName * @param {Function} funct * @namespace Utils * @api public */ var toString$1 = Function.prototype.toString; var functionNameMatch$1 = /\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\s\(\/]+)/; function getFuncName(aFunc) { if (typeof aFunc !== 'function') { return null; } var name = ''; if (typeof Function.prototype.name === 'undefined' && typeof aFunc.name === 'undefined') { // Here we run a polyfill if Function does not support the `name` property and if aFunc.name is not defined var match = toString$1.call(aFunc).match(functionNameMatch$1); if (match) { name = match[1]; } } else { // If we've got a `name` property we just use it name = aFunc.name; } return name; } var getFuncName_1 = getFuncName; /*! * Chai - getProperties utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .getProperties(object) * * This allows the retrieval of property names of an object, enumerable or not, * inherited or not. * * @param {Object} object * @returns {Array} * @namespace Utils * @name getProperties * @api public */ var getProperties = function getProperties(object) { var result = Object.getOwnPropertyNames(object); function addProperty(property) { if (result.indexOf(property) === -1) { result.push(property); } } var proto = Object.getPrototypeOf(object); while (proto !== null) { Object.getOwnPropertyNames(proto).forEach(addProperty); proto = Object.getPrototypeOf(proto); } return result; }; /*! * Chai - getEnumerableProperties utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .getEnumerableProperties(object) * * This allows the retrieval of enumerable property names of an object, * inherited or not. * * @param {Object} object * @returns {Array} * @namespace Utils * @name getEnumerableProperties * @api public */ var getEnumerableProperties = function getEnumerableProperties(object) { var result = []; for (var name in object) { result.push(name); } return result; }; var config$1 = { /** * ### config.includeStack * * User configurable property, influences whether stack trace * is included in Assertion error message. Default of false * suppresses stack trace in the error message. * * chai.config.includeStack = true; // enable stack on error * * @param {Boolean} * @api public */ includeStack: false, /** * ### config.showDiff * * User configurable property, influences whether or not * the `showDiff` flag should be included in the thrown * AssertionErrors. `false` will always be `false`; `true` * will be true when the assertion has requested a diff * be shown. * * @param {Boolean} * @api public */ showDiff: true, /** * ### config.truncateThreshold * * User configurable property, sets length threshold for actual and * expected values in assertion errors. If this threshold is exceeded, for * example for large data structures, the value is replaced with something * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. * * Set it to zero if you want to disable truncating altogether. * * This is especially userful when doing assertions on arrays: having this * set to a reasonable large value makes the failure messages readily * inspectable. * * chai.config.truncateThreshold = 0; // disable truncating * * @param {Number} * @api public */ truncateThreshold: 40, /** * ### config.useProxy * * User configurable property, defines if chai will use a Proxy to throw * an error when a non-existent property is read, which protects users * from typos when using property-based assertions. * * Set it to false if you want to disable this feature. * * chai.config.useProxy = false; // disable use of Proxy * * This feature is automatically disabled regardless of this config value * in environments that don't support proxies. * * @param {Boolean} * @api public */ useProxy: true, /** * ### config.proxyExcludedKeys * * User configurable property, defines which properties should be ignored * instead of throwing an error if they do not exist on the assertion. * This is only applied if the environment Chai is running in supports proxies and * if the `useProxy` configuration setting is enabled. * By default, `then` and `inspect` will not throw an error if they do not exist on the * assertion object because the `.inspect` property is read by `util.inspect` (for example, when * using `console.log` on the assertion object) and `.then` is necessary for promise type-checking. * * // By default these keys will not throw an error if they do not exist on the assertion object * chai.config.proxyExcludedKeys = ['then', 'inspect']; * * @param {Array} * @api public */ proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON'] }; var inspect_1 = createCommonjsModule(function (module, exports) { // This is (almost) directly from Node.js utils // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js module.exports = inspect; /** * ### .inspect(obj, [showHidden], [depth], [colors]) * * Echoes the value of a value. Tries to print the value out * in the best way possible given the different types. * * @param {Object} obj The object to print out. * @param {Boolean} showHidden Flag that shows hidden (not enumerable) * properties of objects. Default is false. * @param {Number} depth Depth in which to descend in object. Default is 2. * @param {Boolean} colors Flag to turn on ANSI escape codes to color the * output. Default is false (no coloring). * @namespace Utils * @name inspect */ function inspect(obj, showHidden, depth, colors) { var ctx = { showHidden: showHidden, seen: [], stylize: function (str) { return str; } }; return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); } // Returns true if object is a DOM element. var isDOMElement = function (object) { if (typeof HTMLElement === 'object') { return object instanceof HTMLElement; } else { return object && typeof object === 'object' && 'nodeType' in object && object.nodeType === 1 && typeof object.nodeName === 'string'; } }; 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 (value && typeof value.inspect === 'function' && // 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 (typeof ret !== 'string') { ret = formatValue(ctx, ret, recurseTimes); } return ret; } // Primitive types cannot have properties var primitive = formatPrimitive(ctx, value); if (primitive) { return primitive; } // If this is a DOM element, try to get the outer HTML. if (isDOMElement(value)) { if ('outerHTML' in value) { return value.outerHTML; // This value does not have an outerHTML attribute, // it could still be an XML element } else { // Attempt to serialize it try { if (document.xmlVersion) { var xmlSerializer = new XMLSerializer(); return xmlSerializer.serializeToString(value); } else { // Firefox 11- do not support outerHTML // It does, however, support innerHTML // Use the following to render the element var ns = "http://www.w3.org/1999/xhtml"; var container = document.createElementNS(ns, '_'); container.appendChild(value.cloneNode(false)); var html = container.innerHTML .replace('><', '>' + value.innerHTML + '<'); container.innerHTML = ''; return html; } } catch (err) { // This could be a non-native DOM implementation, // continue with the normal flow: // printing the element as if it is an object. } } } // Look up the keys of the object. var visibleKeys = getEnumerableProperties(value); var keys = ctx.showHidden ? getProperties(value) : visibleKeys; var name, nameSuffix; // Some type of object without properties can be shortcut. // In IE, errors have a single `stack` property, or if they are vanilla `Error`, // a `stack` plus `description` property; ignore those for consistency. if (keys.length === 0 || (isError(value) && ( (keys.length === 1 && keys[0] === 'stack') || (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') ))) { if (typeof value === 'function') { name = getFuncName_1(value); nameSuffix = name ? ': ' + name : ''; return ctx.stylize('[Function' + nameSuffix + ']', 'special'); } if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } if (isDate(value)) { return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); } if (isError(value)) { return formatError(value); } } var base = '' , array = false , typedArray = false , braces = ['{', '}']; if (isTypedArray(value)) { typedArray = true; braces = ['[', ']']; } // Make Array say that they are Array if (isArray(value)) { array = true; braces = ['[', ']']; } // Make functions say that they are functions if (typeof value === 'function') { name = getFuncName_1(value); nameSuffix = name ? ': ' + name : ''; base = ' [Function' + nameSuffix + ']'; } // 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)) { return 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 if (typedArray) { return formatTypedArray(value); } 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) { switch (typeof value) { case 'undefined': return ctx.stylize('undefined', 'undefined'); case 'string': var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') .replace(/'/g, "\\'") .replace(/\\"/g, '"') + '\''; return ctx.stylize(simple, 'string'); case 'number': if (value === 0 && (1/value) === -Infinity) { return ctx.stylize('-0', 'number'); } return ctx.stylize('' + value, 'number'); case 'boolean': return ctx.stylize('' + value, 'boolean'); case 'symbol': return ctx.stylize(value.toString(), 'symbol'); case 'bigint': return ctx.stylize(value.toString() + 'n', 'bigint'); } // For some reason typeof null is "object", so special case here. if (value === null) { 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 (Object.prototype.hasOwnProperty.call(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 formatTypedArray(value) { var str = '[ '; for (var i = 0; i < value.length; ++i) { if (str.length >= config$1.truncateThreshold - 7) { str += '...'; break; } str += value[i] + ', '; } str += ' ]'; // Removing trailing `, ` if the array was not truncated if (str.indexOf(', ]') !== -1) { str = str.replace(', ]', ' ]'); } return str; } function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { var name; var propDescriptor = Object.getOwnPropertyDescriptor(value, key); var str; if (propDescriptor) { if (propDescriptor.get) { if (propDescriptor.set) { str = ctx.stylize('[Getter/Setter]', 'special'); } else { str = ctx.stylize('[Getter]', 'special'); } } else { if (propDescriptor.set) { str = ctx.stylize('[Setter]', 'special'); } } } if (visibleKeys.indexOf(key) < 0) { name = '[' + key + ']'; } if (!str) { if (ctx.seen.indexOf(value[key]) < 0) { if (recurseTimes === null) { str = formatValue(ctx, value[key], null); } else { str = formatValue(ctx, value[key], 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 (typeof name === 'undefined') { 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 length = output.reduce(function(prev, cur) { return prev + cur.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]; } function isTypedArray(ar) { // Unfortunately there's no way to check if an object is a TypedArray // We have to check if it's one of these types return (typeof ar === 'object' && /\w+Array]$/.test(objectToString(ar))); } function isArray(ar) { return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]'); } function isRegExp(re) { return typeof re === 'object' && objectToString(re) === '[object RegExp]'; } function isDate(d) { return typeof d === 'object' && objectToString(d) === '[object Date]'; } function isError(e) { return typeof e === 'object' && objectToString(e) === '[object Error]'; } function objectToString(o) { return Object.prototype.toString.call(o); } }); /*! * Chai - flag utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /*! * Module dependencies */ /** * ### .objDisplay(object) * * Determines if an object or an array matches * criteria to be inspected in-line for error * messages or should be truncated. * * @param {Mixed} javascript object to inspect * @name objDisplay * @namespace Utils * @api public */ var objDisplay$1 = function objDisplay(obj) { var str = inspect_1(obj) , type = Object.prototype.toString.call(obj); if (config$1.truncateThreshold && str.length >= config$1.truncateThreshold) { if (type === '[object Function]') { return !obj.name || obj.name === '' ? '[Function]' : '[Function: ' + obj.name + ']'; } else if (type === '[object Array]') { return '[ Array(' + obj.length + ') ]'; } else if (type === '[object Object]') { var keys = Object.keys(obj) , kstr = keys.length > 2 ? keys.splice(0, 2).join(', ') + ', ...' : keys.join(', '); return '{ Object (' + kstr + ') }'; } else { return str; } } else { return str; } }; /*! * Chai - message composition utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /*! * Module dependencies */ /** * ### .getMessage(object, message, negateMessage) * * Construct the error message based on flags * and template tags. Template tags will return * a stringified inspection of the object referenced. * * Message template tags: * - `#{this}` current asserted object * - `#{act}` actual value * - `#{exp}` expected value * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments * @namespace Utils * @name getMessage * @api public */ var getMessage$2 = function getMessage(obj, args) { var negate = flag$1(obj, 'negate') , val = flag$1(obj, 'object') , expected = args[3] , actual = getActual$1(obj, args) , msg = negate ? args[2] : args[1] , flagMsg = flag$1(obj, 'message'); if(typeof msg === "function") msg = msg(); msg = msg || ''; msg = msg .replace(/#\{this\}/g, function () { return objDisplay$1(val); }) .replace(/#\{act\}/g, function () { return objDisplay$1(actual); }) .replace(/#\{exp\}/g, function () { return objDisplay$1(expected); }); return flagMsg ? flagMsg + ': ' + msg : msg; }; /*! * Chai - transferFlags utility * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ### .transferFlags(assertion, object, includeAll = true) * * Transfer all the flags for `assertion` to `object`. If * `includeAll` is set to `false`, then the base Chai * assertion flags (namely `object`, `ssfi`, `lockSsfi`, * and `message`) will not be transferred. * * * var newAssertion = new Assertion(); * utils.transferFlags(assertion, newAssertion); * * var anotherAssertion = new Assertion(myObj); * utils.transferFlags(assertion, anotherAssertion, false); * * @param {Assertion} assertion the assertion to transfer the flags from * @param {Object} object the object to transfer the flags to; usually a ne