From 1e1e83e605206e39b0fd8b93d7761d6086418c19 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 15 Jul 2019 16:59:35 +0900 Subject: [PATCH 001/207] Reformat license text. --- LICENSE.txt | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index e1b2c83..d6a9d74 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,20 +2,19 @@ MIT License Copyright © 2011 Sebastian Tschan, https://blueimp.net -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: +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. +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. From 54985716a5568c86ccd66bb0ac779f64e8fa8e24 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 15 Jul 2019 17:01:14 +0900 Subject: [PATCH 002/207] Format markdown using prettier. --- README.md | 324 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 171 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 61d08d4..0b05115 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # JavaScript Load Image + > A JavaScript library to load and transform image files. -## Table of contents +## Contents - [Demo](#demo) - [Description](#description) @@ -19,9 +20,11 @@ - [Credits](#credits) ## Demo + [JavaScript Load Image Demo](https://blueimp.github.io/JavaScript-Load-Image/) ## Description + JavaScript Load Image is a library to load images provided as File or Blob objects or via URL. It returns an optionally scaled and/or cropped HTML img or canvas element. It also provides methods to parse image meta data to extract @@ -29,6 +32,7 @@ IPTC and Exif tags as well as embedded thumbnail images and to restore the complete image header after resizing. ## Setup + Include the (combined and minified) JavaScript Load Image script in your HTML markup: @@ -56,38 +60,42 @@ Or alternatively, choose which components you want to include: ## Usage ### Image loading + In your application code, use the **loadImage()** function like this: ```js -document.getElementById('file-input').onchange = function (e) { - loadImage( - e.target.files[0], - function (img) { - document.body.appendChild(img); - }, - {maxWidth: 600} // Options - ); +document.getElementById("file-input").onchange = function(e) { + loadImage( + e.target.files[0], + function(img) { + document.body.appendChild(img); + }, + { maxWidth: 600 } // Options + ); }; ``` ### Image scaling + It is also possible to use the image scaling functionality with an existing image: ```js var scaledImage = loadImage.scale( - img, // img or canvas element - {maxWidth: 600} + img, // img or canvas element + { maxWidth: 600 } ); ``` ## Requirements + The JavaScript Load Image library has zero dependencies. However, JavaScript Load Image is a very suitable complement to the [Canvas to Blob](https://github.com/blueimp/JavaScript-Canvas-to-Blob) library. ## API + The **loadImage()** function accepts a [File](https://developer.mozilla.org/en/DOM/File) or [Blob](https://developer.mozilla.org/en/DOM/Blob) object or a simple image URL @@ -104,17 +112,17 @@ It always returns a HTML passing an image URL: ```js -document.getElementById('file-input').onchange = function (e) { - var loadingImage = loadImage( - e.target.files[0], - function (img) { - document.body.appendChild(img); - }, - {maxWidth: 600} - ); - if (!loadingImage) { - // Alternative code ... - } +document.getElementById("file-input").onchange = function(e) { + var loadingImage = loadImage( + e.target.files[0], + function(img) { + document.body.appendChild(img); + }, + { maxWidth: 600 } + ); + if (!loadingImage) { + // Alternative code ... + } }; ``` @@ -124,15 +132,15 @@ the **loadImage()** function allows to abort the loading process by setting the **onload** and **onerror** event handlers to null: ```js -document.getElementById('file-input').onchange = function (e) { - var loadingImage = loadImage( - e.target.files[0], - function (img) { - document.body.appendChild(img); - }, - {maxWidth: 600} - ); - loadingImage.onload = loadingImage.onerror = null; +document.getElementById("file-input").onchange = function(e) { + var loadingImage = loadImage( + e.target.files[0], + function(img) { + document.body.appendChild(img); + }, + { maxWidth: 600 } + ); + loadingImage.onload = loadingImage.onerror = null; }; ``` @@ -148,99 +156,102 @@ potentially additional [meta data](#meta-data-parsing): ```js var imageUrl = "https://example.org/image.png"; loadImage( - imageUrl, - function (img, data) { - if(img.type === "error") { - console.error("Error loading image " + imageUrl); - } else { - document.body.appendChild(img); - console.log("Original image width: ", data.originalWidth); - console.log("Original image height: ", data.originalHeight); - } - }, - {maxWidth: 600} + imageUrl, + function(img, data) { + if (img.type === "error") { + console.error("Error loading image " + imageUrl); + } else { + document.body.appendChild(img); + console.log("Original image width: ", data.originalWidth); + console.log("Original image height: ", data.originalHeight); + } + }, + { maxWidth: 600 } ); ``` ## Options + The optional third argument to **loadImage()** is a map of options: -* **maxWidth**: Defines the maximum width of the img/canvas element. -* **maxHeight**: Defines the maximum height of the img/canvas element. -* **minWidth**: Defines the minimum width of the img/canvas element. -* **minHeight**: Defines the minimum height of the img/canvas element. -* **sourceWidth**: The width of the sub-rectangle of the source image to draw -into the destination canvas. -Defaults to the source image width and requires `canvas: true`. -* **sourceHeight**: The height of the sub-rectangle of the source image to draw -into the destination canvas. -Defaults to the source image height and requires `canvas: true`. -* **top**: The top margin of the sub-rectangle of the source image. -Defaults to `0` and requires `canvas: true`. -* **right**: The right margin of the sub-rectangle of the source image. -Defaults to `0` and requires `canvas: true`. -* **bottom**: The bottom margin of the sub-rectangle of the source image. -Defaults to `0` and requires `canvas: true`. -* **left**: The left margin of the sub-rectangle of the source image. -Defaults to `0` and requires `canvas: true`. -* **contain**: Scales the image up/down to contain it in the max dimensions if -set to `true`. -This emulates the CSS feature -[background-image: contain](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#contain). -* **cover**: Scales the image up/down to cover the max dimensions with the image -dimensions if set to `true`. -This emulates the CSS feature -[background-image: cover](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#cover). -* **aspectRatio**: Crops the image to the given aspect ratio (e.g. `16/9`). -Setting the `aspectRatio` also enables the `crop` option. -* **pixelRatio**: Defines the ratio of the canvas pixels to the physical image -pixels on the screen. -Should be set to `window.devicePixelRatio` unless the scaled image is not -rendered on screen. -Defaults to `1` and requires `canvas: true`. -* **downsamplingRatio**: Defines the ratio in which the image is downsampled. -By default, images are downsampled in one step. With a ratio of `0.5`, each step -scales the image to half the size, before reaching the target dimensions. -Requires `canvas: true`. -* **crop**: Crops the image to the maxWidth/maxHeight constraints if set to -`true`. -Enabling the `crop` option also enables the `canvas` option. -* **orientation**: Transform the canvas according to the specified Exif -orientation, which can be an `integer` in the range of `1` to `8` or the boolean -value `true`. -When set to `true`, it will set the orientation value based on the EXIF data of -the image, which will be parsed automatically if the exif library is available. -Setting the `orientation` also enables the `canvas` option. -Setting `orientation` to `true` also enables the `meta` option. -* **meta**: Automatically parses the image meta data if set to `true`. -The meta data is passed to the callback as part of the second argument. -If the file is given as URL and the browser supports the -[fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API), fetches -the file as Blob to be able to parse the meta data. -* **canvas**: Returns the image as -[canvas](https://developer.mozilla.org/en/HTML/Canvas) element if set to `true`. -* **crossOrigin**: Sets the crossOrigin property on the img element for loading -[CORS enabled images](https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image). -* **noRevoke**: By default, the -[created object URL](https://developer.mozilla.org/en/DOM/window.URL.createObjectURL) -is revoked after the image has been loaded, except when this option is set to -`true`. +- **maxWidth**: Defines the maximum width of the img/canvas element. +- **maxHeight**: Defines the maximum height of the img/canvas element. +- **minWidth**: Defines the minimum width of the img/canvas element. +- **minHeight**: Defines the minimum height of the img/canvas element. +- **sourceWidth**: The width of the sub-rectangle of the source image to draw + into the destination canvas. + Defaults to the source image width and requires `canvas: true`. +- **sourceHeight**: The height of the sub-rectangle of the source image to draw + into the destination canvas. + Defaults to the source image height and requires `canvas: true`. +- **top**: The top margin of the sub-rectangle of the source image. + Defaults to `0` and requires `canvas: true`. +- **right**: The right margin of the sub-rectangle of the source image. + Defaults to `0` and requires `canvas: true`. +- **bottom**: The bottom margin of the sub-rectangle of the source image. + Defaults to `0` and requires `canvas: true`. +- **left**: The left margin of the sub-rectangle of the source image. + Defaults to `0` and requires `canvas: true`. +- **contain**: Scales the image up/down to contain it in the max dimensions if + set to `true`. + This emulates the CSS feature + [background-image: contain](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#contain). +- **cover**: Scales the image up/down to cover the max dimensions with the image + dimensions if set to `true`. + This emulates the CSS feature + [background-image: cover](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#cover). +- **aspectRatio**: Crops the image to the given aspect ratio (e.g. `16/9`). + Setting the `aspectRatio` also enables the `crop` option. +- **pixelRatio**: Defines the ratio of the canvas pixels to the physical image + pixels on the screen. + Should be set to `window.devicePixelRatio` unless the scaled image is not + rendered on screen. + Defaults to `1` and requires `canvas: true`. +- **downsamplingRatio**: Defines the ratio in which the image is downsampled. + By default, images are downsampled in one step. With a ratio of `0.5`, each + step scales the image to half the size, before reaching the target dimensions. + Requires `canvas: true`. +- **crop**: Crops the image to the maxWidth/maxHeight constraints if set to + `true`. + Enabling the `crop` option also enables the `canvas` option. +- **orientation**: Transform the canvas according to the specified Exif + orientation, which can be an `integer` in the range of `1` to `8` or the + boolean value `true`. + When set to `true`, it will set the orientation value based on the EXIF data + of the image, which will be parsed automatically if the exif library is + available. + Setting the `orientation` also enables the `canvas` option. + Setting `orientation` to `true` also enables the `meta` option. +- **meta**: Automatically parses the image meta data if set to `true`. + The meta data is passed to the callback as part of the second argument. + If the file is given as URL and the browser supports the + [fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API), fetches + the file as Blob to be able to parse the meta data. +- **canvas**: Returns the image as + [canvas](https://developer.mozilla.org/en/HTML/Canvas) element if set to + `true`. +- **crossOrigin**: Sets the crossOrigin property on the img element for loading + [CORS enabled images](https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image). +- **noRevoke**: By default, the + [created object URL](https://developer.mozilla.org/en/DOM/window.URL.createObjectURL) + is revoked after the image has been loaded, except when this option is set to + `true`. They can be used the following way: ```js loadImage( - fileOrBlobOrUrl, - function (img) { - document.body.appendChild(img); - }, - { - maxWidth: 600, - maxHeight: 300, - minWidth: 100, - minHeight: 50, - canvas: true - } + fileOrBlobOrUrl, + function(img) { + document.body.appendChild(img); + }, + { + maxWidth: 600, + maxHeight: 300, + minWidth: 100, + minHeight: 50, + canvas: true + } ); ``` @@ -248,18 +259,19 @@ All settings are optional. By default, the image is returned as HTML **img** element without any image size restrictions. ## Meta data parsing + If the Load Image Meta extension is included, it is also possible to parse image meta data automatically with the `meta` option: ```js loadImage( - fileOrBlobOrUrl, - function (img, data) { - console.log("Original image head: ", data.imageHead); - console.log("Exif data: ", data.exif); // requires exif extension - console.log("IPTC data: ", data.iptc); // requires iptc extension - }, - { meta: true } + fileOrBlobOrUrl, + function(img, data) { + console.log("Original image head: ", data.imageHead); + console.log("Exif data: ", data.exif); // requires exif extension + console.log("IPTC data: ", data.iptc); // requires iptc extension + }, + { meta: true } ); ``` @@ -268,24 +280,27 @@ used the following way: ```js loadImage.parseMetaData( - fileOrBlob, - function (data) { - if (!data.imageHead) { - return; - } - // Combine data.imageHead with the image body of a resized file - // to create scaled images with the original image meta data, e.g.: - var blob = new Blob([ - data.imageHead, - // Resized images always have a head size of 20 bytes, - // including the JPEG marker and a minimal JFIF header: - loadImage.blobSlice.call(resizedImageBlob, 20) - ], {type: resizedImageBlob.type}); - }, - { - maxMetaDataSize: 262144, - disableImageHead: false + fileOrBlob, + function(data) { + if (!data.imageHead) { + return; } + // Combine data.imageHead with the image body of a resized file + // to create scaled images with the original image meta data, e.g.: + var blob = new Blob( + [ + data.imageHead, + // Resized images always have a head size of 20 bytes, + // including the JPEG marker and a minimal JFIF header: + loadImage.blobSlice.call(resizedImageBlob, 20) + ], + { type: resizedImageBlob.type } + ); + }, + { + maxMetaDataSize: 262144, + disableImageHead: false + } ); ``` @@ -296,10 +311,11 @@ Blob objects of resized images can be created via The Meta data extension also adds additional options used for the `parseMetaData` method: -* **maxMetaDataSize**: Maximum number of bytes of meta data to parse. -* **disableImageHead**: Disable parsing the original image head. +- **maxMetaDataSize**: Maximum number of bytes of meta data to parse. +- **disableImageHead**: Disable parsing the original image head. ### Exif parser + If you include the Load Image Exif Parser extension, the argument passed to the callback for **parseMetaData** will contain the additional property **exif** if Exif data could be found in the given image. @@ -313,7 +329,7 @@ It also provides an **exif.get()** method to retrieve the tag value via the tag's mapped name: ```js -var orientation = data.exif.get('Orientation'); +var orientation = data.exif.get("Orientation"); ``` By default, the only available mapped names are **Orientation** and @@ -323,7 +339,7 @@ become available, as well as two additional methods, **exif.getText()** and **exif.getAll()**: ```js -var flashText = data.exif.getText('Flash'); // e.g.: 'Flash fired, auto mode', +var flashText = data.exif.getText("Flash"); // e.g.: 'Flash fired, auto mode', // A map of all parsed tags with their mapped names/text as keys/values: var allTags = data.exif.getAll(); @@ -332,12 +348,13 @@ var allTags = data.exif.getAll(); The Exif parser also adds additional options for the parseMetaData method, to disable certain aspects of the parser: -* **disableExif**: Disables Exif parsing. -* **disableExifThumbnail**: Disables parsing of the Exif Thumbnail. -* **disableExifSub**: Disables parsing of the Exif Sub IFD. -* **disableExifGps**: Disables parsing of the Exif GPS Info IFD. +- **disableExif**: Disables Exif parsing. +- **disableExifThumbnail**: Disables parsing of the Exif Thumbnail. +- **disableExifSub**: Disables parsing of the Exif Sub IFD. +- **disableExifGps**: Disables parsing of the Exif GPS Info IFD. ### IPTC parser + If you include the Load Image IPTC Parser extension, the argument passed to the callback for **parseMetaData** will contain the additional property **iptc** if IPTC data could be found in the given image. @@ -351,7 +368,7 @@ It also provides an **iptc.get()** method to retrieve the tag value via the tag's mapped name: ```js -var objectname = data.iptc.get('ObjectName'); +var objectname = data.iptc.get("ObjectName"); ``` By default, the only available mapped names are **ObjectName**. @@ -360,7 +377,7 @@ become available, as well as two additional methods, **iptc.getText()** and **iptc.getAll()**: ```js -var keywords = data.iptc.getText('Keywords'); // e.g.: ['Weather','Sky'] +var keywords = data.iptc.getText("Keywords"); // e.g.: ['Weather','Sky'] // A map of all parsed tags with their mapped names/text as keys/values: var allTags = data.iptc.getAll(); @@ -369,16 +386,17 @@ var allTags = data.iptc.getAll(); The IPTC parser also adds additional options for the parseMetaData method, to disable certain aspects of the parser: -* **disableIptc**: Disables IPTC parsing. +- **disableIptc**: Disables IPTC parsing. ## License + The JavaScript Load Image script is released under the [MIT license](https://opensource.org/licenses/MIT). ## Credits -* Image meta data handling implementation based on the help and contribution of -Achim Stöhr. -* Exif tags mapping based on Jacob Seidelin's -[exif-js](https://github.com/jseidelin/exif-js) library. -* IPTC parser implementation by [Dave Bevan](https://github.com/bevand10). +- Image meta data handling implementation based on the help and contribution of + Achim Stöhr. +- Exif tags mapping based on Jacob Seidelin's + [exif-js](https://github.com/jseidelin/exif-js) library. +- IPTC parser implementation by [Dave Bevan](https://github.com/bevand10). From d4d62a01057c0a386f773e93c815e6b4b4246586 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 15 Jul 2019 18:13:06 +0900 Subject: [PATCH 003/207] Use blueimp+jsdoc+prettier config for eslint. Move eslint configs to package.json. Use package.json files property instead of .npmignore. --- .eslintignore | 4 - .eslintrc.js | 3 - .gitignore | 1 - .npmignore | 3 - js/demo/demo.js | 82 ++-- js/index.js | 2 + js/load-image-exif-map.js | 16 +- js/load-image-exif.js | 36 +- js/load-image-fetch.js | 17 +- js/load-image-iptc-map.js | 16 +- js/load-image-iptc.js | 32 +- js/load-image-meta.js | 23 +- js/load-image-orientation.js | 16 +- js/load-image-scale.js | 37 +- js/load-image.js | 55 ++- package-lock.json | 721 ++++++++++------------------------- package.json | 46 ++- test/test.js | 292 +++++++------- 18 files changed, 591 insertions(+), 811 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js delete mode 100644 .npmignore diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index da83a73..0000000 --- a/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -!.eslintrc.js -js/*.min.js -js/vendor -test/vendor diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 2ff6e0a..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: 'standard' -} diff --git a/.gitignore b/.gitignore index 9daa824..3c3629e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -.DS_Store node_modules diff --git a/.npmignore b/.npmignore deleted file mode 100644 index a508bcb..0000000 --- a/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!js/*.js -!js/*.js.map diff --git a/js/demo/demo.js b/js/demo/demo.js index ee72788..1abd033 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -9,9 +9,9 @@ * https://opensource.org/licenses/MIT */ -/* global loadImage, HTMLCanvasElement, $ */ +/* global loadImage, $ */ -$(function () { +$(function() { 'use strict' var result = $('#result') @@ -23,13 +23,19 @@ $(function () { var coordinates var jcropAPI - function displayTagData (node, tags) { + /** + * Displays tag data + * + * @param {*} node jQuery node + * @param {object} tags Tags object + */ + function displayTagData(node, tags) { var table = node.find('table').empty() var row = $('') var cell = $('') var prop for (prop in tags) { - if (tags.hasOwnProperty(prop)) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { table.append( row .clone() @@ -41,12 +47,19 @@ $(function () { node.show() } - function displayThumbnailImage (node, thumbnail, options) { + /** + * Displays the thumbnal image + * + * @param {*} node jQuery node + * @param {string} thumbnail Thumbnail URL + * @param {object} [options] Options object + */ + function displayThumbnailImage(node, thumbnail, options) { if (thumbnail) { thumbNode.empty() loadImage( thumbnail, - function (img) { + function(img) { node.append(img).show() }, options @@ -54,7 +67,12 @@ $(function () { } } - function displayMetaData (data) { + /** + * Displays meta data + * + * @param {object} [data] Meta data object + */ + function displayMetaData(data) { if (!data) return var exif = data.exif var iptc = data.iptc @@ -69,7 +87,13 @@ $(function () { } } - function updateResults (img, data) { + /** + * Updates the results view + * + * @param {*} img Image or canvas element + * @param {object} [data] Meta data object + */ + function updateResults(img, data) { var fileName = currentFile.name var href = img.src var dataURLStart @@ -97,7 +121,13 @@ $(function () { displayMetaData(data) } - function displayImage (file, options) { + /** + * Displays the image + * + * @param {File|Blob|string} file File or Blob object or image URL + * @param {object} [options] Options object + */ + function displayImage(file, options) { currentFile = file if (!loadImage(file, updateResults, options)) { result @@ -112,10 +142,15 @@ $(function () { } } - function dropChangeHandler (e) { - e.preventDefault() - e = e.originalEvent - var target = e.dataTransfer || e.target + /** + * Handles drop and file selection change events + * + * @param {event} event Drop or file selection change event + */ + function dropChangeHandler(event) { + event.preventDefault() + var originalEvent = event.originalEvent + var target = originalEvent.dataTransfer || originalEvent.target var file = target && target.files && target.files[0] var options = { maxWidth: result.width(), @@ -144,21 +179,22 @@ $(function () { } $(document) - .on('dragover', function (e) { + .on('dragover', function(e) { e.preventDefault() - e = e.originalEvent - e.dataTransfer.dropEffect = 'copy' + var originalEvent = event.originalEvent + originalEvent.dataTransfer.dropEffect = 'copy' }) .on('drop', dropChangeHandler) $('#file-input').on('change', dropChangeHandler) - $('#edit').on('click', function (event) { + $('#edit').on('click', function(event) { event.preventDefault() var imgNode = result.find('img, canvas') var img = imgNode[0] var pixelRatio = window.devicePixelRatio || 1 imgNode + // eslint-disable-next-line new-cap .Jcrop( { setSelect: [ @@ -167,24 +203,24 @@ $(function () { img.width / pixelRatio - 40, img.height / pixelRatio - 40 ], - onSelect: function (coords) { + onSelect: function(coords) { coordinates = coords }, - onRelease: function () { + onRelease: function() { coordinates = null } }, - function () { + function() { jcropAPI = this } ) .parent() - .on('click', function (event) { + .on('click', function(event) { event.preventDefault() }) }) - $('#crop').on('click', function (event) { + $('#crop').on('click', function(event) { event.preventDefault() var img = result.find('img, canvas')[0] var pixelRatio = window.devicePixelRatio || 1 @@ -205,7 +241,7 @@ $(function () { } }) - $('#cancel').on('click', function (event) { + $('#cancel').on('click', function(event) { event.preventDefault() if (jcropAPI) { jcropAPI.release() diff --git a/js/index.js b/js/index.js index 776053d..38e1794 100644 --- a/js/index.js +++ b/js/index.js @@ -1,3 +1,5 @@ +/* global module, require */ + module.exports = require('./load-image') require('./load-image-scale') diff --git a/js/load-image-exif-map.js b/js/load-image-exif-map.js index 27e1556..ec23462 100644 --- a/js/load-image-exif-map.js +++ b/js/load-image-exif-map.js @@ -12,9 +12,9 @@ * https://opensource.org/licenses/MIT */ -/* global define */ +/* global define, module, require */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -25,7 +25,7 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' loadImage.ExifMap.prototype.tags = { @@ -321,7 +321,7 @@ } } - loadImage.ExifMap.prototype.getText = function (id) { + loadImage.ExifMap.prototype.getText = function(id) { var value = this.get(id) switch (id) { case 'LightSource': @@ -359,24 +359,24 @@ } return String(value) } - ;(function (exifMapPrototype) { + ;(function(exifMapPrototype) { var tags = exifMapPrototype.tags var map = exifMapPrototype.map var prop // Map the tag names to tags: for (prop in tags) { - if (tags.hasOwnProperty(prop)) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { map[tags[prop]] = prop } } })(loadImage.ExifMap.prototype) - loadImage.ExifMap.prototype.getAll = function () { + loadImage.ExifMap.prototype.getAll = function() { var map = {} var prop var id for (prop in this) { - if (this.hasOwnProperty(prop)) { + if (Object.prototype.hasOwnProperty.call(this, prop)) { id = this.tags[prop] if (id) { map[id] = this.getText(id) diff --git a/js/load-image-exif.js b/js/load-image-exif.js index ee467a4..3e9701f 100644 --- a/js/load-image-exif.js +++ b/js/load-image-exif.js @@ -9,9 +9,11 @@ * https://opensource.org/licenses/MIT */ -/* global define, Blob */ +/* global define, module, require */ -;(function (factory) { +/* eslint-disable no-console */ + +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -22,10 +24,10 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' - loadImage.ExifMap = function () { + loadImage.ExifMap = function() { return this } @@ -33,11 +35,11 @@ Orientation: 0x0112 } - loadImage.ExifMap.prototype.get = function (id) { + loadImage.ExifMap.prototype.get = function(id) { return this[id] || this[this.map[id]] } - loadImage.getExifThumbnail = function (dataView, offset, length) { + loadImage.getExifThumbnail = function(dataView, offset, length) { if (!length || offset + length > dataView.byteLength) { console.log('Invalid Exif data: Invalid thumbnail data.') return @@ -50,14 +52,14 @@ loadImage.exifTagTypes = { // byte, 8-bit unsigned int: 1: { - getValue: function (dataView, dataOffset) { + getValue: function(dataView, dataOffset) { return dataView.getUint8(dataOffset) }, size: 1 }, // ascii, 8-bit byte: 2: { - getValue: function (dataView, dataOffset) { + getValue: function(dataView, dataOffset) { return String.fromCharCode(dataView.getUint8(dataOffset)) }, size: 1, @@ -65,21 +67,21 @@ }, // short, 16 bit int: 3: { - getValue: function (dataView, dataOffset, littleEndian) { + getValue: function(dataView, dataOffset, littleEndian) { return dataView.getUint16(dataOffset, littleEndian) }, size: 2 }, // long, 32 bit int: 4: { - getValue: function (dataView, dataOffset, littleEndian) { + getValue: function(dataView, dataOffset, littleEndian) { return dataView.getUint32(dataOffset, littleEndian) }, size: 4 }, // rational = two long values, first is numerator, second is denominator: 5: { - getValue: function (dataView, dataOffset, littleEndian) { + getValue: function(dataView, dataOffset, littleEndian) { return ( dataView.getUint32(dataOffset, littleEndian) / dataView.getUint32(dataOffset + 4, littleEndian) @@ -89,14 +91,14 @@ }, // slong, 32 bit signed int: 9: { - getValue: function (dataView, dataOffset, littleEndian) { + getValue: function(dataView, dataOffset, littleEndian) { return dataView.getInt32(dataOffset, littleEndian) }, size: 4 }, // srational, two slongs, first is numerator, second is denominator: 10: { - getValue: function (dataView, dataOffset, littleEndian) { + getValue: function(dataView, dataOffset, littleEndian) { return ( dataView.getInt32(dataOffset, littleEndian) / dataView.getInt32(dataOffset + 4, littleEndian) @@ -108,7 +110,7 @@ // undefined, 8-bit byte, value depending on field: loadImage.exifTagTypes[7] = loadImage.exifTagTypes[1] - loadImage.getExifValue = function ( + loadImage.getExifValue = function( dataView, tiffOffset, offset, @@ -165,7 +167,7 @@ return values } - loadImage.parseExifTag = function ( + loadImage.parseExifTag = function( dataView, tiffOffset, offset, @@ -183,7 +185,7 @@ ) } - loadImage.parseExifTags = function ( + loadImage.parseExifTags = function( dataView, tiffOffset, dirOffset, @@ -214,7 +216,7 @@ return dataView.getUint32(dirEndOffset, littleEndian) } - loadImage.parseExifData = function (dataView, offset, length, data, options) { + loadImage.parseExifData = function(dataView, offset, length, data, options) { if (options.disableExif) { return } diff --git a/js/load-image-fetch.js b/js/load-image-fetch.js index 8d8f0a0..5dcd119 100644 --- a/js/load-image-fetch.js +++ b/js/load-image-fetch.js @@ -9,9 +9,9 @@ * https://opensource.org/licenses/MIT */ -/* global define, fetch, Request */ +/* global define, module, require */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -22,24 +22,23 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' if (typeof fetch !== 'undefined' && typeof Request !== 'undefined') { - loadImage.fetchBlob = function (url, callback, options) { + loadImage.fetchBlob = function(url, callback, options) { if (loadImage.hasMetaOption(options)) { return fetch(new Request(url, options)) - .then(function (response) { + .then(function(response) { return response.blob() }) .then(callback) - .catch(function (err) { - console.log(err) + .catch(function(err) { + console.log(err) // eslint-disable-line no-console callback() }) - } else { - callback() } + callback() } } }) diff --git a/js/load-image-iptc-map.js b/js/load-image-iptc-map.js index dab659c..5ed39de 100644 --- a/js/load-image-iptc-map.js +++ b/js/load-image-iptc-map.js @@ -14,9 +14,9 @@ * https://opensource.org/licenses/MIT */ -/* global define */ +/* global define, module, require */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -27,7 +27,7 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' loadImage.IptcMap.prototype.tags = { @@ -96,28 +96,28 @@ // 0xca: 'PreviewData' } - loadImage.IptcMap.prototype.getText = function (id) { + loadImage.IptcMap.prototype.getText = function(id) { var value = this.get(id) return String(value) } - ;(function (iptcMapPrototype) { + ;(function(iptcMapPrototype) { var tags = iptcMapPrototype.tags var map = iptcMapPrototype.map || {} var prop // Map the tag names to tags: for (prop in tags) { - if (tags.hasOwnProperty(prop)) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { map[tags[prop]] = prop } } })(loadImage.IptcMap.prototype) - loadImage.IptcMap.prototype.getAll = function () { + loadImage.IptcMap.prototype.getAll = function() { var map = {} var prop var id for (prop in this) { - if (this.hasOwnProperty(prop)) { + if (Object.prototype.hasOwnProperty.call(this, prop)) { id = this.tags[prop] if (id) { map[id] = this.getText(id) diff --git a/js/load-image-iptc.js b/js/load-image-iptc.js index 877c9a8..be2e764 100644 --- a/js/load-image-iptc.js +++ b/js/load-image-iptc.js @@ -10,9 +10,9 @@ * https://opensource.org/licenses/MIT */ -/* global define */ +/* global define, module, require, Buffer */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -23,10 +23,10 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' - loadImage.IptcMap = function () { + loadImage.IptcMap = function() { return this } @@ -34,17 +34,25 @@ ObjectName: 0x5 } - loadImage.IptcMap.prototype.get = function (id) { + loadImage.IptcMap.prototype.get = function(id) { return this[id] || this[this.map[id]] } - loadImage.parseIptcTags = function ( + loadImage.parseIptcTags = function( dataView, startOffset, sectionLength, data ) { - function getStringFromDB (buffer, start, length) { + /** + * Retrieves string for the given Buffer and range + * + * @param {Buffer} buffer IPTC buffer + * @param {number} start Range start + * @param {number} length Range length + * @returns {string} String value + */ + function getStringFromDB(buffer, start, length) { var outstr = '' for (var n = start; n < start + length; n++) { outstr += String.fromCharCode(buffer.getUint8(n)) @@ -65,7 +73,7 @@ dataSize = dataView.getInt16(segmentStartPos + 3) fieldValue = getStringFromDB(dataView, segmentStartPos + 5, dataSize) // Check if we already stored a value with this name - if (data.iptc.hasOwnProperty(segmentType)) { + if (Object.prototype.hasOwnProperty.call(data.iptc, segmentType)) { // Value already stored with this name, create multivalue field if (data.iptc[segmentType] instanceof Array) { data.iptc[segmentType].push(fieldValue) @@ -81,13 +89,13 @@ } } - loadImage.parseIptcData = function (dataView, offset, length, data, options) { + loadImage.parseIptcData = function(dataView, offset, length, data, options) { if (options.disableIptc) { return } var markerLength = offset + length // Found '8BIM' ? - var isFieldSegmentStart = function (dataView, offset) { + var isFieldSegmentStart = function(dataView, offset) { return ( dataView.getUint32(offset) === 0x3842494d && dataView.getUint16(offset + 4) === 0x0404 @@ -107,11 +115,13 @@ } var startOffset = offset + 8 + nameHeaderLength if (startOffset > markerLength) { + // eslint-disable-next-line no-console console.log('Invalid IPTC data: Invalid segment offset.') break } var sectionLength = dataView.getUint16(offset + 6 + nameHeaderLength) if (offset + sectionLength > markerLength) { + // eslint-disable-next-line no-console console.log('Invalid IPTC data: Invalid segment size.') break } @@ -125,8 +135,10 @@ data ) } + // eslint-disable-next-line no-param-reassign offset++ } + // eslint-disable-next-line no-console console.log('No IPTC data at this offset - could be XMP') } diff --git a/js/load-image-meta.js b/js/load-image-meta.js index 97874e8..c110036 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -13,9 +13,9 @@ * https://opensource.org/licenses/MIT */ -/* global define, Blob */ +/* global define, module, require, DataView, Uint8Array */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -26,7 +26,7 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' var hasblobSlice = @@ -37,7 +37,7 @@ loadImage.blobSlice = hasblobSlice && - function () { + function() { var slice = this.slice || this.webkitSlice || this.mozSlice return slice.apply(this, arguments) } @@ -56,8 +56,10 @@ // properties: // * maxMetaDataSize: Defines the maximum number of bytes to parse. // * disableImageHead: Disables creating the imageHead property. - loadImage.parseMetaData = function (file, callback, options, data) { + loadImage.parseMetaData = function(file, callback, options, data) { + // eslint-disable-next-line no-param-reassign options = options || {} + // eslint-disable-next-line no-param-reassign data = data || {} var that = this // 256 KiB should contain all EXIF/ICC/IPTC segments: @@ -73,9 +75,10 @@ noMetaData || !loadImage.readFile( loadImage.blobSlice.call(file, 0, maxMetaDataSize), - function (e) { + function(e) { if (e.target.error) { // FileReader error + // eslint-disable-next-line no-console console.log(e.target.error) callback(data) return @@ -110,6 +113,7 @@ // but not the marker bytes, so we add 2: markerLength = dataView.getUint16(offset + 2) + 2 if (offset + markerLength > dataView.byteLength) { + // eslint-disable-next-line no-console console.log('Invalid meta data: Invalid segment size.') break } @@ -146,6 +150,7 @@ } } } else { + // eslint-disable-next-line no-console console.log('Invalid JPEG file: Missing JPEG marker.') } callback(data) @@ -158,16 +163,16 @@ } // Determines if meta data should be loaded automatically: - loadImage.hasMetaOption = function (options) { + loadImage.hasMetaOption = function(options) { return options && options.meta } var originalTransform = loadImage.transform - loadImage.transform = function (img, options, callback, file, data) { + loadImage.transform = function(img, options, callback, file, data) { if (loadImage.hasMetaOption(options)) { loadImage.parseMetaData( file, - function (data) { + function(data) { originalTransform.call(loadImage, img, options, callback, file, data) }, options, diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index f14922f..11a5ccf 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -9,9 +9,9 @@ * https://opensource.org/licenses/MIT */ -/* global define */ +/* global define, module, require */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -26,7 +26,7 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' var originalHasCanvasOption = loadImage.hasCanvasOption @@ -35,14 +35,14 @@ var originalGetTransformedOptions = loadImage.getTransformedOptions // Determines if the target image should be a canvas element: - loadImage.hasCanvasOption = function (options) { + loadImage.hasCanvasOption = function(options) { return ( !!options.orientation || originalHasCanvasOption.call(loadImage, options) ) } // Determines if meta data should be loaded automatically: - loadImage.hasMetaOption = function (options) { + loadImage.hasMetaOption = function(options) { return ( (options && options.orientation === true) || originalHasMetaOption.call(loadImage, options) @@ -51,7 +51,7 @@ // Transform image orientation based on // the given EXIF orientation option: - loadImage.transformCoordinates = function (canvas, options) { + loadImage.transformCoordinates = function(canvas, options) { originalTransformCoordinates.call(loadImage, canvas, options) var ctx = canvas.getContext('2d') var width = canvas.width @@ -110,7 +110,7 @@ // Transforms coordinate and dimension options // based on the given orientation option: - loadImage.getTransformedOptions = function (img, opts, data) { + loadImage.getTransformedOptions = function(img, opts, data) { var options = originalGetTransformedOptions.call(loadImage, img, opts) var orientation = options.orientation var newOptions @@ -123,7 +123,7 @@ } newOptions = {} for (i in options) { - if (options.hasOwnProperty(i)) { + if (Object.prototype.hasOwnProperty.call(options, i)) { newOptions[i] = options[i] } } diff --git a/js/load-image-scale.js b/js/load-image-scale.js index aca6134..39be9a5 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -9,9 +9,9 @@ * https://opensource.org/licenses/MIT */ -/* global define */ +/* global define, module, require */ -;(function (factory) { +;(function(factory) { 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -22,12 +22,12 @@ // Browser globals: factory(window.loadImage) } -})(function (loadImage) { +})(function(loadImage) { 'use strict' var originalTransform = loadImage.transform - loadImage.transform = function (img, options, callback, file, data) { + loadImage.transform = function(img, options, callback, file, data) { originalTransform.call( loadImage, loadImage.scale(img, options, data), @@ -41,12 +41,12 @@ // Transform image coordinates, allows to override e.g. // the canvas orientation based on the orientation option, // gets canvas, options passed as arguments: - loadImage.transformCoordinates = function () {} + loadImage.transformCoordinates = function() {} // Returns transformed options, allows to override e.g. // maxWidth, maxHeight and crop options based on the aspectRatio. // gets img, options passed as arguments: - loadImage.getTransformedOptions = function (img, options) { + loadImage.getTransformedOptions = function(img, options) { var aspectRatio = options.aspectRatio var newOptions var i @@ -57,7 +57,7 @@ } newOptions = {} for (i in options) { - if (options.hasOwnProperty(i)) { + if (Object.prototype.hasOwnProperty.call(options, i)) { newOptions[i] = options[i] } } @@ -75,7 +75,7 @@ } // Canvas render method, allows to implement a different rendering algorithm: - loadImage.renderImageToCanvas = function ( + loadImage.renderImageToCanvas = function( canvas, img, sourceX, @@ -104,7 +104,7 @@ } // Determines if the target image should be a canvas element: - loadImage.hasCanvasOption = function (options) { + loadImage.hasCanvasOption = function(options) { return options.canvas || options.crop || !!options.aspectRatio } @@ -113,7 +113,8 @@ // Returns a canvas object if the browser supports canvas // and the hasCanvasOption method returns true or a canvas // object is passed as image, else the scaled image: - loadImage.scale = function (img, options, data) { + loadImage.scale = function(img, options, data) { + // eslint-disable-next-line no-param-reassign options = options || {} var canvas = document.createElement('canvas') var useCanvas = @@ -134,7 +135,10 @@ var pixelRatio var downsamplingRatio var tmp - function scaleUp () { + /** + * Scales up image dimensions + */ + function scaleUp() { var scale = Math.max( (minWidth || destWidth) / destWidth, (minHeight || destHeight) / destHeight @@ -144,7 +148,10 @@ destHeight *= scale } } - function scaleDown () { + /** + * Scales down image dimensions + */ + function scaleDown() { var scale = Math.min( (maxWidth || destWidth) / destWidth, (maxHeight || destHeight) / destHeight @@ -155,6 +162,7 @@ } } if (useCanvas) { + // eslint-disable-next-line no-param-reassign options = loadImage.getTransformedOptions(img, options, data) sourceX = options.left || 0 sourceY = options.top || 0 @@ -186,12 +194,12 @@ destHeight = maxHeight tmp = sourceWidth / sourceHeight - maxWidth / maxHeight if (tmp < 0) { - sourceHeight = maxHeight * sourceWidth / maxWidth + sourceHeight = (maxHeight * sourceWidth) / maxWidth if (options.top === undefined && options.bottom === undefined) { sourceY = (height - sourceHeight) / 2 } } else if (tmp > 0) { - sourceWidth = maxWidth * sourceHeight / maxHeight + sourceWidth = (maxWidth * sourceHeight) / maxHeight if (options.left === undefined && options.right === undefined) { sourceX = (width - sourceWidth) / 2 } @@ -244,6 +252,7 @@ sourceY = 0 sourceWidth = canvas.width sourceHeight = canvas.height + // eslint-disable-next-line no-param-reassign img = document.createElement('canvas') img.width = sourceWidth img.height = sourceHeight diff --git a/js/load-image.js b/js/load-image.js index 870faf8..0119c63 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -9,28 +9,36 @@ * https://opensource.org/licenses/MIT */ -/* global define, URL, webkitURL, FileReader */ +/* global define, webkitURL, module */ -;(function ($) { +;(function($) { 'use strict' - // Loads an image for a given File object. - // Invokes the callback with an img or optional canvas - // element (if supported by the browser) as parameter: - function loadImage (file, callback, options) { + /** + * Loads an image for a given File object. + * Invokes the callback with an img or optional canvas element + * (if supported by the browser) as parameter:. + * + * @param {File|Blob|string} file File or Blob object or image URL + * @param {Function} [callback] Image load event callback + * @param {object} [options] Options object + * @returns {HTMLImageElement|HTMLCanvasElement|FileReader} image object + */ + function loadImage(file, callback, options) { var img = document.createElement('img') var url - img.onerror = function (event) { + img.onerror = function(event) { return loadImage.onerror(img, event, file, callback, options) } - img.onload = function (event) { + img.onload = function(event) { return loadImage.onload(img, event, file, callback, options) } if (typeof file === 'string') { loadImage.fetchBlob( file, - function (blob) { + function(blob) { if (blob) { + // eslint-disable-next-line no-param-reassign file = blob url = loadImage.createObjectURL(file) } else { @@ -55,7 +63,7 @@ img.src = url return img } - return loadImage.readFile(file, function (e) { + return loadImage.readFile(file, function(e) { var target = e.target if (target && target.result) { img.src = target.result @@ -72,7 +80,13 @@ ($.URL && URL.revokeObjectURL && URL) || ($.webkitURL && webkitURL) - function revokeHelper (img, options) { + /** + * Helper function to revoke an object URL + * + * @param {HTMLImageElement} img Image element + * @param {object} [options] Options object + */ + function revokeHelper(img, options) { if (img._objectURL && !(options && options.noRevoke)) { loadImage.revokeObjectURL(img._objectURL) delete img._objectURL @@ -82,27 +96,27 @@ // If the callback given to this function returns a blob, it is used as image // source instead of the original url and overrides the file argument used in // the onload and onerror event callbacks: - loadImage.fetchBlob = function (url, callback, options) { + loadImage.fetchBlob = function(url, callback) { callback() } - loadImage.isInstanceOf = function (type, obj) { + loadImage.isInstanceOf = function(type, obj) { // Cross-frame instanceof check return Object.prototype.toString.call(obj) === '[object ' + type + ']' } - loadImage.transform = function (img, options, callback, file, data) { + loadImage.transform = function(img, options, callback, file, data) { callback(img, data) } - loadImage.onerror = function (img, event, file, callback, options) { + loadImage.onerror = function(img, event, file, callback, options) { revokeHelper(img, options) if (callback) { callback.call(img, event) } } - loadImage.onload = function (img, event, file, callback, options) { + loadImage.onload = function(img, event, file, callback, options) { revokeHelper(img, options) if (callback) { loadImage.transform(img, options, callback, file, { @@ -112,21 +126,22 @@ } } - loadImage.createObjectURL = function (file) { + loadImage.createObjectURL = function(file) { return urlAPI ? urlAPI.createObjectURL(file) : false } - loadImage.revokeObjectURL = function (url) { + loadImage.revokeObjectURL = function(url) { return urlAPI ? urlAPI.revokeObjectURL(url) : false } // Loads a given File object via FileReader interface, // invokes the callback with the event object (load or error). // The result can be read via event.target.result: - loadImage.readFile = function (file, callback, method) { + loadImage.readFile = function(file, callback, method) { if ($.FileReader) { var fileReader = new FileReader() fileReader.onload = fileReader.onerror = callback + // eslint-disable-next-line no-param-reassign method = method || 'readAsDataURL' if (fileReader[method]) { fileReader[method](file) @@ -137,7 +152,7 @@ } if (typeof define === 'function' && define.amd) { - define(function () { + define(function() { return loadImage }) } else if (typeof module === 'object' && module.exports) { diff --git a/package-lock.json b/package-lock.json index 504dcb0..5f9028a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,9 @@ } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", @@ -25,15 +25,15 @@ } }, "@types/node": { - "version": "12.0.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.7.tgz", - "integrity": "sha512-1YKeT4JitGgE4SOzyB9eMwO0nGVNkNEsm9qlIt1Lqm/tG2QEiSMTD4kS3aO6L+w5SClLVxALmIBESK6Mk5wX0A==", + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.2.tgz", + "integrity": "sha512-gojym4tX0FWeV2gsW4Xmzo5wxGjXGm550oVUII7f7G5o4BV6c7DBdiG1RRQd+y1bvqRyYtPfMK85UM95vsapqQ==", "dev": true }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", + "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==", "dev": true }, "acorn-jsx": { @@ -43,9 +43,9 @@ "dev": true }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -90,16 +90,6 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" - } - }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -287,6 +277,12 @@ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, + "comment-parser": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.5.5.tgz", + "integrity": "sha512-oB3TinFT+PV3p8UwDQt71+HkG03+zwPwikDlKU6ZDmql6QX2zFlQ+G0GGSDqyJhdZi4PSlzFBm+YJ+ebOX3Vgw==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -294,9 +290,9 @@ "dev": true }, "concurrently": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.0.tgz", - "integrity": "sha512-pwzXCE7qtOB346LyO9eFWpkFJVO3JQZ/qU/feGeaAHiX1M3Rw3zgXKc5cZ8vSH5DGygkjzLFDzA/pwoQDkRNGg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.1.tgz", + "integrity": "sha512-48+FE5RJ0qc8azwKv4keVQWlni1hZeSjcWr8shBelOBtBHcKj1aJFM9lHRiSc1x7lq416pkvsqfBMhSRja+Lhw==", "dev": true, "requires": { "chalk": "^2.4.1", @@ -310,12 +306,6 @@ "yargs": "^12.0.1" } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, "corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", @@ -398,15 +388,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -460,31 +441,6 @@ "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -492,13 +448,13 @@ "dev": true }, "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", + "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", + "ajv": "^6.10.0", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", @@ -506,18 +462,19 @@ "eslint-scope": "^4.0.3", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", + "espree": "^6.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", + "glob-parent": "^3.1.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.11", @@ -525,7 +482,6 @@ "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^5.5.1", @@ -535,162 +491,44 @@ "text-table": "^0.2.0" } }, - "eslint-config-standard": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", - "integrity": "sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==", + "eslint-config-blueimp": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-1.3.0.tgz", + "integrity": "sha512-6JPmtGdIamQ1AN9X9ejR9pa5kY2aS8s1EJss4ZWj4jLcEmJEGdehQAxSI9H7kT6uUpKPbEx5g5QhpQqCASxwSA==", "dev": true }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", - "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", - "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-es": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz", - "integrity": "sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==", + "eslint-config-prettier": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz", + "integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==", "dev": true, "requires": { - "eslint-utils": "^1.3.0", - "regexpp": "^2.0.1" + "get-stdin": "^6.0.0" } }, - "eslint-plugin-import": { - "version": "2.17.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.17.3.tgz", - "integrity": "sha512-qeVf/UwXFJbeyLbxuY8RgqDyEKCkqV7YC+E5S5uOjAp4tOc8zj01JP3ucoBM8JcEqd1qRasJSg6LLlisirfy0Q==", + "eslint-plugin-jsdoc": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.5.1.tgz", + "integrity": "sha512-ZE2UyTfikhkS9XatRo+UhTFJVrW0XIpK19XQdlFkgpq/BWcewRPYZdO1nJ3r5Z/o4oITfASCPZMArW9Wjhiukg==", "dev": true, "requires": { - "array-includes": "^3.0.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", - "has": "^1.0.3", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "comment-parser": "^0.5.5", + "debug": "^4.1.1", + "flat-map-polyfill": "^0.3.8", + "jsdoctypeparser": "5.0.1", + "lodash": "^4.17.14", + "regextras": "^0.6.1" } }, - "eslint-plugin-node": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-9.1.0.tgz", - "integrity": "sha512-ZwQYGm6EoV2cfLpE1wxJWsfnKUIXfM/KM09/TlorkukgCAwmkgajEJnPCmyzoFPQQkmvo5DrW/nyKutNIw36Mw==", + "eslint-plugin-prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz", + "integrity": "sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA==", "dev": true, "requires": { - "eslint-plugin-es": "^1.4.0", - "eslint-utils": "^1.3.1", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz", - "integrity": "sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==", - "dev": true - }, - "semver": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", - "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", - "dev": true - } + "prettier-linter-helpers": "^1.0.0" } }, - "eslint-plugin-promise": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.1.1.tgz", - "integrity": "sha512-faAHw7uzlNPy7b45J1guyjazw28M+7gJokKUjC5JSFoYfUEyy6Gw/i7YQvmv2Yk00sUjWcmzXQLpU1Ki/C2IZQ==", - "dev": true - }, - "eslint-plugin-standard": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz", - "integrity": "sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA==", - "dev": true - }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -702,10 +540,13 @@ } }, "eslint-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", - "dev": true + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", + "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } }, "eslint-visitor-keys": { "version": "1.0.0", @@ -714,9 +555,9 @@ "dev": true }, "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", "dev": true, "requires": { "acorn": "^6.0.7", @@ -782,9 +623,9 @@ } }, "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "requires": { "chardet": "^0.7.0", @@ -798,6 +639,12 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -848,10 +695,16 @@ "write": "1.0.3" } }, + "flat-map-polyfill": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/flat-map-polyfill/-/flat-map-polyfill-0.3.8.tgz", + "integrity": "sha512-ZfmD5MnU7GglUEhiky9C7yEPaNq1/wh36RDohe+Xr3nJVdccwHbdTkFIYvetcdsoAckUKT51fuf44g7Ni5Doyg==", + "dev": true + }, "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "follow-redirects": { @@ -880,12 +733,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -914,6 +761,12 @@ "meow": "^5.0.0" } }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -937,6 +790,27 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -944,32 +818,17 @@ "dev": true }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1025,9 +884,9 @@ "dev": true }, "import-fresh": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -1042,17 +901,6 @@ "requires": { "pkg-dir": "^3.0.0", "resolve-cwd": "^2.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - } } }, "imurmurhash": { @@ -1078,15 +926,15 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "inquirer": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", - "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", + "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", @@ -1095,7 +943,7 @@ "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.12", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.4.0", @@ -1133,16 +981,10 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { @@ -1151,6 +993,15 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", @@ -1169,42 +1020,18 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1227,6 +1054,12 @@ "esprima": "^4.0.0" } }, + "jsdoctypeparser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.0.1.tgz", + "integrity": "sha512-dYwcK6TKzvq+ZKtbp4sbQSW9JMo6s+4YFfUs5D/K7bZsn3s1NhEhZ+jmIPzby0HbkbECBe+hNPEa6a+E21o94w==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -1292,32 +1125,15 @@ } }, "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", + "parse-json": "^4.0.0", + "pify": "^3.0.0", "strip-bom": "^3.0.0" - }, - "dependencies": { - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "locate-path": { @@ -1331,15 +1147,15 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", "dev": true }, "loglevel": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.2.tgz", - "integrity": "sha512-Jt2MHrCNdtIe1W6co3tF5KXGRkzF+TYffiQstfXa04mrss9IKXzAAXYWak8LbZseAQY03sH2GzMCMU0ZOUc9bg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", + "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", "dev": true }, "loud-rejection": { @@ -1407,91 +1223,6 @@ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, "yargs-parser": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", @@ -1654,12 +1385,6 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1802,6 +1527,12 @@ "json-parse-better-errors": "^1.0.1" } }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -1814,12 +1545,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -1833,20 +1558,12 @@ "dev": true }, "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } + "pify": "^3.0.0" } }, "pify": { @@ -1856,63 +1573,18 @@ "dev": true }, "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "find-up": "^2.1.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - } + "find-up": "^3.0.0" } }, "portfinder": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", - "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", + "version": "1.0.21", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.21.tgz", + "integrity": "sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==", "dev": true, "requires": { "async": "^1.5.2", @@ -1943,6 +1615,21 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "prettier": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -1989,13 +1676,13 @@ } }, "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "read-pkg": "^3.0.0" }, "dependencies": { "find-up": { @@ -2042,14 +1729,14 @@ "dev": true }, "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "load-json-file": "^2.0.0", + "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^3.0.0" } } } @@ -2070,6 +1757,12 @@ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "regextras": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.6.1.tgz", + "integrity": "sha512-EzIHww9xV2Kpqx+corS/I7OBmf2rZ0pKKJPsw5Dc+l6Zq1TslDmtRIP9maVn3UH+72MIXmn8zzDgP07ihQogUA==", + "dev": true + }, "remove-array-items": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/remove-array-items/-/remove-array-items-1.1.1.tgz", @@ -2252,9 +1945,9 @@ } }, "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "sprintf-js": { @@ -2324,9 +2017,9 @@ } }, "table": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.0.tgz", - "integrity": "sha512-nHFDrxmbrkU7JAFKqKbDJXfzrX2UBsWmrieXFTGxiI5e4ncg3VqsZeI4EzNmX0ncp4XNGVeoxIWJXfCIXwrsvw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", + "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==", "dev": true, "requires": { "ajv": "^6.9.1", @@ -2397,9 +2090,9 @@ "dev": true }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "type-check": { diff --git a/package.json b/package.json index 1385920..f1266d8 100644 --- a/package.json +++ b/package.json @@ -32,17 +32,37 @@ }, "license": "MIT", "devDependencies": { - "concurrently": "^4.1.0", - "eslint": "^5.16.0", - "eslint-config-standard": "^12.0.0", - "eslint-plugin-import": "^2.17.3", - "eslint-plugin-node": "^9.1.0", - "eslint-plugin-promise": "^4.1.1", - "eslint-plugin-standard": "^4.0.0", - "get-port-cli": "^2.0.0", - "http-server": "^0.11.1", - "mocha-chrome": "^2.0.0", - "uglify-js": "^3.6.0" + "concurrently": "4", + "eslint": "6", + "eslint-config-blueimp": "1", + "eslint-config-prettier": "6", + "eslint-plugin-jsdoc": "15", + "eslint-plugin-prettier": "3", + "prettier": "1", + "get-port-cli": "2", + "http-server": "0", + "mocha-chrome": "2", + "uglify-js": "3" + }, + "eslintConfig": { + "extends": [ + "blueimp", + "plugin:jsdoc/recommended", + "plugin:prettier/recommended" + ], + "env": { + "browser": true + } + }, + "eslintIgnore": [ + "js/*.min.js", + "js/vendor", + "test/vendor" + ], + "prettier": { + "proseWrap": "always", + "semi": false, + "singleQuote": true }, "scripts": { "lint": "eslint .", @@ -55,5 +75,9 @@ "version": "npm run build && git add -A js", "postversion": "git push --tags origin master master:gh-pages && npm publish" }, + "files": [ + "js/*.js", + "js/*.js.map" + ], "main": "js/index.js" } diff --git a/test/test.js b/test/test.js index 392b30f..09f4cb3 100644 --- a/test/test.js +++ b/test/test.js @@ -9,10 +9,10 @@ * https://opensource.org/licenses/MIT */ -/* global describe, it, Blob */ +/* global describe, it */ /* eslint-disable no-unused-expressions */ -;(function (expect, loadImage) { +;(function(expect, loadImage) { 'use strict' var canCreateBlob = !!window.dataURLtoBlob @@ -43,7 +43,14 @@ '2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A/v4ooooA/9k=' var imageUrlJPEG = 'data:image/jpeg;base64,' + b64DataJPEG var blobJPEG = canCreateBlob && window.dataURLtoBlob(imageUrlJPEG) - function createBlob (data, type) { + /** + * Helper function to create a blob object from the given image data + * + * @param {*} data Image data + * @param {string} type Image content type + * @returns {Blob} Image Blob object + */ + function createBlob(data, type) { try { return new Blob([data], { type: type }) } catch (e) { @@ -58,17 +65,17 @@ } } - describe('Loading', function () { - it('Return an object with onload and onerror methods', function () { - var img = loadImage(blobGIF, function () {}) + describe('Loading', function() { + it('Return an object with onload and onerror methods', function() { + var img = loadImage(blobGIF, function() {}) expect(img).to.be.an.instanceOf(Object) expect(img.onload).to.be.a('function') expect(img.onerror).to.be.a('function') }) - it('Load image url', function (done) { + it('Load image url', function(done) { expect( - loadImage(imageUrlGIF, function (img) { + loadImage(imageUrlGIF, function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -76,9 +83,9 @@ ).to.be.ok }) - it('Load image blob', function (done) { + it('Load image blob', function(done) { expect( - loadImage(blobGIF, function (img) { + loadImage(blobGIF, function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -86,9 +93,9 @@ ).to.be.ok }) - it('Return image loading error to callback', function (done) { + it('Return image loading error to callback', function(done) { expect( - loadImage('404', function (img) { + loadImage('404', function(img) { expect(img).to.be.an.instanceOf(window.Event) expect(img.type).to.equal('error') done() @@ -96,12 +103,12 @@ ).to.be.ok }) - it('Keep object URL if noRevoke is true', function (done) { + it('Keep object URL if noRevoke is true', function(done) { expect( loadImage( blobGIF, - function (img) { - loadImage(img.src, function (img2) { + function(img) { + loadImage(img.src, function(img2) { expect(img.width).to.equal(img2.width) expect(img.height).to.equal(img2.height) done() @@ -112,10 +119,10 @@ ).to.be.ok }) - it('Discard object URL if noRevoke is undefined/false', function (done) { + it('Discard object URL if noRevoke is undefined/false', function(done) { expect( - loadImage(blobGIF, function (img) { - loadImage(img.src, function (img2) { + loadImage(blobGIF, function(img) { + loadImage(img.src, function(img2) { if (!window.callPhantom) { // revokeObjectUrl doesn't seem to have an effect in PhantomJS expect(img2).to.be.an.instanceOf(window.Event) @@ -127,9 +134,9 @@ ).to.be.ok }) - it('Provide original image width+height in callback data', function (done) { + it('Provide original image width+height in callback data', function(done) { expect( - loadImage(imageUrlGIF, function (img, data) { + loadImage(imageUrlGIF, function(img, data) { expect(data.originalWidth).to.equal(80) expect(data.originalHeight).to.equal(60) done() @@ -138,13 +145,13 @@ }) }) - describe('Scaling', function () { - describe('max/min', function () { - it('Scale to maxWidth', function (done) { + describe('Scaling', function() { + describe('max/min', function() { + it('Scale to maxWidth', function(done) { expect( loadImage( blobGIF, - function (img, data) { + function(img, data) { expect(img.width).to.equal(40) expect(img.height).to.equal(30) expect(data.originalWidth).to.equal(80) @@ -156,11 +163,11 @@ ).to.be.ok }) - it('Scale to maxHeight', function (done) { + it('Scale to maxHeight', function(done) { expect( loadImage( blobGIF, - function (img, data) { + function(img, data) { expect(img.width).to.equal(20) expect(img.height).to.equal(15) expect(data.originalWidth).to.equal(80) @@ -172,11 +179,11 @@ ).to.be.ok }) - it('Scale to minWidth', function (done) { + it('Scale to minWidth', function(done) { expect( loadImage( blobGIF, - function (img, data) { + function(img, data) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) expect(data.originalWidth).to.equal(80) @@ -188,11 +195,11 @@ ).to.be.ok }) - it('Scale to minHeight', function (done) { + it('Scale to minHeight', function(done) { expect( loadImage( blobGIF, - function (img, data) { + function(img, data) { expect(img.width).to.equal(320) expect(img.height).to.equal(240) expect(data.originalWidth).to.equal(80) @@ -204,11 +211,11 @@ ).to.be.ok }) - it('Scale to minWidth but respect maxWidth', function (done) { + it('Scale to minWidth but respect maxWidth', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) done() @@ -218,11 +225,11 @@ ).to.be.ok }) - it('Scale to minHeight but respect maxHeight', function (done) { + it('Scale to minHeight but respect maxHeight', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) done() @@ -232,11 +239,11 @@ ).to.be.ok }) - it('Scale to minWidth but respect maxHeight', function (done) { + it('Scale to minWidth but respect maxHeight', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) done() @@ -246,11 +253,11 @@ ).to.be.ok }) - it('Scale to minHeight but respect maxWidth', function (done) { + it('Scale to minHeight but respect maxWidth', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) done() @@ -260,11 +267,11 @@ ).to.be.ok }) - it('Scale up with the given pixelRatio', function (done) { + it('Scale up with the given pixelRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(320) expect(img.height).to.equal(240) expect(img.style.width).to.equal('160px') @@ -276,11 +283,11 @@ ).to.be.ok }) - it('Scale down with the given pixelRatio', function (done) { + it('Scale down with the given pixelRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) expect(img.style.width).to.equal('40px') @@ -292,11 +299,11 @@ ).to.be.ok }) - it('Scale down with the given downsamplingRatio', function (done) { + it('Scale down with the given downsamplingRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(20) expect(img.height).to.equal(15) done() @@ -306,11 +313,11 @@ ).to.be.ok }) - it('Ignore max settings for smaller image dimensions', function (done) { + it('Ignore max settings for smaller image dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -320,11 +327,11 @@ ).to.be.ok }) - it('Ignore min settings for larger image dimensions', function (done) { + it('Ignore min settings for larger image dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -335,12 +342,12 @@ }) }) - describe('contain', function () { - it('Scale up to contain image in max dimensions', function (done) { + describe('contain', function() { + it('Scale up to contain image in max dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) done() @@ -350,11 +357,11 @@ ).to.be.ok }) - it('Scale down to contain image in max dimensions', function (done) { + it('Scale down to contain image in max dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(30) done() @@ -365,14 +372,12 @@ }) }) - describe('cover', function () { - it('Scale up to cover max dimensions with image dimensions', function ( - done - ) { + describe('cover', function() { + it('Scale up to cover max dimensions with image dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(160) expect(img.height).to.equal(120) done() @@ -382,13 +387,11 @@ ).to.be.ok }) - it('Scale down to cover max dimensions with image dimensions', function ( - done - ) { + it('Scale down to cover max dimensions with image dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(30) done() @@ -400,12 +403,12 @@ }) }) - describe('Cropping', function () { - it('Crop to same values for maxWidth and maxHeight', function (done) { + describe('Cropping', function() { + it('Crop to same values for maxWidth and maxHeight', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(40) done() @@ -415,11 +418,11 @@ ).to.be.ok }) - it('Crop to different values for maxWidth and maxHeight', function (done) { + it('Crop to different values for maxWidth and maxHeight', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(60) done() @@ -429,13 +432,11 @@ ).to.be.ok }) - it('Crop using the given sourceWidth/sourceHeight dimensions', function ( - done - ) { + it('Crop using the given sourceWidth/sourceHeight dimensions', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(40) done() @@ -445,11 +446,11 @@ ).to.be.ok }) - it('Crop using the given left/top coordinates', function (done) { + it('Crop using the given left/top coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(20) done() @@ -459,11 +460,11 @@ ).to.be.ok }) - it('Crop using the given right/bottom coordinates', function (done) { + it('Crop using the given right/bottom coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(20) done() @@ -473,11 +474,11 @@ ).to.be.ok }) - it('Crop using the given 2:1 aspectRatio', function (done) { + it('Crop using the given 2:1 aspectRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(40) done() @@ -487,11 +488,11 @@ ).to.be.ok }) - it('Crop using the given 2:3 aspectRatio', function (done) { + it('Crop using the given 2:3 aspectRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(40) expect(img.height).to.equal(60) done() @@ -501,11 +502,11 @@ ).to.be.ok }) - it('Crop using maxWidth/maxHeight and pixelRatio', function (done) { + it('Crop using maxWidth/maxHeight and pixelRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(80) expect(img.style.width).to.equal('40px') @@ -517,11 +518,11 @@ ).to.be.ok }) - it('Crop using sourceWidth/sourceHeight and pixelRatio', function (done) { + it('Crop using sourceWidth/sourceHeight and pixelRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(80) expect(img.style.width).to.equal('40px') @@ -533,11 +534,11 @@ ).to.be.ok }) - it('Crop using maxWidth/maxHeight and downsamplingRatio', function (done) { + it('Crop using maxWidth/maxHeight and downsamplingRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(10) expect(img.height).to.equal(10) @@ -557,12 +558,12 @@ }) }) - describe('Orientation', function () { - it('Should keep the orientation', function (done) { + describe('Orientation', function() { + it('Should keep the orientation', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -572,11 +573,11 @@ ).to.be.ok }) - it('Should rotate left', function (done) { + it('Should rotate left', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(60) expect(img.height).to.equal(80) done() @@ -586,11 +587,11 @@ ).to.be.ok }) - it('Should rotate right', function (done) { + it('Should rotate right', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(60) expect(img.height).to.equal(80) done() @@ -600,11 +601,11 @@ ).to.be.ok }) - it('Should adjust constraints to new coordinates', function (done) { + it('Should adjust constraints to new coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(30) expect(img.height).to.equal(40) done() @@ -614,11 +615,11 @@ ).to.be.ok }) - it('Should adjust left and top to new coordinates', function (done) { + it('Should adjust left and top to new coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(30) expect(img.height).to.equal(60) done() @@ -628,11 +629,11 @@ ).to.be.ok }) - it('Should adjust right and bottom to new coordinates', function (done) { + it('Should adjust right and bottom to new coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(30) expect(img.height).to.equal(60) done() @@ -642,11 +643,11 @@ ).to.be.ok }) - it('Should adjust left and bottom to new coordinates', function (done) { + it('Should adjust left and bottom to new coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(30) expect(img.height).to.equal(60) done() @@ -656,11 +657,11 @@ ).to.be.ok }) - it('Should adjust right and top to new coordinates', function (done) { + it('Should adjust right and top to new coordinates', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(30) expect(img.height).to.equal(60) done() @@ -670,11 +671,11 @@ ).to.be.ok }) - it('Should rotate left with the given pixelRatio', function (done) { + it('Should rotate left with the given pixelRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(120) expect(img.height).to.equal(160) expect(img.style.width).to.equal('60px') @@ -686,11 +687,11 @@ ).to.be.ok }) - it('Should rotate right with the given pixelRatio', function (done) { + it('Should rotate right with the given pixelRatio', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(120) expect(img.height).to.equal(160) expect(img.style.width).to.equal('60px') @@ -702,11 +703,11 @@ ).to.be.ok }) - it('Should ignore too small orientation value', function (done) { + it('Should ignore too small orientation value', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -716,11 +717,11 @@ ).to.be.ok }) - it('Should ignore too large orientation value', function (done) { + it('Should ignore too large orientation value', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.width).to.equal(80) expect(img.height).to.equal(60) done() @@ -730,13 +731,11 @@ ).to.be.ok }) - it('Should rotate right based on the exif orientation value', function ( - done - ) { + it('Should rotate right based on the exif orientation value', function(done) { expect( loadImage( blobJPEG, - function (img, data) { + function(img, data) { expect(data).to.be.ok expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) @@ -749,11 +748,11 @@ ).to.be.ok }) - it('Should scale image after exif based orientation', function (done) { + it('Should scale image after exif based orientation', function(done) { expect( loadImage( blobJPEG, - function (img) { + function(img) { expect(img.width).to.equal(10) expect(img.height).to.equal(20) done() @@ -764,22 +763,22 @@ }) }) - describe('Canvas', function () { - it('Return img element to callback if canvas is not true', function (done) { + describe('Canvas', function() { + it('Return img element to callback if canvas is not true', function(done) { expect( - loadImage(blobGIF, function (img) { - expect(img.getContext).to.be.falsy + loadImage(blobGIF, function(img) { + expect(img.getContext).to.be.undefined expect(img.nodeName.toLowerCase()).to.equal('img') done() }) ).to.be.ok }) - it('Return canvas element to callback if canvas is true', function (done) { + it('Return canvas element to callback if canvas is true', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.getContext).to.be.ok expect(img.nodeName.toLowerCase()).to.equal('canvas') done() @@ -789,11 +788,11 @@ ).to.be.ok }) - it('Return scaled canvas element to callback', function (done) { + it('Return scaled canvas element to callback', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { expect(img.getContext).to.be.ok expect(img.nodeName.toLowerCase()).to.equal('canvas') expect(img.width).to.equal(40) @@ -805,13 +804,12 @@ ).to.be.ok }) - it('Accept a canvas element as parameter for loadImage.scale', function ( - done - ) { + it('Accept a canvas element as parameter for loadImage.scale', function(done) { expect( loadImage( blobGIF, - function (img) { + function(img) { + // eslint-disable-next-line no-param-reassign img = loadImage.scale(img, { maxWidth: 40 }) @@ -827,29 +825,29 @@ }) }) - describe('Metadata', function () { - it('Should parse Exif tags', function (done) { - loadImage.parseMetaData(blobJPEG, function (data) { + describe('Metadata', function() { + it('Should parse Exif tags', function(done) { + loadImage.parseMetaData(blobJPEG, function(data) { expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) done() }) }) - it('Should parse IPTC tags', function (done) { - loadImage.parseMetaData(blobJPEG, function (data) { + it('Should parse IPTC tags', function(done) { + loadImage.parseMetaData(blobJPEG, function(data) { expect(data.iptc).to.be.ok expect(data.iptc.get('ObjectName')).to.equal('objectname') done() }) }) - it('Should parse the complete image head', function (done) { - loadImage.parseMetaData(blobJPEG, function (data) { + it('Should parse the complete image head', function(done) { + loadImage.parseMetaData(blobJPEG, function(data) { expect(data.imageHead).to.be.ok loadImage.parseMetaData( createBlob(data.imageHead, 'image/jpeg'), - function (data) { + function(data) { expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) done() @@ -858,11 +856,11 @@ }) }) - it('Should parse meta data automatically', function (done) { + it('Should parse meta data automatically', function(done) { expect( loadImage( blobJPEG, - function (img, data) { + function(img, data) { expect(data).to.be.ok expect(data.imageHead).to.be.ok expect(data.exif).to.be.ok @@ -878,14 +876,12 @@ }) if ('fetch' in window && 'Request' in window) { - describe('Fetch', function () { - it('Should fetch image URL as blob if meta option is true', function ( - done - ) { + describe('Fetch', function() { + it('Should fetch image URL as blob if meta option is true', function(done) { expect( loadImage( imageUrlJPEG, - function (img, data) { + function(img, data) { expect(data).to.be.ok expect(data.imageHead).to.be.ok expect(data.exif).to.be.ok @@ -899,13 +895,11 @@ ).to.be.ok }) - it('Should load image URL as img if meta option is false', function ( - done - ) { + it('Should load image URL as img if meta option is false', function(done) { expect( - loadImage(imageUrlJPEG, function (img, data) { - expect(data.imageHead).to.be.falsy - expect(data.exif).to.be.falsy + loadImage(imageUrlJPEG, function(img, data) { + expect(data.imageHead).to.be.undefined + expect(data.exif).to.be.undefined expect(img.width).to.equal(2) expect(img.height).to.equal(1) done() From 2d1f933caf00558028bdf848066840f44a9dd2b2 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 15 Jul 2019 18:13:44 +0900 Subject: [PATCH 004/207] Rebuild minified bundle. --- js/load-image.all.min.js | 2 +- js/load-image.all.min.js.map | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/load-image.all.min.js b/js/load-image.all.min.js index 2aae95e..3448289 100644 --- a/js/load-image.all.min.js +++ b/js/load-image.all.min.js @@ -1,2 +1,2 @@ -!function(o){"use strict";function r(t,i,a){var o,n=document.createElement("img");return n.onerror=function(e){return r.onerror(n,e,t,i,a)},n.onload=function(e){return r.onload(n,e,t,i,a)},"string"==typeof t?(r.fetchBlob(t,function(e){e?o=r.createObjectURL(t=e):(o=t,a&&a.crossOrigin&&(n.crossOrigin=a.crossOrigin)),n.src=o},a),n):r.isInstanceOf("Blob",t)||r.isInstanceOf("File",t)?(o=n._objectURL=r.createObjectURL(t))?(n.src=o,n):r.readFile(t,function(e){var t=e.target;t&&t.result?n.src=t.result:i&&i(e)}):void 0}var t=o.createObjectURL&&o||o.URL&&URL.revokeObjectURL&&URL||o.webkitURL&&webkitURL;function n(e,t){!e._objectURL||t&&t.noRevoke||(r.revokeObjectURL(e._objectURL),delete e._objectURL)}r.fetchBlob=function(e,t,i){t()},r.isInstanceOf=function(e,t){return Object.prototype.toString.call(t)==="[object "+e+"]"},r.transform=function(e,t,i,a,o){i(e,o)},r.onerror=function(e,t,i,a,o){n(e,o),a&&a.call(e,t)},r.onload=function(e,t,i,a,o){n(e,o),a&&r.transform(e,o,a,i,{originalWidth:e.naturalWidth||e.width,originalHeight:e.naturalHeight||e.height})},r.createObjectURL=function(e){return!!t&&t.createObjectURL(e)},r.revokeObjectURL=function(e){return!!t&&t.revokeObjectURL(e)},r.readFile=function(e,t,i){if(o.FileReader){var a=new FileReader;if(a.onload=a.onerror=t,a[i=i||"readAsDataURL"])return a[i](e),a}return!1},"function"==typeof define&&define.amd?define(function(){return r}):"object"==typeof module&&module.exports?module.exports=r:o.loadImage=r}("undefined"!=typeof window&&window||this),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):"object"==typeof module&&module.exports?e(require("./load-image")):e(window.loadImage)}(function(v){"use strict";var n=v.transform;v.transform=function(e,t,i,a,o){n.call(v,v.scale(e,t,o),t,i,a,o)},v.transformCoordinates=function(){},v.getTransformedOptions=function(e,t){var i,a,o,n,r=t.aspectRatio;if(!r)return t;for(a in i={},t)t.hasOwnProperty(a)&&(i[a]=t[a]);return i.crop=!0,r<(o=e.naturalWidth||e.width)/(n=e.naturalHeight||e.height)?(i.maxWidth=n*r,i.maxHeight=n):(i.maxWidth=o,i.maxHeight=o/r),i},v.renderImageToCanvas=function(e,t,i,a,o,n,r,s,l,c){return e.getContext("2d").drawImage(t,i,a,o,n,r,s,l,c),e},v.hasCanvasOption=function(e){return e.canvas||e.crop||!!e.aspectRatio},v.scale=function(e,t,i){t=t||{};var a,o,n,r,s,l,c,d,u,f,g,p=document.createElement("canvas"),h=e.getContext||v.hasCanvasOption(t)&&p.getContext,m=e.naturalWidth||e.width,S=e.naturalHeight||e.height,b=m,y=S;function x(){var e=Math.max((n||b)/b,(r||y)/y);1r.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if(a=p.metaDataParsers.jpeg[t])for(o=0;oe.byteLength))return g.createObjectURL(new Blob([e.buffer.slice(t,t+i)]));console.log("Invalid Exif data: Invalid thumbnail data.")},g.exifTagTypes={1:{getValue:function(e,t){return e.getUint8(t)},size:1},2:{getValue:function(e,t){return String.fromCharCode(e.getUint8(t))},size:1,ascii:!0},3:{getValue:function(e,t,i){return e.getUint16(t,i)},size:2},4:{getValue:function(e,t,i){return e.getUint32(t,i)},size:4},5:{getValue:function(e,t,i){return e.getUint32(t,i)/e.getUint32(t+4,i)},size:8},9:{getValue:function(e,t,i){return e.getInt32(t,i)},size:4},10:{getValue:function(e,t,i){return e.getInt32(t,i)/e.getInt32(t+4,i)},size:8}},g.exifTagTypes[7]=g.exifTagTypes[1],g.getExifValue=function(e,t,i,a,o,n){var r,s,l,c,d,u,f=g.exifTagTypes[a];if(f){if(!((s=4<(r=f.size*o)?t+e.getUint32(i+8,n):i+8)+r>e.byteLength)){if(1===o)return f.getValue(e,s,n);for(l=[],c=0;ce.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(!((r=i+2+12*(n=e.getUint16(i,a)))+4>e.byteLength)){for(s=0;se.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===e.getUint16(t+8)){switch(e.getUint16(l)){case 18761:n=!0;break;case 19789:n=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===e.getUint16(l+2,n)?(r=e.getUint32(l+4,n),a.exif=new g.ExifMap,(r=g.parseExifTags(e,l,l+r,n,a))&&!o.disableExifThumbnail&&(s={exif:{}},r=g.parseExifTags(e,l,l+r,n,s),s.exif[513]&&(a.exif.Thumbnail=g.getExifThumbnail(e,l+s.exif[513],s.exif[514]))),a.exif[34665]&&!o.disableExifSub&&g.parseExifTags(e,l,l+a.exif[34665],n,a),a.exif[34853]&&!o.disableExifGps&&g.parseExifTags(e,l,l+a.exif[34853],n,a)):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},g.metaDataParsers.jpeg[65505].push(g.parseExifData)}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";e.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},e.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},e.ExifMap.prototype.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},function(e){var t,i=e.tags,a=e.map;for(t in i)i.hasOwnProperty(t)&&(a[i[t]]=t)}(e.ExifMap.prototype),e.ExifMap.prototype.getAll=function(){var e,t,i={};for(e in this)this.hasOwnProperty(e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(u){"use strict";u.IptcMap=function(){return this},u.IptcMap.prototype.map={ObjectName:5},u.IptcMap.prototype.get=function(e){return this[e]||this[this.map[e]]},u.parseIptcTags=function(e,t,i,a){function o(e,t,i){for(var a="",o=t;or.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if(a=p.metaDataParsers.jpeg[t])for(o=0;oe.byteLength))return g.createObjectURL(new Blob([e.buffer.slice(t,t+i)]));console.log("Invalid Exif data: Invalid thumbnail data.")},g.exifTagTypes={1:{getValue:function(e,t){return e.getUint8(t)},size:1},2:{getValue:function(e,t){return String.fromCharCode(e.getUint8(t))},size:1,ascii:!0},3:{getValue:function(e,t,i){return e.getUint16(t,i)},size:2},4:{getValue:function(e,t,i){return e.getUint32(t,i)},size:4},5:{getValue:function(e,t,i){return e.getUint32(t,i)/e.getUint32(t+4,i)},size:8},9:{getValue:function(e,t,i){return e.getInt32(t,i)},size:4},10:{getValue:function(e,t,i){return e.getInt32(t,i)/e.getInt32(t+4,i)},size:8}},g.exifTagTypes[7]=g.exifTagTypes[1],g.getExifValue=function(e,t,i,a,o,n){var r,s,l,c,d,u,f=g.exifTagTypes[a];if(f){if(!((s=4<(r=f.size*o)?t+e.getUint32(i+8,n):i+8)+r>e.byteLength)){if(1===o)return f.getValue(e,s,n);for(l=[],c=0;ce.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(!((r=i+2+12*(n=e.getUint16(i,a)))+4>e.byteLength)){for(s=0;se.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===e.getUint16(t+8)){switch(e.getUint16(l)){case 18761:n=!0;break;case 19789:n=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===e.getUint16(l+2,n)?(r=e.getUint32(l+4,n),a.exif=new g.ExifMap,(r=g.parseExifTags(e,l,l+r,n,a))&&!o.disableExifThumbnail&&(s={exif:{}},r=g.parseExifTags(e,l,l+r,n,s),s.exif[513]&&(a.exif.Thumbnail=g.getExifThumbnail(e,l+s.exif[513],s.exif[514]))),a.exif[34665]&&!o.disableExifSub&&g.parseExifTags(e,l,l+a.exif[34665],n,a),a.exif[34853]&&!o.disableExifGps&&g.parseExifTags(e,l,l+a.exif[34853],n,a)):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},g.metaDataParsers.jpeg[65505].push(g.parseExifData)}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";e.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},e.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},e.ExifMap.prototype.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},function(e){var t,i=e.tags,a=e.map;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(a[i[t]]=t)}(e.ExifMap.prototype),e.ExifMap.prototype.getAll=function(){var e,t,i={};for(e in this)Object.prototype.hasOwnProperty.call(this,e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(u){"use strict";u.IptcMap=function(){return this},u.IptcMap.prototype.map={ObjectName:5},u.IptcMap.prototype.get=function(e){return this[e]||this[this.map[e]]},u.parseIptcTags=function(e,t,i,a){function o(e,t,i){for(var a="",o=t;o Date: Mon, 15 Jul 2019 18:13:58 +0900 Subject: [PATCH 005/207] Update test vendor dependencies. --- test/vendor/canvas-to-blob.js | 67 +- test/vendor/chai.js | 8682 ++++++++++++++----- test/vendor/mocha.js | 14544 +++++++++++++++++++------------- 3 files changed, 15312 insertions(+), 7981 deletions(-) diff --git a/test/vendor/canvas-to-blob.js b/test/vendor/canvas-to-blob.js index 83f7905..801339c 100644 --- a/test/vendor/canvas-to-blob.js +++ b/test/vendor/canvas-to-blob.js @@ -12,34 +12,44 @@ * http://stackoverflow.com/q/4998908 */ -/* global atob, Blob, define */ +/* global define, Uint8Array, ArrayBuffer, module */ -;(function (window) { +;(function(window) { 'use strict' - var CanvasPrototype = window.HTMLCanvasElement && - window.HTMLCanvasElement.prototype - var hasBlobConstructor = window.Blob && (function () { - try { - return Boolean(new Blob()) - } catch (e) { - return false - } - }()) - var hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array && - (function () { + var CanvasPrototype = + window.HTMLCanvasElement && window.HTMLCanvasElement.prototype + var hasBlobConstructor = + window.Blob && + (function() { + try { + return Boolean(new Blob()) + } catch (e) { + return false + } + })() + var hasArrayBufferViewSupport = + hasBlobConstructor && + window.Uint8Array && + (function() { try { return new Blob([new Uint8Array(100)]).size === 100 } catch (e) { return false } - }()) - var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || - window.MozBlobBuilder || window.MSBlobBuilder + })() + var BlobBuilder = + window.BlobBuilder || + window.WebKitBlobBuilder || + window.MozBlobBuilder || + window.MSBlobBuilder var dataURIPattern = /^data:((.*?)(;charset=.*?)?)(;base64)?,/ - var dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob && - window.ArrayBuffer && window.Uint8Array && - function (dataURI) { + var dataURLtoBlob = + (hasBlobConstructor || BlobBuilder) && + window.atob && + window.ArrayBuffer && + window.Uint8Array && + function(dataURI) { var matches, mediaType, isBase64, @@ -75,10 +85,9 @@ } // Write the ArrayBuffer (or ArrayBufferView) to a blob: if (hasBlobConstructor) { - return new Blob( - [hasArrayBufferViewSupport ? intArray : arrayBuffer], - {type: mediaType} - ) + return new Blob([hasArrayBufferViewSupport ? intArray : arrayBuffer], { + type: mediaType + }) } bb = new BlobBuilder() bb.append(arrayBuffer) @@ -86,9 +95,9 @@ } if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) { if (CanvasPrototype.mozGetAsFile) { - CanvasPrototype.toBlob = function (callback, type, quality) { + CanvasPrototype.toBlob = function(callback, type, quality) { var self = this - setTimeout(function () { + setTimeout(function() { if (quality && CanvasPrototype.toDataURL && dataURLtoBlob) { callback(dataURLtoBlob(self.toDataURL(type, quality))) } else { @@ -97,16 +106,16 @@ }) } } else if (CanvasPrototype.toDataURL && dataURLtoBlob) { - CanvasPrototype.toBlob = function (callback, type, quality) { + CanvasPrototype.toBlob = function(callback, type, quality) { var self = this - setTimeout(function () { + setTimeout(function() { callback(dataURLtoBlob(self.toDataURL(type, quality))) }) } } } if (typeof define === 'function' && define.amd) { - define(function () { + define(function() { return dataURLtoBlob }) } else if (typeof module === 'object' && module.exports) { @@ -114,4 +123,4 @@ } else { window.dataURLtoBlob = dataURLtoBlob } -}(window)) +})(window) diff --git a/test/vendor/chai.js b/test/vendor/chai.js index bbe4c4a..39429c5 100644 --- a/test/vendor/chai.js +++ b/test/vendor/chai.js @@ -1,4 +1,4 @@ -(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.chai = 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'foo'}).to.be.a('foo'); + * `.a` supports objects that have a custom type set via `Symbol.toStringTag`. + * + * var myObj = { + * [Symbol.toStringTag]: 'myCustomType' + * }; + * + * expect(myObj).to.be.a('myCustomType').but.not.an('object'); + * + * It's often best to use `.a` to check a target's type before making more + * assertions on the same target. That way, you avoid unexpected behavior from + * any assertion that does different things based on the target's type. + * + * expect([1, 2, 3]).to.be.an('array').that.includes(2); + * expect([]).to.be.an('array').that.is.empty; * - * // language chain - * expect(foo).to.be.an.instanceof(Foo); + * Add `.not` earlier in the chain to negate `.a`. However, it's often best to + * assert that the target is the expected type, rather than asserting that it + * isn't one of many unexpected types. + * + * expect('foo').to.be.a('string'); // Recommended + * expect('foo').to.not.be.an('array'); // Not recommended + * + * `.a` accepts an optional `msg` argument which is a custom error message to + * show when the assertion fails. The message can also be given as the second + * argument to `expect`. + * + * expect(1).to.be.a('string', 'nooo why fail??'); + * expect(1, 'nooo why fail??').to.be.a('string'); + * + * `.a` can also be used as a language chain to improve the readability of + * your assertions. + * + * expect({b: 2}).to.have.a.property('b'); + * + * The alias `.an` can be used interchangeably with `.a`. * * @name a * @alias an * @param {String} type - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -456,7 +665,7 @@ module.exports = function (chai, _) { , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; this.assert( - type === _.type(obj) + type === _.type(obj).toLowerCase() , 'expected #{this} to be ' + article + type , 'expected #{this} not to be ' + article + type ); @@ -466,60 +675,272 @@ module.exports = function (chai, _) { Assertion.addChainableMethod('a', an); /** - * ### .include(value) + * ### .include(val[, msg]) + * + * When the target is a string, `.include` asserts that the given string `val` + * is a substring of the target. + * + * expect('foobar').to.include('foo'); + * + * When the target is an array, `.include` asserts that the given `val` is a + * member of the target. + * + * expect([1, 2, 3]).to.include(2); + * + * When the target is an object, `.include` asserts that the given object + * `val`'s properties are a subset of the target's properties. + * + * expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2}); + * + * When the target is a Set or WeakSet, `.include` asserts that the given `val` is a + * member of the target. SameValueZero equality algorithm is used. + * + * expect(new Set([1, 2])).to.include(2); + * + * When the target is a Map, `.include` asserts that the given `val` is one of + * the values of the target. SameValueZero equality algorithm is used. + * + * expect(new Map([['a', 1], ['b', 2]])).to.include(2); + * + * Because `.include` does different things based on the target's type, it's + * important to check the target's type before using `.include`. See the `.a` + * doc for info on testing a target's type. + * + * expect([1, 2, 3]).to.be.an('array').that.includes(2); + * + * By default, strict (`===`) equality is used to compare array members and + * object properties. Add `.deep` earlier in the chain to use deep equality + * instead (WeakSet targets are not supported). See the `deep-eql` project + * page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql. + * + * // Target array deeply (but not strictly) includes `{a: 1}` + * expect([{a: 1}]).to.deep.include({a: 1}); + * expect([{a: 1}]).to.not.include({a: 1}); + * + * // Target object deeply (but not strictly) includes `x: {a: 1}` + * expect({x: {a: 1}}).to.deep.include({x: {a: 1}}); + * expect({x: {a: 1}}).to.not.include({x: {a: 1}}); + * + * By default, all of the target's properties are searched when working with + * objects. This includes properties that are inherited and/or non-enumerable. + * Add `.own` earlier in the chain to exclude the target's inherited + * properties from the search. + * + * Object.prototype.b = 2; * - * The `include` and `contain` assertions can be used as either property - * based language chains or as methods to assert the inclusion of an object - * in an array or a substring in a string. When used as language chains, - * they toggle the `contains` flag for the `keys` assertion. + * expect({a: 1}).to.own.include({a: 1}); + * expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2}); * - * expect([1,2,3]).to.include(2); - * expect('foobar').to.contain('foo'); - * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); + * Note that a target object is always only searched for `val`'s own + * enumerable properties. + * + * `.deep` and `.own` can be combined. + * + * expect({a: {b: 2}}).to.deep.own.include({a: {b: 2}}); + * + * Add `.nested` earlier in the chain to enable dot- and bracket-notation when + * referencing nested properties. + * + * expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'}); + * + * If `.` or `[]` are part of an actual property name, they can be escaped by + * adding two backslashes before them. + * + * expect({'.a': {'[b]': 2}}).to.nested.include({'\\.a.\\[b\\]': 2}); + * + * `.deep` and `.nested` can be combined. + * + * expect({a: {b: [{c: 3}]}}).to.deep.nested.include({'a.b[0]': {c: 3}}); + * + * `.own` and `.nested` cannot be combined. + * + * Add `.not` earlier in the chain to negate `.include`. + * + * expect('foobar').to.not.include('taco'); + * expect([1, 2, 3]).to.not.include(4); + * + * However, it's dangerous to negate `.include` when the target is an object. + * The problem is that it creates uncertain expectations by asserting that the + * target object doesn't have all of `val`'s key/value pairs but may or may + * not have some of them. It's often best to identify the exact output that's + * expected, and then write an assertion that only accepts that exact output. + * + * When the target object isn't even expected to have `val`'s keys, it's + * often best to assert exactly that. + * + * expect({c: 3}).to.not.have.any.keys('a', 'b'); // Recommended + * expect({c: 3}).to.not.include({a: 1, b: 2}); // Not recommended + * + * When the target object is expected to have `val`'s keys, it's often best to + * assert that each of the properties has its expected value, rather than + * asserting that each property doesn't have one of many unexpected values. + * + * expect({a: 3, b: 4}).to.include({a: 3, b: 4}); // Recommended + * expect({a: 3, b: 4}).to.not.include({a: 1, b: 2}); // Not recommended + * + * `.include` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect([1, 2, 3]).to.include(4, 'nooo why fail??'); + * expect([1, 2, 3], 'nooo why fail??').to.include(4); + * + * `.include` can also be used as a language chain, causing all `.members` and + * `.keys` assertions that follow in the chain to require the target to be a + * superset of the expected set, rather than an identical set. Note that + * `.members` ignores duplicates in the subset when `.include` is added. + * + * // Target object's keys are a superset of ['a', 'b'] but not identical + * expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b'); + * expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b'); + * + * // Target array is a superset of [1, 2] but not identical + * expect([1, 2, 3]).to.include.members([1, 2]); + * expect([1, 2, 3]).to.not.have.members([1, 2]); + * + * // Duplicates in the subset are ignored + * expect([1, 2, 3]).to.include.members([1, 2, 2, 2]); + * + * Note that adding `.any` earlier in the chain causes the `.keys` assertion + * to ignore `.include`. + * + * // Both assertions are identical + * expect({a: 1}).to.include.any.keys('a', 'b'); + * expect({a: 1}).to.have.any.keys('a', 'b'); + * + * The aliases `.includes`, `.contain`, and `.contains` can be used + * interchangeably with `.include`. * * @name include * @alias contain * @alias includes * @alias contains - * @param {Object|String|Number} obj - * @param {String} message _optional_ + * @param {Mixed} val + * @param {String} msg _optional_ * @namespace BDD * @api public */ + function SameValueZero(a, b) { + return (_.isNaN(a) && _.isNaN(b)) || a === b; + } + function includeChainingBehavior () { flag(this, 'contains', true); } function include (val, msg) { - _.expectTypes(this, ['array', 'object', 'string']); - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - var expected = false; - if (_.type(obj) === 'array' && _.type(val) === 'object') { - for (var i in obj) { - if (_.eql(obj[i], val)) { - expected = true; - break; + var obj = flag(this, 'object') + , objType = _.type(obj).toLowerCase() + , flagMsg = flag(this, 'message') + , negate = flag(this, 'negate') + , ssfi = flag(this, 'ssfi') + , isDeep = flag(this, 'deep') + , descriptor = isDeep ? 'deep ' : ''; + + flagMsg = flagMsg ? flagMsg + ': ' : ''; + + var included = false; + + switch (objType) { + case 'string': + included = obj.indexOf(val) !== -1; + break; + + case 'weakset': + if (isDeep) { + throw new AssertionError( + flagMsg + 'unable to use .deep.include with WeakSet', + undefined, + ssfi + ); + } + + included = obj.has(val); + break; + + case 'map': + var isEql = isDeep ? _.eql : SameValueZero; + obj.forEach(function (item) { + included = included || isEql(item, val); + }); + break; + + case 'set': + if (isDeep) { + obj.forEach(function (item) { + included = included || _.eql(item, val); + }); + } else { + included = obj.has(val); + } + break; + + case 'array': + if (isDeep) { + included = obj.some(function (item) { + return _.eql(item, val); + }) + } else { + included = obj.indexOf(val) !== -1; + } + break; + + default: + // This block is for asserting a subset of properties in an object. + // `_.expectTypes` isn't used here because `.include` should work with + // objects with a custom `@@toStringTag`. + if (val !== Object(val)) { + throw new AssertionError( + flagMsg + 'object tested must be an array, a map, an object,' + + ' a set, a string, or a weakset, but ' + objType + ' given', + undefined, + ssfi + ); + } + + var props = Object.keys(val) + , firstErr = null + , numErrs = 0; + + props.forEach(function (prop) { + var propAssertion = new Assertion(obj); + _.transferFlags(this, propAssertion, true); + flag(propAssertion, 'lockSsfi', true); + + if (!negate || props.length === 1) { + propAssertion.property(prop, val[prop]); + return; + } + + try { + propAssertion.property(prop, val[prop]); + } catch (err) { + if (!_.checkError.compatibleConstructor(err, AssertionError)) { + throw err; + } + if (firstErr === null) firstErr = err; + numErrs++; + } + }, this); + + // When validating .not.include with multiple properties, we only want + // to throw an assertion error if all of the properties are included, + // in which case we throw the first property assertion error that we + // encountered. + if (negate && props.length > 1 && numErrs === props.length) { + throw firstErr; } - } - } else if (_.type(val) === 'object') { - if (!flag(this, 'negate')) { - for (var k in val) new Assertion(obj).property(k, val[k]); return; - } - var subset = {}; - for (var k in val) subset[k] = obj[k]; - expected = _.eql(subset, val); - } else { - expected = (obj != undefined) && ~obj.indexOf(val); } + + // Assert inclusion in collection or substring in a string. this.assert( - expected - , 'expected #{this} to include ' + _.inspect(val) - , 'expected #{this} to not include ' + _.inspect(val)); + included + , 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val) + , 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val)); } Assertion.addChainableMethod('include', include, includeChainingBehavior); @@ -530,13 +951,33 @@ module.exports = function (chai, _) { /** * ### .ok * - * Asserts that the target is truthy. + * Asserts that the target is a truthy value (considered `true` in boolean context). + * However, it's often best to assert that the target is strictly (`===`) or + * deeply equal to its expected value. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.be.ok; // Not recommended + * + * expect(true).to.be.true; // Recommended + * expect(true).to.be.ok; // Not recommended + * + * Add `.not` earlier in the chain to negate `.ok`. * - * expect('everything').to.be.ok; - * expect(1).to.be.ok; - * expect(false).to.not.be.ok; - * expect(undefined).to.not.be.ok; - * expect(null).to.not.be.ok; + * expect(0).to.equal(0); // Recommended + * expect(0).to.not.be.ok; // Not recommended + * + * expect(false).to.be.false; // Recommended + * expect(false).to.not.be.ok; // Not recommended + * + * expect(null).to.be.null; // Recommended + * expect(null).to.not.be.ok; // Not recommended + * + * expect(undefined).to.be.undefined; // Recommended + * expect(undefined).to.not.be.ok; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(false, 'nooo why fail??').to.be.ok; * * @name ok * @namespace BDD @@ -553,10 +994,23 @@ module.exports = function (chai, _) { /** * ### .true * - * Asserts that the target is `true`. + * Asserts that the target is strictly (`===`) equal to `true`. * * expect(true).to.be.true; - * expect(1).to.not.be.true; + * + * Add `.not` earlier in the chain to negate `.true`. However, it's often best + * to assert that the target is equal to its expected value, rather than not + * equal to `true`. + * + * expect(false).to.be.false; // Recommended + * expect(false).to.not.be.true; // Not recommended + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.true; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(false, 'nooo why fail??').to.be.true; * * @name true * @namespace BDD @@ -568,17 +1022,30 @@ module.exports = function (chai, _) { true === flag(this, 'object') , 'expected #{this} to be true' , 'expected #{this} to be false' - , this.negate ? false : true + , flag(this, 'negate') ? false : true ); }); /** * ### .false * - * Asserts that the target is `false`. + * Asserts that the target is strictly (`===`) equal to `false`. * * expect(false).to.be.false; - * expect(0).to.not.be.false; + * + * Add `.not` earlier in the chain to negate `.false`. However, it's often + * best to assert that the target is equal to its expected value, rather than + * not equal to `false`. + * + * expect(true).to.be.true; // Recommended + * expect(true).to.not.be.false; // Not recommended + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.false; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(true, 'nooo why fail??').to.be.false; * * @name false * @namespace BDD @@ -590,17 +1057,27 @@ module.exports = function (chai, _) { false === flag(this, 'object') , 'expected #{this} to be false' , 'expected #{this} to be true' - , this.negate ? true : false + , flag(this, 'negate') ? true : false ); }); /** * ### .null * - * Asserts that the target is `null`. + * Asserts that the target is strictly (`===`) equal to `null`. * * expect(null).to.be.null; - * expect(undefined).to.not.be.null; + * + * Add `.not` earlier in the chain to negate `.null`. However, it's often best + * to assert that the target is equal to its expected value, rather than not + * equal to `null`. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.null; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(42, 'nooo why fail??').to.be.null; * * @name null * @namespace BDD @@ -618,10 +1095,20 @@ module.exports = function (chai, _) { /** * ### .undefined * - * Asserts that the target is `undefined`. + * Asserts that the target is strictly (`===`) equal to `undefined`. * * expect(undefined).to.be.undefined; - * expect(null).to.not.be.undefined; + * + * Add `.not` earlier in the chain to negate `.undefined`. However, it's often + * best to assert that the target is equal to its expected value, rather than + * not equal to `undefined`. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.undefined; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(42, 'nooo why fail??').to.be.undefined; * * @name undefined * @namespace BDD @@ -638,10 +1125,21 @@ module.exports = function (chai, _) { /** * ### .NaN - * Asserts that the target is `NaN`. * - * expect('foo').to.be.NaN; - * expect(4).not.to.be.NaN; + * Asserts that the target is exactly `NaN`. + * + * expect(NaN).to.be.NaN; + * + * Add `.not` earlier in the chain to negate `.NaN`. However, it's often best + * to assert that the target is equal to its expected value, rather than not + * equal to `NaN`. + * + * expect('foo').to.equal('foo'); // Recommended + * expect('foo').to.not.be.NaN; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(42, 'nooo why fail??').to.be.NaN; * * @name NaN * @namespace BDD @@ -650,7 +1148,7 @@ module.exports = function (chai, _) { Assertion.addProperty('NaN', function () { this.assert( - isNaN(flag(this, 'object')) + _.isNaN(flag(this, 'object')) , 'expected #{this} to be NaN' , 'expected #{this} not to be NaN' ); @@ -659,15 +1157,27 @@ module.exports = function (chai, _) { /** * ### .exist * - * Asserts that the target is neither `null` nor `undefined`. + * Asserts that the target is not strictly (`===`) equal to either `null` or + * `undefined`. However, it's often best to assert that the target is equal to + * its expected value. * - * var foo = 'hi' - * , bar = null - * , baz; + * expect(1).to.equal(1); // Recommended + * expect(1).to.exist; // Not recommended + * + * expect(0).to.equal(0); // Recommended + * expect(0).to.exist; // Not recommended + * + * Add `.not` earlier in the chain to negate `.exist`. * - * expect(foo).to.exist; - * expect(bar).to.not.exist; - * expect(baz).to.not.exist; + * expect(null).to.be.null; // Recommended + * expect(null).to.not.exist; // Not recommended + * + * expect(undefined).to.be.undefined; // Recommended + * expect(undefined).to.not.exist; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(null, 'nooo why fail??').to.exist; * * @name exist * @namespace BDD @@ -675,42 +1185,103 @@ module.exports = function (chai, _) { */ Assertion.addProperty('exist', function () { + var val = flag(this, 'object'); this.assert( - null != flag(this, 'object') + val !== null && val !== undefined , 'expected #{this} to exist' , 'expected #{this} to not exist' ); }); - /** * ### .empty * - * Asserts that the target's length is `0`. For arrays and strings, it checks - * the `length` property. For objects, it gets the count of - * enumerable keys. + * When the target is a string or array, `.empty` asserts that the target's + * `length` property is strictly (`===`) equal to `0`. * * expect([]).to.be.empty; * expect('').to.be.empty; + * + * When the target is a map or set, `.empty` asserts that the target's `size` + * property is strictly equal to `0`. + * + * expect(new Set()).to.be.empty; + * expect(new Map()).to.be.empty; + * + * When the target is a non-function object, `.empty` asserts that the target + * doesn't have any own enumerable properties. Properties with Symbol-based + * keys are excluded from the count. + * * expect({}).to.be.empty; * + * Because `.empty` does different things based on the target's type, it's + * important to check the target's type before using `.empty`. See the `.a` + * doc for info on testing a target's type. + * + * expect([]).to.be.an('array').that.is.empty; + * + * Add `.not` earlier in the chain to negate `.empty`. However, it's often + * best to assert that the target contains its expected number of values, + * rather than asserting that it's not empty. + * + * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended + * expect([1, 2, 3]).to.not.be.empty; // Not recommended + * + * expect(new Set([1, 2, 3])).to.have.property('size', 3); // Recommended + * expect(new Set([1, 2, 3])).to.not.be.empty; // Not recommended + * + * expect(Object.keys({a: 1})).to.have.lengthOf(1); // Recommended + * expect({a: 1}).to.not.be.empty; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect([1, 2, 3], 'nooo why fail??').to.be.empty; + * * @name empty * @namespace BDD * @api public */ Assertion.addProperty('empty', function () { - var obj = flag(this, 'object') - , expected = obj; + var val = flag(this, 'object') + , ssfi = flag(this, 'ssfi') + , flagMsg = flag(this, 'message') + , itemsCount; + + flagMsg = flagMsg ? flagMsg + ': ' : ''; - if (Array.isArray(obj) || 'string' === typeof object) { - expected = obj.length; - } else if (typeof obj === 'object') { - expected = Object.keys(obj).length; + switch (_.type(val).toLowerCase()) { + case 'array': + case 'string': + itemsCount = val.length; + break; + case 'map': + case 'set': + itemsCount = val.size; + break; + case 'weakmap': + case 'weakset': + throw new AssertionError( + flagMsg + '.empty was passed a weak collection', + undefined, + ssfi + ); + case 'function': + var msg = flagMsg + '.empty was passed a function ' + _.getName(val); + throw new AssertionError(msg.trim(), undefined, ssfi); + default: + if (val !== Object(val)) { + throw new AssertionError( + flagMsg + '.empty was passed non-string primitive ' + _.inspect(val), + undefined, + ssfi + ); + } + itemsCount = Object.keys(val).length; } this.assert( - !expected + 0 === itemsCount , 'expected #{this} to be empty' , 'expected #{this} not to be empty' ); @@ -719,12 +1290,27 @@ module.exports = function (chai, _) { /** * ### .arguments * - * Asserts that the target is an arguments object. + * Asserts that the target is an `arguments` object. * * function test () { * expect(arguments).to.be.arguments; * } * + * test(); + * + * Add `.not` earlier in the chain to negate `.arguments`. However, it's often + * best to assert which type the target is expected to be, rather than + * asserting that its not an `arguments` object. + * + * expect('foo').to.be.a('string'); // Recommended + * expect('foo').to.not.be.arguments; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect({}, 'nooo why fail??').to.be.arguments; + * + * The alias `.Arguments` can be used interchangeably with `.arguments`. + * * @name arguments * @alias Arguments * @namespace BDD @@ -733,9 +1319,9 @@ module.exports = function (chai, _) { function checkArguments () { var obj = flag(this, 'object') - , type = Object.prototype.toString.call(obj); + , type = _.type(obj); this.assert( - '[object Arguments]' === type + 'Arguments' === type , 'expected #{this} to be arguments but got ' + type , 'expected #{this} to not be arguments' ); @@ -745,24 +1331,46 @@ module.exports = function (chai, _) { Assertion.addProperty('Arguments', checkArguments); /** - * ### .equal(value) + * ### .equal(val[, msg]) + * + * Asserts that the target is strictly (`===`) equal to the given `val`. + * + * expect(1).to.equal(1); + * expect('foo').to.equal('foo'); + * + * Add `.deep` earlier in the chain to use deep equality instead. See the + * `deep-eql` project page for info on the deep equality algorithm: + * https://github.com/chaijs/deep-eql. * - * Asserts that the target is strictly equal (`===`) to `value`. - * Alternately, if the `deep` flag is set, asserts that - * the target is deeply equal to `value`. + * // Target object deeply (but not strictly) equals `{a: 1}` + * expect({a: 1}).to.deep.equal({a: 1}); + * expect({a: 1}).to.not.equal({a: 1}); * - * expect('hello').to.equal('hello'); - * expect(42).to.equal(42); - * expect(1).to.not.equal(true); - * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); - * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); + * // Target array deeply (but not strictly) equals `[1, 2]` + * expect([1, 2]).to.deep.equal([1, 2]); + * expect([1, 2]).to.not.equal([1, 2]); + * + * Add `.not` earlier in the chain to negate `.equal`. However, it's often + * best to assert that the target is equal to its expected value, rather than + * not equal to one of countless unexpected values. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.equal(2); // Not recommended + * + * `.equal` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect(1).to.equal(2, 'nooo why fail??'); + * expect(1, 'nooo why fail??').to.equal(2); + * + * The aliases `.equals` and `eq` can be used interchangeably with `.equal`. * * @name equal * @alias equals * @alias eq - * @alias deep.equal - * @param {Mixed} value - * @param {String} message _optional_ + * @param {Mixed} val + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -771,7 +1379,10 @@ module.exports = function (chai, _) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object'); if (flag(this, 'deep')) { - return this.eql(val); + var prevLockSsfi = flag(this, 'lockSsfi'); + flag(this, 'lockSsfi', true); + this.eql(val); + flag(this, 'lockSsfi', prevLockSsfi); } else { this.assert( val === obj @@ -789,17 +1400,42 @@ module.exports = function (chai, _) { Assertion.addMethod('eq', assertEqual); /** - * ### .eql(value) + * ### .eql(obj[, msg]) + * + * Asserts that the target is deeply equal to the given `obj`. See the + * `deep-eql` project page for info on the deep equality algorithm: + * https://github.com/chaijs/deep-eql. * - * Asserts that the target is deeply equal to `value`. + * // Target object is deeply (but not strictly) equal to {a: 1} + * expect({a: 1}).to.eql({a: 1}).but.not.equal({a: 1}); * - * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); - * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); + * // Target array is deeply (but not strictly) equal to [1, 2] + * expect([1, 2]).to.eql([1, 2]).but.not.equal([1, 2]); + * + * Add `.not` earlier in the chain to negate `.eql`. However, it's often best + * to assert that the target is deeply equal to its expected value, rather + * than not deeply equal to one of countless unexpected values. + * + * expect({a: 1}).to.eql({a: 1}); // Recommended + * expect({a: 1}).to.not.eql({b: 2}); // Not recommended + * + * `.eql` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect({a: 1}).to.eql({b: 2}, 'nooo why fail??'); + * expect({a: 1}, 'nooo why fail??').to.eql({b: 2}); + * + * The alias `.eqls` can be used interchangeably with `.eql`. + * + * The `.deep.equal` assertion is almost identical to `.eql` but with one + * difference: `.deep.equal` causes deep equality comparisons to also be used + * for any other assertions that follow in the chain. * * @name eql * @alias eqls - * @param {Mixed} value - * @param {String} message _optional_ + * @param {Mixed} obj + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -820,47 +1456,101 @@ module.exports = function (chai, _) { Assertion.addMethod('eqls', assertEql); /** - * ### .above(value) + * ### .above(n[, msg]) * - * Asserts that the target is greater than `value`. + * Asserts that the target is a number or a date greater than the given number or date `n` respectively. + * However, it's often best to assert that the target is equal to its expected + * value. * - * expect(10).to.be.above(5); + * expect(2).to.equal(2); // Recommended + * expect(2).to.be.above(1); // Not recommended * - * Can also be used in conjunction with `length` to - * assert a minimum length. The benefit being a - * more informative error message than if the length - * was supplied directly. + * Add `.lengthOf` earlier in the chain to assert that the target's `length` + * or `size` is greater than the given number `n`. * - * expect('foo').to.have.length.above(2); - * expect([ 1, 2, 3 ]).to.have.length.above(2); + * expect('foo').to.have.lengthOf(3); // Recommended + * expect('foo').to.have.lengthOf.above(2); // Not recommended + * + * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended + * expect([1, 2, 3]).to.have.lengthOf.above(2); // Not recommended + * + * Add `.not` earlier in the chain to negate `.above`. + * + * expect(2).to.equal(2); // Recommended + * expect(1).to.not.be.above(2); // Not recommended + * + * `.above` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect(1).to.be.above(2, 'nooo why fail??'); + * expect(1, 'nooo why fail??').to.be.above(2); + * + * The aliases `.gt` and `.greaterThan` can be used interchangeably with + * `.above`. * * @name above * @alias gt * @alias greaterThan - * @param {Number} value - * @param {String} message _optional_ + * @param {Number} n + * @param {String} msg _optional_ * @namespace BDD * @api public */ function assertAbove (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; - this.assert( - len > n - , 'expected #{this} to have a length above #{exp} but got #{act}' - , 'expected #{this} to not have a length above #{exp}' - , n - , len - ); + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength') + , flagMsg = flag(this, 'message') + , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') + , ssfi = flag(this, 'ssfi') + , objType = _.type(obj).toLowerCase() + , nType = _.type(n).toLowerCase() + , errorMessage + , shouldThrow = true; + + if (doLength && objType !== 'map' && objType !== 'set') { + new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); + } + + if (!doLength && (objType === 'date' && nType !== 'date')) { + errorMessage = msgPrefix + 'the argument to above must be a date'; + } else if (nType !== 'number' && (doLength || objType === 'number')) { + errorMessage = msgPrefix + 'the argument to above must be a number'; + } else if (!doLength && (objType !== 'date' && objType !== 'number')) { + var printObj = (objType === 'string') ? "'" + obj + "'" : obj; + errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; } else { - this.assert( + shouldThrow = false; + } + + if (shouldThrow) { + throw new AssertionError(errorMessage, undefined, ssfi); + } + + if (doLength) { + var descriptor = 'length' + , itemsCount; + if (objType === 'map' || objType === 'set') { + descriptor = 'size'; + itemsCount = obj.size; + } else { + itemsCount = obj.length; + } + this.assert( + itemsCount > n + , 'expected #{this} to have a ' + descriptor + ' above #{exp} but got #{act}' + , 'expected #{this} to not have a ' + descriptor + ' above #{exp}' + , n + , itemsCount + ); + } else { + this.assert( obj > n - , 'expected #{this} to be above ' + n - , 'expected #{this} to be at most ' + n + , 'expected #{this} to be above #{exp}' + , 'expected #{this} to be at most #{exp}' + , n ); } } @@ -870,46 +1560,100 @@ module.exports = function (chai, _) { Assertion.addMethod('greaterThan', assertAbove); /** - * ### .least(value) + * ### .least(n[, msg]) + * + * Asserts that the target is a number or a date greater than or equal to the given + * number or date `n` respectively. However, it's often best to assert that the target is equal to + * its expected value. + * + * expect(2).to.equal(2); // Recommended + * expect(2).to.be.at.least(1); // Not recommended + * expect(2).to.be.at.least(2); // Not recommended + * + * Add `.lengthOf` earlier in the chain to assert that the target's `length` + * or `size` is greater than or equal to the given number `n`. + * + * expect('foo').to.have.lengthOf(3); // Recommended + * expect('foo').to.have.lengthOf.at.least(2); // Not recommended * - * Asserts that the target is greater than or equal to `value`. + * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended + * expect([1, 2, 3]).to.have.lengthOf.at.least(2); // Not recommended * - * expect(10).to.be.at.least(10); + * Add `.not` earlier in the chain to negate `.least`. * - * Can also be used in conjunction with `length` to - * assert a minimum length. The benefit being a - * more informative error message than if the length - * was supplied directly. + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.at.least(2); // Not recommended * - * expect('foo').to.have.length.of.at.least(2); - * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); + * `.least` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect(1).to.be.at.least(2, 'nooo why fail??'); + * expect(1, 'nooo why fail??').to.be.at.least(2); + * + * The alias `.gte` can be used interchangeably with `.least`. * * @name least * @alias gte - * @param {Number} value - * @param {String} message _optional_ + * @param {Number} n + * @param {String} msg _optional_ * @namespace BDD * @api public */ function assertLeast (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength') + , flagMsg = flag(this, 'message') + , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') + , ssfi = flag(this, 'ssfi') + , objType = _.type(obj).toLowerCase() + , nType = _.type(n).toLowerCase() + , errorMessage + , shouldThrow = true; + + if (doLength && objType !== 'map' && objType !== 'set') { + new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); + } + + if (!doLength && (objType === 'date' && nType !== 'date')) { + errorMessage = msgPrefix + 'the argument to least must be a date'; + } else if (nType !== 'number' && (doLength || objType === 'number')) { + errorMessage = msgPrefix + 'the argument to least must be a number'; + } else if (!doLength && (objType !== 'date' && objType !== 'number')) { + var printObj = (objType === 'string') ? "'" + obj + "'" : obj; + errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; + } else { + shouldThrow = false; + } + + if (shouldThrow) { + throw new AssertionError(errorMessage, undefined, ssfi); + } + + if (doLength) { + var descriptor = 'length' + , itemsCount; + if (objType === 'map' || objType === 'set') { + descriptor = 'size'; + itemsCount = obj.size; + } else { + itemsCount = obj.length; + } this.assert( - len >= n - , 'expected #{this} to have a length at least #{exp} but got #{act}' - , 'expected #{this} to have a length below #{exp}' + itemsCount >= n + , 'expected #{this} to have a ' + descriptor + ' at least #{exp} but got #{act}' + , 'expected #{this} to have a ' + descriptor + ' below #{exp}' , n - , len + , itemsCount ); } else { this.assert( obj >= n - , 'expected #{this} to be at least ' + n - , 'expected #{this} to be below ' + n + , 'expected #{this} to be at least #{exp}' + , 'expected #{this} to be below #{exp}' + , n ); } } @@ -918,47 +1662,101 @@ module.exports = function (chai, _) { Assertion.addMethod('gte', assertLeast); /** - * ### .below(value) + * ### .below(n[, msg]) * - * Asserts that the target is less than `value`. + * Asserts that the target is a number or a date less than the given number or date `n` respectively. + * However, it's often best to assert that the target is equal to its expected + * value. * - * expect(5).to.be.below(10); + * expect(1).to.equal(1); // Recommended + * expect(1).to.be.below(2); // Not recommended * - * Can also be used in conjunction with `length` to - * assert a maximum length. The benefit being a - * more informative error message than if the length - * was supplied directly. + * Add `.lengthOf` earlier in the chain to assert that the target's `length` + * or `size` is less than the given number `n`. * - * expect('foo').to.have.length.below(4); - * expect([ 1, 2, 3 ]).to.have.length.below(4); + * expect('foo').to.have.lengthOf(3); // Recommended + * expect('foo').to.have.lengthOf.below(4); // Not recommended + * + * expect([1, 2, 3]).to.have.length(3); // Recommended + * expect([1, 2, 3]).to.have.lengthOf.below(4); // Not recommended + * + * Add `.not` earlier in the chain to negate `.below`. + * + * expect(2).to.equal(2); // Recommended + * expect(2).to.not.be.below(1); // Not recommended + * + * `.below` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect(2).to.be.below(1, 'nooo why fail??'); + * expect(2, 'nooo why fail??').to.be.below(1); + * + * The aliases `.lt` and `.lessThan` can be used interchangeably with + * `.below`. * * @name below * @alias lt * @alias lessThan - * @param {Number} value - * @param {String} message _optional_ + * @param {Number} n + * @param {String} msg _optional_ * @namespace BDD * @api public */ function assertBelow (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength') + , flagMsg = flag(this, 'message') + , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') + , ssfi = flag(this, 'ssfi') + , objType = _.type(obj).toLowerCase() + , nType = _.type(n).toLowerCase() + , errorMessage + , shouldThrow = true; + + if (doLength && objType !== 'map' && objType !== 'set') { + new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); + } + + if (!doLength && (objType === 'date' && nType !== 'date')) { + errorMessage = msgPrefix + 'the argument to below must be a date'; + } else if (nType !== 'number' && (doLength || objType === 'number')) { + errorMessage = msgPrefix + 'the argument to below must be a number'; + } else if (!doLength && (objType !== 'date' && objType !== 'number')) { + var printObj = (objType === 'string') ? "'" + obj + "'" : obj; + errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; + } else { + shouldThrow = false; + } + + if (shouldThrow) { + throw new AssertionError(errorMessage, undefined, ssfi); + } + + if (doLength) { + var descriptor = 'length' + , itemsCount; + if (objType === 'map' || objType === 'set') { + descriptor = 'size'; + itemsCount = obj.size; + } else { + itemsCount = obj.length; + } this.assert( - len < n - , 'expected #{this} to have a length below #{exp} but got #{act}' - , 'expected #{this} to not have a length below #{exp}' + itemsCount < n + , 'expected #{this} to have a ' + descriptor + ' below #{exp} but got #{act}' + , 'expected #{this} to not have a ' + descriptor + ' below #{exp}' , n - , len + , itemsCount ); } else { this.assert( obj < n - , 'expected #{this} to be below ' + n - , 'expected #{this} to be at least ' + n + , 'expected #{this} to be below #{exp}' + , 'expected #{this} to be at least #{exp}' + , n ); } } @@ -968,46 +1766,100 @@ module.exports = function (chai, _) { Assertion.addMethod('lessThan', assertBelow); /** - * ### .most(value) + * ### .most(n[, msg]) + * + * Asserts that the target is a number or a date less than or equal to the given number + * or date `n` respectively. However, it's often best to assert that the target is equal to its + * expected value. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.be.at.most(2); // Not recommended + * expect(1).to.be.at.most(1); // Not recommended + * + * Add `.lengthOf` earlier in the chain to assert that the target's `length` + * or `size` is less than or equal to the given number `n`. + * + * expect('foo').to.have.lengthOf(3); // Recommended + * expect('foo').to.have.lengthOf.at.most(4); // Not recommended * - * Asserts that the target is less than or equal to `value`. + * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended + * expect([1, 2, 3]).to.have.lengthOf.at.most(4); // Not recommended * - * expect(5).to.be.at.most(5); + * Add `.not` earlier in the chain to negate `.most`. * - * Can also be used in conjunction with `length` to - * assert a maximum length. The benefit being a - * more informative error message than if the length - * was supplied directly. + * expect(2).to.equal(2); // Recommended + * expect(2).to.not.be.at.most(1); // Not recommended * - * expect('foo').to.have.length.of.at.most(4); - * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); + * `.most` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect(2).to.be.at.most(1, 'nooo why fail??'); + * expect(2, 'nooo why fail??').to.be.at.most(1); + * + * The alias `.lte` can be used interchangeably with `.most`. * * @name most * @alias lte - * @param {Number} value - * @param {String} message _optional_ + * @param {Number} n + * @param {String} msg _optional_ * @namespace BDD * @api public */ function assertMost (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength') + , flagMsg = flag(this, 'message') + , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') + , ssfi = flag(this, 'ssfi') + , objType = _.type(obj).toLowerCase() + , nType = _.type(n).toLowerCase() + , errorMessage + , shouldThrow = true; + + if (doLength && objType !== 'map' && objType !== 'set') { + new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); + } + + if (!doLength && (objType === 'date' && nType !== 'date')) { + errorMessage = msgPrefix + 'the argument to most must be a date'; + } else if (nType !== 'number' && (doLength || objType === 'number')) { + errorMessage = msgPrefix + 'the argument to most must be a number'; + } else if (!doLength && (objType !== 'date' && objType !== 'number')) { + var printObj = (objType === 'string') ? "'" + obj + "'" : obj; + errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; + } else { + shouldThrow = false; + } + + if (shouldThrow) { + throw new AssertionError(errorMessage, undefined, ssfi); + } + + if (doLength) { + var descriptor = 'length' + , itemsCount; + if (objType === 'map' || objType === 'set') { + descriptor = 'size'; + itemsCount = obj.size; + } else { + itemsCount = obj.length; + } this.assert( - len <= n - , 'expected #{this} to have a length at most #{exp} but got #{act}' - , 'expected #{this} to have a length above #{exp}' + itemsCount <= n + , 'expected #{this} to have a ' + descriptor + ' at most #{exp} but got #{act}' + , 'expected #{this} to have a ' + descriptor + ' above #{exp}' , n - , len + , itemsCount ); } else { this.assert( obj <= n - , 'expected #{this} to be at most ' + n - , 'expected #{this} to be above ' + n + , 'expected #{this} to be at most #{exp}' + , 'expected #{this} to be above #{exp}' + , n ); } } @@ -1016,24 +1868,44 @@ module.exports = function (chai, _) { Assertion.addMethod('lte', assertMost); /** - * ### .within(start, finish) + * ### .within(start, finish[, msg]) * - * Asserts that the target is within a range. + * Asserts that the target is a number or a date greater than or equal to the given + * number or date `start`, and less than or equal to the given number or date `finish` respectively. + * However, it's often best to assert that the target is equal to its expected + * value. * - * expect(7).to.be.within(5,10); + * expect(2).to.equal(2); // Recommended + * expect(2).to.be.within(1, 3); // Not recommended + * expect(2).to.be.within(2, 3); // Not recommended + * expect(2).to.be.within(1, 2); // Not recommended * - * Can also be used in conjunction with `length` to - * assert a length range. The benefit being a - * more informative error message than if the length - * was supplied directly. + * Add `.lengthOf` earlier in the chain to assert that the target's `length` + * or `size` is greater than or equal to the given number `start`, and less + * than or equal to the given number `finish`. * - * expect('foo').to.have.length.within(2,4); - * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * expect('foo').to.have.lengthOf(3); // Recommended + * expect('foo').to.have.lengthOf.within(2, 4); // Not recommended + * + * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended + * expect([1, 2, 3]).to.have.lengthOf.within(2, 4); // Not recommended + * + * Add `.not` earlier in the chain to negate `.within`. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.within(2, 4); // Not recommended + * + * `.within` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect(4).to.be.within(1, 3, 'nooo why fail??'); + * expect(4, 'nooo why fail??').to.be.within(1, 3); * * @name within - * @param {Number} start lowerbound inclusive - * @param {Number} finish upperbound inclusive - * @param {String} message _optional_ + * @param {Number} start lower bound inclusive + * @param {Number} finish upper bound inclusive + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -1041,14 +1913,51 @@ module.exports = function (chai, _) { Assertion.addMethod('within', function (start, finish, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') - , range = start + '..' + finish; - if (flag(this, 'doLength')) { - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; + , doLength = flag(this, 'doLength') + , flagMsg = flag(this, 'message') + , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') + , ssfi = flag(this, 'ssfi') + , objType = _.type(obj).toLowerCase() + , startType = _.type(start).toLowerCase() + , finishType = _.type(finish).toLowerCase() + , errorMessage + , shouldThrow = true + , range = (startType === 'date' && finishType === 'date') + ? start.toUTCString() + '..' + finish.toUTCString() + : start + '..' + finish; + + if (doLength && objType !== 'map' && objType !== 'set') { + new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); + } + + if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) { + errorMessage = msgPrefix + 'the arguments to within must be dates'; + } else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) { + errorMessage = msgPrefix + 'the arguments to within must be numbers'; + } else if (!doLength && (objType !== 'date' && objType !== 'number')) { + var printObj = (objType === 'string') ? "'" + obj + "'" : obj; + errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; + } else { + shouldThrow = false; + } + + if (shouldThrow) { + throw new AssertionError(errorMessage, undefined, ssfi); + } + + if (doLength) { + var descriptor = 'length' + , itemsCount; + if (objType === 'map' || objType === 'set') { + descriptor = 'size'; + itemsCount = obj.size; + } else { + itemsCount = obj.length; + } this.assert( - len >= start && len <= finish - , 'expected #{this} to have a length within ' + range - , 'expected #{this} to not have a length within ' + range + itemsCount >= start && itemsCount <= finish + , 'expected #{this} to have a ' + descriptor + ' within ' + range + , 'expected #{this} to not have a ' + descriptor + ' within ' + range ); } else { this.assert( @@ -1060,19 +1969,39 @@ module.exports = function (chai, _) { }); /** - * ### .instanceof(constructor) + * ### .instanceof(constructor[, msg]) * - * Asserts that the target is an instance of `constructor`. + * Asserts that the target is an instance of the given `constructor`. * - * var Tea = function (name) { this.name = name; } - * , Chai = new Tea('chai'); + * function Cat () { } * - * expect(Chai).to.be.an.instanceof(Tea); - * expect([ 1, 2, 3 ]).to.be.instanceof(Array); + * expect(new Cat()).to.be.an.instanceof(Cat); + * expect([1, 2]).to.be.an.instanceof(Array); + * + * Add `.not` earlier in the chain to negate `.instanceof`. + * + * expect({a: 1}).to.not.be.an.instanceof(Array); + * + * `.instanceof` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect(1).to.be.an.instanceof(Array, 'nooo why fail??'); + * expect(1, 'nooo why fail??').to.be.an.instanceof(Array); + * + * Due to limitations in ES5, `.instanceof` may not always work as expected + * when using a transpiler such as Babel or TypeScript. In particular, it may + * produce unexpected results when subclassing built-in object such as + * `Array`, `Error`, and `Map`. See your transpiler's docs for details: + * + * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes)) + * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work)) + * + * The alias `.instanceOf` can be used interchangeably with `.instanceof`. * * @name instanceof * @param {Constructor} constructor - * @param {String} message _optional_ + * @param {String} msg _optional_ * @alias instanceOf * @namespace BDD * @api public @@ -1080,9 +2009,33 @@ module.exports = function (chai, _) { function assertInstanceOf (constructor, msg) { if (msg) flag(this, 'message', msg); + + var target = flag(this, 'object') + var ssfi = flag(this, 'ssfi'); + var flagMsg = flag(this, 'message'); + + try { + var isInstanceOf = target instanceof constructor; + } catch (err) { + if (err instanceof TypeError) { + flagMsg = flagMsg ? flagMsg + ': ' : ''; + throw new AssertionError( + flagMsg + 'The instanceof assertion needs a constructor but ' + + _.type(constructor) + ' was given.', + undefined, + ssfi + ); + } + throw err; + } + var name = _.getName(constructor); + if (name === null) { + name = 'an unnamed constructor'; + } + this.assert( - flag(this, 'object') instanceof constructor + isInstanceOf , 'expected #{this} to be an instance of ' + name , 'expected #{this} to not be an instance of ' + name ); @@ -1092,162 +2045,329 @@ module.exports = function (chai, _) { Assertion.addMethod('instanceOf', assertInstanceOf); /** - * ### .property(name, [value]) + * ### .property(name[, val[, msg]]) * - * Asserts that the target has a property `name`, optionally asserting that - * the value of that property is strictly equal to `value`. - * If the `deep` flag is set, you can use dot- and bracket-notation for deep - * references into objects and arrays. + * Asserts that the target has a property with the given key `name`. * - * // simple referencing - * var obj = { foo: 'bar' }; - * expect(obj).to.have.property('foo'); - * expect(obj).to.have.property('foo', 'bar'); + * expect({a: 1}).to.have.property('a'); * - * // deep referencing - * var deepObj = { - * green: { tea: 'matcha' } - * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] - * }; + * When `val` is provided, `.property` also asserts that the property's value + * is equal to the given `val`. + * + * expect({a: 1}).to.have.property('a', 1); + * + * By default, strict (`===`) equality is used. Add `.deep` earlier in the + * chain to use deep equality instead. See the `deep-eql` project page for + * info on the deep equality algorithm: https://github.com/chaijs/deep-eql. + * + * // Target object deeply (but not strictly) has property `x: {a: 1}` + * expect({x: {a: 1}}).to.have.deep.property('x', {a: 1}); + * expect({x: {a: 1}}).to.not.have.property('x', {a: 1}); + * + * The target's enumerable and non-enumerable properties are always included + * in the search. By default, both own and inherited properties are included. + * Add `.own` earlier in the chain to exclude inherited properties from the + * search. + * + * Object.prototype.b = 2; + * + * expect({a: 1}).to.have.own.property('a'); + * expect({a: 1}).to.have.own.property('a', 1); + * expect({a: 1}).to.have.property('b'); + * expect({a: 1}).to.not.have.own.property('b'); + * + * `.deep` and `.own` can be combined. + * + * expect({x: {a: 1}}).to.have.deep.own.property('x', {a: 1}); + * + * Add `.nested` earlier in the chain to enable dot- and bracket-notation when + * referencing nested properties. + * + * expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]'); + * expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]', 'y'); + * + * If `.` or `[]` are part of an actual property name, they can be escaped by + * adding two backslashes before them. + * + * expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\.a.\\[b\\]'); + * + * `.deep` and `.nested` can be combined. + * + * expect({a: {b: [{c: 3}]}}) + * .to.have.deep.nested.property('a.b[0]', {c: 3}); + * + * `.own` and `.nested` cannot be combined. + * + * Add `.not` earlier in the chain to negate `.property`. + * + * expect({a: 1}).to.not.have.property('b'); + * + * However, it's dangerous to negate `.property` when providing `val`. The + * problem is that it creates uncertain expectations by asserting that the + * target either doesn't have a property with the given key `name`, or that it + * does have a property with the given key `name` but its value isn't equal to + * the given `val`. It's often best to identify the exact output that's + * expected, and then write an assertion that only accepts that exact output. + * + * When the target isn't expected to have a property with the given key + * `name`, it's often best to assert exactly that. + * + * expect({b: 2}).to.not.have.property('a'); // Recommended + * expect({b: 2}).to.not.have.property('a', 1); // Not recommended + * + * When the target is expected to have a property with the given key `name`, + * it's often best to assert that the property has its expected value, rather + * than asserting that it doesn't have one of many unexpected values. * - * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); - * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); - * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); - * - * You can also use an array as the starting point of a `deep.property` - * assertion, or traverse nested arrays. - * - * var arr = [ - * [ 'chai', 'matcha', 'konacha' ] - * , [ { tea: 'chai' } - * , { tea: 'matcha' } - * , { tea: 'konacha' } ] - * ]; - * - * expect(arr).to.have.deep.property('[0][1]', 'matcha'); - * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); - * - * Furthermore, `property` changes the subject of the assertion - * to be the value of that property from the original object. This - * permits for further chainable assertions on that property. - * - * expect(obj).to.have.property('foo') - * .that.is.a('string'); - * expect(deepObj).to.have.property('green') - * .that.is.an('object') - * .that.deep.equals({ tea: 'matcha' }); - * expect(deepObj).to.have.property('teas') - * .that.is.an('array') - * .with.deep.property('[2]') - * .that.deep.equals({ tea: 'konacha' }); - * - * Note that dots and bracket in `name` must be backslash-escaped when - * the `deep` flag is set, while they must NOT be escaped when the `deep` - * flag is not set. - * - * // simple referencing - * var css = { '.link[target]': 42 }; - * expect(css).to.have.property('.link[target]', 42); - * - * // deep referencing - * var deepCss = { '.link': { '[target]': 42 }}; - * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * expect({a: 3}).to.have.property('a', 3); // Recommended + * expect({a: 3}).to.not.have.property('a', 1); // Not recommended + * + * `.property` changes the target of any assertions that follow in the chain + * to be the value of the property from the original target object. + * + * expect({a: 1}).to.have.property('a').that.is.a('number'); + * + * `.property` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. When not providing `val`, only use the + * second form. + * + * // Recommended + * expect({a: 1}).to.have.property('a', 2, 'nooo why fail??'); + * expect({a: 1}, 'nooo why fail??').to.have.property('a', 2); + * expect({a: 1}, 'nooo why fail??').to.have.property('b'); + * + * // Not recommended + * expect({a: 1}).to.have.property('b', undefined, 'nooo why fail??'); + * + * The above assertion isn't the same thing as not providing `val`. Instead, + * it's asserting that the target object has a `b` property that's equal to + * `undefined`. + * + * The assertions `.ownProperty` and `.haveOwnProperty` can be used + * interchangeably with `.own.property`. * * @name property - * @alias deep.property * @param {String} name - * @param {Mixed} value (optional) - * @param {String} message _optional_ + * @param {Mixed} val (optional) + * @param {String} msg _optional_ * @returns value of property for chaining * @namespace BDD * @api public */ - Assertion.addMethod('property', function (name, val, msg) { + function assertProperty (name, val, msg) { if (msg) flag(this, 'message', msg); - var isDeep = !!flag(this, 'deep') - , descriptor = isDeep ? 'deep property ' : 'property ' - , negate = flag(this, 'negate') + var isNested = flag(this, 'nested') + , isOwn = flag(this, 'own') + , flagMsg = flag(this, 'message') , obj = flag(this, 'object') - , pathInfo = isDeep ? _.getPathInfo(name, obj) : null - , hasProperty = isDeep - ? pathInfo.exists - : _.hasProperty(name, obj) - , value = isDeep - ? pathInfo.value - : obj[name]; - - if (negate && arguments.length > 1) { - if (undefined === value) { - msg = (msg != null) ? msg + ': ' : ''; - throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); + , ssfi = flag(this, 'ssfi') + , nameType = typeof name; + + flagMsg = flagMsg ? flagMsg + ': ' : ''; + + if (isNested) { + if (nameType !== 'string') { + throw new AssertionError( + flagMsg + 'the argument to property must be a string when using nested syntax', + undefined, + ssfi + ); } } else { + if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') { + throw new AssertionError( + flagMsg + 'the argument to property must be a string, number, or symbol', + undefined, + ssfi + ); + } + } + + if (isNested && isOwn) { + throw new AssertionError( + flagMsg + 'The "nested" and "own" flags cannot be combined.', + undefined, + ssfi + ); + } + + if (obj === null || obj === undefined) { + throw new AssertionError( + flagMsg + 'Target cannot be null or undefined.', + undefined, + ssfi + ); + } + + var isDeep = flag(this, 'deep') + , negate = flag(this, 'negate') + , pathInfo = isNested ? _.getPathInfo(obj, name) : null + , value = isNested ? pathInfo.value : obj[name]; + + var descriptor = ''; + if (isDeep) descriptor += 'deep '; + if (isOwn) descriptor += 'own '; + if (isNested) descriptor += 'nested '; + descriptor += 'property '; + + var hasProperty; + if (isOwn) hasProperty = Object.prototype.hasOwnProperty.call(obj, name); + else if (isNested) hasProperty = pathInfo.exists; + else hasProperty = _.hasProperty(obj, name); + + // When performing a negated assertion for both name and val, merely having + // a property with the given name isn't enough to cause the assertion to + // fail. It must both have a property with the given name, and the value of + // that property must equal the given val. Therefore, skip this assertion in + // favor of the next. + if (!negate || arguments.length === 1) { this.assert( hasProperty - , 'expected #{this} to have a ' + descriptor + _.inspect(name) + , 'expected #{this} to have ' + descriptor + _.inspect(name) , 'expected #{this} to not have ' + descriptor + _.inspect(name)); } if (arguments.length > 1) { this.assert( - val === value - , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' - , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' + hasProperty && (isDeep ? _.eql(val, value) : val === value) + , 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' + , 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}' , val , value ); } flag(this, 'object', value); - }); - + } - /** - * ### .ownProperty(name) - * - * Asserts that the target has an own property `name`. - * - * expect('test').to.have.ownProperty('length'); - * - * @name ownProperty - * @alias haveOwnProperty - * @param {String} name - * @param {String} message _optional_ - * @namespace BDD - * @api public - */ + Assertion.addMethod('property', assertProperty); - function assertOwnProperty (name, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - this.assert( - obj.hasOwnProperty(name) - , 'expected #{this} to have own property ' + _.inspect(name) - , 'expected #{this} to not have own property ' + _.inspect(name) - ); + function assertOwnProperty (name, value, msg) { + flag(this, 'own', true); + assertProperty.apply(this, arguments); } Assertion.addMethod('ownProperty', assertOwnProperty); Assertion.addMethod('haveOwnProperty', assertOwnProperty); /** - * ### .ownPropertyDescriptor(name[, descriptor[, message]]) - * - * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. - * - * expect('test').to.have.ownPropertyDescriptor('length'); - * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); - * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); - * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); - * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); + * ### .ownPropertyDescriptor(name[, descriptor[, msg]]) + * + * Asserts that the target has its own property descriptor with the given key + * `name`. Enumerable and non-enumerable properties are included in the + * search. + * + * expect({a: 1}).to.have.ownPropertyDescriptor('a'); + * + * When `descriptor` is provided, `.ownPropertyDescriptor` also asserts that + * the property's descriptor is deeply equal to the given `descriptor`. See + * the `deep-eql` project page for info on the deep equality algorithm: + * https://github.com/chaijs/deep-eql. + * + * expect({a: 1}).to.have.ownPropertyDescriptor('a', { + * configurable: true, + * enumerable: true, + * writable: true, + * value: 1, + * }); + * + * Add `.not` earlier in the chain to negate `.ownPropertyDescriptor`. + * + * expect({a: 1}).to.not.have.ownPropertyDescriptor('b'); + * + * However, it's dangerous to negate `.ownPropertyDescriptor` when providing + * a `descriptor`. The problem is that it creates uncertain expectations by + * asserting that the target either doesn't have a property descriptor with + * the given key `name`, or that it does have a property descriptor with the + * given key `name` but its not deeply equal to the given `descriptor`. It's + * often best to identify the exact output that's expected, and then write an + * assertion that only accepts that exact output. + * + * When the target isn't expected to have a property descriptor with the given + * key `name`, it's often best to assert exactly that. + * + * // Recommended + * expect({b: 2}).to.not.have.ownPropertyDescriptor('a'); + * + * // Not recommended + * expect({b: 2}).to.not.have.ownPropertyDescriptor('a', { + * configurable: true, + * enumerable: true, + * writable: true, + * value: 1, + * }); + * + * When the target is expected to have a property descriptor with the given + * key `name`, it's often best to assert that the property has its expected + * descriptor, rather than asserting that it doesn't have one of many + * unexpected descriptors. + * + * // Recommended + * expect({a: 3}).to.have.ownPropertyDescriptor('a', { + * configurable: true, + * enumerable: true, + * writable: true, + * value: 3, + * }); + * + * // Not recommended + * expect({a: 3}).to.not.have.ownPropertyDescriptor('a', { + * configurable: true, + * enumerable: true, + * writable: true, + * value: 1, + * }); + * + * `.ownPropertyDescriptor` changes the target of any assertions that follow + * in the chain to be the value of the property descriptor from the original + * target object. + * + * expect({a: 1}).to.have.ownPropertyDescriptor('a') + * .that.has.property('enumerable', true); + * + * `.ownPropertyDescriptor` accepts an optional `msg` argument which is a + * custom error message to show when the assertion fails. The message can also + * be given as the second argument to `expect`. When not providing + * `descriptor`, only use the second form. + * + * // Recommended + * expect({a: 1}).to.have.ownPropertyDescriptor('a', { + * configurable: true, + * enumerable: true, + * writable: true, + * value: 2, + * }, 'nooo why fail??'); + * + * // Recommended + * expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('a', { + * configurable: true, + * enumerable: true, + * writable: true, + * value: 2, + * }); + * + * // Recommended + * expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('b'); + * + * // Not recommended + * expect({a: 1}) + * .to.have.ownPropertyDescriptor('b', undefined, 'nooo why fail??'); + * + * The above assertion isn't the same thing as not providing `descriptor`. + * Instead, it's asserting that the target object has a `b` property + * descriptor that's deeply equal to `undefined`. + * + * The alias `.haveOwnPropertyDescriptor` can be used interchangeably with + * `.ownPropertyDescriptor`. * * @name ownPropertyDescriptor * @alias haveOwnPropertyDescriptor * @param {String} name * @param {Object} descriptor _optional_ - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -1283,40 +2403,59 @@ module.exports = function (chai, _) { Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); /** - * ### .length + * ### .lengthOf(n[, msg]) * - * Sets the `doLength` flag later used as a chain precursor to a value - * comparison for the `length` property. + * Asserts that the target's `length` or `size` is equal to the given number + * `n`. * - * expect('foo').to.have.length.above(2); - * expect([ 1, 2, 3 ]).to.have.length.above(2); - * expect('foo').to.have.length.below(4); - * expect([ 1, 2, 3 ]).to.have.length.below(4); - * expect('foo').to.have.length.within(2,4); - * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * expect([1, 2, 3]).to.have.lengthOf(3); + * expect('foo').to.have.lengthOf(3); + * expect(new Set([1, 2, 3])).to.have.lengthOf(3); + * expect(new Map([['a', 1], ['b', 2], ['c', 3]])).to.have.lengthOf(3); * - * *Deprecation notice:* Using `length` as an assertion will be deprecated - * in version 2.4.0 and removed in 3.0.0. Code using the old style of - * asserting for `length` property value using `length(value)` should be - * switched to use `lengthOf(value)` instead. + * Add `.not` earlier in the chain to negate `.lengthOf`. However, it's often + * best to assert that the target's `length` property is equal to its expected + * value, rather than not equal to one of many unexpected values. * - * @name length - * @namespace BDD - * @api public - */ - - /** - * ### .lengthOf(value[, message]) + * expect('foo').to.have.lengthOf(3); // Recommended + * expect('foo').to.not.have.lengthOf(4); // Not recommended * - * Asserts that the target's `length` property has - * the expected value. + * `.lengthOf` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. * - * expect([ 1, 2, 3]).to.have.lengthOf(3); - * expect('foobar').to.have.lengthOf(6); + * expect([1, 2, 3]).to.have.lengthOf(2, 'nooo why fail??'); + * expect([1, 2, 3], 'nooo why fail??').to.have.lengthOf(2); + * + * `.lengthOf` can also be used as a language chain, causing all `.above`, + * `.below`, `.least`, `.most`, and `.within` assertions that follow in the + * chain to use the target's `length` property as the target. However, it's + * often best to assert that the target's `length` property is equal to its + * expected length, rather than asserting that its `length` property falls + * within some range of values. + * + * // Recommended + * expect([1, 2, 3]).to.have.lengthOf(3); + * + * // Not recommended + * expect([1, 2, 3]).to.have.lengthOf.above(2); + * expect([1, 2, 3]).to.have.lengthOf.below(4); + * expect([1, 2, 3]).to.have.lengthOf.at.least(3); + * expect([1, 2, 3]).to.have.lengthOf.at.most(3); + * expect([1, 2, 3]).to.have.lengthOf.within(2,4); + * + * Due to a compatibility issue, the alias `.length` can't be chained directly + * off of an uninvoked method such as `.a`. Therefore, `.length` can't be used + * interchangeably with `.lengthOf` in every situation. It's recommended to + * always use `.lengthOf` instead of `.length`. + * + * expect([1, 2, 3]).to.have.a.length(3); // incompatible; throws error + * expect([1, 2, 3]).to.have.a.lengthOf(3); // passes as expected * * @name lengthOf - * @param {Number} length - * @param {String} message _optional_ + * @alias length + * @param {Number} n + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -1327,33 +2466,60 @@ module.exports = function (chai, _) { function assertLength (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - new Assertion(obj, msg).to.have.property('length'); - var len = obj.length; + var obj = flag(this, 'object') + , objType = _.type(obj).toLowerCase() + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi') + , descriptor = 'length' + , itemsCount; + + switch (objType) { + case 'map': + case 'set': + descriptor = 'size'; + itemsCount = obj.size; + break; + default: + new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); + itemsCount = obj.length; + } this.assert( - len == n - , 'expected #{this} to have a length of #{exp} but got #{act}' - , 'expected #{this} to not have a length of #{act}' + itemsCount == n + , 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}' + , 'expected #{this} to not have a ' + descriptor + ' of #{act}' , n - , len + , itemsCount ); } Assertion.addChainableMethod('length', assertLength, assertLengthChain); - Assertion.addMethod('lengthOf', assertLength); + Assertion.addChainableMethod('lengthOf', assertLength, assertLengthChain); /** - * ### .match(regexp) + * ### .match(re[, msg]) * - * Asserts that the target matches a regular expression. + * Asserts that the target matches the given regular expression `re`. * * expect('foobar').to.match(/^foo/); * + * Add `.not` earlier in the chain to negate `.match`. + * + * expect('foobar').to.not.match(/taco/); + * + * `.match` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect('foobar').to.match(/taco/, 'nooo why fail??'); + * expect('foobar', 'nooo why fail??').to.match(/taco/); + * + * The alias `.matches` can be used interchangeably with `.match`. + * * @name match * @alias matches - * @param {RegExp} RegularExpression - * @param {String} message _optional_ + * @param {RegExp} re + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -1371,23 +2537,36 @@ module.exports = function (chai, _) { Assertion.addMethod('matches', assertMatch); /** - * ### .string(string) + * ### .string(str[, msg]) * - * Asserts that the string target contains another string. + * Asserts that the target string contains the given substring `str`. * * expect('foobar').to.have.string('bar'); * + * Add `.not` earlier in the chain to negate `.string`. + * + * expect('foobar').to.not.have.string('taco'); + * + * `.string` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect('foobar').to.have.string('taco', 'nooo why fail??'); + * expect('foobar', 'nooo why fail??').to.have.string('taco'); + * * @name string - * @param {String} string - * @param {String} message _optional_ + * @param {String} str + * @param {String} msg _optional_ * @namespace BDD * @api public */ Assertion.addMethod('string', function (str, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - new Assertion(obj, msg).is.a('string'); + var obj = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); + new Assertion(obj, flagMsg, ssfi, true).is.a('string'); this.assert( ~obj.indexOf(str) @@ -1396,38 +2575,102 @@ module.exports = function (chai, _) { ); }); - /** - * ### .keys(key1, [key2], [...]) + * ### .keys(key1[, key2[, ...]]) + * + * Asserts that the target object, array, map, or set has the given keys. Only + * the target's own inherited properties are included in the search. + * + * When the target is an object or array, keys can be provided as one or more + * string arguments, a single array argument, or a single object argument. In + * the latter case, only the keys in the given object matter; the values are + * ignored. + * + * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); + * expect(['x', 'y']).to.have.all.keys(0, 1); + * + * expect({a: 1, b: 2}).to.have.all.keys(['a', 'b']); + * expect(['x', 'y']).to.have.all.keys([0, 1]); + * + * expect({a: 1, b: 2}).to.have.all.keys({a: 4, b: 5}); // ignore 4 and 5 + * expect(['x', 'y']).to.have.all.keys({0: 4, 1: 5}); // ignore 4 and 5 + * + * When the target is a map or set, each key must be provided as a separate + * argument. * - * Asserts that the target contains any or all of the passed-in keys. - * Use in combination with `any`, `all`, `contains`, or `have` will affect - * what will pass. + * expect(new Map([['a', 1], ['b', 2]])).to.have.all.keys('a', 'b'); + * expect(new Set(['a', 'b'])).to.have.all.keys('a', 'b'); * - * When used in conjunction with `any`, at least one key that is passed - * in must exist in the target object. This is regardless whether or not - * the `have` or `contain` qualifiers are used. Note, either `any` or `all` - * should be used in the assertion. If neither are used, the assertion is - * defaulted to `all`. + * Because `.keys` does different things based on the target's type, it's + * important to check the target's type before using `.keys`. See the `.a` doc + * for info on testing a target's type. * - * When both `all` and `contain` are used, the target object must have at - * least all of the passed-in keys but may have more keys not listed. + * expect({a: 1, b: 2}).to.be.an('object').that.has.all.keys('a', 'b'); * - * When both `all` and `have` are used, the target object must both contain - * all of the passed-in keys AND the number of keys in the target object must - * match the number of keys passed in (in other words, a target object must - * have all and only all of the passed-in keys). + * By default, strict (`===`) equality is used to compare keys of maps and + * sets. Add `.deep` earlier in the chain to use deep equality instead. See + * the `deep-eql` project page for info on the deep equality algorithm: + * https://github.com/chaijs/deep-eql. * - * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); - * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); - * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); - * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); - * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); - * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); - * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); - * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); - * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); + * // Target set deeply (but not strictly) has key `{a: 1}` + * expect(new Set([{a: 1}])).to.have.all.deep.keys([{a: 1}]); + * expect(new Set([{a: 1}])).to.not.have.all.keys([{a: 1}]); * + * By default, the target must have all of the given keys and no more. Add + * `.any` earlier in the chain to only require that the target have at least + * one of the given keys. Also, add `.not` earlier in the chain to negate + * `.keys`. It's often best to add `.any` when negating `.keys`, and to use + * `.all` when asserting `.keys` without negation. + * + * When negating `.keys`, `.any` is preferred because `.not.any.keys` asserts + * exactly what's expected of the output, whereas `.not.all.keys` creates + * uncertain expectations. + * + * // Recommended; asserts that target doesn't have any of the given keys + * expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd'); + * + * // Not recommended; asserts that target doesn't have all of the given + * // keys but may or may not have some of them + * expect({a: 1, b: 2}).to.not.have.all.keys('c', 'd'); + * + * When asserting `.keys` without negation, `.all` is preferred because + * `.all.keys` asserts exactly what's expected of the output, whereas + * `.any.keys` creates uncertain expectations. + * + * // Recommended; asserts that target has all the given keys + * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); + * + * // Not recommended; asserts that target has at least one of the given + * // keys but may or may not have more of them + * expect({a: 1, b: 2}).to.have.any.keys('a', 'b'); + * + * Note that `.all` is used by default when neither `.all` nor `.any` appear + * earlier in the chain. However, it's often best to add `.all` anyway because + * it improves readability. + * + * // Both assertions are identical + * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); // Recommended + * expect({a: 1, b: 2}).to.have.keys('a', 'b'); // Not recommended + * + * Add `.include` earlier in the chain to require that the target's keys be a + * superset of the expected keys, rather than identical sets. + * + * // Target object's keys are a superset of ['a', 'b'] but not identical + * expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b'); + * expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b'); + * + * However, if `.any` and `.include` are combined, only the `.any` takes + * effect. The `.include` is ignored in this case. + * + * // Both assertions are identical + * expect({a: 1}).to.have.any.keys('a', 'b'); + * expect({a: 1}).to.include.any.keys('a', 'b'); + * + * A custom error message can be given as the second argument to `expect`. + * + * expect({a: 1}, 'nooo why fail??').to.have.key('b'); + * + * The alias `.key` can be used interchangeably with `.keys`. * * @name keys * @alias key @@ -1438,29 +2681,62 @@ module.exports = function (chai, _) { function assertKeys (keys) { var obj = flag(this, 'object') + , objType = _.type(obj) + , keysType = _.type(keys) + , ssfi = flag(this, 'ssfi') + , isDeep = flag(this, 'deep') , str + , deepStr = '' + , actual , ok = true - , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; + , flagMsg = flag(this, 'message'); - switch (_.type(keys)) { - case "array": - if (arguments.length > 1) throw (new Error(mixedArgsMsg)); - break; - case "object": - if (arguments.length > 1) throw (new Error(mixedArgsMsg)); - keys = Object.keys(keys); - break; - default: + flagMsg = flagMsg ? flagMsg + ': ' : ''; + var mixedArgsMsg = flagMsg + 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments'; + + if (objType === 'Map' || objType === 'Set') { + deepStr = isDeep ? 'deeply ' : ''; + actual = []; + + // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach. + obj.forEach(function (val, key) { actual.push(key) }); + + if (keysType !== 'Array') { keys = Array.prototype.slice.call(arguments); + } + } else { + actual = _.getOwnEnumerableProperties(obj); + + switch (keysType) { + case 'Array': + if (arguments.length > 1) { + throw new AssertionError(mixedArgsMsg, undefined, ssfi); + } + break; + case 'Object': + if (arguments.length > 1) { + throw new AssertionError(mixedArgsMsg, undefined, ssfi); + } + keys = Object.keys(keys); + break; + default: + keys = Array.prototype.slice.call(arguments); + } + + // Only stringify non-Symbols because Symbols would become "Symbol()" + keys = keys.map(function (val) { + return typeof val === 'symbol' ? val : String(val); + }); } - if (!keys.length) throw new Error('keys required'); + if (!keys.length) { + throw new AssertionError(flagMsg + 'keys required', undefined, ssfi); + } - var actual = Object.keys(obj) - , expected = keys - , len = keys.length + var len = keys.length , any = flag(this, 'any') - , all = flag(this, 'all'); + , all = flag(this, 'all') + , expected = keys; if (!any && !all) { all = true; @@ -1468,25 +2744,37 @@ module.exports = function (chai, _) { // Has any if (any) { - var intersection = expected.filter(function(key) { - return ~actual.indexOf(key); + ok = expected.some(function(expectedKey) { + return actual.some(function(actualKey) { + if (isDeep) { + return _.eql(expectedKey, actualKey); + } else { + return expectedKey === actualKey; + } + }); }); - ok = intersection.length > 0; } // Has all if (all) { - ok = keys.every(function(key){ - return ~actual.indexOf(key); + ok = expected.every(function(expectedKey) { + return actual.some(function(actualKey) { + if (isDeep) { + return _.eql(expectedKey, actualKey); + } else { + return expectedKey === actualKey; + } + }); }); - if (!flag(this, 'negate') && !flag(this, 'contains')) { + + if (!flag(this, 'contains')) { ok = ok && keys.length == actual.length; } } // Key string if (len > 1) { - keys = keys.map(function(key){ + keys = keys.map(function(key) { return _.inspect(key); }); var last = keys.pop(); @@ -1509,10 +2797,10 @@ module.exports = function (chai, _) { // Assertion this.assert( ok - , 'expected #{this} to ' + str - , 'expected #{this} to not ' + str - , expected.slice(0).sort() - , actual.sort() + , 'expected #{this} to ' + deepStr + str + , 'expected #{this} to not ' + deepStr + str + , expected.slice(0).sort(_.compareByInspect) + , actual.sort(_.compareByInspect) , true ); } @@ -1521,156 +2809,294 @@ module.exports = function (chai, _) { Assertion.addMethod('key', assertKeys); /** - * ### .throw(constructor) + * ### .throw([errorLike], [errMsgMatcher], [msg]) * - * Asserts that the function target will throw a specific error, or specific type of error - * (as determined using `instanceof`), optionally with a RegExp or string inclusion test - * for the error's message. + * When no arguments are provided, `.throw` invokes the target function and + * asserts that an error is thrown. * - * var err = new ReferenceError('This is a bad function.'); - * var fn = function () { throw err; } - * expect(fn).to.throw(ReferenceError); - * expect(fn).to.throw(Error); - * expect(fn).to.throw(/bad function/); - * expect(fn).to.not.throw('good function'); - * expect(fn).to.throw(ReferenceError, /bad function/); - * expect(fn).to.throw(err); + * var badFn = function () { throw new TypeError('Illegal salmon!'); }; * - * Please note that when a throw expectation is negated, it will check each - * parameter independently, starting with error constructor type. The appropriate way - * to check for the existence of a type of error but for a message that does not match - * is to use `and`. + * expect(badFn).to.throw(); * - * expect(fn).to.throw(ReferenceError) - * .and.not.throw(/good function/); + * When one argument is provided, and it's an error constructor, `.throw` + * invokes the target function and asserts that an error is thrown that's an + * instance of that error constructor. * - * @name throw - * @alias throws - * @alias Throw - * @param {ErrorConstructor} constructor - * @param {String|RegExp} expected error message - * @param {String} message _optional_ - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @returns error for chaining (null if no error) - * @namespace BDD - * @api public - */ - - function assertThrows (constructor, errMsg, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - new Assertion(obj, msg).is.a('function'); - - var thrown = false - , desiredError = null - , name = null - , thrownError = null; - - if (arguments.length === 0) { - errMsg = null; - constructor = null; - } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { - errMsg = constructor; - constructor = null; - } else if (constructor && constructor instanceof Error) { - desiredError = constructor; - constructor = null; - errMsg = null; - } else if (typeof constructor === 'function') { - name = constructor.prototype.name; - if (!name || (name === 'Error' && constructor !== Error)) { - name = constructor.name || (new constructor()).name; - } - } else { - constructor = null; - } - - try { + * var badFn = function () { throw new TypeError('Illegal salmon!'); }; + * + * expect(badFn).to.throw(TypeError); + * + * When one argument is provided, and it's an error instance, `.throw` invokes + * the target function and asserts that an error is thrown that's strictly + * (`===`) equal to that error instance. + * + * var err = new TypeError('Illegal salmon!'); + * var badFn = function () { throw err; }; + * + * expect(badFn).to.throw(err); + * + * When one argument is provided, and it's a string, `.throw` invokes the + * target function and asserts that an error is thrown with a message that + * contains that string. + * + * var badFn = function () { throw new TypeError('Illegal salmon!'); }; + * + * expect(badFn).to.throw('salmon'); + * + * When one argument is provided, and it's a regular expression, `.throw` + * invokes the target function and asserts that an error is thrown with a + * message that matches that regular expression. + * + * var badFn = function () { throw new TypeError('Illegal salmon!'); }; + * + * expect(badFn).to.throw(/salmon/); + * + * When two arguments are provided, and the first is an error instance or + * constructor, and the second is a string or regular expression, `.throw` + * invokes the function and asserts that an error is thrown that fulfills both + * conditions as described above. + * + * var err = new TypeError('Illegal salmon!'); + * var badFn = function () { throw err; }; + * + * expect(badFn).to.throw(TypeError, 'salmon'); + * expect(badFn).to.throw(TypeError, /salmon/); + * expect(badFn).to.throw(err, 'salmon'); + * expect(badFn).to.throw(err, /salmon/); + * + * Add `.not` earlier in the chain to negate `.throw`. + * + * var goodFn = function () {}; + * + * expect(goodFn).to.not.throw(); + * + * However, it's dangerous to negate `.throw` when providing any arguments. + * The problem is that it creates uncertain expectations by asserting that the + * target either doesn't throw an error, or that it throws an error but of a + * different type than the given type, or that it throws an error of the given + * type but with a message that doesn't include the given string. It's often + * best to identify the exact output that's expected, and then write an + * assertion that only accepts that exact output. + * + * When the target isn't expected to throw an error, it's often best to assert + * exactly that. + * + * var goodFn = function () {}; + * + * expect(goodFn).to.not.throw(); // Recommended + * expect(goodFn).to.not.throw(ReferenceError, 'x'); // Not recommended + * + * When the target is expected to throw an error, it's often best to assert + * that the error is of its expected type, and has a message that includes an + * expected string, rather than asserting that it doesn't have one of many + * unexpected types, and doesn't have a message that includes some string. + * + * var badFn = function () { throw new TypeError('Illegal salmon!'); }; + * + * expect(badFn).to.throw(TypeError, 'salmon'); // Recommended + * expect(badFn).to.not.throw(ReferenceError, 'x'); // Not recommended + * + * `.throw` changes the target of any assertions that follow in the chain to + * be the error object that's thrown. + * + * var err = new TypeError('Illegal salmon!'); + * err.code = 42; + * var badFn = function () { throw err; }; + * + * expect(badFn).to.throw(TypeError).with.property('code', 42); + * + * `.throw` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. When not providing two arguments, always use + * the second form. + * + * var goodFn = function () {}; + * + * expect(goodFn).to.throw(TypeError, 'x', 'nooo why fail??'); + * expect(goodFn, 'nooo why fail??').to.throw(); + * + * Due to limitations in ES5, `.throw` may not always work as expected when + * using a transpiler such as Babel or TypeScript. In particular, it may + * produce unexpected results when subclassing the built-in `Error` object and + * then passing the subclassed constructor to `.throw`. See your transpiler's + * docs for details: + * + * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes)) + * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work)) + * + * Beware of some common mistakes when using the `throw` assertion. One common + * mistake is to accidentally invoke the function yourself instead of letting + * the `throw` assertion invoke the function for you. For example, when + * testing if a function named `fn` throws, provide `fn` instead of `fn()` as + * the target for the assertion. + * + * expect(fn).to.throw(); // Good! Tests `fn` as desired + * expect(fn()).to.throw(); // Bad! Tests result of `fn()`, not `fn` + * + * If you need to assert that your function `fn` throws when passed certain + * arguments, then wrap a call to `fn` inside of another function. + * + * expect(function () { fn(42); }).to.throw(); // Function expression + * expect(() => fn(42)).to.throw(); // ES6 arrow function + * + * Another common mistake is to provide an object method (or any stand-alone + * function that relies on `this`) as the target of the assertion. Doing so is + * problematic because the `this` context will be lost when the function is + * invoked by `.throw`; there's no way for it to know what `this` is supposed + * to be. There are two ways around this problem. One solution is to wrap the + * method or function call inside of another function. Another solution is to + * use `bind`. + * + * expect(function () { cat.meow(); }).to.throw(); // Function expression + * expect(() => cat.meow()).to.throw(); // ES6 arrow function + * expect(cat.meow.bind(cat)).to.throw(); // Bind + * + * Finally, it's worth mentioning that it's a best practice in JavaScript to + * only throw `Error` and derivatives of `Error` such as `ReferenceError`, + * `TypeError`, and user-defined objects that extend `Error`. No other type of + * value will generate a stack trace when initialized. With that said, the + * `throw` assertion does technically support any type of value being thrown, + * not just `Error` and its derivatives. + * + * The aliases `.throws` and `.Throw` can be used interchangeably with + * `.throw`. + * + * @name throw + * @alias throws + * @alias Throw + * @param {Error|ErrorConstructor} errorLike + * @param {String|RegExp} errMsgMatcher error message + * @param {String} msg _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @returns error for chaining (null if no error) + * @namespace BDD + * @api public + */ + + function assertThrows (errorLike, errMsgMatcher, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , ssfi = flag(this, 'ssfi') + , flagMsg = flag(this, 'message') + , negate = flag(this, 'negate') || false; + new Assertion(obj, flagMsg, ssfi, true).is.a('function'); + + if (errorLike instanceof RegExp || typeof errorLike === 'string') { + errMsgMatcher = errorLike; + errorLike = null; + } + + var caughtErr; + try { obj(); } catch (err) { - // first, check desired error - if (desiredError) { - this.assert( - err === desiredError - , 'expected #{this} to throw #{exp} but #{act} was thrown' - , 'expected #{this} to not throw #{exp}' - , (desiredError instanceof Error ? desiredError.toString() : desiredError) - , (err instanceof Error ? err.toString() : err) - ); + caughtErr = err; + } - flag(this, 'object', err); - return this; + // If we have the negate flag enabled and at least one valid argument it means we do expect an error + // but we want it to match a given set of criteria + var everyArgIsUndefined = errorLike === undefined && errMsgMatcher === undefined; + + // If we've got the negate flag enabled and both args, we should only fail if both aren't compatible + // See Issue #551 and PR #683@GitHub + var everyArgIsDefined = Boolean(errorLike && errMsgMatcher); + var errorLikeFail = false; + var errMsgMatcherFail = false; + + // Checking if error was thrown + if (everyArgIsUndefined || !everyArgIsUndefined && !negate) { + // We need this to display results correctly according to their types + var errorLikeString = 'an error'; + if (errorLike instanceof Error) { + errorLikeString = '#{exp}'; + } else if (errorLike) { + errorLikeString = _.checkError.getConstructorName(errorLike); } - // next, check constructor - if (constructor) { - this.assert( - err instanceof constructor - , 'expected #{this} to throw #{exp} but #{act} was thrown' - , 'expected #{this} to not throw #{exp} but #{act} was thrown' - , name - , (err instanceof Error ? err.toString() : err) - ); + this.assert( + caughtErr + , 'expected #{this} to throw ' + errorLikeString + , 'expected #{this} to not throw an error but #{act} was thrown' + , errorLike && errorLike.toString() + , (caughtErr instanceof Error ? + caughtErr.toString() : (typeof caughtErr === 'string' ? caughtErr : caughtErr && + _.checkError.getConstructorName(caughtErr))) + ); + } - if (!errMsg) { - flag(this, 'object', err); - return this; + if (errorLike && caughtErr) { + // We should compare instances only if `errorLike` is an instance of `Error` + if (errorLike instanceof Error) { + var isCompatibleInstance = _.checkError.compatibleInstance(caughtErr, errorLike); + + if (isCompatibleInstance === negate) { + // These checks were created to ensure we won't fail too soon when we've got both args and a negate + // See Issue #551 and PR #683@GitHub + if (everyArgIsDefined && negate) { + errorLikeFail = true; + } else { + this.assert( + negate + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + (caughtErr && !negate ? ' but #{act} was thrown' : '') + , errorLike.toString() + , caughtErr.toString() + ); + } } } - // next, check message - var message = 'error' === _.type(err) && "message" in err - ? err.message - : '' + err; - - if ((message != null) && errMsg && errMsg instanceof RegExp) { - this.assert( - errMsg.exec(message) - , 'expected #{this} to throw error matching #{exp} but got #{act}' - , 'expected #{this} to throw error not matching #{exp}' - , errMsg - , message - ); - - flag(this, 'object', err); - return this; - } else if ((message != null) && errMsg && 'string' === typeof errMsg) { - this.assert( - ~message.indexOf(errMsg) - , 'expected #{this} to throw error including #{exp} but got #{act}' - , 'expected #{this} to throw error not including #{act}' - , errMsg - , message - ); - - flag(this, 'object', err); - return this; - } else { - thrown = true; - thrownError = err; + var isCompatibleConstructor = _.checkError.compatibleConstructor(caughtErr, errorLike); + if (isCompatibleConstructor === negate) { + if (everyArgIsDefined && negate) { + errorLikeFail = true; + } else { + this.assert( + negate + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '') + , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike)) + , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr)) + ); + } } } - var actuallyGot = '' - , expectedThrown = name !== null - ? name - : desiredError - ? '#{exp}' //_.inspect(desiredError) - : 'an error'; + if (caughtErr && errMsgMatcher !== undefined && errMsgMatcher !== null) { + // Here we check compatible messages + var placeholder = 'including'; + if (errMsgMatcher instanceof RegExp) { + placeholder = 'matching' + } - if (thrown) { - actuallyGot = ' but #{act} was thrown' + var isCompatibleMessage = _.checkError.compatibleMessage(caughtErr, errMsgMatcher); + if (isCompatibleMessage === negate) { + if (everyArgIsDefined && negate) { + errMsgMatcherFail = true; + } else { + this.assert( + negate + , 'expected #{this} to throw error ' + placeholder + ' #{exp} but got #{act}' + , 'expected #{this} to throw error not ' + placeholder + ' #{exp}' + , errMsgMatcher + , _.checkError.getMessage(caughtErr) + ); + } + } } - this.assert( - thrown === true - , 'expected #{this} to throw ' + expectedThrown + actuallyGot - , 'expected #{this} to not throw ' + expectedThrown + actuallyGot - , (desiredError instanceof Error ? desiredError.toString() : desiredError) - , (thrownError instanceof Error ? thrownError.toString() : thrownError) - ); + // If both assertions failed and both should've matched we throw an error + if (errorLikeFail && errMsgMatcherFail) { + this.assert( + negate + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '') + , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike)) + , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr)) + ); + } - flag(this, 'object', thrownError); + flag(this, 'object', caughtErr); }; Assertion.addMethod('throw', assertThrows); @@ -1678,24 +3104,66 @@ module.exports = function (chai, _) { Assertion.addMethod('Throw', assertThrows); /** - * ### .respondTo(method) + * ### .respondTo(method[, msg]) + * + * When the target is a non-function object, `.respondTo` asserts that the + * target has a method with the given name `method`. The method can be own or + * inherited, and it can be enumerable or non-enumerable. + * + * function Cat () {} + * Cat.prototype.meow = function () {}; + * + * expect(new Cat()).to.respondTo('meow'); + * + * When the target is a function, `.respondTo` asserts that the target's + * `prototype` property has a method with the given name `method`. Again, the + * method can be own or inherited, and it can be enumerable or non-enumerable. * - * Asserts that the object or class target will respond to a method. + * function Cat () {} + * Cat.prototype.meow = function () {}; * - * Klass.prototype.bar = function(){}; - * expect(Klass).to.respondTo('bar'); - * expect(obj).to.respondTo('bar'); + * expect(Cat).to.respondTo('meow'); * - * To check if a constructor will respond to a static function, - * set the `itself` flag. + * Add `.itself` earlier in the chain to force `.respondTo` to treat the + * target as a non-function object, even if it's a function. Thus, it asserts + * that the target has a method with the given name `method`, rather than + * asserting that the target's `prototype` property has a method with the + * given name `method`. * - * Klass.baz = function(){}; - * expect(Klass).itself.to.respondTo('baz'); + * function Cat () {} + * Cat.prototype.meow = function () {}; + * Cat.hiss = function () {}; + * + * expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow'); + * + * When not adding `.itself`, it's important to check the target's type before + * using `.respondTo`. See the `.a` doc for info on checking a target's type. + * + * function Cat () {} + * Cat.prototype.meow = function () {}; + * + * expect(new Cat()).to.be.an('object').that.respondsTo('meow'); + * + * Add `.not` earlier in the chain to negate `.respondTo`. + * + * function Dog () {} + * Dog.prototype.bark = function () {}; + * + * expect(new Dog()).to.not.respondTo('meow'); + * + * `.respondTo` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect({}).to.respondTo('meow', 'nooo why fail??'); + * expect({}, 'nooo why fail??').to.respondTo('meow'); + * + * The alias `.respondsTo` can be used interchangeably with `.respondTo`. * * @name respondTo * @alias respondsTo * @param {String} method - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -1704,7 +3172,7 @@ module.exports = function (chai, _) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') , itself = flag(this, 'itself') - , context = ('function' === _.type(obj) && !itself) + , context = ('function' === typeof obj && !itself) ? obj.prototype[method] : obj[method]; @@ -1721,14 +3189,17 @@ module.exports = function (chai, _) { /** * ### .itself * - * Sets the `itself` flag, later used by the `respondTo` assertion. + * Forces all `.respondTo` assertions that follow in the chain to behave as if + * the target is a non-function object, even if it's a function. Thus, it + * causes `.respondTo` to assert that the target has a method with the given + * name, rather than asserting that the target's `prototype` property has a + * method with the given name. * - * function Foo() {} - * Foo.bar = function() {} - * Foo.prototype.baz = function() {} + * function Cat () {} + * Cat.prototype.meow = function () {}; + * Cat.hiss = function () {}; * - * expect(Foo).itself.to.respondTo('bar'); - * expect(Foo).itself.not.to.respondTo('baz'); + * expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow'); * * @name itself * @namespace BDD @@ -1740,16 +3211,39 @@ module.exports = function (chai, _) { }); /** - * ### .satisfy(method) + * ### .satisfy(matcher[, msg]) + * + * Invokes the given `matcher` function with the target being passed as the + * first argument, and asserts that the value returned is truthy. + * + * expect(1).to.satisfy(function(num) { + * return num > 0; + * }); + * + * Add `.not` earlier in the chain to negate `.satisfy`. + * + * expect(1).to.not.satisfy(function(num) { + * return num > 2; + * }); + * + * `.satisfy` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. * - * Asserts that the target passes a given truth test. + * expect(1).to.satisfy(function(num) { + * return num > 2; + * }, 'nooo why fail??'); * - * expect(1).to.satisfy(function(num) { return num > 0; }); + * expect(1, 'nooo why fail??').to.satisfy(function(num) { + * return num > 2; + * }); + * + * The alias `.satisfies` can be used interchangeably with `.satisfy`. * * @name satisfy * @alias satisfies * @param {Function} matcher - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ @@ -1762,7 +3256,7 @@ module.exports = function (chai, _) { result , 'expected #{this} to satisfy ' + _.objDisplay(matcher) , 'expected #{this} to not satisfy' + _.objDisplay(matcher) - , this.negate ? false : true + , flag(this, 'negate') ? false : true , result ); } @@ -1771,28 +3265,57 @@ module.exports = function (chai, _) { Assertion.addMethod('satisfies', satisfy); /** - * ### .closeTo(expected, delta) + * ### .closeTo(expected, delta[, msg]) * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * Asserts that the target is a number that's within a given +/- `delta` range + * of the given number `expected`. However, it's often best to assert that the + * target is equal to its expected value. + * + * // Recommended + * expect(1.5).to.equal(1.5); * + * // Not recommended * expect(1.5).to.be.closeTo(1, 0.5); + * expect(1.5).to.be.closeTo(2, 0.5); + * expect(1.5).to.be.closeTo(1, 1); + * + * Add `.not` earlier in the chain to negate `.closeTo`. + * + * expect(1.5).to.equal(1.5); // Recommended + * expect(1.5).to.not.be.closeTo(3, 1); // Not recommended + * + * `.closeTo` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect(1.5).to.be.closeTo(3, 1, 'nooo why fail??'); + * expect(1.5, 'nooo why fail??').to.be.closeTo(3, 1); + * + * The alias `.approximately` can be used interchangeably with `.closeTo`. * * @name closeTo * @alias approximately * @param {Number} expected * @param {Number} delta - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ function closeTo(expected, delta, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - - new Assertion(obj, msg).is.a('number'); - if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { - throw new Error('the arguments to closeTo or approximately must be numbers'); + var obj = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); + + new Assertion(obj, flagMsg, ssfi, true).is.a('number'); + if (typeof expected !== 'number' || typeof delta !== 'number') { + flagMsg = flagMsg ? flagMsg + ': ' : ''; + throw new AssertionError( + flagMsg + 'the arguments to closeTo or approximately must be numbers', + undefined, + ssfi + ); } this.assert( @@ -1805,93 +3328,176 @@ module.exports = function (chai, _) { Assertion.addMethod('closeTo', closeTo); Assertion.addMethod('approximately', closeTo); - function isSubsetOf(subset, superset, cmp) { - return subset.every(function(elem) { - if (!cmp) return superset.indexOf(elem) !== -1; + // Note: Duplicates are ignored if testing for inclusion instead of sameness. + function isSubsetOf(subset, superset, cmp, contains, ordered) { + if (!contains) { + if (subset.length !== superset.length) return false; + superset = superset.slice(); + } + + return subset.every(function(elem, idx) { + if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx]; - return superset.some(function(elem2) { - return cmp(elem, elem2); + if (!cmp) { + var matchIdx = superset.indexOf(elem); + if (matchIdx === -1) return false; + + // Remove match from superset so not counted twice if duplicate in subset. + if (!contains) superset.splice(matchIdx, 1); + return true; + } + + return superset.some(function(elem2, matchIdx) { + if (!cmp(elem, elem2)) return false; + + // Remove match from superset so not counted twice if duplicate in subset. + if (!contains) superset.splice(matchIdx, 1); + return true; }); - }) + }); } /** - * ### .members(set) + * ### .members(set[, msg]) + * + * Asserts that the target array has the same members as the given array + * `set`. + * + * expect([1, 2, 3]).to.have.members([2, 1, 3]); + * expect([1, 2, 2]).to.have.members([2, 1, 2]); + * + * By default, members are compared using strict (`===`) equality. Add `.deep` + * earlier in the chain to use deep equality instead. See the `deep-eql` + * project page for info on the deep equality algorithm: + * https://github.com/chaijs/deep-eql. + * + * // Target array deeply (but not strictly) has member `{a: 1}` + * expect([{a: 1}]).to.have.deep.members([{a: 1}]); + * expect([{a: 1}]).to.not.have.members([{a: 1}]); + * + * By default, order doesn't matter. Add `.ordered` earlier in the chain to + * require that members appear in the same order. + * + * expect([1, 2, 3]).to.have.ordered.members([1, 2, 3]); + * expect([1, 2, 3]).to.have.members([2, 1, 3]) + * .but.not.ordered.members([2, 1, 3]); + * + * By default, both arrays must be the same size. Add `.include` earlier in + * the chain to require that the target's members be a superset of the + * expected members. Note that duplicates are ignored in the subset when + * `.include` is added. + * + * // Target array is a superset of [1, 2] but not identical + * expect([1, 2, 3]).to.include.members([1, 2]); + * expect([1, 2, 3]).to.not.have.members([1, 2]); + * + * // Duplicates in the subset are ignored + * expect([1, 2, 3]).to.include.members([1, 2, 2, 2]); * - * Asserts that the target is a superset of `set`, - * or that the target and `set` have the same strictly-equal (===) members. - * Alternately, if the `deep` flag is set, set members are compared for deep - * equality. + * `.deep`, `.ordered`, and `.include` can all be combined. However, if + * `.include` and `.ordered` are combined, the ordering begins at the start of + * both arrays. * - * expect([1, 2, 3]).to.include.members([3, 2]); - * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); + * expect([{a: 1}, {b: 2}, {c: 3}]) + * .to.include.deep.ordered.members([{a: 1}, {b: 2}]) + * .but.not.include.deep.ordered.members([{b: 2}, {c: 3}]); * - * expect([4, 2]).to.have.members([2, 4]); - * expect([5, 2]).to.not.have.members([5, 2, 1]); + * Add `.not` earlier in the chain to negate `.members`. However, it's + * dangerous to do so. The problem is that it creates uncertain expectations + * by asserting that the target array doesn't have all of the same members as + * the given array `set` but may or may not have some of them. It's often best + * to identify the exact output that's expected, and then write an assertion + * that only accepts that exact output. * - * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); + * expect([1, 2]).to.not.include(3).and.not.include(4); // Recommended + * expect([1, 2]).to.not.have.members([3, 4]); // Not recommended + * + * `.members` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. + * + * expect([1, 2]).to.have.members([1, 2, 3], 'nooo why fail??'); + * expect([1, 2], 'nooo why fail??').to.have.members([1, 2, 3]); * * @name members * @param {Array} set - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ Assertion.addMethod('members', function (subset, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); + var obj = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); - new Assertion(obj).to.be.an('array'); - new Assertion(subset).to.be.an('array'); + new Assertion(obj, flagMsg, ssfi, true).to.be.an('array'); + new Assertion(subset, flagMsg, ssfi, true).to.be.an('array'); - var cmp = flag(this, 'deep') ? _.eql : undefined; + var contains = flag(this, 'contains'); + var ordered = flag(this, 'ordered'); - if (flag(this, 'contains')) { - return this.assert( - isSubsetOf(subset, obj, cmp) - , 'expected #{this} to be a superset of #{act}' - , 'expected #{this} to not be a superset of #{act}' - , obj - , subset - ); + var subject, failMsg, failNegateMsg; + + if (contains) { + subject = ordered ? 'an ordered superset' : 'a superset'; + failMsg = 'expected #{this} to be ' + subject + ' of #{exp}'; + failNegateMsg = 'expected #{this} to not be ' + subject + ' of #{exp}'; + } else { + subject = ordered ? 'ordered members' : 'members'; + failMsg = 'expected #{this} to have the same ' + subject + ' as #{exp}'; + failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}'; } + var cmp = flag(this, 'deep') ? _.eql : undefined; + this.assert( - isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) - , 'expected #{this} to have the same members as #{act}' - , 'expected #{this} to not have the same members as #{act}' - , obj - , subset + isSubsetOf(subset, obj, cmp, contains, ordered) + , failMsg + , failNegateMsg + , subset + , obj + , true ); }); /** - * ### .oneOf(list) + * ### .oneOf(list[, msg]) + * + * Asserts that the target is a member of the given array `list`. However, + * it's often best to assert that the target is equal to its expected value. + * + * expect(1).to.equal(1); // Recommended + * expect(1).to.be.oneOf([1, 2, 3]); // Not recommended + * + * Comparisons are performed using strict (`===`) equality. * - * Assert that a value appears somewhere in the top level of array `list`. + * Add `.not` earlier in the chain to negate `.oneOf`. * - * expect('a').to.be.oneOf(['a', 'b', 'c']); - * expect(9).to.not.be.oneOf(['z']); - * expect([3]).to.not.be.oneOf([1, 2, [3]]); + * expect(1).to.equal(1); // Recommended + * expect(1).to.not.be.oneOf([2, 3, 4]); // Not recommended * - * var three = [3]; - * // for object-types, contents are not compared - * expect(three).to.not.be.oneOf([1, 2, [3]]); - * // comparing references works - * expect(three).to.be.oneOf([1, 2, three]); + * `.oneOf` accepts an optional `msg` argument which is a custom error message + * to show when the assertion fails. The message can also be given as the + * second argument to `expect`. + * + * expect(1).to.be.oneOf([2, 3, 4], 'nooo why fail??'); + * expect(1, 'nooo why fail??').to.be.oneOf([2, 3, 4]); * * @name oneOf * @param {Array<*>} list - * @param {String} message _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ function oneOf (list, msg) { if (msg) flag(this, 'message', msg); - var expected = flag(this, 'object'); - new Assertion(list).to.be.an('array'); + var expected = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); + new Assertion(list, flagMsg, ssfi, true).to.be.an('array'); this.assert( list.indexOf(expected) > -1 @@ -1904,159 +3510,505 @@ module.exports = function (chai, _) { Assertion.addMethod('oneOf', oneOf); - /** - * ### .change(function) + * ### .change(subject[, prop[, msg]]) * - * Asserts that a function changes an object property + * When one argument is provided, `.change` asserts that the given function + * `subject` returns a different value when it's invoked before the target + * function compared to when it's invoked afterward. However, it's often best + * to assert that `subject` is equal to its expected value. * - * var obj = { val: 10 }; - * var fn = function() { obj.val += 3 }; - * var noChangeFn = function() { return 'foo' + 'bar'; } - * expect(fn).to.change(obj, 'val'); - * expect(noChangeFn).to.not.change(obj, 'val') + * var dots = '' + * , addDot = function () { dots += '.'; } + * , getDots = function () { return dots; }; + * + * // Recommended + * expect(getDots()).to.equal(''); + * addDot(); + * expect(getDots()).to.equal('.'); + * + * // Not recommended + * expect(addDot).to.change(getDots); + * + * When two arguments are provided, `.change` asserts that the value of the + * given object `subject`'s `prop` property is different before invoking the + * target function compared to afterward. + * + * var myObj = {dots: ''} + * , addDot = function () { myObj.dots += '.'; }; + * + * // Recommended + * expect(myObj).to.have.property('dots', ''); + * addDot(); + * expect(myObj).to.have.property('dots', '.'); + * + * // Not recommended + * expect(addDot).to.change(myObj, 'dots'); + * + * Strict (`===`) equality is used to compare before and after values. + * + * Add `.not` earlier in the chain to negate `.change`. + * + * var dots = '' + * , noop = function () {} + * , getDots = function () { return dots; }; + * + * expect(noop).to.not.change(getDots); + * + * var myObj = {dots: ''} + * , noop = function () {}; + * + * expect(noop).to.not.change(myObj, 'dots'); + * + * `.change` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. When not providing two arguments, always + * use the second form. + * + * var myObj = {dots: ''} + * , addDot = function () { myObj.dots += '.'; }; + * + * expect(addDot).to.not.change(myObj, 'dots', 'nooo why fail??'); + * + * var dots = '' + * , addDot = function () { dots += '.'; } + * , getDots = function () { return dots; }; + * + * expect(addDot, 'nooo why fail??').to.not.change(getDots); + * + * `.change` also causes all `.by` assertions that follow in the chain to + * assert how much a numeric subject was increased or decreased by. However, + * it's dangerous to use `.change.by`. The problem is that it creates + * uncertain expectations by asserting that the subject either increases by + * the given delta, or that it decreases by the given delta. It's often best + * to identify the exact output that's expected, and then write an assertion + * that only accepts that exact output. + * + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; } + * , subtractTwo = function () { myObj.val -= 2; }; + * + * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended + * expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended + * + * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended + * expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended + * + * The alias `.changes` can be used interchangeably with `.change`. * * @name change * @alias changes - * @alias Change - * @param {String} object - * @param {String} property name - * @param {String} message _optional_ + * @param {String} subject + * @param {String} prop name _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ - function assertChanges (object, prop, msg) { + function assertChanges (subject, prop, msg) { if (msg) flag(this, 'message', msg); - var fn = flag(this, 'object'); - new Assertion(object, msg).to.have.property(prop); - new Assertion(fn).is.a('function'); + var fn = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); + new Assertion(fn, flagMsg, ssfi, true).is.a('function'); + + var initial; + if (!prop) { + new Assertion(subject, flagMsg, ssfi, true).is.a('function'); + initial = subject(); + } else { + new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop); + initial = subject[prop]; + } - var initial = object[prop]; fn(); + var final = prop === undefined || prop === null ? subject() : subject[prop]; + var msgObj = prop === undefined || prop === null ? initial : '.' + prop; + + // This gets flagged because of the .by(delta) assertion + flag(this, 'deltaMsgObj', msgObj); + flag(this, 'initialDeltaValue', initial); + flag(this, 'finalDeltaValue', final); + flag(this, 'deltaBehavior', 'change'); + flag(this, 'realDelta', final !== initial); + this.assert( - initial !== object[prop] - , 'expected .' + prop + ' to change' - , 'expected .' + prop + ' to not change' + initial !== final + , 'expected ' + msgObj + ' to change' + , 'expected ' + msgObj + ' to not change' ); } - Assertion.addChainableMethod('change', assertChanges); - Assertion.addChainableMethod('changes', assertChanges); + Assertion.addMethod('change', assertChanges); + Assertion.addMethod('changes', assertChanges); /** - * ### .increase(function) + * ### .increase(subject[, prop[, msg]]) * - * Asserts that a function increases an object property + * When one argument is provided, `.increase` asserts that the given function + * `subject` returns a greater number when it's invoked after invoking the + * target function compared to when it's invoked beforehand. `.increase` also + * causes all `.by` assertions that follow in the chain to assert how much + * greater of a number is returned. It's often best to assert that the return + * value increased by the expected amount, rather than asserting it increased + * by any amount. * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 15 }; - * expect(fn).to.increase(obj, 'val'); + * var val = 1 + * , addTwo = function () { val += 2; } + * , getVal = function () { return val; }; + * + * expect(addTwo).to.increase(getVal).by(2); // Recommended + * expect(addTwo).to.increase(getVal); // Not recommended + * + * When two arguments are provided, `.increase` asserts that the value of the + * given object `subject`'s `prop` property is greater after invoking the + * target function compared to beforehand. + * + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; }; + * + * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended + * expect(addTwo).to.increase(myObj, 'val'); // Not recommended + * + * Add `.not` earlier in the chain to negate `.increase`. However, it's + * dangerous to do so. The problem is that it creates uncertain expectations + * by asserting that the subject either decreases, or that it stays the same. + * It's often best to identify the exact output that's expected, and then + * write an assertion that only accepts that exact output. + * + * When the subject is expected to decrease, it's often best to assert that it + * decreased by the expected amount. + * + * var myObj = {val: 1} + * , subtractTwo = function () { myObj.val -= 2; }; + * + * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended + * expect(subtractTwo).to.not.increase(myObj, 'val'); // Not recommended + * + * When the subject is expected to stay the same, it's often best to assert + * exactly that. + * + * var myObj = {val: 1} + * , noop = function () {}; + * + * expect(noop).to.not.change(myObj, 'val'); // Recommended + * expect(noop).to.not.increase(myObj, 'val'); // Not recommended + * + * `.increase` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. When not providing two arguments, always + * use the second form. + * + * var myObj = {val: 1} + * , noop = function () {}; + * + * expect(noop).to.increase(myObj, 'val', 'nooo why fail??'); + * + * var val = 1 + * , noop = function () {} + * , getVal = function () { return val; }; + * + * expect(noop, 'nooo why fail??').to.increase(getVal); + * + * The alias `.increases` can be used interchangeably with `.increase`. * * @name increase * @alias increases - * @alias Increase - * @param {String} object - * @param {String} property name - * @param {String} message _optional_ + * @param {String|Function} subject + * @param {String} prop name _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ - function assertIncreases (object, prop, msg) { + function assertIncreases (subject, prop, msg) { if (msg) flag(this, 'message', msg); - var fn = flag(this, 'object'); - new Assertion(object, msg).to.have.property(prop); - new Assertion(fn).is.a('function'); + var fn = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); + new Assertion(fn, flagMsg, ssfi, true).is.a('function'); + + var initial; + if (!prop) { + new Assertion(subject, flagMsg, ssfi, true).is.a('function'); + initial = subject(); + } else { + new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop); + initial = subject[prop]; + } + + // Make sure that the target is a number + new Assertion(initial, flagMsg, ssfi, true).is.a('number'); - var initial = object[prop]; fn(); + var final = prop === undefined || prop === null ? subject() : subject[prop]; + var msgObj = prop === undefined || prop === null ? initial : '.' + prop; + + flag(this, 'deltaMsgObj', msgObj); + flag(this, 'initialDeltaValue', initial); + flag(this, 'finalDeltaValue', final); + flag(this, 'deltaBehavior', 'increase'); + flag(this, 'realDelta', final - initial); + this.assert( - object[prop] - initial > 0 - , 'expected .' + prop + ' to increase' - , 'expected .' + prop + ' to not increase' + final - initial > 0 + , 'expected ' + msgObj + ' to increase' + , 'expected ' + msgObj + ' to not increase' ); } - Assertion.addChainableMethod('increase', assertIncreases); - Assertion.addChainableMethod('increases', assertIncreases); + Assertion.addMethod('increase', assertIncreases); + Assertion.addMethod('increases', assertIncreases); /** - * ### .decrease(function) + * ### .decrease(subject[, prop[, msg]]) * - * Asserts that a function decreases an object property + * When one argument is provided, `.decrease` asserts that the given function + * `subject` returns a lesser number when it's invoked after invoking the + * target function compared to when it's invoked beforehand. `.decrease` also + * causes all `.by` assertions that follow in the chain to assert how much + * lesser of a number is returned. It's often best to assert that the return + * value decreased by the expected amount, rather than asserting it decreased + * by any amount. * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 5 }; - * expect(fn).to.decrease(obj, 'val'); + * var val = 1 + * , subtractTwo = function () { val -= 2; } + * , getVal = function () { return val; }; + * + * expect(subtractTwo).to.decrease(getVal).by(2); // Recommended + * expect(subtractTwo).to.decrease(getVal); // Not recommended + * + * When two arguments are provided, `.decrease` asserts that the value of the + * given object `subject`'s `prop` property is lesser after invoking the + * target function compared to beforehand. + * + * var myObj = {val: 1} + * , subtractTwo = function () { myObj.val -= 2; }; + * + * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended + * expect(subtractTwo).to.decrease(myObj, 'val'); // Not recommended + * + * Add `.not` earlier in the chain to negate `.decrease`. However, it's + * dangerous to do so. The problem is that it creates uncertain expectations + * by asserting that the subject either increases, or that it stays the same. + * It's often best to identify the exact output that's expected, and then + * write an assertion that only accepts that exact output. + * + * When the subject is expected to increase, it's often best to assert that it + * increased by the expected amount. + * + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; }; + * + * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended + * expect(addTwo).to.not.decrease(myObj, 'val'); // Not recommended + * + * When the subject is expected to stay the same, it's often best to assert + * exactly that. + * + * var myObj = {val: 1} + * , noop = function () {}; + * + * expect(noop).to.not.change(myObj, 'val'); // Recommended + * expect(noop).to.not.decrease(myObj, 'val'); // Not recommended + * + * `.decrease` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. When not providing two arguments, always + * use the second form. + * + * var myObj = {val: 1} + * , noop = function () {}; + * + * expect(noop).to.decrease(myObj, 'val', 'nooo why fail??'); + * + * var val = 1 + * , noop = function () {} + * , getVal = function () { return val; }; + * + * expect(noop, 'nooo why fail??').to.decrease(getVal); + * + * The alias `.decreases` can be used interchangeably with `.decrease`. * * @name decrease * @alias decreases - * @alias Decrease - * @param {String} object - * @param {String} property name - * @param {String} message _optional_ + * @param {String|Function} subject + * @param {String} prop name _optional_ + * @param {String} msg _optional_ * @namespace BDD * @api public */ - function assertDecreases (object, prop, msg) { + function assertDecreases (subject, prop, msg) { if (msg) flag(this, 'message', msg); - var fn = flag(this, 'object'); - new Assertion(object, msg).to.have.property(prop); - new Assertion(fn).is.a('function'); + var fn = flag(this, 'object') + , flagMsg = flag(this, 'message') + , ssfi = flag(this, 'ssfi'); + new Assertion(fn, flagMsg, ssfi, true).is.a('function'); + + var initial; + if (!prop) { + new Assertion(subject, flagMsg, ssfi, true).is.a('function'); + initial = subject(); + } else { + new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop); + initial = subject[prop]; + } + + // Make sure that the target is a number + new Assertion(initial, flagMsg, ssfi, true).is.a('number'); - var initial = object[prop]; fn(); + var final = prop === undefined || prop === null ? subject() : subject[prop]; + var msgObj = prop === undefined || prop === null ? initial : '.' + prop; + + flag(this, 'deltaMsgObj', msgObj); + flag(this, 'initialDeltaValue', initial); + flag(this, 'finalDeltaValue', final); + flag(this, 'deltaBehavior', 'decrease'); + flag(this, 'realDelta', initial - final); + this.assert( - object[prop] - initial < 0 - , 'expected .' + prop + ' to decrease' - , 'expected .' + prop + ' to not decrease' + final - initial < 0 + , 'expected ' + msgObj + ' to decrease' + , 'expected ' + msgObj + ' to not decrease' ); } - Assertion.addChainableMethod('decrease', assertDecreases); - Assertion.addChainableMethod('decreases', assertDecreases); + Assertion.addMethod('decrease', assertDecreases); + Assertion.addMethod('decreases', assertDecreases); /** - * ### .extensible + * ### .by(delta[, msg]) * - * Asserts that the target is extensible (can have new properties added to - * it). + * When following an `.increase` assertion in the chain, `.by` asserts that + * the subject of the `.increase` assertion increased by the given `delta`. * - * var nonExtensibleObject = Object.preventExtensions({}); - * var sealedObject = Object.seal({}); - * var frozenObject = Object.freeze({}); + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; }; * - * expect({}).to.be.extensible; - * expect(nonExtensibleObject).to.not.be.extensible; - * expect(sealedObject).to.not.be.extensible; - * expect(frozenObject).to.not.be.extensible; + * expect(addTwo).to.increase(myObj, 'val').by(2); * - * @name extensible + * When following a `.decrease` assertion in the chain, `.by` asserts that the + * subject of the `.decrease` assertion decreased by the given `delta`. + * + * var myObj = {val: 1} + * , subtractTwo = function () { myObj.val -= 2; }; + * + * expect(subtractTwo).to.decrease(myObj, 'val').by(2); + * + * When following a `.change` assertion in the chain, `.by` asserts that the + * subject of the `.change` assertion either increased or decreased by the + * given `delta`. However, it's dangerous to use `.change.by`. The problem is + * that it creates uncertain expectations. It's often best to identify the + * exact output that's expected, and then write an assertion that only accepts + * that exact output. + * + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; } + * , subtractTwo = function () { myObj.val -= 2; }; + * + * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended + * expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended + * + * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended + * expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended + * + * Add `.not` earlier in the chain to negate `.by`. However, it's often best + * to assert that the subject changed by its expected delta, rather than + * asserting that it didn't change by one of countless unexpected deltas. + * + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; }; + * + * // Recommended + * expect(addTwo).to.increase(myObj, 'val').by(2); + * + * // Not recommended + * expect(addTwo).to.increase(myObj, 'val').but.not.by(3); + * + * `.by` accepts an optional `msg` argument which is a custom error message to + * show when the assertion fails. The message can also be given as the second + * argument to `expect`. + * + * var myObj = {val: 1} + * , addTwo = function () { myObj.val += 2; }; + * + * expect(addTwo).to.increase(myObj, 'val').by(3, 'nooo why fail??'); + * expect(addTwo, 'nooo why fail??').to.increase(myObj, 'val').by(3); + * + * @name by + * @param {Number} delta + * @param {String} msg _optional_ * @namespace BDD * @api public */ - Assertion.addProperty('extensible', function() { - var obj = flag(this, 'object'); + function assertDelta(delta, msg) { + if (msg) flag(this, 'message', msg); - // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. - // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible - // The following provides ES6 behavior when a TypeError is thrown under ES5. + var msgObj = flag(this, 'deltaMsgObj'); + var initial = flag(this, 'initialDeltaValue'); + var final = flag(this, 'finalDeltaValue'); + var behavior = flag(this, 'deltaBehavior'); + var realDelta = flag(this, 'realDelta'); - var isExtensible; + var expression; + if (behavior === 'change') { + expression = Math.abs(final - initial) === Math.abs(delta); + } else { + expression = realDelta === Math.abs(delta); + } - try { - isExtensible = Object.isExtensible(obj); - } catch (err) { - if (err instanceof TypeError) isExtensible = false; - else throw err; - } + this.assert( + expression + , 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta + , 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta + ); + } + + Assertion.addMethod('by', assertDelta); + + /** + * ### .extensible + * + * Asserts that the target is extensible, which means that new properties can + * be added to it. Primitives are never extensible. + * + * expect({a: 1}).to.be.extensible; + * + * Add `.not` earlier in the chain to negate `.extensible`. + * + * var nonExtensibleObject = Object.preventExtensions({}) + * , sealedObject = Object.seal({}) + * , frozenObject = Object.freeze({}); + * + * expect(nonExtensibleObject).to.not.be.extensible; + * expect(sealedObject).to.not.be.extensible; + * expect(frozenObject).to.not.be.extensible; + * expect(1).to.not.be.extensible; + * + * A custom error message can be given as the second argument to `expect`. + * + * expect(1, 'nooo why fail??').to.be.extensible; + * + * @name extensible + * @namespace BDD + * @api public + */ + + Assertion.addProperty('extensible', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is a primitive, then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible + // The following provides ES6 behavior for ES5 environments. + + var isExtensible = obj === Object(obj) && Object.isExtensible(obj); this.assert( isExtensible @@ -2068,15 +4020,25 @@ module.exports = function (chai, _) { /** * ### .sealed * - * Asserts that the target is sealed (cannot have new properties added to it - * and its existing properties cannot be removed). + * Asserts that the target is sealed, which means that new properties can't be + * added to it, and its existing properties can't be reconfigured or deleted. + * However, it's possible that its existing properties can still be reassigned + * to different values. Primitives are always sealed. * * var sealedObject = Object.seal({}); * var frozenObject = Object.freeze({}); * * expect(sealedObject).to.be.sealed; * expect(frozenObject).to.be.sealed; - * expect({}).to.not.be.sealed; + * expect(1).to.be.sealed; + * + * Add `.not` earlier in the chain to negate `.sealed`. + * + * expect({a: 1}).to.not.be.sealed; + * + * A custom error message can be given as the second argument to `expect`. + * + * expect({a: 1}, 'nooo why fail??').to.be.sealed; * * @name sealed * @namespace BDD @@ -2086,19 +4048,12 @@ module.exports = function (chai, _) { Assertion.addProperty('sealed', function() { var obj = flag(this, 'object'); - // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES5, if the argument to this method is a primitive, then it will cause a TypeError. // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed - // The following provides ES6 behavior when a TypeError is thrown under ES5. + // The following provides ES6 behavior for ES5 environments. - var isSealed; - - try { - isSealed = Object.isSealed(obj); - } catch (err) { - if (err instanceof TypeError) isSealed = true; - else throw err; - } + var isSealed = obj === Object(obj) ? Object.isSealed(obj) : true; this.assert( isSealed @@ -2110,13 +4065,22 @@ module.exports = function (chai, _) { /** * ### .frozen * - * Asserts that the target is frozen (cannot have new properties added to it - * and its existing properties cannot be modified). + * Asserts that the target is frozen, which means that new properties can't be + * added to it, and its existing properties can't be reassigned to different + * values, reconfigured, or deleted. Primitives are always frozen. * * var frozenObject = Object.freeze({}); * * expect(frozenObject).to.be.frozen; - * expect({}).to.not.be.frozen; + * expect(1).to.be.frozen; + * + * Add `.not` earlier in the chain to negate `.frozen`. + * + * expect({a: 1}).to.not.be.frozen; + * + * A custom error message can be given as the second argument to `expect`. + * + * expect({a: 1}, 'nooo why fail??').to.be.frozen; * * @name frozen * @namespace BDD @@ -2126,19 +4090,12 @@ module.exports = function (chai, _) { Assertion.addProperty('frozen', function() { var obj = flag(this, 'object'); - // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES5, if the argument to this method is a primitive, then it will cause a TypeError. // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen - // The following provides ES6 behavior when a TypeError is thrown under ES5. - - var isFrozen; + // The following provides ES6 behavior for ES5 environments. - try { - isFrozen = Object.isFrozen(obj); - } catch (err) { - if (err instanceof TypeError) isFrozen = true; - else throw err; - } + var isFrozen = obj === Object(obj) ? Object.isFrozen(obj) : true; this.assert( isFrozen @@ -2146,6 +4103,65 @@ module.exports = function (chai, _) { , 'expected #{this} to not be frozen' ); }); + + /** + * ### .finite + * + * Asserts that the target is a number, and isn't `NaN` or positive/negative + * `Infinity`. + * + * expect(1).to.be.finite; + * + * Add `.not` earlier in the chain to negate `.finite`. However, it's + * dangerous to do so. The problem is that it creates uncertain expectations + * by asserting that the subject either isn't a number, or that it's `NaN`, or + * that it's positive `Infinity`, or that it's negative `Infinity`. It's often + * best to identify the exact output that's expected, and then write an + * assertion that only accepts that exact output. + * + * When the target isn't expected to be a number, it's often best to assert + * that it's the expected type, rather than asserting that it isn't one of + * many unexpected types. + * + * expect('foo').to.be.a('string'); // Recommended + * expect('foo').to.not.be.finite; // Not recommended + * + * When the target is expected to be `NaN`, it's often best to assert exactly + * that. + * + * expect(NaN).to.be.NaN; // Recommended + * expect(NaN).to.not.be.finite; // Not recommended + * + * When the target is expected to be positive infinity, it's often best to + * assert exactly that. + * + * expect(Infinity).to.equal(Infinity); // Recommended + * expect(Infinity).to.not.be.finite; // Not recommended + * + * When the target is expected to be negative infinity, it's often best to + * assert exactly that. + * + * expect(-Infinity).to.equal(-Infinity); // Recommended + * expect(-Infinity).to.not.be.finite; // Not recommended + * + * A custom error message can be given as the second argument to `expect`. + * + * expect('foo', 'nooo why fail??').to.be.finite; + * + * @name finite + * @namespace BDD + * @api public + */ + + Assertion.addProperty('finite', function(msg) { + var obj = flag(this, 'object'); + + this.assert( + typeof obj === 'number' && isFinite(obj) + , 'expected #{this} to be a finite number' + , 'expected #{this} to not be a finite number' + ); + }); }; },{}],6:[function(require,module,exports){ @@ -2155,9 +4171,7 @@ module.exports = function (chai, _) { * MIT Licensed */ - module.exports = function (chai, util) { - /*! * Chai dependencies. */ @@ -2185,7 +4199,7 @@ module.exports = function (chai, util) { */ var assert = chai.assert = function (express, errmsg) { - var test = new Assertion(null, null, chai.assert); + var test = new Assertion(null, null, chai.assert, true); test.assert( express , errmsg @@ -2194,10 +4208,18 @@ module.exports = function (chai, util) { }; /** + * ### .fail([message]) * ### .fail(actual, expected, [message], [operator]) * * Throw a failure. Node.js `assert` module-compatible. * + * assert.fail(); + * assert.fail("custom error message"); + * assert.fail(1, 2); + * assert.fail(1, 2, "custom error message"); + * assert.fail(1, 2, "custom error message", ">"); + * assert.fail(1, 2, undefined, ">"); + * * @name fail * @param {Mixed} actual * @param {Mixed} expected @@ -2208,6 +4230,13 @@ module.exports = function (chai, util) { */ assert.fail = function (actual, expected, message, operator) { + if (arguments.length < 2) { + // Comply with Node's fail([message]) interface + + message = actual; + actual = undefined; + } + message = message || 'assert.fail()'; throw new chai.AssertionError(message, { actual: actual @@ -2233,7 +4262,7 @@ module.exports = function (chai, util) { */ assert.isOk = function (val, msg) { - new Assertion(val, msg).is.ok; + new Assertion(val, msg, assert.isOk, true).is.ok; }; /** @@ -2253,7 +4282,7 @@ module.exports = function (chai, util) { */ assert.isNotOk = function (val, msg) { - new Assertion(val, msg).is.not.ok; + new Assertion(val, msg, assert.isNotOk, true).is.not.ok; }; /** @@ -2272,7 +4301,7 @@ module.exports = function (chai, util) { */ assert.equal = function (act, exp, msg) { - var test = new Assertion(act, msg, assert.equal); + var test = new Assertion(act, msg, assert.equal, true); test.assert( exp == flag(test, 'object') @@ -2280,6 +4309,7 @@ module.exports = function (chai, util) { , 'expected #{this} to not equal #{act}' , exp , act + , true ); }; @@ -2299,7 +4329,7 @@ module.exports = function (chai, util) { */ assert.notEqual = function (act, exp, msg) { - var test = new Assertion(act, msg, assert.notEqual); + var test = new Assertion(act, msg, assert.notEqual, true); test.assert( exp != flag(test, 'object') @@ -2307,6 +4337,7 @@ module.exports = function (chai, util) { , 'expected #{this} to equal #{act}' , exp , act + , true ); }; @@ -2326,7 +4357,7 @@ module.exports = function (chai, util) { */ assert.strictEqual = function (act, exp, msg) { - new Assertion(act, msg).to.equal(exp); + new Assertion(act, msg, assert.strictEqual, true).to.equal(exp); }; /** @@ -2345,7 +4376,7 @@ module.exports = function (chai, util) { */ assert.notStrictEqual = function (act, exp, msg) { - new Assertion(act, msg).to.not.equal(exp); + new Assertion(act, msg, assert.notStrictEqual, true).to.not.equal(exp); }; /** @@ -2359,12 +4390,13 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @alias deepStrictEqual * @namespace Assert * @api public */ - assert.deepEqual = function (act, exp, msg) { - new Assertion(act, msg).to.eql(exp); + assert.deepEqual = assert.deepStrictEqual = function (act, exp, msg) { + new Assertion(act, msg, assert.deepEqual, true).to.eql(exp); }; /** @@ -2383,13 +4415,13 @@ module.exports = function (chai, util) { */ assert.notDeepEqual = function (act, exp, msg) { - new Assertion(act, msg).to.not.eql(exp); + new Assertion(act, msg, assert.notDeepEqual, true).to.not.eql(exp); }; /** * ### .isAbove(valueToCheck, valueToBeAbove, [message]) * - * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove` + * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove`. * * assert.isAbove(5, 2, '5 is strictly greater than 2'); * @@ -2402,13 +4434,13 @@ module.exports = function (chai, util) { */ assert.isAbove = function (val, abv, msg) { - new Assertion(val, msg).to.be.above(abv); + new Assertion(val, msg, assert.isAbove, true).to.be.above(abv); }; /** * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message]) * - * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast` + * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast`. * * assert.isAtLeast(5, 2, '5 is greater or equal to 2'); * assert.isAtLeast(3, 3, '3 is greater or equal to 3'); @@ -2422,13 +4454,13 @@ module.exports = function (chai, util) { */ assert.isAtLeast = function (val, atlst, msg) { - new Assertion(val, msg).to.be.least(atlst); + new Assertion(val, msg, assert.isAtLeast, true).to.be.least(atlst); }; /** * ### .isBelow(valueToCheck, valueToBeBelow, [message]) * - * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow` + * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow`. * * assert.isBelow(3, 6, '3 is strictly less than 6'); * @@ -2441,13 +4473,13 @@ module.exports = function (chai, util) { */ assert.isBelow = function (val, blw, msg) { - new Assertion(val, msg).to.be.below(blw); + new Assertion(val, msg, assert.isBelow, true).to.be.below(blw); }; /** * ### .isAtMost(valueToCheck, valueToBeAtMost, [message]) * - * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost` + * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost`. * * assert.isAtMost(3, 6, '3 is less than or equal to 6'); * assert.isAtMost(4, 4, '4 is less than or equal to 4'); @@ -2461,7 +4493,7 @@ module.exports = function (chai, util) { */ assert.isAtMost = function (val, atmst, msg) { - new Assertion(val, msg).to.be.most(atmst); + new Assertion(val, msg, assert.isAtMost, true).to.be.most(atmst); }; /** @@ -2480,7 +4512,7 @@ module.exports = function (chai, util) { */ assert.isTrue = function (val, msg) { - new Assertion(val, msg).is['true']; + new Assertion(val, msg, assert.isTrue, true).is['true']; }; /** @@ -2499,7 +4531,7 @@ module.exports = function (chai, util) { */ assert.isNotTrue = function (val, msg) { - new Assertion(val, msg).to.not.equal(true); + new Assertion(val, msg, assert.isNotTrue, true).to.not.equal(true); }; /** @@ -2518,7 +4550,7 @@ module.exports = function (chai, util) { */ assert.isFalse = function (val, msg) { - new Assertion(val, msg).is['false']; + new Assertion(val, msg, assert.isFalse, true).is['false']; }; /** @@ -2537,7 +4569,7 @@ module.exports = function (chai, util) { */ assert.isNotFalse = function (val, msg) { - new Assertion(val, msg).to.not.equal(false); + new Assertion(val, msg, assert.isNotFalse, true).to.not.equal(false); }; /** @@ -2555,7 +4587,7 @@ module.exports = function (chai, util) { */ assert.isNull = function (val, msg) { - new Assertion(val, msg).to.equal(null); + new Assertion(val, msg, assert.isNull, true).to.equal(null); }; /** @@ -2574,14 +4606,15 @@ module.exports = function (chai, util) { */ assert.isNotNull = function (val, msg) { - new Assertion(val, msg).to.not.equal(null); + new Assertion(val, msg, assert.isNotNull, true).to.not.equal(null); }; /** * ### .isNaN - * Asserts that value is NaN * - * assert.isNaN('foo', 'foo is NaN'); + * Asserts that value is NaN. + * + * assert.isNaN(NaN, 'NaN is NaN'); * * @name isNaN * @param {Mixed} value @@ -2591,14 +4624,15 @@ module.exports = function (chai, util) { */ assert.isNaN = function (val, msg) { - new Assertion(val, msg).to.be.NaN; + new Assertion(val, msg, assert.isNaN, true).to.be.NaN; }; /** * ### .isNotNaN - * Asserts that value is not NaN * - * assert.isNotNaN(4, '4 is not NaN'); + * Asserts that value is not NaN. + * + * assert.isNotNaN(4, '4 is not NaN'); * * @name isNotNaN * @param {Mixed} value @@ -2607,7 +4641,49 @@ module.exports = function (chai, util) { * @api public */ assert.isNotNaN = function (val, msg) { - new Assertion(val, msg).not.to.be.NaN; + new Assertion(val, msg, assert.isNotNaN, true).not.to.be.NaN; + }; + + /** + * ### .exists + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi'; + * + * assert.exists(foo, 'foo is neither `null` nor `undefined`'); + * + * @name exists + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.exists = function (val, msg) { + new Assertion(val, msg, assert.exists, true).to.exist; + }; + + /** + * ### .notExists + * + * Asserts that the target is either `null` or `undefined`. + * + * var bar = null + * , baz; + * + * assert.notExists(bar); + * assert.notExists(baz, 'baz is either null or undefined'); + * + * @name notExists + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notExists = function (val, msg) { + new Assertion(val, msg, assert.notExists, true).to.not.exist; }; /** @@ -2626,7 +4702,7 @@ module.exports = function (chai, util) { */ assert.isUndefined = function (val, msg) { - new Assertion(val, msg).to.equal(undefined); + new Assertion(val, msg, assert.isUndefined, true).to.equal(undefined); }; /** @@ -2645,7 +4721,7 @@ module.exports = function (chai, util) { */ assert.isDefined = function (val, msg) { - new Assertion(val, msg).to.not.equal(undefined); + new Assertion(val, msg, assert.isDefined, true).to.not.equal(undefined); }; /** @@ -2664,7 +4740,7 @@ module.exports = function (chai, util) { */ assert.isFunction = function (val, msg) { - new Assertion(val, msg).to.be.a('function'); + new Assertion(val, msg, assert.isFunction, true).to.be.a('function'); }; /** @@ -2683,7 +4759,7 @@ module.exports = function (chai, util) { */ assert.isNotFunction = function (val, msg) { - new Assertion(val, msg).to.not.be.a('function'); + new Assertion(val, msg, assert.isNotFunction, true).to.not.be.a('function'); }; /** @@ -2703,7 +4779,7 @@ module.exports = function (chai, util) { */ assert.isObject = function (val, msg) { - new Assertion(val, msg).to.be.a('object'); + new Assertion(val, msg, assert.isObject, true).to.be.a('object'); }; /** @@ -2723,7 +4799,7 @@ module.exports = function (chai, util) { */ assert.isNotObject = function (val, msg) { - new Assertion(val, msg).to.not.be.a('object'); + new Assertion(val, msg, assert.isNotObject, true).to.not.be.a('object'); }; /** @@ -2742,7 +4818,7 @@ module.exports = function (chai, util) { */ assert.isArray = function (val, msg) { - new Assertion(val, msg).to.be.an('array'); + new Assertion(val, msg, assert.isArray, true).to.be.an('array'); }; /** @@ -2761,7 +4837,7 @@ module.exports = function (chai, util) { */ assert.isNotArray = function (val, msg) { - new Assertion(val, msg).to.not.be.an('array'); + new Assertion(val, msg, assert.isNotArray, true).to.not.be.an('array'); }; /** @@ -2780,7 +4856,7 @@ module.exports = function (chai, util) { */ assert.isString = function (val, msg) { - new Assertion(val, msg).to.be.a('string'); + new Assertion(val, msg, assert.isString, true).to.be.a('string'); }; /** @@ -2799,7 +4875,7 @@ module.exports = function (chai, util) { */ assert.isNotString = function (val, msg) { - new Assertion(val, msg).to.not.be.a('string'); + new Assertion(val, msg, assert.isNotString, true).to.not.be.a('string'); }; /** @@ -2818,7 +4894,7 @@ module.exports = function (chai, util) { */ assert.isNumber = function (val, msg) { - new Assertion(val, msg).to.be.a('number'); + new Assertion(val, msg, assert.isNumber, true).to.be.a('number'); }; /** @@ -2837,7 +4913,28 @@ module.exports = function (chai, util) { */ assert.isNotNumber = function (val, msg) { - new Assertion(val, msg).to.not.be.a('number'); + new Assertion(val, msg, assert.isNotNumber, true).to.not.be.a('number'); + }; + + /** + * ### .isFinite(value, [message]) + * + * Asserts that `value` is a finite number. Unlike `.isNumber`, this will fail for `NaN` and `Infinity`. + * + * var cups = 2; + * assert.isFinite(cups, 'how many cups'); + * + * assert.isFinite(NaN); // throws + * + * @name isFinite + * @param {Number} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isFinite = function (val, msg) { + new Assertion(val, msg, assert.isFinite, true).to.be.finite; }; /** @@ -2859,7 +4956,7 @@ module.exports = function (chai, util) { */ assert.isBoolean = function (val, msg) { - new Assertion(val, msg).to.be.a('boolean'); + new Assertion(val, msg, assert.isBoolean, true).to.be.a('boolean'); }; /** @@ -2881,7 +4978,7 @@ module.exports = function (chai, util) { */ assert.isNotBoolean = function (val, msg) { - new Assertion(val, msg).to.not.be.a('boolean'); + new Assertion(val, msg, assert.isNotBoolean, true).to.not.be.a('boolean'); }; /** @@ -2906,7 +5003,7 @@ module.exports = function (chai, util) { */ assert.typeOf = function (val, type, msg) { - new Assertion(val, msg).to.be.a(type); + new Assertion(val, msg, assert.typeOf, true).to.be.a(type); }; /** @@ -2926,7 +5023,7 @@ module.exports = function (chai, util) { */ assert.notTypeOf = function (val, type, msg) { - new Assertion(val, msg).to.not.be.a(type); + new Assertion(val, msg, assert.notTypeOf, true).to.not.be.a(type); }; /** @@ -2948,7 +5045,7 @@ module.exports = function (chai, util) { */ assert.instanceOf = function (val, type, msg) { - new Assertion(val, msg).to.be.instanceOf(type); + new Assertion(val, msg, assert.instanceOf, true).to.be.instanceOf(type); }; /** @@ -2970,17 +5067,32 @@ module.exports = function (chai, util) { */ assert.notInstanceOf = function (val, type, msg) { - new Assertion(val, msg).to.not.be.instanceOf(type); + new Assertion(val, msg, assert.notInstanceOf, true) + .to.not.be.instanceOf(type); }; /** * ### .include(haystack, needle, [message]) * - * Asserts that `haystack` includes `needle`. Works - * for strings and arrays. + * Asserts that `haystack` includes `needle`. Can be used to assert the + * inclusion of a value in an array, a substring in a string, or a subset of + * properties in an object. + * + * assert.include([1,2,3], 2, 'array contains value'); + * assert.include('foobar', 'foo', 'string contains substring'); + * assert.include({ foo: 'bar', hello: 'universe' }, { foo: 'bar' }, 'object contains property'); + * + * Strict equality (===) is used. When asserting the inclusion of a value in + * an array, the array is searched for an element that's strictly equal to the + * given value. When asserting a subset of properties in an object, the object + * is searched for the given property keys, checking that each one is present + * and strictly equal to the given property value. For instance: * - * assert.include('foobar', 'bar', 'foobar contains string "bar"'); - * assert.include([ 1, 2, 3 ], 3, 'array contains value'); + * var obj1 = {a: 1} + * , obj2 = {b: 2}; + * assert.include([obj1, obj2], obj1); + * assert.include({foo: obj1, bar: obj2}, {foo: obj1}); + * assert.include({foo: obj1, bar: obj2}, {foo: obj1, bar: obj2}); * * @name include * @param {Array|String} haystack @@ -2991,17 +5103,32 @@ module.exports = function (chai, util) { */ assert.include = function (exp, inc, msg) { - new Assertion(exp, msg, assert.include).include(inc); + new Assertion(exp, msg, assert.include, true).include(inc); }; /** * ### .notInclude(haystack, needle, [message]) * - * Asserts that `haystack` does not include `needle`. Works - * for strings and arrays. + * Asserts that `haystack` does not include `needle`. Can be used to assert + * the absence of a value in an array, a substring in a string, or a subset of + * properties in an object. * - * assert.notInclude('foobar', 'baz', 'string not include substring'); - * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); + * assert.notInclude([1,2,3], 4, "array doesn't contain value"); + * assert.notInclude('foobar', 'baz', "string doesn't contain substring"); + * assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn't contain property'); + * + * Strict equality (===) is used. When asserting the absence of a value in an + * array, the array is searched to confirm the absence of an element that's + * strictly equal to the given value. When asserting a subset of properties in + * an object, the object is searched to confirm that at least one of the given + * property keys is either not present or not strictly equal to the given + * property value. For instance: + * + * var obj1 = {a: 1} + * , obj2 = {b: 2}; + * assert.notInclude([obj1, obj2], {a: 1}); + * assert.notInclude({foo: obj1, bar: obj2}, {foo: {a: 1}}); + * assert.notInclude({foo: obj1, bar: obj2}, {foo: obj1, bar: {b: 2}}); * * @name notInclude * @param {Array|String} haystack @@ -3012,727 +5139,2030 @@ module.exports = function (chai, util) { */ assert.notInclude = function (exp, inc, msg) { - new Assertion(exp, msg, assert.notInclude).not.include(inc); + new Assertion(exp, msg, assert.notInclude, true).not.include(inc); }; /** - * ### .match(value, regexp, [message]) + * ### .deepInclude(haystack, needle, [message]) * - * Asserts that `value` matches the regular expression `regexp`. + * Asserts that `haystack` includes `needle`. Can be used to assert the + * inclusion of a value in an array or a subset of properties in an object. + * Deep equality is used. * - * assert.match('foobar', /^foo/, 'regexp matches'); + * var obj1 = {a: 1} + * , obj2 = {b: 2}; + * assert.deepInclude([obj1, obj2], {a: 1}); + * assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}}); + * assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 2}}); * - * @name match - * @param {Mixed} value - * @param {RegExp} regexp + * @name deepInclude + * @param {Array|String} haystack + * @param {Mixed} needle * @param {String} message * @namespace Assert * @api public */ - assert.match = function (exp, re, msg) { - new Assertion(exp, msg).to.match(re); + assert.deepInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.deepInclude, true).deep.include(inc); }; /** - * ### .notMatch(value, regexp, [message]) + * ### .notDeepInclude(haystack, needle, [message]) * - * Asserts that `value` does not match the regular expression `regexp`. + * Asserts that `haystack` does not include `needle`. Can be used to assert + * the absence of a value in an array or a subset of properties in an object. + * Deep equality is used. * - * assert.notMatch('foobar', /^foo/, 'regexp does not match'); + * var obj1 = {a: 1} + * , obj2 = {b: 2}; + * assert.notDeepInclude([obj1, obj2], {a: 9}); + * assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 9}}); + * assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}}); * - * @name notMatch - * @param {Mixed} value - * @param {RegExp} regexp + * @name notDeepInclude + * @param {Array|String} haystack + * @param {Mixed} needle * @param {String} message * @namespace Assert * @api public */ - assert.notMatch = function (exp, re, msg) { - new Assertion(exp, msg).to.not.match(re); + assert.notDeepInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.notDeepInclude, true).not.deep.include(inc); }; /** - * ### .property(object, property, [message]) + * ### .nestedInclude(haystack, needle, [message]) * - * Asserts that `object` has a property named by `property`. + * Asserts that 'haystack' includes 'needle'. + * Can be used to assert the inclusion of a subset of properties in an + * object. + * Enables the use of dot- and bracket-notation for referencing nested + * properties. + * '[]' and '.' in property names can be escaped using double backslashes. * - * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * assert.nestedInclude({'.a': {'b': 'x'}}, {'\\.a.[b]': 'x'}); + * assert.nestedInclude({'a': {'[b]': 'x'}}, {'a.\\[b\\]': 'x'}); * - * @name property - * @param {Object} object - * @param {String} property + * @name nestedInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.property = function (obj, prop, msg) { - new Assertion(obj, msg).to.have.property(prop); + assert.nestedInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.nestedInclude, true).nested.include(inc); }; /** - * ### .notProperty(object, property, [message]) + * ### .notNestedInclude(haystack, needle, [message]) * - * Asserts that `object` does _not_ have a property named by `property`. + * Asserts that 'haystack' does not include 'needle'. + * Can be used to assert the absence of a subset of properties in an + * object. + * Enables the use of dot- and bracket-notation for referencing nested + * properties. + * '[]' and '.' in property names can be escaped using double backslashes. * - * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); + * assert.notNestedInclude({'.a': {'b': 'x'}}, {'\\.a.b': 'y'}); + * assert.notNestedInclude({'a': {'[b]': 'x'}}, {'a.\\[b\\]': 'y'}); * - * @name notProperty - * @param {Object} object - * @param {String} property + * @name notNestedInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.notProperty = function (obj, prop, msg) { - new Assertion(obj, msg).to.not.have.property(prop); + assert.notNestedInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.notNestedInclude, true) + .not.nested.include(inc); }; /** - * ### .deepProperty(object, property, [message]) + * ### .deepNestedInclude(haystack, needle, [message]) * - * Asserts that `object` has a property named by `property`, which can be a - * string using dot- and bracket-notation for deep reference. + * Asserts that 'haystack' includes 'needle'. + * Can be used to assert the inclusion of a subset of properties in an + * object while checking for deep equality. + * Enables the use of dot- and bracket-notation for referencing nested + * properties. + * '[]' and '.' in property names can be escaped using double backslashes. * - * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); + * assert.deepNestedInclude({a: {b: [{x: 1}]}}, {'a.b[0]': {x: 1}}); + * assert.deepNestedInclude({'.a': {'[b]': {x: 1}}}, {'\\.a.\\[b\\]': {x: 1}}); * - * @name deepProperty - * @param {Object} object - * @param {String} property + * @name deepNestedInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.deepProperty = function (obj, prop, msg) { - new Assertion(obj, msg).to.have.deep.property(prop); + assert.deepNestedInclude = function(exp, inc, msg) { + new Assertion(exp, msg, assert.deepNestedInclude, true) + .deep.nested.include(inc); }; /** - * ### .notDeepProperty(object, property, [message]) + * ### .notDeepNestedInclude(haystack, needle, [message]) * - * Asserts that `object` does _not_ have a property named by `property`, which - * can be a string using dot- and bracket-notation for deep reference. + * Asserts that 'haystack' does not include 'needle'. + * Can be used to assert the absence of a subset of properties in an + * object while checking for deep equality. + * Enables the use of dot- and bracket-notation for referencing nested + * properties. + * '[]' and '.' in property names can be escaped using double backslashes. * - * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); + * assert.notDeepNestedInclude({a: {b: [{x: 1}]}}, {'a.b[0]': {y: 1}}) + * assert.notDeepNestedInclude({'.a': {'[b]': {x: 1}}}, {'\\.a.\\[b\\]': {y: 2}}); * - * @name notDeepProperty - * @param {Object} object - * @param {String} property + * @name notDeepNestedInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.notDeepProperty = function (obj, prop, msg) { - new Assertion(obj, msg).to.not.have.deep.property(prop); + assert.notDeepNestedInclude = function(exp, inc, msg) { + new Assertion(exp, msg, assert.notDeepNestedInclude, true) + .not.deep.nested.include(inc); }; /** - * ### .propertyVal(object, property, value, [message]) + * ### .ownInclude(haystack, needle, [message]) * - * Asserts that `object` has a property named by `property` with value given - * by `value`. + * Asserts that 'haystack' includes 'needle'. + * Can be used to assert the inclusion of a subset of properties in an + * object while ignoring inherited properties. * - * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); + * assert.ownInclude({ a: 1 }, { a: 1 }); * - * @name propertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value + * @name ownInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.propertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.have.property(prop, val); + assert.ownInclude = function(exp, inc, msg) { + new Assertion(exp, msg, assert.ownInclude, true).own.include(inc); }; /** - * ### .propertyNotVal(object, property, value, [message]) + * ### .notOwnInclude(haystack, needle, [message]) * - * Asserts that `object` has a property named by `property`, but with a value - * different from that given by `value`. + * Asserts that 'haystack' includes 'needle'. + * Can be used to assert the absence of a subset of properties in an + * object while ignoring inherited properties. * - * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); + * Object.prototype.b = 2; * - * @name propertyNotVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value + * assert.notOwnInclude({ a: 1 }, { b: 2 }); + * + * @name notOwnInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.propertyNotVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.not.have.property(prop, val); + assert.notOwnInclude = function(exp, inc, msg) { + new Assertion(exp, msg, assert.notOwnInclude, true).not.own.include(inc); }; /** - * ### .deepPropertyVal(object, property, value, [message]) + * ### .deepOwnInclude(haystack, needle, [message]) * - * Asserts that `object` has a property named by `property` with value given - * by `value`. `property` can use dot- and bracket-notation for deep - * reference. + * Asserts that 'haystack' includes 'needle'. + * Can be used to assert the inclusion of a subset of properties in an + * object while ignoring inherited properties and checking for deep equality. * - * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); + * assert.deepOwnInclude({a: {b: 2}}, {a: {b: 2}}); * - * @name deepPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value + * @name deepOwnInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.deepPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.have.deep.property(prop, val); + assert.deepOwnInclude = function(exp, inc, msg) { + new Assertion(exp, msg, assert.deepOwnInclude, true) + .deep.own.include(inc); }; - /** - * ### .deepPropertyNotVal(object, property, value, [message]) + /** + * ### .notDeepOwnInclude(haystack, needle, [message]) * - * Asserts that `object` has a property named by `property`, but with a value - * different from that given by `value`. `property` can use dot- and - * bracket-notation for deep reference. + * Asserts that 'haystack' includes 'needle'. + * Can be used to assert the absence of a subset of properties in an + * object while ignoring inherited properties and checking for deep equality. * - * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * assert.notDeepOwnInclude({a: {b: 2}}, {a: {c: 3}}); * - * @name deepPropertyNotVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value + * @name notDeepOwnInclude + * @param {Object} haystack + * @param {Object} needle * @param {String} message * @namespace Assert * @api public */ - assert.deepPropertyNotVal = function (obj, prop, val, msg) { - new Assertion(obj, msg).to.not.have.deep.property(prop, val); + assert.notDeepOwnInclude = function(exp, inc, msg) { + new Assertion(exp, msg, assert.notDeepOwnInclude, true) + .not.deep.own.include(inc); }; /** - * ### .lengthOf(object, length, [message]) + * ### .match(value, regexp, [message]) * - * Asserts that `object` has a `length` property with the expected value. + * Asserts that `value` matches the regular expression `regexp`. * - * assert.lengthOf([1,2,3], 3, 'array has length of 3'); - * assert.lengthOf('foobar', 6, 'string has length of 6'); + * assert.match('foobar', /^foo/, 'regexp matches'); * - * @name lengthOf - * @param {Mixed} object - * @param {Number} length + * @name match + * @param {Mixed} value + * @param {RegExp} regexp * @param {String} message * @namespace Assert * @api public */ - assert.lengthOf = function (exp, len, msg) { - new Assertion(exp, msg).to.have.length(len); + assert.match = function (exp, re, msg) { + new Assertion(exp, msg, assert.match, true).to.match(re); }; /** - * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) + * ### .notMatch(value, regexp, [message]) * - * Asserts that `function` will throw an error that is an instance of - * `constructor`, or alternately that it will throw an error with message - * matching `regexp`. + * Asserts that `value` does not match the regular expression `regexp`. * - * assert.throws(fn, 'function throws a reference error'); - * assert.throws(fn, /function throws a reference error/); - * assert.throws(fn, ReferenceError); - * assert.throws(fn, ReferenceError, 'function throws a reference error'); - * assert.throws(fn, ReferenceError, /function throws a reference error/); + * assert.notMatch('foobar', /^foo/, 'regexp does not match'); * - * @name throws - * @alias throw - * @alias Throw - * @param {Function} function - * @param {ErrorConstructor} constructor + * @name notMatch + * @param {Mixed} value * @param {RegExp} regexp * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types * @namespace Assert * @api public */ - assert.throws = function (fn, errt, errs, msg) { - if ('string' === typeof errt || errt instanceof RegExp) { - errs = errt; - errt = null; - } - - var assertErr = new Assertion(fn, msg).to.throw(errt, errs); - return flag(assertErr, 'object'); + assert.notMatch = function (exp, re, msg) { + new Assertion(exp, msg, assert.notMatch, true).to.not.match(re); }; /** - * ### .doesNotThrow(function, [constructor/regexp], [message]) + * ### .property(object, property, [message]) * - * Asserts that `function` will _not_ throw an error that is an instance of - * `constructor`, or alternately that it will not throw an error with message - * matching `regexp`. + * Asserts that `object` has a direct or inherited property named by + * `property`. * - * assert.doesNotThrow(fn, Error, 'function does not throw'); + * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * assert.property({ tea: { green: 'matcha' }}, 'toString'); * - * @name doesNotThrow - * @param {Function} function - * @param {ErrorConstructor} constructor - * @param {RegExp} regexp + * @name property + * @param {Object} object + * @param {String} property * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types * @namespace Assert * @api public */ - assert.doesNotThrow = function (fn, type, msg) { - if ('string' === typeof type) { - msg = type; - type = null; - } - - new Assertion(fn, msg).to.not.Throw(type); + assert.property = function (obj, prop, msg) { + new Assertion(obj, msg, assert.property, true).to.have.property(prop); }; /** - * ### .operator(val1, operator, val2, [message]) + * ### .notProperty(object, property, [message]) * - * Compares two values using `operator`. + * Asserts that `object` does _not_ have a direct or inherited property named + * by `property`. * - * assert.operator(1, '<', 2, 'everything is ok'); - * assert.operator(1, '>', 2, 'this will fail'); + * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); * - * @name operator - * @param {Mixed} val1 - * @param {String} operator - * @param {Mixed} val2 + * @name notProperty + * @param {Object} object + * @param {String} property * @param {String} message * @namespace Assert * @api public */ - assert.operator = function (val, operator, val2, msg) { - var ok; - switch(operator) { - case '==': - ok = val == val2; - break; - case '===': - ok = val === val2; - break; - case '>': - ok = val > val2; - break; - case '>=': - ok = val >= val2; - break; - case '<': - ok = val < val2; - break; - case '<=': - ok = val <= val2; - break; - case '!=': - ok = val != val2; - break; - case '!==': - ok = val !== val2; - break; - default: - throw new Error('Invalid operator "' + operator + '"'); - } - var test = new Assertion(ok, msg); - test.assert( - true === flag(test, 'object') - , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) - , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + assert.notProperty = function (obj, prop, msg) { + new Assertion(obj, msg, assert.notProperty, true) + .to.not.have.property(prop); }; /** - * ### .closeTo(actual, expected, delta, [message]) + * ### .propertyVal(object, property, value, [message]) * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * Asserts that `object` has a direct or inherited property named by + * `property` with a value given by `value`. Uses a strict equality check + * (===). * - * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); * - * @name closeTo - * @param {Number} actual - * @param {Number} expected - * @param {Number} delta + * @name propertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value * @param {String} message * @namespace Assert * @api public */ - assert.closeTo = function (act, exp, delta, msg) { - new Assertion(act, msg).to.be.closeTo(exp, delta); + assert.propertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.propertyVal, true) + .to.have.property(prop, val); }; /** - * ### .approximately(actual, expected, delta, [message]) + * ### .notPropertyVal(object, property, value, [message]) * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * Asserts that `object` does _not_ have a direct or inherited property named + * by `property` with value given by `value`. Uses a strict equality check + * (===). * - * assert.approximately(1.5, 1, 0.5, 'numbers are close'); + * assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad'); + * assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good'); * - * @name approximately - * @param {Number} actual - * @param {Number} expected - * @param {Number} delta + * @name notPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value * @param {String} message * @namespace Assert * @api public */ - assert.approximately = function (act, exp, delta, msg) { - new Assertion(act, msg).to.be.approximately(exp, delta); + assert.notPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.notPropertyVal, true) + .to.not.have.property(prop, val); }; /** - * ### .sameMembers(set1, set2, [message]) + * ### .deepPropertyVal(object, property, value, [message]) * - * Asserts that `set1` and `set2` have the same members. - * Order is not taken into account. + * Asserts that `object` has a direct or inherited property named by + * `property` with a value given by `value`. Uses a deep equality check. * - * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); + * assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' }); * - * @name sameMembers - * @param {Array} set1 - * @param {Array} set2 + * @name deepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value * @param {String} message * @namespace Assert * @api public */ - assert.sameMembers = function (set1, set2, msg) { - new Assertion(set1, msg).to.have.same.members(set2); - } + assert.deepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.deepPropertyVal, true) + .to.have.deep.property(prop, val); + }; /** - * ### .sameDeepMembers(set1, set2, [message]) + * ### .notDeepPropertyVal(object, property, value, [message]) * - * Asserts that `set1` and `set2` have the same members - using a deep equality checking. - * Order is not taken into account. + * Asserts that `object` does _not_ have a direct or inherited property named + * by `property` with value given by `value`. Uses a deep equality check. * - * assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members'); + * assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' }); + * assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' }); + * assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' }); * - * @name sameDeepMembers - * @param {Array} set1 - * @param {Array} set2 + * @name notDeepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value * @param {String} message * @namespace Assert * @api public */ - assert.sameDeepMembers = function (set1, set2, msg) { - new Assertion(set1, msg).to.have.same.deep.members(set2); - } + assert.notDeepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.notDeepPropertyVal, true) + .to.not.have.deep.property(prop, val); + }; /** - * ### .includeMembers(superset, subset, [message]) + * ### .ownProperty(object, property, [message]) * - * Asserts that `subset` is included in `superset`. - * Order is not taken into account. + * Asserts that `object` has a direct property named by `property`. Inherited + * properties aren't checked. * - * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); + * assert.ownProperty({ tea: { green: 'matcha' }}, 'tea'); * - * @name includeMembers - * @param {Array} superset - * @param {Array} subset + * @name ownProperty + * @param {Object} object + * @param {String} property * @param {String} message - * @namespace Assert * @api public */ - assert.includeMembers = function (superset, subset, msg) { - new Assertion(superset, msg).to.include.members(subset); - } + assert.ownProperty = function (obj, prop, msg) { + new Assertion(obj, msg, assert.ownProperty, true) + .to.have.own.property(prop); + }; /** - * ### .includeDeepMembers(superset, subset, [message]) + * ### .notOwnProperty(object, property, [message]) * - * Asserts that `subset` is included in `superset` - using deep equality checking. - * Order is not taken into account. - * Duplicates are ignored. + * Asserts that `object` does _not_ have a direct property named by + * `property`. Inherited properties aren't checked. * - * assert.includeDeepMembers([ {a: 1}, {b: 2}, {c: 3} ], [ {b: 2}, {a: 1}, {b: 2} ], 'include deep members'); + * assert.notOwnProperty({ tea: { green: 'matcha' }}, 'coffee'); + * assert.notOwnProperty({}, 'toString'); * - * @name includeDeepMembers - * @param {Array} superset - * @param {Array} subset + * @name notOwnProperty + * @param {Object} object + * @param {String} property * @param {String} message - * @namespace Assert * @api public */ - assert.includeDeepMembers = function (superset, subset, msg) { - new Assertion(superset, msg).to.include.deep.members(subset); - } + assert.notOwnProperty = function (obj, prop, msg) { + new Assertion(obj, msg, assert.notOwnProperty, true) + .to.not.have.own.property(prop); + }; /** - * ### .oneOf(inList, list, [message]) + * ### .ownPropertyVal(object, property, value, [message]) * - * Asserts that non-object, non-array value `inList` appears in the flat array `list`. + * Asserts that `object` has a direct property named by `property` and a value + * equal to the provided `value`. Uses a strict equality check (===). + * Inherited properties aren't checked. * - * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); + * assert.ownPropertyVal({ coffee: 'is good'}, 'coffee', 'is good'); * - * @name oneOf - * @param {*} inList - * @param {Array<*>} list + * @name ownPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value * @param {String} message - * @namespace Assert * @api public */ - assert.oneOf = function (inList, list, msg) { - new Assertion(inList, msg).to.be.oneOf(list); - } + assert.ownPropertyVal = function (obj, prop, value, msg) { + new Assertion(obj, msg, assert.ownPropertyVal, true) + .to.have.own.property(prop, value); + }; - /** - * ### .changes(function, object, property) + /** + * ### .notOwnPropertyVal(object, property, value, [message]) * - * Asserts that a function changes the value of a property + * Asserts that `object` does _not_ have a direct property named by `property` + * with a value equal to the provided `value`. Uses a strict equality check + * (===). Inherited properties aren't checked. * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 22 }; - * assert.changes(fn, obj, 'val'); + * assert.notOwnPropertyVal({ tea: 'is better'}, 'tea', 'is worse'); + * assert.notOwnPropertyVal({}, 'toString', Object.prototype.toString); * - * @name changes - * @param {Function} modifier function + * @name notOwnPropertyVal * @param {Object} object - * @param {String} property name - * @param {String} message _optional_ - * @namespace Assert + * @param {String} property + * @param {Mixed} value + * @param {String} message * @api public */ - assert.changes = function (fn, obj, prop) { - new Assertion(fn).to.change(obj, prop); - } + assert.notOwnPropertyVal = function (obj, prop, value, msg) { + new Assertion(obj, msg, assert.notOwnPropertyVal, true) + .to.not.have.own.property(prop, value); + }; - /** - * ### .doesNotChange(function, object, property) + /** + * ### .deepOwnPropertyVal(object, property, value, [message]) * - * Asserts that a function does not changes the value of a property + * Asserts that `object` has a direct property named by `property` and a value + * equal to the provided `value`. Uses a deep equality check. Inherited + * properties aren't checked. * - * var obj = { val: 10 }; - * var fn = function() { console.log('foo'); }; - * assert.doesNotChange(fn, obj, 'val'); + * assert.deepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' }); * - * @name doesNotChange - * @param {Function} modifier function + * @name deepOwnPropertyVal * @param {Object} object - * @param {String} property name - * @param {String} message _optional_ - * @namespace Assert + * @param {String} property + * @param {Mixed} value + * @param {String} message * @api public */ - assert.doesNotChange = function (fn, obj, prop) { - new Assertion(fn).to.not.change(obj, prop); - } + assert.deepOwnPropertyVal = function (obj, prop, value, msg) { + new Assertion(obj, msg, assert.deepOwnPropertyVal, true) + .to.have.deep.own.property(prop, value); + }; - /** - * ### .increases(function, object, property) + /** + * ### .notDeepOwnPropertyVal(object, property, value, [message]) * - * Asserts that a function increases an object property + * Asserts that `object` does _not_ have a direct property named by `property` + * with a value equal to the provided `value`. Uses a deep equality check. + * Inherited properties aren't checked. * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 13 }; - * assert.increases(fn, obj, 'val'); + * assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' }); + * assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' }); + * assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' }); + * assert.notDeepOwnPropertyVal({}, 'toString', Object.prototype.toString); * - * @name increases - * @param {Function} modifier function + * @name notDeepOwnPropertyVal * @param {Object} object - * @param {String} property name - * @param {String} message _optional_ - * @namespace Assert + * @param {String} property + * @param {Mixed} value + * @param {String} message * @api public */ - assert.increases = function (fn, obj, prop) { - new Assertion(fn).to.increase(obj, prop); - } + assert.notDeepOwnPropertyVal = function (obj, prop, value, msg) { + new Assertion(obj, msg, assert.notDeepOwnPropertyVal, true) + .to.not.have.deep.own.property(prop, value); + }; - /** - * ### .doesNotIncrease(function, object, property) + /** + * ### .nestedProperty(object, property, [message]) * - * Asserts that a function does not increase object property + * Asserts that `object` has a direct or inherited property named by + * `property`, which can be a string using dot- and bracket-notation for + * nested reference. * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 8 }; - * assert.doesNotIncrease(fn, obj, 'val'); + * assert.nestedProperty({ tea: { green: 'matcha' }}, 'tea.green'); * - * @name doesNotIncrease - * @param {Function} modifier function + * @name nestedProperty * @param {Object} object - * @param {String} property name - * @param {String} message _optional_ + * @param {String} property + * @param {String} message * @namespace Assert * @api public */ - assert.doesNotIncrease = function (fn, obj, prop) { - new Assertion(fn).to.not.increase(obj, prop); - } + assert.nestedProperty = function (obj, prop, msg) { + new Assertion(obj, msg, assert.nestedProperty, true) + .to.have.nested.property(prop); + }; - /** - * ### .decreases(function, object, property) + /** + * ### .notNestedProperty(object, property, [message]) * - * Asserts that a function decreases an object property + * Asserts that `object` does _not_ have a property named by `property`, which + * can be a string using dot- and bracket-notation for nested reference. The + * property cannot exist on the object nor anywhere in its prototype chain. * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 5 }; - * assert.decreases(fn, obj, 'val'); + * assert.notNestedProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); * - * @name decreases - * @param {Function} modifier function + * @name notNestedProperty * @param {Object} object - * @param {String} property name - * @param {String} message _optional_ + * @param {String} property + * @param {String} message * @namespace Assert * @api public */ - assert.decreases = function (fn, obj, prop) { - new Assertion(fn).to.decrease(obj, prop); - } + assert.notNestedProperty = function (obj, prop, msg) { + new Assertion(obj, msg, assert.notNestedProperty, true) + .to.not.have.nested.property(prop); + }; - /** - * ### .doesNotDecrease(function, object, property) + /** + * ### .nestedPropertyVal(object, property, value, [message]) * - * Asserts that a function does not decreases an object property + * Asserts that `object` has a property named by `property` with value given + * by `value`. `property` can use dot- and bracket-notation for nested + * reference. Uses a strict equality check (===). * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 15 }; - * assert.doesNotDecrease(fn, obj, 'val'); + * assert.nestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); * - * @name doesNotDecrease - * @param {Function} modifier function + * @name nestedPropertyVal * @param {Object} object - * @param {String} property name - * @param {String} message _optional_ + * @param {String} property + * @param {Mixed} value + * @param {String} message * @namespace Assert * @api public */ - assert.doesNotDecrease = function (fn, obj, prop) { - new Assertion(fn).to.not.decrease(obj, prop); - } + assert.nestedPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.nestedPropertyVal, true) + .to.have.nested.property(prop, val); + }; - /*! - * ### .ifError(object) + /** + * ### .notNestedPropertyVal(object, property, value, [message]) * - * Asserts if value is not a false value, and throws if it is a true value. - * This is added to allow for chai to be a drop-in replacement for Node's - * assert class. + * Asserts that `object` does _not_ have a property named by `property` with + * value given by `value`. `property` can use dot- and bracket-notation for + * nested reference. Uses a strict equality check (===). * - * var err = new Error('I am a custom error'); - * assert.ifError(err); // Rethrows err! + * assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'coffee.green', 'matcha'); * - * @name ifError + * @name notNestedPropertyVal * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message * @namespace Assert * @api public */ - assert.ifError = function (val) { - if (val) { - throw(val); - } + assert.notNestedPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.notNestedPropertyVal, true) + .to.not.have.nested.property(prop, val); }; /** - * ### .isExtensible(object) + * ### .deepNestedPropertyVal(object, property, value, [message]) * - * Asserts that `object` is extensible (can have new properties added to it). + * Asserts that `object` has a property named by `property` with a value given + * by `value`. `property` can use dot- and bracket-notation for nested + * reference. Uses a deep equality check. * - * assert.isExtensible({}); + * assert.deepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yum' }); * - * @name isExtensible - * @alias extensible + * @name deepNestedPropertyVal * @param {Object} object - * @param {String} message _optional_ + * @param {String} property + * @param {Mixed} value + * @param {String} message * @namespace Assert * @api public */ - assert.isExtensible = function (obj, msg) { - new Assertion(obj, msg).to.be.extensible; + assert.deepNestedPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.deepNestedPropertyVal, true) + .to.have.deep.nested.property(prop, val); }; /** - * ### .isNotExtensible(object) - * - * Asserts that `object` is _not_ extensible. + * ### .notDeepNestedPropertyVal(object, property, value, [message]) * - * var nonExtensibleObject = Object.preventExtensions({}); - * var sealedObject = Object.seal({}); - * var frozenObject = Object.freese({}); + * Asserts that `object` does _not_ have a property named by `property` with + * value given by `value`. `property` can use dot- and bracket-notation for + * nested reference. Uses a deep equality check. * - * assert.isNotExtensible(nonExtensibleObject); - * assert.isNotExtensible(sealedObject); - * assert.isNotExtensible(frozenObject); + * assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' }); + * assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' }); + * assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' }); * - * @name isNotExtensible - * @alias notExtensible + * @name notDeepNestedPropertyVal * @param {Object} object - * @param {String} message _optional_ + * @param {String} property + * @param {Mixed} value + * @param {String} message * @namespace Assert * @api public */ - assert.isNotExtensible = function (obj, msg) { - new Assertion(obj, msg).to.not.be.extensible; - }; + assert.notDeepNestedPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg, assert.notDeepNestedPropertyVal, true) + .to.not.have.deep.nested.property(prop, val); + } /** - * ### .isSealed(object) - * - * Asserts that `object` is sealed (cannot have new properties added to it - * and its existing properties cannot be removed). + * ### .lengthOf(object, length, [message]) * - * var sealedObject = Object.seal({}); - * var frozenObject = Object.seal({}); + * Asserts that `object` has a `length` or `size` with the expected value. * - * assert.isSealed(sealedObject); - * assert.isSealed(frozenObject); + * assert.lengthOf([1,2,3], 3, 'array has length of 3'); + * assert.lengthOf('foobar', 6, 'string has length of 6'); + * assert.lengthOf(new Set([1,2,3]), 3, 'set has size of 3'); + * assert.lengthOf(new Map([['a',1],['b',2],['c',3]]), 3, 'map has size of 3'); * - * @name isSealed - * @alias sealed - * @param {Object} object - * @param {String} message _optional_ + * @name lengthOf + * @param {Mixed} object + * @param {Number} length + * @param {String} message * @namespace Assert * @api public */ - assert.isSealed = function (obj, msg) { - new Assertion(obj, msg).to.be.sealed; + assert.lengthOf = function (exp, len, msg) { + new Assertion(exp, msg, assert.lengthOf, true).to.have.lengthOf(len); }; /** - * ### .isNotSealed(object) + * ### .hasAnyKeys(object, [keys], [message]) * - * Asserts that `object` is _not_ sealed. + * Asserts that `object` has at least one of the `keys` provided. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. * - * assert.isNotSealed({}); + * assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'iDontExist', 'baz']); + * assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, iDontExist: 99, baz: 1337}); + * assert.hasAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']); + * assert.hasAnyKeys(new Set([{foo: 'bar'}, 'anotherKey']), [{foo: 'bar'}, 'anotherKey']); * - * @name isNotSealed - * @alias notSealed - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert + * @name hasAnyKeys + * @param {Mixed} object + * @param {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAnyKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.hasAnyKeys, true).to.have.any.keys(keys); + } + + /** + * ### .hasAllKeys(object, [keys], [message]) + * + * Asserts that `object` has all and only all of the `keys` provided. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.hasAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'bar', 'baz']); + * assert.hasAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, bar: 99, baz: 1337]); + * assert.hasAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']); + * assert.hasAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'anotherKey']); + * + * @name hasAllKeys + * @param {Mixed} object + * @param {String[]} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAllKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.hasAllKeys, true).to.have.all.keys(keys); + } + + /** + * ### .containsAllKeys(object, [keys], [message]) + * + * Asserts that `object` has all of the `keys` provided but may have more keys not listed. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'baz']); + * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'bar', 'baz']); + * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, baz: 1337}); + * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, bar: 99, baz: 1337}); + * assert.containsAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}]); + * assert.containsAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']); + * assert.containsAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}]); + * assert.containsAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'anotherKey']); + * + * @name containsAllKeys + * @param {Mixed} object + * @param {String[]} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.containsAllKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.containsAllKeys, true) + .to.contain.all.keys(keys); + } + + /** + * ### .doesNotHaveAnyKeys(object, [keys], [message]) + * + * Asserts that `object` has none of the `keys` provided. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.doesNotHaveAnyKeys({foo: 1, bar: 2, baz: 3}, ['one', 'two', 'example']); + * assert.doesNotHaveAnyKeys({foo: 1, bar: 2, baz: 3}, {one: 1, two: 2, example: 'foo'}); + * assert.doesNotHaveAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{one: 'two'}, 'example']); + * assert.doesNotHaveAnyKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{one: 'two'}, 'example']); + * + * @name doesNotHaveAnyKeys + * @param {Mixed} object + * @param {String[]} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAnyKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.doesNotHaveAnyKeys, true) + .to.not.have.any.keys(keys); + } + + /** + * ### .doesNotHaveAllKeys(object, [keys], [message]) + * + * Asserts that `object` does not have at least one of the `keys` provided. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.doesNotHaveAllKeys({foo: 1, bar: 2, baz: 3}, ['one', 'two', 'example']); + * assert.doesNotHaveAllKeys({foo: 1, bar: 2, baz: 3}, {one: 1, two: 2, example: 'foo'}); + * assert.doesNotHaveAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{one: 'two'}, 'example']); + * assert.doesNotHaveAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{one: 'two'}, 'example']); + * + * @name doesNotHaveAllKeys + * @param {Mixed} object + * @param {String[]} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAllKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.doesNotHaveAllKeys, true) + .to.not.have.all.keys(keys); + } + + /** + * ### .hasAnyDeepKeys(object, [keys], [message]) + * + * Asserts that `object` has at least one of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'}); + * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), [{one: 'one'}, {two: 'two'}]); + * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); + * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'}); + * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {three: 'three'}]); + * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); + * + * @name doesNotHaveAllKeys + * @param {Mixed} object + * @param {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAnyDeepKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.hasAnyDeepKeys, true) + .to.have.any.deep.keys(keys); + } + + /** + * ### .hasAllDeepKeys(object, [keys], [message]) + * + * Asserts that `object` has all and only all of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne']]), {one: 'one'}); + * assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); + * assert.hasAllDeepKeys(new Set([{one: 'one'}]), {one: 'one'}); + * assert.hasAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); + * + * @name hasAllDeepKeys + * @param {Mixed} object + * @param {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAllDeepKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.hasAllDeepKeys, true) + .to.have.all.deep.keys(keys); + } + + /** + * ### .containsAllDeepKeys(object, [keys], [message]) + * + * Asserts that `object` contains all of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'}); + * assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); + * assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'}); + * assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); + * + * @name containsAllDeepKeys + * @param {Mixed} object + * @param {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.containsAllDeepKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.containsAllDeepKeys, true) + .to.contain.all.deep.keys(keys); + } + + /** + * ### .doesNotHaveAnyDeepKeys(object, [keys], [message]) + * + * Asserts that `object` has none of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'}); + * assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {fifty: 'fifty'}]); + * assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'}); + * assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{twenty: 'twenty'}, {fifty: 'fifty'}]); + * + * @name doesNotHaveAnyDeepKeys + * @param {Mixed} object + * @param {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAnyDeepKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.doesNotHaveAnyDeepKeys, true) + .to.not.have.any.deep.keys(keys); + } + + /** + * ### .doesNotHaveAllDeepKeys(object, [keys], [message]) + * + * Asserts that `object` does not have at least one of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'}); + * assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {one: 'one'}]); + * assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'}); + * assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {fifty: 'fifty'}]); + * + * @name doesNotHaveAllDeepKeys + * @param {Mixed} object + * @param {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAllDeepKeys = function (obj, keys, msg) { + new Assertion(obj, msg, assert.doesNotHaveAllDeepKeys, true) + .to.not.have.all.deep.keys(keys); + } + + /** + * ### .throws(fn, [errorLike/string/regexp], [string/regexp], [message]) + * + * If `errorLike` is an `Error` constructor, asserts that `fn` will throw an error that is an + * instance of `errorLike`. + * If `errorLike` is an `Error` instance, asserts that the error thrown is the same + * instance as `errorLike`. + * If `errMsgMatcher` is provided, it also asserts that the error thrown will have a + * message matching `errMsgMatcher`. + * + * assert.throws(fn, 'Error thrown must have this msg'); + * assert.throws(fn, /Error thrown must have a msg that matches this/); + * assert.throws(fn, ReferenceError); + * assert.throws(fn, errorInstance); + * assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg'); + * assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg'); + * assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/); + * assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/); + * + * @name throws + * @alias throw + * @alias Throw + * @param {Function} fn + * @param {ErrorConstructor|Error} errorLike + * @param {RegExp|String} errMsgMatcher + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert + * @api public + */ + + assert.throws = function (fn, errorLike, errMsgMatcher, msg) { + if ('string' === typeof errorLike || errorLike instanceof RegExp) { + errMsgMatcher = errorLike; + errorLike = null; + } + + var assertErr = new Assertion(fn, msg, assert.throws, true) + .to.throw(errorLike, errMsgMatcher); + return flag(assertErr, 'object'); + }; + + /** + * ### .doesNotThrow(fn, [errorLike/string/regexp], [string/regexp], [message]) + * + * If `errorLike` is an `Error` constructor, asserts that `fn` will _not_ throw an error that is an + * instance of `errorLike`. + * If `errorLike` is an `Error` instance, asserts that the error thrown is _not_ the same + * instance as `errorLike`. + * If `errMsgMatcher` is provided, it also asserts that the error thrown will _not_ have a + * message matching `errMsgMatcher`. + * + * assert.doesNotThrow(fn, 'Any Error thrown must not have this message'); + * assert.doesNotThrow(fn, /Any Error thrown must not match this/); + * assert.doesNotThrow(fn, Error); + * assert.doesNotThrow(fn, errorInstance); + * assert.doesNotThrow(fn, Error, 'Error must not have this message'); + * assert.doesNotThrow(fn, errorInstance, 'Error must not have this message'); + * assert.doesNotThrow(fn, Error, /Error must not match this/); + * assert.doesNotThrow(fn, errorInstance, /Error must not match this/); + * + * @name doesNotThrow + * @param {Function} fn + * @param {ErrorConstructor} errorLike + * @param {RegExp|String} errMsgMatcher + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert + * @api public + */ + + assert.doesNotThrow = function (fn, errorLike, errMsgMatcher, msg) { + if ('string' === typeof errorLike || errorLike instanceof RegExp) { + errMsgMatcher = errorLike; + errorLike = null; + } + + new Assertion(fn, msg, assert.doesNotThrow, true) + .to.not.throw(errorLike, errMsgMatcher); + }; + + /** + * ### .operator(val1, operator, val2, [message]) + * + * Compares two values using `operator`. + * + * assert.operator(1, '<', 2, 'everything is ok'); + * assert.operator(1, '>', 2, 'this will fail'); + * + * @name operator + * @param {Mixed} val1 + * @param {String} operator + * @param {Mixed} val2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.operator = function (val, operator, val2, msg) { + var ok; + switch(operator) { + case '==': + ok = val == val2; + break; + case '===': + ok = val === val2; + break; + case '>': + ok = val > val2; + break; + case '>=': + ok = val >= val2; + break; + case '<': + ok = val < val2; + break; + case '<=': + ok = val <= val2; + break; + case '!=': + ok = val != val2; + break; + case '!==': + ok = val !== val2; + break; + default: + msg = msg ? msg + ': ' : msg; + throw new chai.AssertionError( + msg + 'Invalid operator "' + operator + '"', + undefined, + assert.operator + ); + } + var test = new Assertion(ok, msg, assert.operator, true); + test.assert( + true === flag(test, 'object') + , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) + , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + }; + + /** + * ### .closeTo(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * + * @name closeTo + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.closeTo = function (act, exp, delta, msg) { + new Assertion(act, msg, assert.closeTo, true).to.be.closeTo(exp, delta); + }; + + /** + * ### .approximately(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.approximately(1.5, 1, 0.5, 'numbers are close'); + * + * @name approximately + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.approximately = function (act, exp, delta, msg) { + new Assertion(act, msg, assert.approximately, true) + .to.be.approximately(exp, delta); + }; + + /** + * ### .sameMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members in any order. Uses a + * strict equality check (===). + * + * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); + * + * @name sameMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.sameMembers, true) + .to.have.same.members(set2); + } + + /** + * ### .notSameMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` don't have the same members in any order. + * Uses a strict equality check (===). + * + * assert.notSameMembers([ 1, 2, 3 ], [ 5, 1, 3 ], 'not same members'); + * + * @name notSameMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notSameMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.notSameMembers, true) + .to.not.have.same.members(set2); + } + + /** + * ### .sameDeepMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members in any order. Uses a + * deep equality check. + * + * assert.sameDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members'); + * + * @name sameDeepMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameDeepMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.sameDeepMembers, true) + .to.have.same.deep.members(set2); + } + + /** + * ### .notSameDeepMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` don't have the same members in any order. + * Uses a deep equality check. + * + * assert.notSameDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [{ b: 2 }, { a: 1 }, { f: 5 }], 'not same deep members'); + * + * @name notSameDeepMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notSameDeepMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.notSameDeepMembers, true) + .to.not.have.same.deep.members(set2); + } + + /** + * ### .sameOrderedMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members in the same order. + * Uses a strict equality check (===). + * + * assert.sameOrderedMembers([ 1, 2, 3 ], [ 1, 2, 3 ], 'same ordered members'); + * + * @name sameOrderedMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameOrderedMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.sameOrderedMembers, true) + .to.have.same.ordered.members(set2); + } + + /** + * ### .notSameOrderedMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` don't have the same members in the same + * order. Uses a strict equality check (===). + * + * assert.notSameOrderedMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'not same ordered members'); + * + * @name notSameOrderedMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notSameOrderedMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.notSameOrderedMembers, true) + .to.not.have.same.ordered.members(set2); + } + + /** + * ### .sameDeepOrderedMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members in the same order. + * Uses a deep equality check. + * + * assert.sameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 }, { c: 3 } ], 'same deep ordered members'); + * + * @name sameDeepOrderedMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameDeepOrderedMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.sameDeepOrderedMembers, true) + .to.have.same.deep.ordered.members(set2); + } + + /** + * ### .notSameDeepOrderedMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` don't have the same members in the same + * order. Uses a deep equality check. + * + * assert.notSameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 }, { z: 5 } ], 'not same deep ordered members'); + * assert.notSameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 }, { c: 3 } ], 'not same deep ordered members'); + * + * @name notSameDeepOrderedMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notSameDeepOrderedMembers = function (set1, set2, msg) { + new Assertion(set1, msg, assert.notSameDeepOrderedMembers, true) + .to.not.have.same.deep.ordered.members(set2); + } + + /** + * ### .includeMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset` in any order. Uses a + * strict equality check (===). Duplicates are ignored. + * + * assert.includeMembers([ 1, 2, 3 ], [ 2, 1, 2 ], 'include members'); + * + * @name includeMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.includeMembers, true) + .to.include.members(subset); + } + + /** + * ### .notIncludeMembers(superset, subset, [message]) + * + * Asserts that `subset` isn't included in `superset` in any order. Uses a + * strict equality check (===). Duplicates are ignored. + * + * assert.notIncludeMembers([ 1, 2, 3 ], [ 5, 1 ], 'not include members'); + * + * @name notIncludeMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notIncludeMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.notIncludeMembers, true) + .to.not.include.members(subset); + } + + /** + * ### .includeDeepMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset` in any order. Uses a deep + * equality check. Duplicates are ignored. + * + * assert.includeDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 }, { b: 2 } ], 'include deep members'); + * + * @name includeDeepMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeDeepMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.includeDeepMembers, true) + .to.include.deep.members(subset); + } + + /** + * ### .notIncludeDeepMembers(superset, subset, [message]) + * + * Asserts that `subset` isn't included in `superset` in any order. Uses a + * deep equality check. Duplicates are ignored. + * + * assert.notIncludeDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { f: 5 } ], 'not include deep members'); + * + * @name notIncludeDeepMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notIncludeDeepMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.notIncludeDeepMembers, true) + .to.not.include.deep.members(subset); + } + + /** + * ### .includeOrderedMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset` in the same order + * beginning with the first element in `superset`. Uses a strict equality + * check (===). + * + * assert.includeOrderedMembers([ 1, 2, 3 ], [ 1, 2 ], 'include ordered members'); + * + * @name includeOrderedMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeOrderedMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.includeOrderedMembers, true) + .to.include.ordered.members(subset); + } + + /** + * ### .notIncludeOrderedMembers(superset, subset, [message]) + * + * Asserts that `subset` isn't included in `superset` in the same order + * beginning with the first element in `superset`. Uses a strict equality + * check (===). + * + * assert.notIncludeOrderedMembers([ 1, 2, 3 ], [ 2, 1 ], 'not include ordered members'); + * assert.notIncludeOrderedMembers([ 1, 2, 3 ], [ 2, 3 ], 'not include ordered members'); + * + * @name notIncludeOrderedMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notIncludeOrderedMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.notIncludeOrderedMembers, true) + .to.not.include.ordered.members(subset); + } + + /** + * ### .includeDeepOrderedMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset` in the same order + * beginning with the first element in `superset`. Uses a deep equality + * check. + * + * assert.includeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 } ], 'include deep ordered members'); + * + * @name includeDeepOrderedMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeDeepOrderedMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.includeDeepOrderedMembers, true) + .to.include.deep.ordered.members(subset); + } + + /** + * ### .notIncludeDeepOrderedMembers(superset, subset, [message]) + * + * Asserts that `subset` isn't included in `superset` in the same order + * beginning with the first element in `superset`. Uses a deep equality + * check. + * + * assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { f: 5 } ], 'not include deep ordered members'); + * assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 } ], 'not include deep ordered members'); + * assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { c: 3 } ], 'not include deep ordered members'); + * + * @name notIncludeDeepOrderedMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notIncludeDeepOrderedMembers = function (superset, subset, msg) { + new Assertion(superset, msg, assert.notIncludeDeepOrderedMembers, true) + .to.not.include.deep.ordered.members(subset); + } + + /** + * ### .oneOf(inList, list, [message]) + * + * Asserts that non-object, non-array value `inList` appears in the flat array `list`. + * + * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); + * + * @name oneOf + * @param {*} inList + * @param {Array<*>} list + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.oneOf = function (inList, list, msg) { + new Assertion(inList, msg, assert.oneOf, true).to.be.oneOf(list); + } + + /** + * ### .changes(function, object, property, [message]) + * + * Asserts that a function changes the value of a property. + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 22 }; + * assert.changes(fn, obj, 'val'); + * + * @name changes + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.changes = function (fn, obj, prop, msg) { + if (arguments.length === 3 && typeof obj === 'function') { + msg = prop; + prop = null; + } + + new Assertion(fn, msg, assert.changes, true).to.change(obj, prop); + } + + /** + * ### .changesBy(function, object, property, delta, [message]) + * + * Asserts that a function changes the value of a property by an amount (delta). + * + * var obj = { val: 10 }; + * var fn = function() { obj.val += 2 }; + * assert.changesBy(fn, obj, 'val', 2); + * + * @name changesBy + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.changesBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + new Assertion(fn, msg, assert.changesBy, true) + .to.change(obj, prop).by(delta); + } + + /** + * ### .doesNotChange(function, object, property, [message]) + * + * Asserts that a function does not change the value of a property. + * + * var obj = { val: 10 }; + * var fn = function() { console.log('foo'); }; + * assert.doesNotChange(fn, obj, 'val'); + * + * @name doesNotChange + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotChange = function (fn, obj, prop, msg) { + if (arguments.length === 3 && typeof obj === 'function') { + msg = prop; + prop = null; + } + + return new Assertion(fn, msg, assert.doesNotChange, true) + .to.not.change(obj, prop); + } + + /** + * ### .changesButNotBy(function, object, property, delta, [message]) + * + * Asserts that a function does not change the value of a property or of a function's return value by an amount (delta) + * + * var obj = { val: 10 }; + * var fn = function() { obj.val += 10 }; + * assert.changesButNotBy(fn, obj, 'val', 5); + * + * @name changesButNotBy + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.changesButNotBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + new Assertion(fn, msg, assert.changesButNotBy, true) + .to.change(obj, prop).but.not.by(delta); + } + + /** + * ### .increases(function, object, property, [message]) + * + * Asserts that a function increases a numeric object property. + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 13 }; + * assert.increases(fn, obj, 'val'); + * + * @name increases + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.increases = function (fn, obj, prop, msg) { + if (arguments.length === 3 && typeof obj === 'function') { + msg = prop; + prop = null; + } + + return new Assertion(fn, msg, assert.increases, true) + .to.increase(obj, prop); + } + + /** + * ### .increasesBy(function, object, property, delta, [message]) + * + * Asserts that a function increases a numeric object property or a function's return value by an amount (delta). + * + * var obj = { val: 10 }; + * var fn = function() { obj.val += 10 }; + * assert.increasesBy(fn, obj, 'val', 10); + * + * @name increasesBy + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.increasesBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + new Assertion(fn, msg, assert.increasesBy, true) + .to.increase(obj, prop).by(delta); + } + + /** + * ### .doesNotIncrease(function, object, property, [message]) + * + * Asserts that a function does not increase a numeric object property. + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 8 }; + * assert.doesNotIncrease(fn, obj, 'val'); + * + * @name doesNotIncrease + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotIncrease = function (fn, obj, prop, msg) { + if (arguments.length === 3 && typeof obj === 'function') { + msg = prop; + prop = null; + } + + return new Assertion(fn, msg, assert.doesNotIncrease, true) + .to.not.increase(obj, prop); + } + + /** + * ### .increasesButNotBy(function, object, property, [message]) + * + * Asserts that a function does not increase a numeric object property or function's return value by an amount (delta). + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * assert.increasesButNotBy(fn, obj, 'val', 10); + * + * @name increasesButNotBy + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.increasesButNotBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + new Assertion(fn, msg, assert.increasesButNotBy, true) + .to.increase(obj, prop).but.not.by(delta); + } + + /** + * ### .decreases(function, object, property, [message]) + * + * Asserts that a function decreases a numeric object property. + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * assert.decreases(fn, obj, 'val'); + * + * @name decreases + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.decreases = function (fn, obj, prop, msg) { + if (arguments.length === 3 && typeof obj === 'function') { + msg = prop; + prop = null; + } + + return new Assertion(fn, msg, assert.decreases, true) + .to.decrease(obj, prop); + } + + /** + * ### .decreasesBy(function, object, property, delta, [message]) + * + * Asserts that a function decreases a numeric object property or a function's return value by an amount (delta) + * + * var obj = { val: 10 }; + * var fn = function() { obj.val -= 5 }; + * assert.decreasesBy(fn, obj, 'val', 5); + * + * @name decreasesBy + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.decreasesBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + new Assertion(fn, msg, assert.decreasesBy, true) + .to.decrease(obj, prop).by(delta); + } + + /** + * ### .doesNotDecrease(function, object, property, [message]) + * + * Asserts that a function does not decreases a numeric object property. + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * assert.doesNotDecrease(fn, obj, 'val'); + * + * @name doesNotDecrease + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotDecrease = function (fn, obj, prop, msg) { + if (arguments.length === 3 && typeof obj === 'function') { + msg = prop; + prop = null; + } + + return new Assertion(fn, msg, assert.doesNotDecrease, true) + .to.not.decrease(obj, prop); + } + + /** + * ### .doesNotDecreaseBy(function, object, property, delta, [message]) + * + * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta) + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * assert.doesNotDecreaseBy(fn, obj, 'val', 1); + * + * @name doesNotDecrease + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotDecreaseBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + return new Assertion(fn, msg, assert.doesNotDecreaseBy, true) + .to.not.decrease(obj, prop).by(delta); + } + + /** + * ### .decreasesButNotBy(function, object, property, delta, [message]) + * + * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta) + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * assert.decreasesButNotBy(fn, obj, 'val', 1); + * + * @name decreasesButNotBy + * @param {Function} modifier function + * @param {Object} object or getter function + * @param {String} property name _optional_ + * @param {Number} change amount (delta) + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.decreasesButNotBy = function (fn, obj, prop, delta, msg) { + if (arguments.length === 4 && typeof obj === 'function') { + var tmpMsg = delta; + delta = prop; + msg = tmpMsg; + } else if (arguments.length === 3) { + delta = prop; + prop = null; + } + + new Assertion(fn, msg, assert.decreasesButNotBy, true) + .to.decrease(obj, prop).but.not.by(delta); + } + + /*! + * ### .ifError(object) + * + * Asserts if value is not a false value, and throws if it is a true value. + * This is added to allow for chai to be a drop-in replacement for Node's + * assert class. + * + * var err = new Error('I am a custom error'); + * assert.ifError(err); // Rethrows err! + * + * @name ifError + * @param {Object} object + * @namespace Assert + * @api public + */ + + assert.ifError = function (val) { + if (val) { + throw(val); + } + }; + + /** + * ### .isExtensible(object) + * + * Asserts that `object` is extensible (can have new properties added to it). + * + * assert.isExtensible({}); + * + * @name isExtensible + * @alias extensible + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isExtensible = function (obj, msg) { + new Assertion(obj, msg, assert.isExtensible, true).to.be.extensible; + }; + + /** + * ### .isNotExtensible(object) + * + * Asserts that `object` is _not_ extensible. + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * assert.isNotExtensible(nonExtensibleObject); + * assert.isNotExtensible(sealedObject); + * assert.isNotExtensible(frozenObject); + * + * @name isNotExtensible + * @alias notExtensible + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotExtensible = function (obj, msg) { + new Assertion(obj, msg, assert.isNotExtensible, true).to.not.be.extensible; + }; + + /** + * ### .isSealed(object) + * + * Asserts that `object` is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.seal({}); + * + * assert.isSealed(sealedObject); + * assert.isSealed(frozenObject); + * + * @name isSealed + * @alias sealed + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isSealed = function (obj, msg) { + new Assertion(obj, msg, assert.isSealed, true).to.be.sealed; + }; + + /** + * ### .isNotSealed(object) + * + * Asserts that `object` is _not_ sealed. + * + * assert.isNotSealed({}); + * + * @name isNotSealed + * @alias notSealed + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert * @api public */ assert.isNotSealed = function (obj, msg) { - new Assertion(obj, msg).to.not.be.sealed; + new Assertion(obj, msg, assert.isNotSealed, true).to.not.be.sealed; }; /** @@ -3753,7 +7183,7 @@ module.exports = function (chai, util) { */ assert.isFrozen = function (obj, msg) { - new Assertion(obj, msg).to.be.frozen; + new Assertion(obj, msg, assert.isFrozen, true).to.be.frozen; }; /** @@ -3772,7 +7202,59 @@ module.exports = function (chai, util) { */ assert.isNotFrozen = function (obj, msg) { - new Assertion(obj, msg).to.not.be.frozen; + new Assertion(obj, msg, assert.isNotFrozen, true).to.not.be.frozen; + }; + + /** + * ### .isEmpty(target) + * + * Asserts that the target does not contain any values. + * For arrays and strings, it checks the `length` property. + * For `Map` and `Set` instances, it checks the `size` property. + * For non-function objects, it gets the count of own + * enumerable string keys. + * + * assert.isEmpty([]); + * assert.isEmpty(''); + * assert.isEmpty(new Map); + * assert.isEmpty({}); + * + * @name isEmpty + * @alias empty + * @param {Object|Array|String|Map|Set} target + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isEmpty = function(val, msg) { + new Assertion(val, msg, assert.isEmpty, true).to.be.empty; + }; + + /** + * ### .isNotEmpty(target) + * + * Asserts that the target contains values. + * For arrays and strings, it checks the `length` property. + * For `Map` and `Set` instances, it checks the `size` property. + * For non-function objects, it gets the count of own + * enumerable string keys. + * + * assert.isNotEmpty([1, 2]); + * assert.isNotEmpty('34'); + * assert.isNotEmpty(new Set([5, 6])); + * assert.isNotEmpty({ key: 7 }); + * + * @name isNotEmpty + * @alias notEmpty + * @param {Object|Array|String|Map|Set} target + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotEmpty = function(val, msg) { + new Assertion(val, msg, assert.isNotEmpty, true).to.not.be.empty; }; /*! @@ -3792,7 +7274,9 @@ module.exports = function (chai, util) { ('isSealed', 'sealed') ('isNotSealed', 'notSealed') ('isFrozen', 'frozen') - ('isNotFrozen', 'notFrozen'); + ('isNotFrozen', 'notFrozen') + ('isEmpty', 'empty') + ('isNotEmpty', 'notEmpty'); }; },{}],7:[function(require,module,exports){ @@ -3808,20 +7292,33 @@ module.exports = function (chai, util) { }; /** + * ### .fail([message]) * ### .fail(actual, expected, [message], [operator]) * * Throw a failure. * + * expect.fail(); + * expect.fail("custom error message"); + * expect.fail(1, 2); + * expect.fail(1, 2, "custom error message"); + * expect.fail(1, 2, "custom error message", ">"); + * expect.fail(1, 2, undefined, ">"); + * * @name fail * @param {Mixed} actual * @param {Mixed} expected * @param {String} message * @param {String} operator - * @namespace Expect + * @namespace BDD * @api public */ chai.expect.fail = function (actual, expected, message, operator) { + if (arguments.length < 2) { + message = actual; + actual = undefined; + } + message = message || 'expect.fail()'; throw new chai.AssertionError(message, { actual: actual @@ -3844,7 +7341,10 @@ module.exports = function (chai, util) { function loadShould () { // explicitly define this method as function as to have it's name to include as `ssfi` function shouldGetter() { - if (this instanceof String || this instanceof Number || this instanceof Boolean ) { + if (this instanceof String + || this instanceof Number + || this instanceof Boolean + || typeof Symbol === 'function' && this instanceof Symbol) { return new Assertion(this.valueOf(), null, shouldGetter); } return new Assertion(this, null, shouldGetter); @@ -3873,20 +7373,34 @@ module.exports = function (chai, util) { var should = {}; /** + * ### .fail([message]) * ### .fail(actual, expected, [message], [operator]) * * Throw a failure. * + * should.fail(); + * should.fail("custom error message"); + * should.fail(1, 2); + * should.fail(1, 2, "custom error message"); + * should.fail(1, 2, "custom error message", ">"); + * should.fail(1, 2, undefined, ">"); + * + * * @name fail * @param {Mixed} actual * @param {Mixed} expected * @param {String} message * @param {String} operator - * @namespace Should + * @namespace BDD * @api public */ should.fail = function (actual, expected, message, operator) { + if (arguments.length < 2) { + message = actual; + actual = undefined; + } + message = message || 'should.fail()'; throw new chai.AssertionError(message, { actual: actual @@ -4045,28 +7559,41 @@ module.exports = function (chai, util) { * Module dependencies */ -var transferFlags = require('./transferFlags'); +var addLengthGuard = require('./addLengthGuard'); +var chai = require('../../chai'); var flag = require('./flag'); -var config = require('../config'); +var proxify = require('./proxify'); +var transferFlags = require('./transferFlags'); /*! * Module variables */ -// Check whether `__proto__` is supported -var hasProtoSupport = '__proto__' in Object; +// Check whether `Object.setPrototypeOf` is supported +var canSetPrototype = typeof Object.setPrototypeOf === 'function'; + +// Without `Object.setPrototypeOf` support, this module will need to add properties to a function. +// However, some of functions' own props are not configurable and should be skipped. +var testFn = function() {}; +var excludeNames = Object.getOwnPropertyNames(testFn).filter(function(name) { + var propDesc = Object.getOwnPropertyDescriptor(testFn, name); -// Without `__proto__` support, this module will need to add properties to a function. -// However, some Function.prototype methods cannot be overwritten, -// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). -var excludeNames = /^(?:length|name|arguments|caller)$/; + // Note: PhantomJS 1.x includes `callee` as one of `testFn`'s own properties, + // but then returns `undefined` as the property descriptor for `callee`. As a + // workaround, we perform an otherwise unnecessary type-check for `propDesc`, + // and then filter it out if it's not an object as it should be. + if (typeof propDesc !== 'object') + return true; + + return !propDesc.configurable; +}); // Cache `Function` properties var call = Function.prototype.call, apply = Function.prototype.apply; /** - * ### addChainableMethod (ctx, name, method, chainingBehavior) + * ### .addChainableMethod(ctx, name, method, chainingBehavior) * * Adds a method to an object, such that the method can also be chained. * @@ -4094,7 +7621,7 @@ var call = Function.prototype.call, * @api public */ -module.exports = function (ctx, name, method, chainingBehavior) { +module.exports = function addChainableMethod(ctx, name, method, chainingBehavior) { if (typeof chainingBehavior !== 'function') { chainingBehavior = function () { }; } @@ -4111,54 +7638,147 @@ module.exports = function (ctx, name, method, chainingBehavior) { ctx.__methods[name] = chainableBehavior; Object.defineProperty(ctx, name, - { get: function () { + { get: function chainableMethodGetter() { chainableBehavior.chainingBehavior.call(this); - var assert = function assert() { - var old_ssfi = flag(this, 'ssfi'); - if (old_ssfi && config.includeStack === false) - flag(this, 'ssfi', assert); + var chainableMethodWrapper = function () { + // Setting the `ssfi` flag to `chainableMethodWrapper` causes this + // function to be the starting point for removing implementation + // frames from the stack trace of a failed assertion. + // + // However, we only want to use this function as the starting point if + // the `lockSsfi` flag isn't set. + // + // If the `lockSsfi` flag is set, then this assertion is being + // invoked from inside of another assertion. In this case, the `ssfi` + // flag has already been set by the outer assertion. + // + // Note that overwriting a chainable method merely replaces the saved + // methods in `ctx.__methods` instead of completely replacing the + // overwritten assertion. Therefore, an overwriting assertion won't + // set the `ssfi` or `lockSsfi` flags. + if (!flag(this, 'lockSsfi')) { + flag(this, 'ssfi', chainableMethodWrapper); + } + var result = chainableBehavior.method.apply(this, arguments); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; - // Use `__proto__` if available - if (hasProtoSupport) { + addLengthGuard(chainableMethodWrapper, name, true); + + // Use `Object.setPrototypeOf` if available + if (canSetPrototype) { // Inherit all properties from the object by replacing the `Function` prototype - var prototype = assert.__proto__ = Object.create(this); + var prototype = Object.create(this); // Restore the `call` and `apply` methods from `Function` prototype.call = call; prototype.apply = apply; + Object.setPrototypeOf(chainableMethodWrapper, prototype); } // Otherwise, redefine all properties (slow!) else { var asserterNames = Object.getOwnPropertyNames(ctx); asserterNames.forEach(function (asserterName) { - if (!excludeNames.test(asserterName)) { - var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); - Object.defineProperty(assert, asserterName, pd); + if (excludeNames.indexOf(asserterName) !== -1) { + return; } + + var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); + Object.defineProperty(chainableMethodWrapper, asserterName, pd); }); } - transferFlags(this, assert); - return assert; + transferFlags(this, chainableMethodWrapper); + return proxify(chainableMethodWrapper); } , configurable: true }); }; -},{"../config":4,"./flag":13,"./transferFlags":29}],10:[function(require,module,exports){ +},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],10:[function(require,module,exports){ +var fnLengthDesc = Object.getOwnPropertyDescriptor(function () {}, 'length'); + +/*! + * Chai - addLengthGuard utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .addLengthGuard(fn, assertionName, isChainable) + * + * Define `length` as a getter on the given uninvoked method assertion. The + * getter acts as a guard against chaining `length` directly off of an uninvoked + * method assertion, which is a problem because it references `function`'s + * built-in `length` property instead of Chai's `length` assertion. When the + * getter catches the user making this mistake, it throws an error with a + * helpful message. + * + * There are two ways in which this mistake can be made. The first way is by + * chaining the `length` assertion directly off of an uninvoked chainable + * method. In this case, Chai suggests that the user use `lengthOf` instead. The + * second way is by chaining the `length` assertion directly off of an uninvoked + * non-chainable method. Non-chainable methods must be invoked prior to + * chaining. In this case, Chai suggests that the user consult the docs for the + * given assertion. + * + * If the `length` property of functions is unconfigurable, then return `fn` + * without modification. + * + * Note that in ES6, the function's `length` property is configurable, so once + * support for legacy environments is dropped, Chai's `length` property can + * replace the built-in function's `length` property, and this length guard will + * no longer be necessary. In the mean time, maintaining consistency across all + * environments is the priority. + * + * @param {Function} fn + * @param {String} assertionName + * @param {Boolean} isChainable + * @namespace Utils + * @name addLengthGuard + */ + +module.exports = function addLengthGuard (fn, assertionName, isChainable) { + if (!fnLengthDesc.configurable) return fn; + + Object.defineProperty(fn, 'length', { + get: function () { + if (isChainable) { + throw Error('Invalid Chai property: ' + assertionName + '.length. Due' + + ' to a compatibility issue, "length" cannot directly follow "' + + assertionName + '". Use "' + assertionName + '.lengthOf" instead.'); + } + + throw Error('Invalid Chai property: ' + assertionName + '.length. See' + + ' docs for proper usage of "' + assertionName + '".'); + } + }); + + return fn; +}; + +},{}],11:[function(require,module,exports){ /*! * Chai - addMethod utility * Copyright(c) 2012-2014 Jake Luer * MIT Licensed */ -var config = require('../config'); +var addLengthGuard = require('./addLengthGuard'); +var chai = require('../../chai'); +var flag = require('./flag'); +var proxify = require('./proxify'); +var transferFlags = require('./transferFlags'); /** - * ### .addMethod (ctx, name, method) + * ### .addMethod(ctx, name, method) * * Adds a method to the prototype of an object. * @@ -4182,30 +7802,52 @@ var config = require('../config'); * @name addMethod * @api public */ -var flag = require('./flag'); -module.exports = function (ctx, name, method) { - ctx[name] = function () { - var old_ssfi = flag(this, 'ssfi'); - if (old_ssfi && config.includeStack === false) - flag(this, 'ssfi', ctx[name]); +module.exports = function addMethod(ctx, name, method) { + var methodWrapper = function () { + // Setting the `ssfi` flag to `methodWrapper` causes this function to be the + // starting point for removing implementation frames from the stack trace of + // a failed assertion. + // + // However, we only want to use this function as the starting point if the + // `lockSsfi` flag isn't set. + // + // If the `lockSsfi` flag is set, then either this assertion has been + // overwritten by another assertion, or this assertion is being invoked from + // inside of another assertion. In the first case, the `ssfi` flag has + // already been set by the overwriting assertion. In the second case, the + // `ssfi` flag has already been set by the outer assertion. + if (!flag(this, 'lockSsfi')) { + flag(this, 'ssfi', methodWrapper); + } + var result = method.apply(this, arguments); - return result === undefined ? this : result; + if (result !== undefined) + return result; + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; + + addLengthGuard(methodWrapper, name, false); + ctx[name] = proxify(methodWrapper, name); }; -},{"../config":4,"./flag":13}],11:[function(require,module,exports){ +},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],12:[function(require,module,exports){ /*! * Chai - addProperty utility * Copyright(c) 2012-2014 Jake Luer * MIT Licensed */ -var config = require('../config'); +var chai = require('../../chai'); var flag = require('./flag'); +var isProxyEnabled = require('./isProxyEnabled'); +var transferFlags = require('./transferFlags'); /** - * ### addProperty (ctx, name, getter) + * ### .addProperty(ctx, name, getter) * * Adds a property to the prototype of an object. * @@ -4230,21 +7872,76 @@ var flag = require('./flag'); * @api public */ -module.exports = function (ctx, name, getter) { - Object.defineProperty(ctx, name, - { get: function addProperty() { - var old_ssfi = flag(this, 'ssfi'); - if (old_ssfi && config.includeStack === false) - flag(this, 'ssfi', addProperty); - - var result = getter.call(this); - return result === undefined ? this : result; - } - , configurable: true - }); +module.exports = function addProperty(ctx, name, getter) { + getter = getter === undefined ? function () {} : getter; + + Object.defineProperty(ctx, name, + { get: function propertyGetter() { + // Setting the `ssfi` flag to `propertyGetter` causes this function to + // be the starting point for removing implementation frames from the + // stack trace of a failed assertion. + // + // However, we only want to use this function as the starting point if + // the `lockSsfi` flag isn't set and proxy protection is disabled. + // + // If the `lockSsfi` flag is set, then either this assertion has been + // overwritten by another assertion, or this assertion is being invoked + // from inside of another assertion. In the first case, the `ssfi` flag + // has already been set by the overwriting assertion. In the second + // case, the `ssfi` flag has already been set by the outer assertion. + // + // If proxy protection is enabled, then the `ssfi` flag has already been + // set by the proxy getter. + if (!isProxyEnabled() && !flag(this, 'lockSsfi')) { + flag(this, 'ssfi', propertyGetter); + } + + var result = getter.call(this); + if (result !== undefined) + return result; + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; + } + , configurable: true + }); +}; + +},{"../../chai":2,"./flag":15,"./isProxyEnabled":25,"./transferFlags":32}],13:[function(require,module,exports){ +/*! + * Chai - compareByInspect utility + * Copyright(c) 2011-2016 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var inspect = require('./inspect'); + +/** + * ### .compareByInspect(mixed, mixed) + * + * To be used as a compareFunction with Array.prototype.sort. Compares elements + * using inspect instead of default behavior of using toString so that Symbols + * and objects with irregular/missing toString can still be sorted without a + * TypeError. + * + * @param {Mixed} first element to compare + * @param {Mixed} second element to compare + * @returns {Number} -1 if 'a' should come before 'b'; otherwise 1 + * @name compareByInspect + * @namespace Utils + * @api public + */ + +module.exports = function compareByInspect(a, b) { + return inspect(a) < inspect(b) ? -1 : 1; }; -},{"../config":4,"./flag":13}],12:[function(require,module,exports){ +},{"./inspect":23}],14:[function(require,module,exports){ /*! * Chai - expectTypes utility * Copyright(c) 2012-2014 Jake Luer @@ -4252,7 +7949,7 @@ module.exports = function (ctx, name, getter) { */ /** - * ### expectTypes(obj, types) + * ### .expectTypes(obj, types) * * Ensures that the object being tested against is of a valid type. * @@ -4269,26 +7966,35 @@ var AssertionError = require('assertion-error'); var flag = require('./flag'); var type = require('type-detect'); -module.exports = function (obj, types) { - var obj = flag(obj, 'object'); +module.exports = function expectTypes(obj, types) { + var flagMsg = flag(obj, 'message'); + var ssfi = flag(obj, 'ssfi'); + + flagMsg = flagMsg ? flagMsg + ': ' : ''; + + obj = flag(obj, 'object'); types = types.map(function (t) { return t.toLowerCase(); }); types.sort(); - // Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum' + // 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(', '); - if (!types.some(function (expected) { return type(obj) === expected; })) { + var objType = type(obj).toLowerCase(); + + if (!types.some(function (expected) { return objType === expected; })) { throw new AssertionError( - 'object tested must be ' + str + ', but ' + type(obj) + ' given' + flagMsg + 'object tested must be ' + str + ', but ' + objType + ' given', + undefined, + ssfi ); } }; -},{"./flag":13,"assertion-error":30,"type-detect":35}],13:[function(require,module,exports){ +},{"./flag":15,"assertion-error":33,"type-detect":38}],15:[function(require,module,exports){ /*! * Chai - flag utility * Copyright(c) 2012-2014 Jake Luer @@ -4296,7 +8002,7 @@ module.exports = function (obj, types) { */ /** - * ### flag(object, key, [value]) + * ### .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 @@ -4314,7 +8020,7 @@ module.exports = function (obj, types) { * @api private */ -module.exports = function (obj, key, value) { +module.exports = function flag(obj, key, value) { var flags = obj.__flags || (obj.__flags = Object.create(null)); if (arguments.length === 3) { flags[key] = value; @@ -4323,7 +8029,7 @@ module.exports = function (obj, key, value) { } }; -},{}],14:[function(require,module,exports){ +},{}],16:[function(require,module,exports){ /*! * Chai - getActual utility * Copyright(c) 2012-2014 Jake Luer @@ -4331,9 +8037,9 @@ module.exports = function (obj, key, value) { */ /** - * # getActual(object, [actual]) + * ### .getActual(object, [actual]) * - * Returns the `actual` value for an Assertion + * Returns the `actual` value for an Assertion. * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments @@ -4341,11 +8047,11 @@ module.exports = function (obj, key, value) { * @name getActual */ -module.exports = function (obj, args) { +module.exports = function getActual(obj, args) { return args.length > 4 ? args[4] : obj._obj; }; -},{}],15:[function(require,module,exports){ +},{}],17:[function(require,module,exports){ /*! * Chai - getEnumerableProperties utility * Copyright(c) 2012-2014 Jake Luer @@ -4373,7 +8079,7 @@ module.exports = function getEnumerableProperties(object) { return result; }; -},{}],16:[function(require,module,exports){ +},{}],18:[function(require,module,exports){ /*! * Chai - message composition utility * Copyright(c) 2012-2014 Jake Luer @@ -4381,12 +8087,11 @@ module.exports = function getEnumerableProperties(object) { */ /*! - * Module dependancies + * Module dependencies */ var flag = require('./flag') , getActual = require('./getActual') - , inspect = require('./inspect') , objDisplay = require('./objDisplay'); /** @@ -4408,7 +8113,7 @@ var flag = require('./flag') * @api public */ -module.exports = function (obj, args) { +module.exports = function getMessage(obj, args) { var negate = flag(obj, 'negate') , val = flag(obj, 'object') , expected = args[3] @@ -4426,189 +8131,67 @@ module.exports = function (obj, args) { return flagMsg ? flagMsg + ': ' + msg : msg; }; -},{"./flag":13,"./getActual":14,"./inspect":23,"./objDisplay":24}],17:[function(require,module,exports){ +},{"./flag":15,"./getActual":16,"./objDisplay":26}],19:[function(require,module,exports){ /*! - * Chai - getName utility - * Copyright(c) 2012-2014 Jake Luer + * Chai - getOwnEnumerableProperties utility + * Copyright(c) 2011-2016 Jake Luer * MIT Licensed */ -/** - * # getName(func) - * - * Gets the name of a function, in a cross-browser way. - * - * @param {Function} a function (usually a constructor) - * @namespace Utils - * @name getName - */ - -module.exports = function (func) { - if (func.name) return func.name; - - var match = /^\s?function ([^(]*)\(/.exec(func); - return match && match[1] ? match[1] : ""; -}; - -},{}],18:[function(require,module,exports){ /*! - * Chai - getPathInfo utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed + * Module dependencies */ -var hasProperty = require('./hasProperty'); +var getOwnEnumerablePropertySymbols = require('./getOwnEnumerablePropertySymbols'); /** - * ### .getPathInfo(path, object) - * - * 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: + * ### .getOwnEnumerableProperties(object) * - * * 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 + * This allows the retrieval of directly-owned enumerable property names and + * symbols of an object. This function is necessary because Object.keys only + * returns enumerable property names, not enumerable property symbols. * - * @param {String} path * @param {Object} object - * @returns {Object} info + * @returns {Array} * @namespace Utils - * @name getPathInfo + * @name getOwnEnumerableProperties * @api public */ -module.exports = function getPathInfo(path, obj) { - var parsed = parsePath(path), - last = parsed[parsed.length - 1]; - - var info = { - parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj, - name: last.p || last.i, - value: _getPathValue(parsed, obj) - }; - info.exists = hasProperty(info.name, info.parent); - - return info; +module.exports = function getOwnEnumerableProperties(obj) { + return Object.keys(obj).concat(getOwnEnumerablePropertySymbols(obj)); }; - -/*! - * ## parsePath(path) - * - * Helper function used to parse string object - * paths. Use in conjunction with `_getPathValue`. - * - * var parsed = parsePath('myobject.property.subprop'); - * - * ### Paths: - * - * * Can be as near 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.[') - , parts = str.match(/(\\\.|[^.]+?)+/g); - return parts.map(function (value) { - var re = /^\[(\d+)\]$/ - , mArr = re.exec(value); - if (mArr) return { i: parseFloat(mArr[1]) }; - else return { p: value.replace(/\\([.\[\]])/g, '$1') }; - }); -} - - -/*! - * ## _getPathValue(parsed, obj) - * - * Helper companion function for `.parsePath` that returns - * the value located at the parsed address. - * - * var value = getPathValue(parsed, obj); - * - * @param {Object} parsed definition from `parsePath`. - * @param {Object} object to search against - * @param {Number} object to search against - * @returns {Object|Undefined} value - * @api private - */ - -function _getPathValue (parsed, obj, index) { - var tmp = obj - , res; - - index = (index === undefined ? parsed.length : index); - - for (var i = 0, l = index; i < l; i++) { - var part = parsed[i]; - if (tmp) { - if ('undefined' !== typeof part.p) - tmp = tmp[part.p]; - else if ('undefined' !== typeof part.i) - tmp = tmp[part.i]; - if (i == (l - 1)) res = tmp; - } else { - res = undefined; - } - } - return res; -} - -},{"./hasProperty":21}],19:[function(require,module,exports){ +},{"./getOwnEnumerablePropertySymbols":20}],20:[function(require,module,exports){ /*! - * Chai - getPathValue utility - * Copyright(c) 2012-2014 Jake Luer - * @see https://github.com/logicalparadox/filtr + * Chai - getOwnEnumerablePropertySymbols utility + * Copyright(c) 2011-2016 Jake Luer * MIT Licensed */ -var getPathInfo = require('./getPathInfo'); - /** - * ### .getPathValue(path, object) - * - * This allows the retrieval of values in an - * object given a string path. + * ### .getOwnEnumerablePropertySymbols(object) * - * var obj = { - * prop1: { - * arr: ['a', 'b', 'c'] - * , str: 'Hello' - * } - * , prop2: { - * arr: [ { nested: 'Universe' } ] - * , str: 'Hello again!' - * } - * } - * - * The following would be the results. + * This allows the retrieval of directly-owned enumerable property symbols of an + * object. This function is necessary because Object.getOwnPropertySymbols + * returns both enumerable and non-enumerable property symbols. * - * getPathValue('prop1.str', obj); // Hello - * getPathValue('prop1.att[2]', obj); // b - * getPathValue('prop2.arr[0].nested', obj); // Universe - * - * @param {String} path * @param {Object} object - * @returns {Object} value or `undefined` + * @returns {Array} * @namespace Utils - * @name getPathValue + * @name getOwnEnumerablePropertySymbols * @api public */ -module.exports = function(path, obj) { - var info = getPathInfo(path, obj); - return info.value; + +module.exports = function getOwnEnumerablePropertySymbols(obj) { + if (typeof Object.getOwnPropertySymbols !== 'function') return []; + + return Object.getOwnPropertySymbols(obj).filter(function (sym) { + return Object.getOwnPropertyDescriptor(obj, sym).enumerable; + }); }; -},{"./getPathInfo":18}],20:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ /*! * Chai - getProperties utility * Copyright(c) 2012-2014 Jake Luer @@ -4646,73 +8229,7 @@ module.exports = function getProperties(object) { return result; }; -},{}],21:[function(require,module,exports){ -/*! - * Chai - hasProperty utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -var type = require('type-detect'); - -/** - * ### .hasProperty(object, name) - * - * This allows checking whether an object has - * named property or numeric array index. - * - * Basically does the same thing as the `in` - * operator but works properly with natives - * and null/undefined values. - * - * var obj = { - * arr: ['a', 'b', 'c'] - * , str: 'Hello' - * } - * - * The following would be the results. - * - * hasProperty('str', obj); // true - * hasProperty('constructor', obj); // true - * hasProperty('bar', obj); // false - * - * hasProperty('length', obj.str); // true - * hasProperty(1, obj.str); // true - * hasProperty(5, obj.str); // false - * - * hasProperty('length', obj.arr); // true - * hasProperty(2, obj.arr); // true - * hasProperty(3, obj.arr); // false - * - * @param {Objuect} object - * @param {String|Number} name - * @returns {Boolean} whether it exists - * @namespace Utils - * @name getPathInfo - * @api public - */ - -var literals = { - 'number': Number - , 'string': String -}; - -module.exports = function hasProperty(name, obj) { - var ot = type(obj); - - // Bad Object, obviously no props at all - if(ot === 'null' || ot === 'undefined') - return false; - - // The `in` operator does not work with certain literals - // box these before the check - if(literals[ot] && typeof obj !== 'object') - obj = new literals[ot](obj); - - return name in obj; -}; - -},{"type-detect":35}],22:[function(require,module,exports){ +},{}],22:[function(require,module,exports){ /*! * chai * Copyright(c) 2011 Jake Luer @@ -4720,10 +8237,10 @@ module.exports = function hasProperty(name, obj) { */ /*! - * Main exports + * Dependencies that are used for multiple exports are required here only once */ -var exports = module.exports = {}; +var pathval = require('pathval'); /*! * test utility @@ -4784,29 +8301,23 @@ exports.transferFlags = require('./transferFlags'); exports.eql = require('deep-eql'); -/*! - * Deep path value - */ - -exports.getPathValue = require('./getPathValue'); - /*! * Deep path info */ -exports.getPathInfo = require('./getPathInfo'); +exports.getPathInfo = pathval.getPathInfo; /*! * Check if a property exists */ -exports.hasProperty = require('./hasProperty'); +exports.hasProperty = pathval.hasProperty; /*! * Function name */ -exports.getName = require('./getName'); +exports.getName = require('get-func-name'); /*! * add Property @@ -4844,23 +8355,74 @@ exports.addChainableMethod = require('./addChainableMethod'); exports.overwriteChainableMethod = require('./overwriteChainableMethod'); -},{"./addChainableMethod":9,"./addMethod":10,"./addProperty":11,"./expectTypes":12,"./flag":13,"./getActual":14,"./getMessage":16,"./getName":17,"./getPathInfo":18,"./getPathValue":19,"./hasProperty":21,"./inspect":23,"./objDisplay":24,"./overwriteChainableMethod":25,"./overwriteMethod":26,"./overwriteProperty":27,"./test":28,"./transferFlags":29,"deep-eql":31,"type-detect":35}],23:[function(require,module,exports){ +/*! + * Compare by inspect method + */ + +exports.compareByInspect = require('./compareByInspect'); + +/*! + * Get own enumerable property symbols method + */ + +exports.getOwnEnumerablePropertySymbols = require('./getOwnEnumerablePropertySymbols'); + +/*! + * Get own enumerable properties method + */ + +exports.getOwnEnumerableProperties = require('./getOwnEnumerableProperties'); + +/*! + * Checks error against a given set of criteria + */ + +exports.checkError = require('check-error'); + +/*! + * Proxify util + */ + +exports.proxify = require('./proxify'); + +/*! + * addLengthGuard util + */ + +exports.addLengthGuard = require('./addLengthGuard'); + +/*! + * isProxyEnabled helper + */ + +exports.isProxyEnabled = require('./isProxyEnabled'); + +/*! + * isNaN method + */ + +exports.isNaN = require('./isNaN'); + +},{"./addChainableMethod":9,"./addLengthGuard":10,"./addMethod":11,"./addProperty":12,"./compareByInspect":13,"./expectTypes":14,"./flag":15,"./getActual":16,"./getMessage":18,"./getOwnEnumerableProperties":19,"./getOwnEnumerablePropertySymbols":20,"./inspect":23,"./isNaN":24,"./isProxyEnabled":25,"./objDisplay":26,"./overwriteChainableMethod":27,"./overwriteMethod":28,"./overwriteProperty":29,"./proxify":30,"./test":31,"./transferFlags":32,"check-error":34,"deep-eql":35,"get-func-name":36,"pathval":37,"type-detect":38}],23:[function(require,module,exports){ // This is (almost) directly from Node.js utils // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js -var getName = require('./getName'); +var getName = require('get-func-name'); var getProperties = require('./getProperties'); var getEnumerableProperties = require('./getEnumerableProperties'); +var config = require('../config'); module.exports = inspect; /** - * Echos the value of a value. Trys to print the value out + * ### .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. + * 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). @@ -4883,6 +8445,7 @@ var isDOMElement = function (object) { } else { return object && typeof object === 'object' && + 'nodeType' in object && object.nodeType === 1 && typeof object.nodeName === 'string'; } @@ -4896,7 +8459,7 @@ function formatValue(ctx, value, recurseTimes) { 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); + var ret = value.inspect(recurseTimes, ctx); if (typeof ret !== 'string') { ret = formatValue(ctx, ret, recurseTimes); } @@ -4929,7 +8492,7 @@ function formatValue(ctx, value, recurseTimes) { var container = document.createElementNS(ns, '_'); container.appendChild(value.cloneNode(false)); - html = container.innerHTML + var html = container.innerHTML .replace('><', '>' + value.innerHTML + '<'); container.innerHTML = ''; return html; @@ -4946,7 +8509,9 @@ function formatValue(ctx, value, recurseTimes) { var visibleKeys = getEnumerableProperties(value); var keys = ctx.showHidden ? getProperties(value) : visibleKeys; - // Some type of object without properties can be shortcutted. + 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) && ( @@ -4954,8 +8519,8 @@ function formatValue(ctx, value, recurseTimes) { (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') ))) { if (typeof value === 'function') { - var name = getName(value); - var nameSuffix = name ? ': ' + name : ''; + name = getName(value); + nameSuffix = name ? ': ' + name : ''; return ctx.stylize('[Function' + nameSuffix + ']', 'special'); } if (isRegExp(value)) { @@ -4969,7 +8534,15 @@ function formatValue(ctx, value, recurseTimes) { } } - var base = '', array = false, braces = ['{', '}']; + var base = '' + , array = false + , typedArray = false + , braces = ['{', '}']; + + if (isTypedArray(value)) { + typedArray = true; + braces = ['[', ']']; + } // Make Array say that they are Array if (isArray(value)) { @@ -4979,8 +8552,8 @@ function formatValue(ctx, value, recurseTimes) { // Make functions say that they are functions if (typeof value === 'function') { - var name = getName(value); - var nameSuffix = name ? ': ' + name : ''; + name = getName(value); + nameSuffix = name ? ': ' + name : ''; base = ' [Function' + nameSuffix + ']'; } @@ -5016,6 +8589,8 @@ function formatValue(ctx, value, recurseTimes) { 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); @@ -5027,7 +8602,6 @@ function formatValue(ctx, value, recurseTimes) { return reduceToSingleString(output, base, braces); } - function formatPrimitive(ctx, value) { switch (typeof value) { case 'undefined': @@ -5047,6 +8621,9 @@ function formatPrimitive(ctx, value) { case 'boolean': return ctx.stylize('' + value, 'boolean'); + + case 'symbol': + return ctx.stylize(value.toString(), 'symbol'); } // For some reason typeof null is "object", so special case here. if (value === null) { @@ -5054,12 +8631,10 @@ function formatPrimitive(ctx, value) { } } - 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) { @@ -5070,6 +8645,7 @@ function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { output.push(''); } } + keys.forEach(function(key) { if (!key.match(/^\d+$/)) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, @@ -5079,18 +8655,40 @@ function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { return output; } +function formatTypedArray(value) { + var str = '[ '; + + for (var i = 0; i < value.length; ++i) { + if (str.length >= config.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, str; - if (value.__lookupGetter__) { - if (value.__lookupGetter__(key)) { - if (value.__lookupSetter__(key)) { + 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 (value.__lookupSetter__(key)) { + if (propDescriptor.set) { str = ctx.stylize('[Setter]', 'special'); } } @@ -5139,12 +8737,8 @@ function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 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.length + 1; }, 0); @@ -5160,6 +8754,12 @@ function reduceToSingleString(output, base, braces) { 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]'); @@ -5181,7 +8781,61 @@ function objectToString(o) { return Object.prototype.toString.call(o); } -},{"./getEnumerableProperties":15,"./getName":17,"./getProperties":20}],24:[function(require,module,exports){ +},{"../config":4,"./getEnumerableProperties":17,"./getProperties":21,"get-func-name":36}],24:[function(require,module,exports){ +/*! + * Chai - isNaN utility + * Copyright(c) 2012-2015 Sakthipriyan Vairamani + * MIT Licensed + */ + +/** + * ### .isNaN(value) + * + * Checks if the given value is NaN or not. + * + * utils.isNaN(NaN); // true + * + * @param {Value} The value which has to be checked if it is NaN + * @name isNaN + * @api private + */ + +function isNaN(value) { + // Refer http://www.ecma-international.org/ecma-262/6.0/#sec-isnan-number + // section's NOTE. + return value !== value; +} + +// If ECMAScript 6's Number.isNaN is present, prefer that. +module.exports = Number.isNaN || isNaN; + +},{}],25:[function(require,module,exports){ +var config = require('../config'); + +/*! + * Chai - isProxyEnabled helper + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .isProxyEnabled() + * + * Helper function to check if Chai's proxy protection feature is enabled. If + * proxies are unsupported or disabled via the user's Chai config, then return + * false. Otherwise, return true. + * + * @namespace Utils + * @name isProxyEnabled + */ + +module.exports = function isProxyEnabled() { + return config.useProxy && + typeof Proxy !== 'undefined' && + typeof Reflect !== 'undefined'; +}; + +},{"../config":4}],26:[function(require,module,exports){ /*! * Chai - flag utility * Copyright(c) 2012-2014 Jake Luer @@ -5189,14 +8843,14 @@ function objectToString(o) { */ /*! - * Module dependancies + * Module dependencies */ var inspect = require('./inspect'); var config = require('../config'); /** - * ### .objDisplay (object) + * ### .objDisplay(object) * * Determines if an object or an array matches * criteria to be inspected in-line for error @@ -5208,7 +8862,7 @@ var config = require('../config'); * @api public */ -module.exports = function (obj) { +module.exports = function objDisplay(obj) { var str = inspect(obj) , type = Object.prototype.toString.call(obj); @@ -5233,22 +8887,25 @@ module.exports = function (obj) { } }; -},{"../config":4,"./inspect":23}],25:[function(require,module,exports){ +},{"../config":4,"./inspect":23}],27:[function(require,module,exports){ /*! * Chai - overwriteChainableMethod utility * Copyright(c) 2012-2014 Jake Luer * MIT Licensed */ +var chai = require('../../chai'); +var transferFlags = require('./transferFlags'); + /** - * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) + * ### .overwriteChainableMethod(ctx, name, method, chainingBehavior) * - * Overwites an already existing chainable method + * Overwrites an already existing chainable method * and provides access to the previous function or * property. Must return functions to be used for * name. * - * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', + * utils.overwriteChainableMethod(chai.Assertion.prototype, 'lengthOf', * function (_super) { * } * , function (_super) { @@ -5261,8 +8918,8 @@ module.exports = function (obj) { * * Then can be used as any other assertion. * - * expect(myFoo).to.have.length(3); - * expect(myFoo).to.have.length.above(3); + * expect(myFoo).to.have.lengthOf(3); + * expect(myFoo).to.have.lengthOf.above(3); * * @param {Object} ctx object whose method / property is to be overwritten * @param {String} name of method / property to overwrite @@ -5273,33 +8930,51 @@ module.exports = function (obj) { * @api public */ -module.exports = function (ctx, name, method, chainingBehavior) { +module.exports = function overwriteChainableMethod(ctx, name, method, chainingBehavior) { var chainableBehavior = ctx.__methods[name]; var _chainingBehavior = chainableBehavior.chainingBehavior; - chainableBehavior.chainingBehavior = function () { + chainableBehavior.chainingBehavior = function overwritingChainableMethodGetter() { var result = chainingBehavior(_chainingBehavior).call(this); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; var _method = chainableBehavior.method; - chainableBehavior.method = function () { + chainableBehavior.method = function overwritingChainableMethodWrapper() { var result = method(_method).apply(this, arguments); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; }; -},{}],26:[function(require,module,exports){ +},{"../../chai":2,"./transferFlags":32}],28:[function(require,module,exports){ /*! * Chai - overwriteMethod utility * Copyright(c) 2012-2014 Jake Luer * MIT Licensed */ +var addLengthGuard = require('./addLengthGuard'); +var chai = require('../../chai'); +var flag = require('./flag'); +var proxify = require('./proxify'); +var transferFlags = require('./transferFlags'); + /** - * ### overwriteMethod (ctx, name, fn) + * ### .overwriteMethod(ctx, name, fn) * - * Overwites an already existing method and provides + * Overwrites an already existing method and provides * access to previous function. Must return function * to be used for name. * @@ -5330,30 +9005,69 @@ module.exports = function (ctx, name, method, chainingBehavior) { * @api public */ -module.exports = function (ctx, name, method) { +module.exports = function overwriteMethod(ctx, name, method) { var _method = ctx[name] - , _super = function () { return this; }; + , _super = function () { + throw new Error(name + ' is not a function'); + }; if (_method && 'function' === typeof _method) _super = _method; - ctx[name] = function () { + var overwritingMethodWrapper = function () { + // Setting the `ssfi` flag to `overwritingMethodWrapper` causes this + // function to be the starting point for removing implementation frames from + // the stack trace of a failed assertion. + // + // However, we only want to use this function as the starting point if the + // `lockSsfi` flag isn't set. + // + // If the `lockSsfi` flag is set, then either this assertion has been + // overwritten by another assertion, or this assertion is being invoked from + // inside of another assertion. In the first case, the `ssfi` flag has + // already been set by the overwriting assertion. In the second case, the + // `ssfi` flag has already been set by the outer assertion. + if (!flag(this, 'lockSsfi')) { + flag(this, 'ssfi', overwritingMethodWrapper); + } + + // Setting the `lockSsfi` flag to `true` prevents the overwritten assertion + // from changing the `ssfi` flag. By this point, the `ssfi` flag is already + // set to the correct starting point for this assertion. + var origLockSsfi = flag(this, 'lockSsfi'); + flag(this, 'lockSsfi', true); var result = method(_super).apply(this, arguments); - return result === undefined ? this : result; + flag(this, 'lockSsfi', origLockSsfi); + + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; } + + addLengthGuard(overwritingMethodWrapper, name, false); + ctx[name] = proxify(overwritingMethodWrapper, name); }; -},{}],27:[function(require,module,exports){ +},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],29:[function(require,module,exports){ /*! * Chai - overwriteProperty utility * Copyright(c) 2012-2014 Jake Luer * MIT Licensed */ +var chai = require('../../chai'); +var flag = require('./flag'); +var isProxyEnabled = require('./isProxyEnabled'); +var transferFlags = require('./transferFlags'); + /** - * ### overwriteProperty (ctx, name, fn) + * ### .overwriteProperty(ctx, name, fn) * - * Overwites an already existing property getter and provides + * Overwrites an already existing property getter and provides * access to previous value. Must return function to use as getter. * * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { @@ -5384,7 +9098,7 @@ module.exports = function (ctx, name, method) { * @api public */ -module.exports = function (ctx, name, getter) { +module.exports = function overwriteProperty(ctx, name, getter) { var _get = Object.getOwnPropertyDescriptor(ctx, name) , _super = function () {}; @@ -5392,15 +9106,196 @@ module.exports = function (ctx, name, getter) { _super = _get.get Object.defineProperty(ctx, name, - { get: function () { + { get: function overwritingPropertyGetter() { + // Setting the `ssfi` flag to `overwritingPropertyGetter` causes this + // function to be the starting point for removing implementation frames + // from the stack trace of a failed assertion. + // + // However, we only want to use this function as the starting point if + // the `lockSsfi` flag isn't set and proxy protection is disabled. + // + // If the `lockSsfi` flag is set, then either this assertion has been + // overwritten by another assertion, or this assertion is being invoked + // from inside of another assertion. In the first case, the `ssfi` flag + // has already been set by the overwriting assertion. In the second + // case, the `ssfi` flag has already been set by the outer assertion. + // + // If proxy protection is enabled, then the `ssfi` flag has already been + // set by the proxy getter. + if (!isProxyEnabled() && !flag(this, 'lockSsfi')) { + flag(this, 'ssfi', overwritingPropertyGetter); + } + + // Setting the `lockSsfi` flag to `true` prevents the overwritten + // assertion from changing the `ssfi` flag. By this point, the `ssfi` + // flag is already set to the correct starting point for this assertion. + var origLockSsfi = flag(this, 'lockSsfi'); + flag(this, 'lockSsfi', true); var result = getter(_super).call(this); - return result === undefined ? this : result; + flag(this, 'lockSsfi', origLockSsfi); + + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; } , configurable: true }); }; -},{}],28:[function(require,module,exports){ +},{"../../chai":2,"./flag":15,"./isProxyEnabled":25,"./transferFlags":32}],30:[function(require,module,exports){ +var config = require('../config'); +var flag = require('./flag'); +var getProperties = require('./getProperties'); +var isProxyEnabled = require('./isProxyEnabled'); + +/*! + * Chai - proxify utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .proxify(object) + * + * Return a proxy of given object that throws an error when a non-existent + * property is read. By default, the root cause is assumed to be a misspelled + * property, and thus an attempt is made to offer a reasonable suggestion from + * the list of existing properties. However, if a nonChainableMethodName is + * provided, then the root cause is instead a failure to invoke a non-chainable + * method prior to reading the non-existent property. + * + * If proxies are unsupported or disabled via the user's Chai config, then + * return object without modification. + * + * @param {Object} obj + * @param {String} nonChainableMethodName + * @namespace Utils + * @name proxify + */ + +var builtins = ['__flags', '__methods', '_obj', 'assert']; + +module.exports = function proxify(obj, nonChainableMethodName) { + if (!isProxyEnabled()) return obj; + + return new Proxy(obj, { + get: function proxyGetter(target, property) { + // This check is here because we should not throw errors on Symbol properties + // such as `Symbol.toStringTag`. + // The values for which an error should be thrown can be configured using + // the `config.proxyExcludedKeys` setting. + if (typeof property === 'string' && + config.proxyExcludedKeys.indexOf(property) === -1 && + !Reflect.has(target, property)) { + // Special message for invalid property access of non-chainable methods. + if (nonChainableMethodName) { + throw Error('Invalid Chai property: ' + nonChainableMethodName + '.' + + property + '. See docs for proper usage of "' + + nonChainableMethodName + '".'); + } + + // If the property is reasonably close to an existing Chai property, + // suggest that property to the user. Only suggest properties with a + // distance less than 4. + var suggestion = null; + var suggestionDistance = 4; + getProperties(target).forEach(function(prop) { + if ( + !Object.prototype.hasOwnProperty(prop) && + builtins.indexOf(prop) === -1 + ) { + var dist = stringDistanceCapped( + property, + prop, + suggestionDistance + ); + if (dist < suggestionDistance) { + suggestion = prop; + suggestionDistance = dist; + } + } + }); + + if (suggestion !== null) { + throw Error('Invalid Chai property: ' + property + + '. Did you mean "' + suggestion + '"?'); + } else { + throw Error('Invalid Chai property: ' + property); + } + } + + // Use this proxy getter as the starting point for removing implementation + // frames from the stack trace of a failed assertion. For property + // assertions, this prevents the proxy getter from showing up in the stack + // trace since it's invoked before the property getter. For method and + // chainable method assertions, this flag will end up getting changed to + // the method wrapper, which is good since this frame will no longer be in + // the stack once the method is invoked. Note that Chai builtin assertion + // properties such as `__flags` are skipped since this is only meant to + // capture the starting point of an assertion. This step is also skipped + // if the `lockSsfi` flag is set, thus indicating that this assertion is + // being called from within another assertion. In that case, the `ssfi` + // flag is already set to the outer assertion's starting point. + if (builtins.indexOf(property) === -1 && !flag(target, 'lockSsfi')) { + flag(target, 'ssfi', proxyGetter); + } + + return Reflect.get(target, property); + } + }); +}; + +/** + * # stringDistanceCapped(strA, strB, cap) + * Return the Levenshtein distance between two strings, but no more than cap. + * @param {string} strA + * @param {string} strB + * @param {number} number + * @return {number} min(string distance between strA and strB, cap) + * @api private + */ + +function stringDistanceCapped(strA, strB, cap) { + if (Math.abs(strA.length - strB.length) >= cap) { + return cap; + } + + var memo = []; + // `memo` is a two-dimensional array containing distances. + // memo[i][j] is the distance between strA.slice(0, i) and + // strB.slice(0, j). + for (var i = 0; i <= strA.length; i++) { + memo[i] = Array(strB.length + 1).fill(0); + memo[i][0] = i; + } + for (var j = 0; j < strB.length; j++) { + memo[0][j] = j; + } + + for (var i = 1; i <= strA.length; i++) { + var ch = strA.charCodeAt(i - 1); + for (var j = 1; j <= strB.length; j++) { + if (Math.abs(i - j) >= cap) { + memo[i][j] = cap; + continue; + } + memo[i][j] = Math.min( + memo[i - 1][j] + 1, + memo[i][j - 1] + 1, + memo[i - 1][j - 1] + + (ch === strB.charCodeAt(j - 1) ? 0 : 1) + ); + } + } + + return memo[strA.length][strB.length]; +} + +},{"../config":4,"./flag":15,"./getProperties":21,"./isProxyEnabled":25}],31:[function(require,module,exports){ /*! * Chai - test utility * Copyright(c) 2012-2014 Jake Luer @@ -5408,13 +9303,13 @@ module.exports = function (ctx, name, getter) { */ /*! - * Module dependancies + * Module dependencies */ var flag = require('./flag'); /** - * # test(object, expression) + * ### .test(object, expression) * * Test and object for expression. * @@ -5424,13 +9319,13 @@ var flag = require('./flag'); * @name test */ -module.exports = function (obj, args) { +module.exports = function test(obj, args) { var negate = flag(obj, 'negate') , expr = args[0]; return negate ? !expr : expr; }; -},{"./flag":13}],29:[function(require,module,exports){ +},{"./flag":15}],32:[function(require,module,exports){ /*! * Chai - transferFlags utility * Copyright(c) 2012-2014 Jake Luer @@ -5438,18 +9333,18 @@ module.exports = function (obj, args) { */ /** - * ### transferFlags(assertion, object, includeAll = true) + * ### .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`, and `message`) - * will not be transferred. + * assertion flags (namely `object`, `ssfi`, `lockSsfi`, + * and `message`) will not be transferred. * * * var newAssertion = new Assertion(); * utils.transferFlags(assertion, newAssertion); * - * var anotherAsseriton = new Assertion(myObj); + * var anotherAssertion = new Assertion(myObj); * utils.transferFlags(assertion, anotherAssertion, false); * * @param {Assertion} assertion the assertion to transfer the flags from @@ -5460,7 +9355,7 @@ module.exports = function (obj, args) { * @api private */ -module.exports = function (assertion, object, includeAll) { +module.exports = function transferFlags(assertion, object, includeAll) { var flags = assertion.__flags || (assertion.__flags = Object.create(null)); if (!object.__flags) { @@ -5471,13 +9366,13 @@ module.exports = function (assertion, object, includeAll) { for (var flag in flags) { if (includeAll || - (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { + (flag !== 'object' && flag !== 'ssfi' && flag !== 'lockSsfi' && flag != 'message')) { object.__flags[flag] = flags[flag]; } } }; -},{}],30:[function(require,module,exports){ +},{}],33:[function(require,module,exports){ /*! * assertion-error * Copyright(c) 2013 Jake Luer @@ -5546,11 +9441,15 @@ function AssertionError (message, _props, ssf) { } // capture stack trace - ssf = ssf || arguments.callee; - if (ssf && Error.captureStackTrace) { + ssf = ssf || AssertionError; + if (Error.captureStackTrace) { Error.captureStackTrace(this, ssf); } else { - this.stack = new Error().stack; + try { + throw new Error(); + } catch(e) { + this.stack = e.stack; + } } } @@ -5591,552 +9490,1365 @@ AssertionError.prototype.toJSON = function (stack) { return props; }; -},{}],31:[function(require,module,exports){ -module.exports = require('./lib/eql'); +},{}],34:[function(require,module,exports){ +'use strict'; -},{"./lib/eql":32}],32:[function(require,module,exports){ -/*! - * deep-eql - * Copyright(c) 2013 Jake Luer +/* ! + * Chai - checkError utility + * Copyright(c) 2012-2016 Jake Luer * MIT Licensed */ -/*! - * Module dependencies +/** + * ### .checkError + * + * Checks that an error conforms to a given set of criteria and/or retrieves information about it. + * + * @api public */ -var type = require('type-detect'); - -/*! - * Buffer.isBuffer browser shim +/** + * ### .compatibleInstance(thrown, errorLike) + * + * Checks if two instances are compatible (strict equal). + * Returns false if errorLike is not an instance of Error, because instances + * can only be compatible if they're both error instances. + * + * @name compatibleInstance + * @param {Error} thrown error + * @param {Error|ErrorConstructor} errorLike object to compare against + * @namespace Utils + * @api public */ -var Buffer; -try { Buffer = require('buffer').Buffer; } -catch(ex) { - Buffer = {}; - Buffer.isBuffer = function() { return false; } +function compatibleInstance(thrown, errorLike) { + return errorLike instanceof Error && thrown === errorLike; } -/*! - * Primary Export +/** + * ### .compatibleConstructor(thrown, errorLike) + * + * Checks if two constructors are compatible. + * This function can receive either an error constructor or + * an error instance as the `errorLike` argument. + * Constructors are compatible if they're the same or if one is + * an instance of another. + * + * @name compatibleConstructor + * @param {Error} thrown error + * @param {Error|ErrorConstructor} errorLike object to compare against + * @namespace Utils + * @api public */ -module.exports = deepEqual; +function compatibleConstructor(thrown, errorLike) { + if (errorLike instanceof Error) { + // If `errorLike` is an instance of any error we compare their constructors + return thrown.constructor === errorLike.constructor || thrown instanceof errorLike.constructor; + } else if (errorLike.prototype instanceof Error || errorLike === Error) { + // If `errorLike` is a constructor that inherits from Error, we compare `thrown` to `errorLike` directly + return thrown.constructor === errorLike || thrown instanceof errorLike; + } + + return false; +} /** - * Assert super-strict (egal) equality between - * two objects of any type. + * ### .compatibleMessage(thrown, errMatcher) * - * @param {Mixed} a - * @param {Mixed} b - * @param {Array} memoised (optional) - * @return {Boolean} equal match + * Checks if an error's message is compatible with a matcher (String or RegExp). + * If the message contains the String or passes the RegExp test, + * it is considered compatible. + * + * @name compatibleMessage + * @param {Error} thrown error + * @param {String|RegExp} errMatcher to look for into the message + * @namespace Utils + * @api public */ -function deepEqual(a, b, m) { - if (sameValue(a, b)) { - return true; - } else if ('date' === type(a)) { - return dateEqual(a, b); - } else if ('regexp' === type(a)) { - return regexpEqual(a, b); - } else if (Buffer.isBuffer(a)) { - return bufferEqual(a, b); - } else if ('arguments' === type(a)) { - return argumentsEqual(a, b, m); - } else if (!typeEqual(a, b)) { - return false; - } else if (('object' !== type(a) && 'object' !== type(b)) - && ('array' !== type(a) && 'array' !== type(b))) { - return sameValue(a, b); - } else { - return objectEqual(a, b, m); +function compatibleMessage(thrown, errMatcher) { + var comparisonString = typeof thrown === 'string' ? thrown : thrown.message; + if (errMatcher instanceof RegExp) { + return errMatcher.test(comparisonString); + } else if (typeof errMatcher === 'string') { + return comparisonString.indexOf(errMatcher) !== -1; // eslint-disable-line no-magic-numbers } + + return false; } -/*! - * Strict (egal) equality test. Ensures that NaN always - * equals NaN and `-0` does not equal `+0`. +/** + * ### .getFunctionName(constructorFn) * - * @param {Mixed} a - * @param {Mixed} b - * @return {Boolean} equal match + * Returns the name of a function. + * This also includes a polyfill function if `constructorFn.name` is not defined. + * + * @name getFunctionName + * @param {Function} constructorFn + * @namespace Utils + * @api private */ -function sameValue(a, b) { - if (a === b) return a !== 0 || 1 / a === 1 / b; - return a !== a && b !== b; +var functionNameMatch = /\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\(\/]+)/; +function getFunctionName(constructorFn) { + var name = ''; + if (typeof constructorFn.name === 'undefined') { + // Here we run a polyfill if constructorFn.name is not defined + var match = String(constructorFn).match(functionNameMatch); + if (match) { + name = match[1]; + } + } else { + name = constructorFn.name; + } + + return name; } -/*! - * Compare the types of two given objects and - * return if they are equal. Note that an Array - * has a type of `array` (not `object`) and arguments - * have a type of `arguments` (not `array`/`object`). +/** + * ### .getConstructorName(errorLike) * - * @param {Mixed} a - * @param {Mixed} b - * @return {Boolean} result + * Gets the constructor name for an Error instance or constructor itself. + * + * @name getConstructorName + * @param {Error|ErrorConstructor} errorLike + * @namespace Utils + * @api public */ -function typeEqual(a, b) { - return type(a) === type(b); +function getConstructorName(errorLike) { + var constructorName = errorLike; + if (errorLike instanceof Error) { + constructorName = getFunctionName(errorLike.constructor); + } else if (typeof errorLike === 'function') { + // If `err` is not an instance of Error it is an error constructor itself or another function. + // If we've got a common function we get its name, otherwise we may need to create a new instance + // of the error just in case it's a poorly-constructed error. Please see chaijs/chai/issues/45 to know more. + constructorName = getFunctionName(errorLike).trim() || + getFunctionName(new errorLike()); // eslint-disable-line new-cap + } + + return constructorName; } -/*! - * Compare two Date objects by asserting that - * the time values are equal using `saveValue`. +/** + * ### .getMessage(errorLike) * - * @param {Date} a - * @param {Date} b - * @return {Boolean} result + * Gets the error message from an error. + * If `err` is a String itself, we return it. + * If the error has no message, we return an empty string. + * + * @name getMessage + * @param {Error|String} errorLike + * @namespace Utils + * @api public */ -function dateEqual(a, b) { - if ('date' !== type(b)) return false; - return sameValue(a.getTime(), b.getTime()); +function getMessage(errorLike) { + var msg = ''; + if (errorLike && errorLike.message) { + msg = errorLike.message; + } else if (typeof errorLike === 'string') { + msg = errorLike; + } + + return msg; } +module.exports = { + compatibleInstance: compatibleInstance, + compatibleConstructor: compatibleConstructor, + compatibleMessage: compatibleMessage, + getMessage: getMessage, + getConstructorName: getConstructorName, +}; + +},{}],35:[function(require,module,exports){ +'use strict'; +/* globals Symbol: false, Uint8Array: false, WeakMap: false */ /*! - * Compare two regular expressions by converting them - * to string and checking for `sameValue`. - * - * @param {RegExp} a - * @param {RegExp} b - * @return {Boolean} result + * deep-eql + * Copyright(c) 2013 Jake Luer + * MIT Licensed */ -function regexpEqual(a, b) { - if ('regexp' !== type(b)) return false; - return sameValue(a.toString(), b.toString()); +var type = require('type-detect'); +function FakeMap() { + this._key = 'chai/deep-eql__' + Math.random() + Date.now(); } +FakeMap.prototype = { + get: function getMap(key) { + return key[this._key]; + }, + set: function setMap(key, value) { + if (Object.isExtensible(key)) { + Object.defineProperty(key, this._key, { + value: value, + configurable: true, + }); + } + }, +}; + +var MemoizeMap = typeof WeakMap === 'function' ? WeakMap : FakeMap; /*! - * Assert deep equality of two `arguments` objects. - * Unfortunately, these must be sliced to arrays - * prior to test to ensure no bad behavior. - * - * @param {Arguments} a - * @param {Arguments} b - * @param {Array} memoize (optional) - * @return {Boolean} result - */ + * Check to see if the MemoizeMap has recorded a result of the two operands + * + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @param {MemoizeMap} memoizeMap + * @returns {Boolean|null} result +*/ +function memoizeCompare(leftHandOperand, rightHandOperand, memoizeMap) { + // Technically, WeakMap keys can *only* be objects, not primitives. + if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { + return null; + } + var leftHandMap = memoizeMap.get(leftHandOperand); + if (leftHandMap) { + var result = leftHandMap.get(rightHandOperand); + if (typeof result === 'boolean') { + return result; + } + } + return null; +} -function argumentsEqual(a, b, m) { - if ('arguments' !== type(b)) return false; - a = [].slice.call(a); - b = [].slice.call(b); - return deepEqual(a, b, m); +/*! + * Set the result of the equality into the MemoizeMap + * + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @param {MemoizeMap} memoizeMap + * @param {Boolean} result +*/ +function memoizeSet(leftHandOperand, rightHandOperand, memoizeMap, result) { + // Technically, WeakMap keys can *only* be objects, not primitives. + if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { + return; + } + var leftHandMap = memoizeMap.get(leftHandOperand); + if (leftHandMap) { + leftHandMap.set(rightHandOperand, result); + } else { + leftHandMap = new MemoizeMap(); + leftHandMap.set(rightHandOperand, result); + memoizeMap.set(leftHandOperand, leftHandMap); + } } /*! - * Get enumerable properties of a given object. - * - * @param {Object} a - * @return {Array} property names + * Primary Export */ -function enumerable(a) { - var res = []; - for (var key in a) res.push(key); - return res; +module.exports = deepEqual; +module.exports.MemoizeMap = MemoizeMap; + +/** + * Assert deeply nested sameValue equality between two objects of any type. + * + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @param {Object} [options] (optional) Additional options + * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality. + * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of + complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular + references to blow the stack. + * @return {Boolean} equal match + */ +function deepEqual(leftHandOperand, rightHandOperand, options) { + // If we have a comparator, we can't assume anything; so bail to its check first. + if (options && options.comparator) { + return extensiveDeepEqual(leftHandOperand, rightHandOperand, options); + } + + var simpleResult = simpleEqual(leftHandOperand, rightHandOperand); + if (simpleResult !== null) { + return simpleResult; + } + + // Deeper comparisons are pushed through to a larger function + return extensiveDeepEqual(leftHandOperand, rightHandOperand, options); } -/*! - * Simple equality for flat iterable objects - * such as Arrays or Node.js buffers. - * - * @param {Iterable} a - * @param {Iterable} b - * @return {Boolean} result +/** + * Many comparisons can be canceled out early via simple equality or primitive checks. + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @return {Boolean|null} equal match */ +function simpleEqual(leftHandOperand, rightHandOperand) { + // Equal references (except for Numbers) can be returned early + if (leftHandOperand === rightHandOperand) { + // Handle +-0 cases + return leftHandOperand !== 0 || 1 / leftHandOperand === 1 / rightHandOperand; + } -function iterableEqual(a, b) { - if (a.length !== b.length) return false; + // handle NaN cases + if ( + leftHandOperand !== leftHandOperand && // eslint-disable-line no-self-compare + rightHandOperand !== rightHandOperand // eslint-disable-line no-self-compare + ) { + return true; + } - var i = 0; - var match = true; + // Anything that is not an 'object', i.e. symbols, functions, booleans, numbers, + // strings, and undefined, can be compared by reference. + if (isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { + // Easy out b/c it would have passed the first equality check + return false; + } + return null; +} - for (; i < a.length; i++) { - if (a[i] !== b[i]) { - match = false; - break; +/*! + * The main logic of the `deepEqual` function. + * + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @param {Object} [options] (optional) Additional options + * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality. + * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of + complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular + references to blow the stack. + * @return {Boolean} equal match +*/ +function extensiveDeepEqual(leftHandOperand, rightHandOperand, options) { + options = options || {}; + options.memoize = options.memoize === false ? false : options.memoize || new MemoizeMap(); + var comparator = options && options.comparator; + + // Check if a memoized result exists. + var memoizeResultLeft = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize); + if (memoizeResultLeft !== null) { + return memoizeResultLeft; + } + var memoizeResultRight = memoizeCompare(rightHandOperand, leftHandOperand, options.memoize); + if (memoizeResultRight !== null) { + return memoizeResultRight; + } + + // If a comparator is present, use it. + if (comparator) { + var comparatorResult = comparator(leftHandOperand, rightHandOperand); + // Comparators may return null, in which case we want to go back to default behavior. + if (comparatorResult === false || comparatorResult === true) { + memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult); + return comparatorResult; + } + // To allow comparators to override *any* behavior, we ran them first. Since it didn't decide + // what to do, we need to make sure to return the basic tests first before we move on. + var simpleResult = simpleEqual(leftHandOperand, rightHandOperand); + if (simpleResult !== null) { + // Don't memoize this, it takes longer to set/retrieve than to just compare. + return simpleResult; } } - return match; + var leftHandType = type(leftHandOperand); + if (leftHandType !== type(rightHandOperand)) { + memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false); + return false; + } + + // Temporarily set the operands in the memoize object to prevent blowing the stack + memoizeSet(leftHandOperand, rightHandOperand, options.memoize, true); + + var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options); + memoizeSet(leftHandOperand, rightHandOperand, options.memoize, result); + return result; +} + +function extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options) { + switch (leftHandType) { + case 'String': + case 'Number': + case 'Boolean': + case 'Date': + // If these types are their instance types (e.g. `new Number`) then re-deepEqual against their values + return deepEqual(leftHandOperand.valueOf(), rightHandOperand.valueOf()); + case 'Promise': + case 'Symbol': + case 'function': + case 'WeakMap': + case 'WeakSet': + case 'Error': + return leftHandOperand === rightHandOperand; + case 'Arguments': + case 'Int8Array': + case 'Uint8Array': + case 'Uint8ClampedArray': + case 'Int16Array': + case 'Uint16Array': + case 'Int32Array': + case 'Uint32Array': + case 'Float32Array': + case 'Float64Array': + case 'Array': + return iterableEqual(leftHandOperand, rightHandOperand, options); + case 'RegExp': + return regexpEqual(leftHandOperand, rightHandOperand); + case 'Generator': + return generatorEqual(leftHandOperand, rightHandOperand, options); + case 'DataView': + return iterableEqual(new Uint8Array(leftHandOperand.buffer), new Uint8Array(rightHandOperand.buffer), options); + case 'ArrayBuffer': + return iterableEqual(new Uint8Array(leftHandOperand), new Uint8Array(rightHandOperand), options); + case 'Set': + return entriesEqual(leftHandOperand, rightHandOperand, options); + case 'Map': + return entriesEqual(leftHandOperand, rightHandOperand, options); + default: + return objectEqual(leftHandOperand, rightHandOperand, options); + } } /*! - * Extension to `iterableEqual` specifically - * for Node.js Buffers. + * Compare two Regular Expressions for equality. * - * @param {Buffer} a - * @param {Mixed} b + * @param {RegExp} leftHandOperand + * @param {RegExp} rightHandOperand * @return {Boolean} result */ -function bufferEqual(a, b) { - if (!Buffer.isBuffer(b)) return false; - return iterableEqual(a, b); +function regexpEqual(leftHandOperand, rightHandOperand) { + return leftHandOperand.toString() === rightHandOperand.toString(); } /*! - * Block for `objectEqual` ensuring non-existing - * values don't get in. + * Compare two Sets/Maps for equality. Faster than other equality functions. * - * @param {Mixed} object + * @param {Set} leftHandOperand + * @param {Set} rightHandOperand + * @param {Object} [options] (Optional) * @return {Boolean} result */ -function isValue(a) { - return a !== null && a !== undefined; +function entriesEqual(leftHandOperand, rightHandOperand, options) { + // IE11 doesn't support Set#entries or Set#@@iterator, so we need manually populate using Set#forEach + if (leftHandOperand.size !== rightHandOperand.size) { + return false; + } + if (leftHandOperand.size === 0) { + return true; + } + var leftHandItems = []; + var rightHandItems = []; + leftHandOperand.forEach(function gatherEntries(key, value) { + leftHandItems.push([ key, value ]); + }); + rightHandOperand.forEach(function gatherEntries(key, value) { + rightHandItems.push([ key, value ]); + }); + return iterableEqual(leftHandItems.sort(), rightHandItems.sort(), options); } /*! - * Recursively check the equality of two objects. - * Once basic sameness has been established it will - * defer to `deepEqual` for each enumerable key - * in the object. + * Simple equality for flat iterable objects such as Arrays, TypedArrays or Node.js buffers. * - * @param {Mixed} a - * @param {Mixed} b + * @param {Iterable} leftHandOperand + * @param {Iterable} rightHandOperand + * @param {Object} [options] (Optional) * @return {Boolean} result */ -function objectEqual(a, b, m) { - if (!isValue(a) || !isValue(b)) { +function iterableEqual(leftHandOperand, rightHandOperand, options) { + var length = leftHandOperand.length; + if (length !== rightHandOperand.length) { return false; } - - if (a.prototype !== b.prototype) { - return false; + if (length === 0) { + return true; } - - var i; - if (m) { - for (i = 0; i < m.length; i++) { - if ((m[i][0] === a && m[i][1] === b) - || (m[i][0] === b && m[i][1] === a)) { - return true; - } + var index = -1; + while (++index < length) { + if (deepEqual(leftHandOperand[index], rightHandOperand[index], options) === false) { + return false; } - } else { - m = []; } + return true; +} - try { - var ka = enumerable(a); - var kb = enumerable(b); - } catch (ex) { - return false; - } +/*! + * Simple equality for generator objects such as those returned by generator functions. + * + * @param {Iterable} leftHandOperand + * @param {Iterable} rightHandOperand + * @param {Object} [options] (Optional) + * @return {Boolean} result + */ - ka.sort(); - kb.sort(); +function generatorEqual(leftHandOperand, rightHandOperand, options) { + return iterableEqual(getGeneratorEntries(leftHandOperand), getGeneratorEntries(rightHandOperand), options); +} - if (!iterableEqual(ka, kb)) { - return false; +/*! + * Determine if the given object has an @@iterator function. + * + * @param {Object} target + * @return {Boolean} `true` if the object has an @@iterator function. + */ +function hasIteratorFunction(target) { + return typeof Symbol !== 'undefined' && + typeof target === 'object' && + typeof Symbol.iterator !== 'undefined' && + typeof target[Symbol.iterator] === 'function'; +} + +/*! + * Gets all iterator entries from the given Object. If the Object has no @@iterator function, returns an empty array. + * This will consume the iterator - which could have side effects depending on the @@iterator implementation. + * + * @param {Object} target + * @returns {Array} an array of entries from the @@iterator function + */ +function getIteratorEntries(target) { + if (hasIteratorFunction(target)) { + try { + return getGeneratorEntries(target[Symbol.iterator]()); + } catch (iteratorError) { + return []; + } + } + return []; +} + +/*! + * Gets all entries from a Generator. This will consume the generator - which could have side effects. + * + * @param {Generator} target + * @returns {Array} an array of entries from the Generator. + */ +function getGeneratorEntries(generator) { + var generatorResult = generator.next(); + var accumulator = [ generatorResult.value ]; + while (generatorResult.done === false) { + generatorResult = generator.next(); + accumulator.push(generatorResult.value); } + return accumulator; +} - m.push([ a, b ]); +/*! + * Gets all own and inherited enumerable keys from a target. + * + * @param {Object} target + * @returns {Array} an array of own and inherited enumerable keys from the target. + */ +function getEnumerableKeys(target) { + var keys = []; + for (var key in target) { + keys.push(key); + } + return keys; +} - var key; - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!deepEqual(a[key], b[key], m)) { +/*! + * Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of + * each key. If any value of the given key is not equal, the function will return false (early). + * + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @param {Array} keys An array of keys to compare the values of leftHandOperand and rightHandOperand against + * @param {Object} [options] (Optional) + * @return {Boolean} result + */ +function keysEqual(leftHandOperand, rightHandOperand, keys, options) { + var length = keys.length; + if (length === 0) { + return true; + } + for (var i = 0; i < length; i += 1) { + if (deepEqual(leftHandOperand[keys[i]], rightHandOperand[keys[i]], options) === false) { return false; } } - return true; } -},{"buffer":undefined,"type-detect":33}],33:[function(require,module,exports){ -module.exports = require('./lib/type'); - -},{"./lib/type":34}],34:[function(require,module,exports){ /*! - * type-detect - * Copyright(c) 2013 jake luer - * MIT Licensed + * Recursively check the equality of two Objects. Once basic sameness has been established it will defer to `deepEqual` + * for each enumerable key in the object. + * + * @param {Mixed} leftHandOperand + * @param {Mixed} rightHandOperand + * @param {Object} [options] (Optional) + * @return {Boolean} result */ -/*! - * Primary Exports - */ +function objectEqual(leftHandOperand, rightHandOperand, options) { + var leftHandKeys = getEnumerableKeys(leftHandOperand); + var rightHandKeys = getEnumerableKeys(rightHandOperand); + if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) { + leftHandKeys.sort(); + rightHandKeys.sort(); + if (iterableEqual(leftHandKeys, rightHandKeys) === false) { + return false; + } + return keysEqual(leftHandOperand, rightHandOperand, leftHandKeys, options); + } + + var leftHandEntries = getIteratorEntries(leftHandOperand); + var rightHandEntries = getIteratorEntries(rightHandOperand); + if (leftHandEntries.length && leftHandEntries.length === rightHandEntries.length) { + leftHandEntries.sort(); + rightHandEntries.sort(); + return iterableEqual(leftHandEntries, rightHandEntries, options); + } + + if (leftHandKeys.length === 0 && + leftHandEntries.length === 0 && + rightHandKeys.length === 0 && + rightHandEntries.length === 0) { + return true; + } -var exports = module.exports = getType; + return false; +} /*! - * Detectable javascript natives + * Returns true if the argument is a primitive. + * + * This intentionally returns true for all objects that can be compared by reference, + * including functions and symbols. + * + * @param {Mixed} value + * @return {Boolean} result */ +function isPrimitive(value) { + return value === null || typeof value !== 'object'; +} -var natives = { - '[object Array]': 'array' - , '[object RegExp]': 'regexp' - , '[object Function]': 'function' - , '[object Arguments]': 'arguments' - , '[object Date]': 'date' -}; +},{"type-detect":38}],36:[function(require,module,exports){ +'use strict'; + +/* ! + * Chai - getFuncName utility + * Copyright(c) 2012-2016 Jake Luer + * MIT Licensed + */ /** - * ### typeOf (obj) - * - * Use several different techniques to determine - * the type of object being tested. + * ### .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. * - * @param {Mixed} object - * @return {String} object type + * @name getFuncName + * @param {Function} funct + * @namespace Utils * @api public */ -function getType (obj) { - var str = Object.prototype.toString.call(obj); - if (natives[str]) return natives[str]; - if (obj === null) return 'null'; - if (obj === undefined) return 'undefined'; - if (obj === Object(obj)) return 'object'; - return typeof obj; +var toString = Function.prototype.toString; +var functionNameMatch = /\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.call(aFunc).match(functionNameMatch); + if (match) { + name = match[1]; + } + } else { + // If we've got a `name` property we just use it + name = aFunc.name; + } + + return name; } -exports.Library = Library; +module.exports = getFuncName; + +},{}],37:[function(require,module,exports){ +'use strict'; + +/* ! + * Chai - pathval utility + * Copyright(c) 2012-2014 Jake Luer + * @see https://github.com/logicalparadox/filtr + * MIT Licensed + */ /** - * ### Library + * ### .hasProperty(object, name) * - * Create a repository for custom type detection. + * This allows checking whether an object has own + * or inherited from prototype chain named property. * - * ```js - * var lib = new type.Library; - * ``` + * Basically does the same thing as the `in` + * operator but works properly with null/undefined values + * and other primitives. * - */ - -function Library () { - this.tests = {}; -} - -/** - * #### .of (obj) + * var obj = { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } * - * Expose replacement `typeof` detection to the library. + * The following would be the results. * - * ```js - * if ('string' === lib.of('hello world')) { - * // ... - * } - * ``` + * 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 * - * @param {Mixed} object to test - * @return {String} type + * 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 */ -Library.prototype.of = getType; +function hasProperty(obj, name) { + if (typeof obj === 'undefined' || obj === null) { + return false; + } -/** - * #### .define (type, test) - * - * Add a test to for the `.test()` assertion. + // The `in` operator does not work with primitives. + return name in Object(obj); +} + +/* ! + * ## parsePath(path) * - * Can be defined as a regular expression: + * Helper function used to parse string object + * paths. Use in conjunction with `internalGetPathValue`. * - * ```js - * lib.define('int', /^[0-9]+$/); - * ``` + * var parsed = parsePath('myobject.property.subprop'); * - * ... or as a function: + * ### Paths: * - * ```js - * lib.define('bln', function (obj) { - * if ('boolean' === lib.of(obj)) return true; - * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; - * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); - * return !! ~blns.indexOf(obj); - * }); - * ``` + * * 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} type - * @param {RegExp|Function} test - * @api public + * @param {String} path + * @returns {Object} parsed + * @api private */ -Library.prototype.define = function (type, test) { - if (arguments.length === 1) return this.tests[type]; - this.tests[type] = test; - return this; -}; +function parsePath(path) { + var str = path.replace(/([^\\])\[/g, '$1.['); + var parts = str.match(/(\\\.|[^.]+?)+/g); + return parts.map(function mapMatches(value) { + 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') }; + } -/** - * #### .test (obj, test) + return parsed; + }); +} + +/* ! + * ## internalGetPathValue(obj, parsed[, pathDepth]) * - * Assert that an object is of type. Will first - * check natives, and if that does not pass it will - * use the user defined custom tests. + * Helper companion function for `.parsePath` that returns + * the value located at the parsed address. * - * ```js - * assert(lib.test('1', 'int')); - * assert(lib.test('yes', 'bln')); - * ``` + * var value = getPathValue(obj, parsed); * - * @param {Mixed} object - * @param {String} type - * @return {Boolean} result - * @api public + * @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 */ -Library.prototype.test = function (obj, type) { - if (type === getType(obj)) return true; - var test = this.tests[type]; - - if (test && 'regexp' === getType(test)) { - return test.test(obj); - } else if (test && 'function' === getType(test)) { - return test(obj); - } else { - throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); - } -}; +function internalGetPathValue(obj, parsed, pathDepth) { + var temporaryValue = obj; + var res = null; + pathDepth = (typeof pathDepth === 'undefined' ? parsed.length : pathDepth); -},{}],35:[function(require,module,exports){ -arguments[4][33][0].apply(exports,arguments) -},{"./lib/type":36,"dup":33}],36:[function(require,module,exports){ -/*! - * type-detect - * Copyright(c) 2013 jake luer - * MIT Licensed - */ + 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]; + } -/*! - * Primary Exports - */ + if (i === (pathDepth - 1)) { + res = temporaryValue; + } + } + } -var exports = module.exports = getType; + return res; +} -/** - * ### typeOf (obj) +/* ! + * ## internalSetPathValue(obj, value, parsed) * - * Use several different techniques to determine - * the type of object being tested. + * Companion function for `parsePath` that sets + * the value located at a parsed address. * + * internalSetPathValue(obj, 'value', parsed); * - * @param {Mixed} object - * @return {String} object type - * @api public + * @param {Object} object to search and define on + * @param {*} value to use upon set + * @param {Object} parsed definition from `parsePath` + * @api private */ -var objectTypeRegexp = /^\[object (.*)\]$/; - -function getType(obj) { - var type = Object.prototype.toString.call(obj).match(objectTypeRegexp)[1].toLowerCase(); - // Let "new String('')" return 'object' - if (typeof Promise === 'function' && obj instanceof Promise) return 'promise'; - // PhantomJS has type "DOMWindow" for null - if (obj === null) return 'null'; - // PhantomJS has type "DOMWindow" for undefined - if (obj === undefined) return 'undefined'; - return type; -} -exports.Library = Library; +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]; + } + } +} /** - * ### Library + * ### .getPathInfo(object, path) * - * Create a repository for custom type detection. + * This allows the retrieval of property info in an + * object given a string path. * - * ```js - * var lib = new type.Library; - * ``` + * 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 Library() { - if (!(this instanceof Library)) return new Library(); - this.tests = {}; +function getPathInfo(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(info.parent, info.name); + + return info; } /** - * #### .of (obj) + * ### .getPathValue(object, path) * - * Expose replacement `typeof` detection to the library. + * This allows the retrieval of values in an + * object given a string path. * - * ```js - * if ('string' === lib.of('hello world')) { - * // ... - * } - * ``` + * 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 {Mixed} object to test - * @return {String} type + * @param {Object} object + * @param {String} path + * @returns {Object} value or `undefined` + * @namespace Utils + * @name getPathValue + * @api public */ -Library.prototype.of = getType; +function getPathValue(obj, path) { + var info = getPathInfo(obj, path); + return info.value; +} /** - * #### .define (type, test) + * ### .setPathValue(object, path, value) * - * Add a test to for the `.test()` assertion. - * - * Can be defined as a regular expression: + * Define the value in an object at a given string path. * * ```js - * lib.define('int', /^[0-9]+$/); + * var obj = { + * prop1: { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * , prop2: { + * arr: [ { nested: 'Universe' } ] + * , str: 'Hello again!' + * } + * }; * ``` * - * ... or as a function: + * The following would be acceptable. * * ```js - * lib.define('bln', function (obj) { - * if ('boolean' === lib.of(obj)) return true; - * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; - * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); - * return !! ~blns.indexOf(obj); - * }); + * 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 {String} type - * @param {RegExp|Function} test - * @api public + * @param {Object} object + * @param {String} path + * @param {Mixed} value + * @api private */ -Library.prototype.define = function(type, test) { - if (arguments.length === 1) return this.tests[type]; - this.tests[type] = test; - return this; +function setPathValue(obj, path, val) { + var parsed = parsePath(path); + internalSetPathValue(obj, val, parsed); + return obj; +} + +module.exports = { + hasProperty: hasProperty, + getPathInfo: getPathInfo, + getPathValue: getPathValue, + setPathValue: setPathValue, }; +},{}],38:[function(require,module,exports){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.typeDetect = factory()); +}(this, (function () { 'use strict'; + +/* ! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ +var promiseExists = typeof Promise === 'function'; + +/* eslint-disable no-undef */ +var globalObject = typeof self === 'object' ? self : global; // 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; /** - * #### .test (obj, test) - * - * Assert that an object is of type. Will first - * check natives, and if that does not pass it will - * use the user defined custom tests. + * ### typeOf (obj) * - * ```js - * assert(lib.test('1', 'int')); - * assert(lib.test('yes', 'bln')); - * ``` + * Uses `Object.prototype.toString` to determine the type of an object, + * normalising behaviour across engine versions & well optimised. * * @param {Mixed} object - * @param {String} type - * @return {Boolean} result + * @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'; + } -Library.prototype.test = function(obj, type) { - if (type === getType(obj)) return true; - var test = this.tests[type]; + /* ! 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'; + } - if (test && 'regexp' === getType(test)) { - return test.test(obj); - } else if (test && 'function' === getType(test)) { - return test(obj); - } else { - throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + /* ! 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; + +}))); },{}]},{},[1])(1) }); diff --git a/test/vendor/mocha.js b/test/vendor/mocha.js index a1ec48f..508a306 100644 --- a/test/vendor/mocha.js +++ b/test/vendor/mocha.js @@ -1,12 +1,15 @@ -(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} promise determining if browser notification + * permissible when fulfilled. + */ +function isPermitted() { + var permitted = { + granted: function allow() { + return Promise.resolve(true); + }, + denied: function deny() { + return Promise.resolve(false); + }, + default: function ask() { + return Notification.requestPermission().then(function(permission) { + return permission === 'granted'; + }); } - } + }; - return this; -}; + return permitted[Notification.permission](); +} /** - * Remove all listeners for an event. + * @summary + * Determines if notification should proceed. * - * @api public - * @param {string} name Event name. - * @return {EventEmitter} Emitter instance. + * @description + * Notification shall not proceed unless `value` is true. + * + * `value` will equal one of: + *
    + *
  • true (from `isPermitted`)
  • + *
  • false (from `isPermitted`)
  • + *
  • undefined (from `Promise.race`)
  • + *
+ * + * @private + * @param {boolean|undefined} value - Determines if notification permissible. + * @returns {Promise} Notification can proceed */ -EventEmitter.prototype.removeAllListeners = function(name) { - if (name === undefined) { - this.$events = {}; - return this; +function canNotify(value) { + if (!value) { + var why = value === false ? 'blocked' : 'unacknowledged'; + var reason = 'not permitted by user (' + why + ')'; + return Promise.reject(new Error(reason)); } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; -}; + return Promise.resolve(); +} /** - * Get all listeners for a given event. + * Displays the notification. * - * @api public - * @param {string} name Event name. - * @return {EventEmitter} Emitter instance. + * @private + * @param {Runner} runner - Runner instance. */ -EventEmitter.prototype.listeners = function(name) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = []; - } +function display(runner) { + var stats = runner.stats; + var symbol = { + cross: '\u274C', + tick: '\u2705' + }; + var logo = require('../../package').notifyLogo; + var _message; + var message; + var title; - if (!isArray(this.$events[name])) { - this.$events[name] = [this.$events[name]]; - } + if (stats.failures) { + _message = stats.failures + ' of ' + stats.tests + ' tests failed'; + message = symbol.cross + ' ' + _message; + title = 'Failed'; + } else { + _message = stats.passes + ' tests passed in ' + stats.duration + 'ms'; + message = symbol.tick + ' ' + _message; + title = 'Passed'; + } + + // Send notification + var options = { + badge: logo, + body: message, + dir: 'ltr', + icon: logo, + lang: 'en-US', + name: 'mocha', + requireInteraction: false, + timestamp: Date.now() + }; + var notification = new Notification(title, options); - return this.$events[name]; -}; + // Autoclose after brief delay (makes various browsers act same) + var FORCE_DURATION = 4000; + setTimeout(notification.close.bind(notification), FORCE_DURATION); +} /** - * Emit an event. + * As notifications are tangential to our purpose, just log the error. * - * @api public - * @param {string} name Event name. - * @return {boolean} true if at least one handler was invoked, else false. + * @private + * @param {Error} err - Why notification didn't happen. */ -EventEmitter.prototype.emit = function(name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = Array.prototype.slice.call(arguments, 1); - - if (typeof handler === 'function') { - handler.apply(this, args); - } else if (isArray(handler)) { - var listeners = handler.slice(); - - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - } else { - return false; - } +function notPermitted(err) { + console.error('notification error:', err.message); +} - return true; -}; +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../../package":90,"../runner":34,"_process":69}],3:[function(require,module,exports){ +'use strict'; -},{}],4:[function(require,module,exports){ /** * Expose `Progress`. */ @@ -407,7 +387,7 @@ function Progress() { /** * Set progress size to `size`. * - * @api public + * @public * @param {number} size * @return {Progress} Progress instance. */ @@ -419,7 +399,7 @@ Progress.prototype.size = function(size) { /** * Set text to `text`. * - * @api public + * @public * @param {string} text * @return {Progress} Progress instance. */ @@ -431,7 +411,7 @@ Progress.prototype.text = function(text) { /** * Set font size to `size`. * - * @api public + * @public * @param {number} size * @return {Progress} Progress instance. */ @@ -500,14 +480,16 @@ Progress.prototype.draw = function(ctx) { var w = ctx.measureText(text).width; ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1); - } catch (err) { + } catch (ignore) { // don't fail if we can't render progress } return this; }; -},{}],5:[function(require,module,exports){ +},{}],4:[function(require,module,exports){ (function (global){ +'use strict'; + exports.isatty = function isatty() { return true; }; @@ -521,13 +503,11 @@ exports.getWindowSize = function getWindowSize() { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],6:[function(require,module,exports){ +},{}],5:[function(require,module,exports){ +'use strict'; /** - * Module dependencies. + * @module Context */ - -var JSON = require('json3'); - /** * Expose `Context`. */ @@ -537,16 +517,16 @@ module.exports = Context; /** * Initialize a new `Context`. * - * @api private + * @private */ function Context() {} /** * Set or get the context `Runnable` to `runnable`. * - * @api private + * @private * @param {Runnable} runnable - * @return {Context} + * @return {Context} context */ Context.prototype.runnable = function(runnable) { if (!arguments.length) { @@ -557,9 +537,9 @@ Context.prototype.runnable = function(runnable) { }; /** - * Set test timeout `ms`. + * Set or get test timeout `ms`. * - * @api private + * @private * @param {number} ms * @return {Context} self */ @@ -574,23 +554,29 @@ Context.prototype.timeout = function(ms) { /** * Set test timeout `enabled`. * - * @api private + * @private * @param {boolean} enabled * @return {Context} self */ Context.prototype.enableTimeouts = function(enabled) { + if (!arguments.length) { + return this.runnable().enableTimeouts(); + } this.runnable().enableTimeouts(enabled); return this; }; /** - * Set test slowness threshold `ms`. + * Set or get test slowness threshold `ms`. * - * @api private + * @private * @param {number} ms * @return {Context} self */ Context.prototype.slow = function(ms) { + if (!arguments.length) { + return this.runnable().slow(); + } this.runnable().slow(ms); return this; }; @@ -598,18 +584,17 @@ Context.prototype.slow = function(ms) { /** * Mark a test as skipped. * - * @api private - * @return {Context} self + * @private + * @throws Pending */ Context.prototype.skip = function() { this.runnable().skip(); - return this; }; /** - * Allow a number of retries on failed tests + * Set or get a number of allowed retries on failed tests * - * @api private + * @private * @param {number} n * @return {Context} self */ @@ -621,22 +606,151 @@ Context.prototype.retries = function(n) { return this; }; +},{}],6:[function(require,module,exports){ +'use strict'; +/** + * @module Errors + */ +/** + * Factory functions to create throwable error objects + */ + /** - * Inspect the context void of `._runnable`. + * Creates an error object to be thrown when no files to be tested could be found using specified pattern. * - * @api private - * @return {string} + * @public + * @param {string} message - Error message to be displayed. + * @param {string} pattern - User-specified argument value. + * @returns {Error} instance detailing the error condition */ -Context.prototype.inspect = function() { - return JSON.stringify(this, function(key, val) { - return key === 'runnable' || key === 'test' ? undefined : val; - }, 2); -}; +function createNoFilesMatchPatternError(message, pattern) { + var err = new Error(message); + err.code = 'ERR_MOCHA_NO_FILES_MATCH_PATTERN'; + err.pattern = pattern; + return err; +} -},{"json3":54}],7:[function(require,module,exports){ /** - * Module dependencies. + * Creates an error object to be thrown when the reporter specified in the options was not found. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} reporter - User-specified reporter value. + * @returns {Error} instance detailing the error condition + */ +function createInvalidReporterError(message, reporter) { + var err = new TypeError(message); + err.code = 'ERR_MOCHA_INVALID_REPORTER'; + err.reporter = reporter; + return err; +} + +/** + * Creates an error object to be thrown when the interface specified in the options was not found. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} ui - User-specified interface value. + * @returns {Error} instance detailing the error condition + */ +function createInvalidInterfaceError(message, ui) { + var err = new Error(message); + err.code = 'ERR_MOCHA_INVALID_INTERFACE'; + err.interface = ui; + return err; +} + +/** + * Creates an error object to be thrown when a behavior, option, or parameter is unsupported. + * + * @public + * @param {string} message - Error message to be displayed. + * @returns {Error} instance detailing the error condition + */ +function createUnsupportedError(message) { + var err = new Error(message); + err.code = 'ERR_MOCHA_UNSUPPORTED'; + return err; +} + +/** + * Creates an error object to be thrown when an argument is missing. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} argument - Argument name. + * @param {string} expected - Expected argument datatype. + * @returns {Error} instance detailing the error condition + */ +function createMissingArgumentError(message, argument, expected) { + return createInvalidArgumentTypeError(message, argument, expected); +} + +/** + * Creates an error object to be thrown when an argument did not use the supported type + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} argument - Argument name. + * @param {string} expected - Expected argument datatype. + * @returns {Error} instance detailing the error condition + */ +function createInvalidArgumentTypeError(message, argument, expected) { + var err = new TypeError(message); + err.code = 'ERR_MOCHA_INVALID_ARG_TYPE'; + err.argument = argument; + err.expected = expected; + err.actual = typeof argument; + return err; +} + +/** + * Creates an error object to be thrown when an argument did not use the supported value + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} argument - Argument name. + * @param {string} value - Argument value. + * @param {string} [reason] - Why value is invalid. + * @returns {Error} instance detailing the error condition + */ +function createInvalidArgumentValueError(message, argument, value, reason) { + var err = new TypeError(message); + err.code = 'ERR_MOCHA_INVALID_ARG_VALUE'; + err.argument = argument; + err.value = value; + err.reason = typeof reason !== 'undefined' ? reason : 'is invalid'; + return err; +} + +/** + * Creates an error object to be thrown when an exception was caught, but the `Error` is falsy or undefined. + * + * @public + * @param {string} message - Error message to be displayed. + * @returns {Error} instance detailing the error condition */ +function createInvalidExceptionError(message, value) { + var err = new Error(message); + err.code = 'ERR_MOCHA_INVALID_EXCEPTION'; + err.valueType = typeof value; + err.value = value; + return err; +} + +module.exports = { + createInvalidArgumentTypeError: createInvalidArgumentTypeError, + createInvalidArgumentValueError: createInvalidArgumentValueError, + createInvalidExceptionError: createInvalidExceptionError, + createInvalidInterfaceError: createInvalidInterfaceError, + createInvalidReporterError: createInvalidReporterError, + createMissingArgumentError: createMissingArgumentError, + createNoFilesMatchPatternError: createNoFilesMatchPatternError, + createUnsupportedError: createUnsupportedError +}; + +},{}],7:[function(require,module,exports){ +'use strict'; var Runnable = require('./runnable'); var inherits = require('./utils').inherits; @@ -648,11 +762,12 @@ var inherits = require('./utils').inherits; module.exports = Hook; /** - * Initialize a new `Hook` with the given `title` and callback `fn`. + * Initialize a new `Hook` with the given `title` and callback `fn` * + * @class + * @extends Runnable * @param {String} title * @param {Function} fn - * @api private */ function Hook(title, fn) { Runnable.call(this, title, fn); @@ -667,9 +782,10 @@ inherits(Hook, Runnable); /** * Get or set the test `err`. * + * @memberof Hook + * @public * @param {Error} err * @return {Error} - * @api public */ Hook.prototype.error = function(err) { if (!arguments.length) { @@ -682,11 +798,11 @@ Hook.prototype.error = function(err) { }; },{"./runnable":33,"./utils":38}],8:[function(require,module,exports){ -/** - * Module dependencies. - */ +'use strict'; var Test = require('../test'); +var EVENT_FILE_PRE_REQUIRE = require('../suite').constants + .EVENT_FILE_PRE_REQUIRE; /** * BDD-style interface: @@ -705,10 +821,10 @@ var Test = require('../test'); * * @param {Suite} suite Root suite. */ -module.exports = function(suite) { +module.exports = function bddInterface(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha) { + suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) { var common = require('./common')(suites, context, mocha); context.before = common.before; @@ -734,7 +850,10 @@ module.exports = function(suite) { * Pending describe. */ - context.xdescribe = context.xcontext = context.describe.skip = function(title, fn) { + context.xdescribe = context.xcontext = context.describe.skip = function( + title, + fn + ) { return common.suite.skip({ title: title, file: file, @@ -784,7 +903,7 @@ module.exports = function(suite) { */ context.xit = context.xspecify = context.it.skip = function(title) { - context.it(title); + return context.it(title); }; /** @@ -796,10 +915,14 @@ module.exports = function(suite) { }); }; -},{"../test":36,"./common":9}],9:[function(require,module,exports){ +module.exports.description = 'BDD or RSpec style [default]'; + +},{"../suite":36,"../test":37,"./common":9}],9:[function(require,module,exports){ 'use strict'; var Suite = require('../suite'); +var errors = require('../errors'); +var createMissingArgumentError = errors.createMissingArgumentError; /** * Functions common to more than one interface. @@ -810,12 +933,28 @@ var Suite = require('../suite'); * @return {Object} An object containing common functions. */ module.exports = function(suites, context, mocha) { + /** + * Check if the suite should be tested. + * + * @private + * @param {Suite} suite - suite to check + * @returns {boolean} + */ + function shouldBeTested(suite) { + return ( + !mocha.options.grep || + (mocha.options.grep && + mocha.options.grep.test(suite.fullTitle()) && + !mocha.options.invert) + ); + } + return { /** * This is only present if flag --delay is passed into Mocha. It triggers * root suite execution. * - * @param {Suite} suite The root wuite. + * @param {Suite} suite The root suite. * @return {Function} A function which runs the root suite */ runWithSuite: function runWithSuite(suite) { @@ -873,7 +1012,6 @@ module.exports = function(suites, context, mocha) { * @returns {Suite} */ only: function only(opts) { - mocha.options.hasOnly = true; opts.isOnly = true; return this.create(opts); }, @@ -892,6 +1030,7 @@ module.exports = function(suites, context, mocha) { /** * Creates a suite. + * * @param {Object} opts Options * @param {string} opts.title Title of Suite * @param {Function} [opts.fn] Suite Function (not always applicable) @@ -906,14 +1045,31 @@ module.exports = function(suites, context, mocha) { suite.file = opts.file; suites.unshift(suite); if (opts.isOnly) { - suite.parent._onlySuites = suite.parent._onlySuites.concat(suite); - mocha.options.hasOnly = true; + if (mocha.options.forbidOnly && shouldBeTested(suite)) { + throw new Error('`.only` forbidden'); + } + + suite.parent.appendOnlySuite(suite); + } + if (suite.pending) { + if (mocha.options.forbidPending && shouldBeTested(suite)) { + throw new Error('Pending test forbidden'); + } } if (typeof opts.fn === 'function') { opts.fn.call(suite); suites.shift(); } else if (typeof opts.fn === 'undefined' && !suite.pending) { - throw new Error('Suite "' + suite.fullTitle() + '" was defined but no callback was supplied. Supply a callback or explicitly skip the suite.'); + throw createMissingArgumentError( + 'Suite "' + + suite.fullTitle() + + '" was defined but no callback was supplied. ' + + 'Supply a callback or explicitly skip the suite.', + 'callback', + 'function' + ); + } else if (!opts.fn && suite.pending) { + suites.shift(); } return suite; @@ -921,7 +1077,6 @@ module.exports = function(suites, context, mocha) { }, test: { - /** * Exclusive test-case. * @@ -930,8 +1085,7 @@ module.exports = function(suites, context, mocha) { * @returns {*} */ only: function(mocha, test) { - test.parent._onlyTests = test.parent._onlyTests.concat(test); - mocha.options.hasOnly = true; + test.parent.appendOnlyTest(test); return test; }, @@ -956,11 +1110,8 @@ module.exports = function(suites, context, mocha) { }; }; -},{"../suite":35}],10:[function(require,module,exports){ -/** - * Module dependencies. - */ - +},{"../errors":6,"../suite":36}],10:[function(require,module,exports){ +'use strict'; var Suite = require('../suite'); var Test = require('../test'); @@ -984,7 +1135,7 @@ var Test = require('../test'); module.exports = function(suite) { var suites = [suite]; - suite.on('require', visit); + suite.on(Suite.constants.EVENT_FILE_REQUIRE, visit); function visit(obj, file) { var suite; @@ -1019,18 +1170,22 @@ module.exports = function(suite) { } }; -},{"../suite":35,"../test":36}],11:[function(require,module,exports){ +module.exports.description = 'Node.js module ("exports") style'; + +},{"../suite":36,"../test":37}],11:[function(require,module,exports){ +'use strict'; + exports.bdd = require('./bdd'); exports.tdd = require('./tdd'); exports.qunit = require('./qunit'); exports.exports = require('./exports'); },{"./bdd":8,"./exports":10,"./qunit":12,"./tdd":13}],12:[function(require,module,exports){ -/** - * Module dependencies. - */ +'use strict'; var Test = require('../test'); +var EVENT_FILE_PRE_REQUIRE = require('../suite').constants + .EVENT_FILE_PRE_REQUIRE; /** * QUnit-style interface: @@ -1057,10 +1212,10 @@ var Test = require('../test'); * * @param {Suite} suite Root suite. */ -module.exports = function(suite) { +module.exports = function qUnitInterface(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha) { + suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) { var common = require('./common')(suites, context, mocha); context.before = common.before; @@ -1124,12 +1279,14 @@ module.exports = function(suite) { }); }; -},{"../test":36,"./common":9}],13:[function(require,module,exports){ -/** - * Module dependencies. - */ +module.exports.description = 'QUnit style'; + +},{"../suite":36,"../test":37,"./common":9}],13:[function(require,module,exports){ +'use strict'; var Test = require('../test'); +var EVENT_FILE_PRE_REQUIRE = require('../suite').constants + .EVENT_FILE_PRE_REQUIRE; /** * TDD-style interface: @@ -1159,7 +1316,7 @@ var Test = require('../test'); module.exports = function(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha) { + suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) { var common = require('./common')(suites, context, mocha); context.setup = common.beforeEach; @@ -1230,26 +1387,34 @@ module.exports = function(suite) { }); }; -},{"../test":36,"./common":9}],14:[function(require,module,exports){ -(function (process,global,__dirname){ +module.exports.description = + 'traditional "suite"/"test" instead of BDD\'s "describe"/"it"'; + +},{"../suite":36,"../test":37,"./common":9}],14:[function(require,module,exports){ +(function (process,global){ +'use strict'; + /*! * mocha * Copyright(c) 2011 TJ Holowaychuk * MIT Licensed */ -/** - * Module dependencies. - */ - var escapeRe = require('escape-string-regexp'); var path = require('path'); -var reporters = require('./reporters'); +var builtinReporters = require('./reporters'); +var growl = require('./growl'); var utils = require('./utils'); - -/** - * Expose `Mocha`. - */ +var mocharc = require('./mocharc.json'); +var errors = require('./errors'); +var Suite = require('./suite'); +var createStatsCollector = require('./stats-collector'); +var createInvalidReporterError = errors.createInvalidReporterError; +var createInvalidInterfaceError = errors.createInvalidInterfaceError; +var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE; +var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE; +var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE; +var sQuote = utils.sQuote; exports = module.exports = Mocha; @@ -1266,80 +1431,132 @@ if (!process.browser) { * Expose internals. */ +/** + * @public + * @class utils + * @memberof Mocha + */ exports.utils = utils; exports.interfaces = require('./interfaces'); -exports.reporters = reporters; +/** + * @public + * @memberof Mocha + */ +exports.reporters = builtinReporters; exports.Runnable = require('./runnable'); exports.Context = require('./context'); -exports.Runner = require('./runner'); -exports.Suite = require('./suite'); -exports.Hook = require('./hook'); -exports.Test = require('./test'); - /** - * Return image `name` path. * - * @api private - * @param {string} name - * @return {string} + * @memberof Mocha */ -function image(name) { - return path.join(__dirname, '../images', name + '.png'); -} +exports.Runner = require('./runner'); +exports.Suite = Suite; +exports.Hook = require('./hook'); +exports.Test = require('./test'); /** - * Set up mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.spec` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `retries` number of times to retry failed tests - * - `bail` bail on the first test failure - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `fullTrace` display the full stack-trace on failing - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public + * Constructs a new Mocha instance with `options`. + * + * @public + * @class Mocha + * @param {Object} [options] - Settings object. + * @param {boolean} [options.allowUncaught] - Propagate uncaught errors? + * @param {boolean} [options.asyncOnly] - Force `done` callback or promise? + * @param {boolean} [options.bail] - Bail after first test failure? + * @param {boolean} [options.checkLeaks] - If true, check leaks. + * @param {boolean} [options.delay] - Delay root suite execution? + * @param {boolean} [options.enableTimeouts] - Enable timeouts? + * @param {string} [options.fgrep] - Test filter given string. + * @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite? + * @param {boolean} [options.forbidPending] - Pending tests fail the suite? + * @param {boolean} [options.fullStackTrace] - Full stacktrace upon failure? + * @param {string[]} [options.global] - Variables expected in global scope. + * @param {RegExp|string} [options.grep] - Test filter given regular expression. + * @param {boolean} [options.growl] - Enable desktop notifications? + * @param {boolean} [options.hideDiff] - Suppress diffs from failures? + * @param {boolean} [options.ignoreLeaks] - Ignore global leaks? + * @param {boolean} [options.invert] - Invert test filter matches? + * @param {boolean} [options.noHighlighting] - Disable syntax highlighting? + * @param {string} [options.reporter] - Reporter name. + * @param {Object} [options.reporterOption] - Reporter settings object. + * @param {number} [options.retries] - Number of times to retry failed tests. + * @param {number} [options.slow] - Slow threshold value. + * @param {number|string} [options.timeout] - Timeout threshold value. + * @param {string} [options.ui] - Interface name. + * @param {boolean} [options.color] - Color TTY output from reporter? + * @param {boolean} [options.useInlineDiffs] - Use inline diffs? */ function Mocha(options) { - options = options || {}; + options = utils.assign({}, mocharc, options || {}); this.files = []; this.options = options; - if (options.grep) { - this.grep(new RegExp(options.grep)); + // root suite + this.suite = new exports.Suite('', new exports.Context(), true); + + if ('useColors' in options) { + utils.deprecate( + 'useColors is DEPRECATED and will be removed from a future version of Mocha. Instead, use the "color" option' + ); + options.color = 'color' in options ? options.color : options.useColors; } - if (options.fgrep) { - this.fgrep(options.fgrep); + + this.grep(options.grep) + .fgrep(options.fgrep) + .ui(options.ui) + .bail(options.bail) + .reporter(options.reporter, options.reporterOptions) + .useColors(options.color) + .slow(options.slow) + .useInlineDiffs(options.inlineDiffs) + .globals(options.globals); + + if ('enableTimeouts' in options) { + utils.deprecate( + 'enableTimeouts is DEPRECATED and will be removed from a future version of Mocha. Instead, use "timeout: false" to disable timeouts.' + ); + if (options.enableTimeouts === false) { + this.timeout(0); + } } - this.suite = new exports.Suite('', new exports.Context()); - this.ui(options.ui); - this.bail(options.bail); - this.reporter(options.reporter, options.reporterOptions); - if (typeof options.timeout !== 'undefined' && options.timeout !== null) { - this.timeout(options.timeout); + + // this guard exists because Suite#timeout does not consider `undefined` to be valid input + if (typeof options.timeout !== 'undefined') { + this.timeout(options.timeout === false ? 0 : options.timeout); } - if (typeof options.retries !== 'undefined' && options.retries !== null) { + + if ('retries' in options) { this.retries(options.retries); } - this.useColors(options.useColors); - if (options.enableTimeouts !== null) { - this.enableTimeouts(options.enableTimeouts); - } - if (options.slow) { - this.slow(options.slow); + + if ('diff' in options) { + this.hideDiff(!options.diff); } + + [ + 'allowUncaught', + 'asyncOnly', + 'checkLeaks', + 'delay', + 'forbidOnly', + 'forbidPending', + 'fullTrace', + 'growl', + 'invert' + ].forEach(function(opt) { + if (options[opt]) { + this[opt](); + } + }, this); } /** - * Enable or disable bailing on the first failure. + * Enables or disables bailing on the first failure. * - * @api public - * @param {boolean} [bail] + * @public + * @see {@link https://mochajs.org/#-b---bail|CLI option} + * @param {boolean} [bail=true] - Whether to bail on first error. + * @returns {Mocha} this + * @chainable */ Mocha.prototype.bail = function(bail) { if (!arguments.length) { @@ -1350,10 +1567,17 @@ Mocha.prototype.bail = function(bail) { }; /** - * Add test `file`. + * @summary + * Adds `file` to be loaded for execution. * - * @api public - * @param {string} file + * @description + * Useful for generic setup code that must be included within test suite. + * + * @public + * @see {@link https://mochajs.org/#--file-file|CLI option} + * @param {string} file - Pathname of file to be loaded. + * @returns {Mocha} this + * @chainable */ Mocha.prototype.addFile = function(file) { this.files.push(file); @@ -1361,13 +1585,20 @@ Mocha.prototype.addFile = function(file) { }; /** - * Set reporter to `reporter`, defaults to "spec". + * Sets reporter to `reporter`, defaults to "spec". * - * @param {String|Function} reporter name or constructor - * @param {Object} reporterOptions optional options - * @api public - * @param {string|Function} reporter name or constructor - * @param {Object} reporterOptions optional options + * @public + * @see {@link https://mochajs.org/#-r---reporter-name|CLI option} + * @see {@link https://mochajs.org/#reporters|Reporters} + * @param {String|Function} reporter - Reporter name or constructor. + * @param {Object} [reporterOptions] - Options used to configure the reporter. + * @returns {Mocha} this + * @chainable + * @throws {Error} if requested reporter cannot be loaded + * @example + * + * // Use XUnit reporter and direct its output to file + * mocha.reporter('xunit', { output: '/path/to/testspec.xunit.xml' }); */ Mocha.prototype.reporter = function(reporter, reporterOptions) { if (typeof reporter === 'function') { @@ -1376,26 +1607,43 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) { reporter = reporter || 'spec'; var _reporter; // Try to load a built-in reporter. - if (reporters[reporter]) { - _reporter = reporters[reporter]; + if (builtinReporters[reporter]) { + _reporter = builtinReporters[reporter]; } // Try to load reporters from process.cwd() and node_modules if (!_reporter) { try { _reporter = require(reporter); } catch (err) { - err.message.indexOf('Cannot find module') !== -1 - ? console.warn('"' + reporter + '" reporter not found') - : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); + if ( + err.code !== 'MODULE_NOT_FOUND' || + err.message.indexOf('Cannot find module') !== -1 + ) { + // Try to load reporters from a path (absolute or relative) + try { + _reporter = require(path.resolve(process.cwd(), reporter)); + } catch (_err) { + _err.code !== 'MODULE_NOT_FOUND' || + _err.message.indexOf('Cannot find module') !== -1 + ? console.warn(sQuote(reporter) + ' reporter not found') + : console.warn( + sQuote(reporter) + + ' reporter blew up with error:\n' + + err.stack + ); + } + } else { + console.warn( + sQuote(reporter) + ' reporter blew up with error:\n' + err.stack + ); + } } } - if (!_reporter && reporter === 'teamcity') { - console.warn('The Teamcity reporter was moved to a package named ' - + 'mocha-teamcity-reporter ' - + '(https://npmjs.org/package/mocha-teamcity-reporter).'); - } if (!_reporter) { - throw new Error('invalid reporter "' + reporter + '"'); + throw createInvalidReporterError( + 'invalid reporter ' + sQuote(reporter), + reporter + ); } this._reporter = _reporter; } @@ -1404,30 +1652,44 @@ Mocha.prototype.reporter = function(reporter, reporterOptions) { }; /** - * Set test UI `name`, defaults to "bdd". + * Sets test UI `name`, defaults to "bdd". * - * @api public - * @param {string} bdd + * @public + * @see {@link https://mochajs.org/#-u---ui-name|CLI option} + * @see {@link https://mochajs.org/#interfaces|Interface DSLs} + * @param {string|Function} [ui=bdd] - Interface name or class. + * @returns {Mocha} this + * @chainable + * @throws {Error} if requested interface cannot be loaded */ -Mocha.prototype.ui = function(name) { - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) { - try { - this._ui = require(name); - } catch (err) { - throw new Error('invalid interface "' + name + '"'); +Mocha.prototype.ui = function(ui) { + var bindInterface; + if (typeof ui === 'function') { + bindInterface = ui; + } else { + ui = ui || 'bdd'; + bindInterface = exports.interfaces[ui]; + if (!bindInterface) { + try { + bindInterface = require(ui); + } catch (err) { + throw createInvalidInterfaceError( + 'invalid interface ' + sQuote(ui), + ui + ); + } } } - this._ui = this._ui(this.suite); + bindInterface(this.suite); - this.suite.on('pre-require', function(context) { + this.suite.on(EVENT_FILE_PRE_REQUIRE, function(context) { exports.afterEach = context.afterEach || context.teardown; exports.after = context.after || context.suiteTeardown; exports.beforeEach = context.beforeEach || context.setup; exports.before = context.before || context.suiteSetup; exports.describe = context.describe || context.suite; exports.it = context.it || context.test; + exports.xit = context.xit || (context.test && context.test.skip); exports.setup = context.setup || context.beforeEach; exports.suiteSetup = context.suiteSetup || context.before; exports.suiteTeardown = context.suiteTeardown || context.after; @@ -1441,64 +1703,116 @@ Mocha.prototype.ui = function(name) { }; /** - * Load registered files. + * Loads `files` prior to execution. * - * @api private + * @description + * The implementation relies on Node's `require` to execute + * the test interface functions and will be subject to its cache. + * + * @private + * @see {@link Mocha#addFile} + * @see {@link Mocha#run} + * @see {@link Mocha#unloadFiles} + * @param {Function} [fn] - Callback invoked upon completion. */ Mocha.prototype.loadFiles = function(fn) { var self = this; var suite = this.suite; this.files.forEach(function(file) { file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); + suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self); + suite.emit(EVENT_FILE_REQUIRE, require(file), file, self); + suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self); }); fn && fn(); }; /** - * Enable growl support. + * Removes a previously loaded file from Node's `require` cache. * - * @api private + * @private + * @static + * @see {@link Mocha#unloadFiles} + * @param {string} file - Pathname of file to be unloaded. */ -Mocha.prototype._growl = function(runner, reporter) { - var notify = require('growl'); +Mocha.unloadFile = function(file) { + delete require.cache[require.resolve(file)]; +}; - runner.on('end', function() { - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha', - title: 'Passed', - image: image('ok') - }); - } - }); +/** + * Unloads `files` from Node's `require` cache. + * + * @description + * This allows files to be "freshly" reloaded, providing the ability + * to reuse a Mocha instance programmatically. + * + * Intended for consumers — not used internally + * + * @public + * @see {@link Mocha.unloadFile} + * @see {@link Mocha#loadFiles} + * @see {@link Mocha#run} + * @returns {Mocha} this + * @chainable + */ +Mocha.prototype.unloadFiles = function() { + this.files.forEach(Mocha.unloadFile); + return this; }; /** - * Escape string and add it to grep as a regexp. + * Sets `grep` filter after escaping RegExp special characters. * - * @api public - * @param str - * @returns {Mocha} + * @public + * @see {@link Mocha#grep} + * @param {string} str - Value to be converted to a regexp. + * @returns {Mocha} this + * @chainable + * @example + * + * // Select tests whose full title begins with `"foo"` followed by a period + * mocha.fgrep('foo.'); */ Mocha.prototype.fgrep = function(str) { + if (!str) { + return this; + } return this.grep(new RegExp(escapeRe(str))); }; /** - * Add regexp to grep, if `re` is a string it is escaped. + * @summary + * Sets `grep` filter used to select specific tests for execution. * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - * @param {RegExp|string} re - * @return {Mocha} + * @description + * If `re` is a regexp-like string, it will be converted to regexp. + * The regexp is tested against the full title of each test (i.e., the + * name of the test preceded by titles of each its ancestral suites). + * As such, using an exact-match fixed pattern against the + * test name itself will not yield any matches. + *
+ * Previous filter value will be overwritten on each call! + * + * @public + * @see {@link https://mochajs.org/#-g---grep-pattern|CLI option} + * @see {@link Mocha#fgrep} + * @see {@link Mocha#invert} + * @param {RegExp|String} re - Regular expression used to select tests. + * @return {Mocha} this + * @chainable + * @example + * + * // Select tests whose full title contains `"match"`, ignoring case + * mocha.grep(/match/i); + * @example + * + * // Same as above but with regexp-like string argument + * mocha.grep('/match/i'); + * @example + * + * // ## Anti-example + * // Given embedded test `it('only-this-test')`... + * mocha.grep('/^only-this-test$/'); // NO! Use `.only()` to do this! */ Mocha.prototype.grep = function(re) { if (utils.isString(re)) { @@ -1510,11 +1824,18 @@ Mocha.prototype.grep = function(re) { } return this; }; + /** - * Invert `.grep()` matches. + * Inverts `grep` matches. * - * @return {Mocha} - * @api public + * @public + * @see {@link Mocha#grep} + * @return {Mocha} this + * @chainable + * @example + * + * // Select tests whose full title does *not* contain `"match"`, ignoring case + * mocha.grep(/match/i).invert(); */ Mocha.prototype.invert = function() { this.options.invert = true; @@ -1522,24 +1843,31 @@ Mocha.prototype.invert = function() { }; /** - * Ignore global leaks. + * Enables or disables ignoring global leaks. * - * @param {Boolean} ignore - * @return {Mocha} - * @api public - * @param {boolean} ignore - * @return {Mocha} + * @public + * @see {@link Mocha#checkLeaks} + * @param {boolean} ignoreLeaks - Whether to ignore global leaks. + * @return {Mocha} this + * @chainable + * @example + * + * // Ignore global leaks + * mocha.ignoreLeaks(true); */ -Mocha.prototype.ignoreLeaks = function(ignore) { - this.options.ignoreLeaks = Boolean(ignore); +Mocha.prototype.ignoreLeaks = function(ignoreLeaks) { + this.options.ignoreLeaks = Boolean(ignoreLeaks); return this; }; /** - * Enable global leak checking. + * Enables checking for global variables leaked while running tests. * - * @return {Mocha} - * @api public + * @public + * @see {@link https://mochajs.org/#--check-leaks|CLI option} + * @see {@link Mocha#ignoreLeaks} + * @return {Mocha} this + * @chainable */ Mocha.prototype.checkLeaks = function() { this.options.ignoreLeaks = false; @@ -1547,10 +1875,11 @@ Mocha.prototype.checkLeaks = function() { }; /** - * Display long stack-trace on failing + * Displays full stack trace upon test failure. * - * @return {Mocha} - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.fullTrace = function() { this.options.fullStackTrace = true; @@ -1558,38 +1887,77 @@ Mocha.prototype.fullTrace = function() { }; /** - * Enable growl support. + * Enables desktop notification support if prerequisite software installed. * - * @return {Mocha} - * @api public + * @public + * @see {@link Mocha#isGrowlCapable} + * @see {@link Mocha#_growl} + * @return {Mocha} this + * @chainable */ Mocha.prototype.growl = function() { - this.options.growl = true; + this.options.growl = this.isGrowlCapable(); + if (!this.options.growl) { + var detail = process.browser + ? 'notification support not available in this browser...' + : 'notification support prerequisites not installed...'; + console.error(detail + ' cannot enable!'); + } return this; }; /** - * Ignore `globals` array or string. + * @summary + * Determines if Growl support seems likely. * - * @param {Array|String} globals - * @return {Mocha} - * @api public - * @param {Array|string} globals - * @return {Mocha} + * @description + * Not available when run in browser. + * + * @private + * @see {@link Growl#isCapable} + * @see {@link Mocha#growl} + * @return {boolean} whether Growl support can be expected + */ +Mocha.prototype.isGrowlCapable = growl.isCapable; + +/** + * Implements desktop notifications using a pseudo-reporter. + * + * @private + * @see {@link Mocha#growl} + * @see {@link Growl#notify} + * @param {Runner} runner - Runner instance. + */ +Mocha.prototype._growl = growl.notify; + +/** + * Specifies whitelist of variable names to be expected in global scope. + * + * @public + * @see {@link https://mochajs.org/#--globals-names|CLI option} + * @see {@link Mocha#checkLeaks} + * @param {String[]|String} globals - Accepted global variable name(s). + * @return {Mocha} this + * @chainable + * @example + * + * // Specify variables to be expected in global scope + * mocha.globals(['jQuery', 'MyLib']); */ Mocha.prototype.globals = function(globals) { - this.options.globals = (this.options.globals || []).concat(globals); + this.options.globals = (this.options.globals || []) + .concat(globals) + .filter(Boolean); return this; }; /** - * Emit color output. + * Enables or disables TTY color output by screen-oriented reporters. * - * @param {Boolean} colors - * @return {Mocha} - * @api public - * @param {boolean} colors - * @return {Mocha} + * @public + * @param {boolean} colors - Whether to enable color output. + * @return {Mocha} this + * @chainable */ Mocha.prototype.useColors = function(colors) { if (colors !== undefined) { @@ -1599,13 +1967,13 @@ Mocha.prototype.useColors = function(colors) { }; /** - * Use inline diffs rather than +/-. + * Determines if reporter should use inline diffs (rather than +/-) + * in test failure output. * - * @param {Boolean} inlineDiffs - * @return {Mocha} - * @api public - * @param {boolean} inlineDiffs - * @return {Mocha} + * @public + * @param {boolean} inlineDiffs - Whether to use inline diffs. + * @return {Mocha} this + * @chainable */ Mocha.prototype.useInlineDiffs = function(inlineDiffs) { this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; @@ -1613,25 +1981,60 @@ Mocha.prototype.useInlineDiffs = function(inlineDiffs) { }; /** - * Set the timeout in milliseconds. + * Determines if reporter should include diffs in test failure output. * - * @param {Number} timeout - * @return {Mocha} - * @api public - * @param {number} timeout - * @return {Mocha} + * @public + * @param {boolean} hideDiff - Whether to hide diffs. + * @return {Mocha} this + * @chainable + */ +Mocha.prototype.hideDiff = function(hideDiff) { + this.options.hideDiff = hideDiff !== undefined && hideDiff; + return this; +}; + +/** + * @summary + * Sets timeout threshold value. + * + * @description + * A string argument can use shorthand (such as "2s") and will be converted. + * If the value is `0`, timeouts will be disabled. + * + * @public + * @see {@link https://mochajs.org/#-t---timeout-ms|CLI option} + * @see {@link https://mochajs.org/#--no-timeouts|CLI option} + * @see {@link https://mochajs.org/#timeouts|Timeouts} + * @see {@link Mocha#enableTimeouts} + * @param {number|string} msecs - Timeout threshold value. + * @return {Mocha} this + * @chainable + * @example + * + * // Sets timeout to one second + * mocha.timeout(1000); + * @example + * + * // Same as above but using string argument + * mocha.timeout('1s'); */ -Mocha.prototype.timeout = function(timeout) { - this.suite.timeout(timeout); +Mocha.prototype.timeout = function(msecs) { + this.suite.timeout(msecs); return this; }; /** - * Set the number of times to retry failed tests. + * Sets the number of times to retry failed tests. * - * @param {Number} retry times - * @return {Mocha} - * @api public + * @public + * @see {@link https://mochajs.org/#retry-tests|Retry Tests} + * @param {number} retry - Number of times to retry failed tests. + * @return {Mocha} this + * @chainable + * @example + * + * // Allow any failed test to retry one more time + * mocha.retries(1); */ Mocha.prototype.retries = function(n) { this.suite.retries(n); @@ -1639,38 +2042,50 @@ Mocha.prototype.retries = function(n) { }; /** - * Set slowness threshold in milliseconds. + * Sets slowness threshold value. * - * @param {Number} slow - * @return {Mocha} - * @api public - * @param {number} slow - * @return {Mocha} + * @public + * @see {@link https://mochajs.org/#-s---slow-ms|CLI option} + * @param {number} msecs - Slowness threshold value. + * @return {Mocha} this + * @chainable + * @example + * + * // Sets "slow" threshold to half a second + * mocha.slow(500); + * @example + * + * // Same as above but using string argument + * mocha.slow('0.5s'); */ -Mocha.prototype.slow = function(slow) { - this.suite.slow(slow); +Mocha.prototype.slow = function(msecs) { + this.suite.slow(msecs); return this; }; /** - * Enable timeouts. + * Enables or disables timeouts. * - * @param {Boolean} enabled - * @return {Mocha} - * @api public - * @param {boolean} enabled - * @return {Mocha} + * @public + * @see {@link https://mochajs.org/#-t---timeout-ms|CLI option} + * @see {@link https://mochajs.org/#--no-timeouts|CLI option} + * @param {boolean} enableTimeouts - Whether to enable timeouts. + * @return {Mocha} this + * @chainable */ -Mocha.prototype.enableTimeouts = function(enabled) { - this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true); +Mocha.prototype.enableTimeouts = function(enableTimeouts) { + this.suite.enableTimeouts( + arguments.length && enableTimeouts !== undefined ? enableTimeouts : true + ); return this; }; /** - * Makes all tests async (accepting a callback) + * Forces all tests to either accept a `done` callback or return a promise. * - * @return {Mocha} - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.asyncOnly = function() { this.options.asyncOnly = true; @@ -1678,9 +2093,11 @@ Mocha.prototype.asyncOnly = function() { }; /** - * Disable syntax highlighting (in browser). + * Disables syntax highlighting (in browser). * - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.noHighlighting = function() { this.options.noHighlighting = true; @@ -1688,10 +2105,11 @@ Mocha.prototype.noHighlighting = function() { }; /** - * Enable uncaught errors to propagate (in browser). + * Enables uncaught errors to propagate (in browser). * - * @return {Mocha} - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.allowUncaught = function() { this.options.allowUncaught = true; @@ -1699,8 +2117,16 @@ Mocha.prototype.allowUncaught = function() { }; /** - * Delay root suite execution. - * @returns {Mocha} + * @summary + * Delays root suite execution. + * + * @description + * Used to perform asynch operations before any suites are run. + * + * @public + * @see {@link https://mochajs.org/#delayed-root-suite|delayed root suite} + * @returns {Mocha} this + * @chainable */ Mocha.prototype.delay = function delay() { this.options.delay = true; @@ -1708,11 +2134,64 @@ Mocha.prototype.delay = function delay() { }; /** - * Run tests and invoke `fn()` when complete. + * Causes tests marked `only` to fail the suite. * - * @api public - * @param {Function} fn - * @return {Runner} + * @public + * @returns {Mocha} this + * @chainable + */ +Mocha.prototype.forbidOnly = function() { + this.options.forbidOnly = true; + return this; +}; + +/** + * Causes pending tests and tests marked `skip` to fail the suite. + * + * @public + * @returns {Mocha} this + * @chainable + */ +Mocha.prototype.forbidPending = function() { + this.options.forbidPending = true; + return this; +}; + +/** + * Mocha version as specified by "package.json". + * + * @name Mocha#version + * @type string + * @readonly + */ +Object.defineProperty(Mocha.prototype, 'version', { + value: require('../package.json').version, + configurable: false, + enumerable: true, + writable: false +}); + +/** + * Callback to be invoked when test execution is complete. + * + * @callback DoneCB + * @param {number} failures - Number of failures that occurred. + */ + +/** + * Runs root suite and invokes `fn()` when complete. + * + * @description + * To run tests multiple times (or to run tests in files that are + * already in the `require` cache), make sure to clear them from + * the cache first! + * + * @public + * @see {@link Mocha#loadFiles} + * @see {@link Mocha#unloadFiles} + * @see {@link Runner#run} + * @param {DoneCB} [fn] - Callback invoked when test execution completed. + * @return {Runner} runner instance */ Mocha.prototype.run = function(fn) { if (this.files.length) { @@ -1722,12 +2201,14 @@ Mocha.prototype.run = function(fn) { var options = this.options; options.files = this.files; var runner = new exports.Runner(suite, options.delay); + createStatsCollector(runner); var reporter = new this._reporter(runner, options); runner.ignoreLeaks = options.ignoreLeaks !== false; runner.fullStackTrace = options.fullStackTrace; - runner.hasOnly = options.hasOnly; runner.asyncOnly = options.asyncOnly; runner.allowUncaught = options.allowUncaught; + runner.forbidOnly = options.forbidOnly; + runner.forbidPending = options.forbidPending; if (options.grep) { runner.grep(options.grep, options.invert); } @@ -1735,214 +2216,91 @@ Mocha.prototype.run = function(fn) { runner.globals(options.globals); } if (options.growl) { - this._growl(runner, reporter); + this._growl(runner); } if (options.useColors !== undefined) { exports.reporters.Base.useColors = options.useColors; } exports.reporters.Base.inlineDiffs = options.useInlineDiffs; + exports.reporters.Base.hideDiff = options.hideDiff; function done(failures) { + fn = fn || utils.noop; if (reporter.done) { reporter.done(failures, fn); } else { - fn && fn(failures); + fn(failures); } } return runner.run(done); }; -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/lib") -},{"./context":6,"./hook":7,"./interfaces":11,"./reporters":21,"./runnable":33,"./runner":34,"./suite":35,"./test":36,"./utils":38,"_process":67,"escape-string-regexp":47,"growl":49,"path":42}],15:[function(require,module,exports){ -/** - * Helpers. - */ +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../package.json":90,"./context":5,"./errors":6,"./growl":2,"./hook":7,"./interfaces":11,"./mocharc.json":15,"./reporters":21,"./runnable":33,"./runner":34,"./stats-collector":35,"./suite":36,"./test":37,"./utils":38,"_process":69,"escape-string-regexp":49,"path":42}],15:[function(require,module,exports){ +module.exports={ + "diff": true, + "extension": ["js"], + "opts": "./test/mocha.opts", + "package": "./package.json", + "reporter": "spec", + "slow": 75, + "timeout": 2000, + "ui": "bdd" +} -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; +},{}],16:[function(require,module,exports){ +'use strict'; + +module.exports = Pending; /** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] + * Initialize a new `Pending` error with the given message. * - * @api public - * @param {string|number} val - * @param {Object} options - * @return {string|number} + * @param {string} message */ -module.exports = function(val, options) { - options = options || {}; - if (typeof val === 'string') { - return parse(val); - } - // https://github.com/mochajs/mocha/pull/1035 - return options['long'] ? longFormat(val) : shortFormat(val); -}; +function Pending(message) { + this.message = message; +} +},{}],17:[function(require,module,exports){ +(function (process){ +'use strict'; /** - * Parse the given `str` and return milliseconds. - * - * @api private - * @param {string} str - * @return {number} + * @module Base + */ +/** + * Module dependencies. */ -function parse(str) { - var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 's': - return n * s; - case 'ms': - return n; - default: - // No default case - } -} + +var tty = require('tty'); +var diff = require('diff'); +var milliseconds = require('ms'); +var utils = require('../utils'); +var supportsColor = process.browser ? null : require('supports-color'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; /** - * Short format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} + * Expose `Base`. */ -function shortFormat(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} + +exports = module.exports = Base; /** - * Long format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} + * Check if both stdio streams are associated with a tty. */ -function longFormat(ms) { - return plural(ms, d, 'day') - || plural(ms, h, 'hour') - || plural(ms, m, 'minute') - || plural(ms, s, 'second') - || ms + ' ms'; -} - -/** - * Pluralization helper. - * - * @api private - * @param {number} ms - * @param {number} n - * @param {string} name - */ -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - -},{}],16:[function(require,module,exports){ - -/** - * Expose `Pending`. - */ - -module.exports = Pending; - -/** - * Initialize a new `Pending` error with the given message. - * - * @param {string} message - */ -function Pending(message) { - this.message = message; -} - -},{}],17:[function(require,module,exports){ -(function (process,global){ -/** - * Module dependencies. - */ - -var tty = require('tty'); -var diff = require('diff'); -var ms = require('../ms'); -var utils = require('../utils'); -var supportsColor = process.browser ? null : require('supports-color'); - -/** - * Expose `Base`. - */ - -exports = module.exports = Base; - -/** - * Save timer references to avoid Sinon interfering. - * See: https://github.com/mochajs/mocha/issues/237 - */ - -/* eslint-disable no-unused-vars, no-native-reassign */ -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** - * Check if both stdio streams are associated with a tty. - */ - -var isatty = tty.isatty(1) && tty.isatty(2); + +var isatty = tty.isatty(1) && tty.isatty(2); /** * Enable coloring by default, except in the browser interface. */ -exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined)); +exports.useColors = + !process.browser && + (supportsColor.stdout || process.env.MOCHA_COLORS !== undefined); /** * Inline diffs instead of +/- @@ -2001,17 +2359,17 @@ if (process.platform === 'win32') { * as well as user-defined color * schemes. * + * @private * @param {string} type * @param {string} str * @return {string} - * @api private */ -var color = exports.color = function(type, str) { +var color = (exports.color = function(type, str) { if (!exports.useColors) { return String(str); } return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; -}; +}); /** * Expose term window size, with some defaults for when stderr is not a tty. @@ -2023,8 +2381,8 @@ exports.window = { if (isatty) { exports.window.width = process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1]; + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1]; } /** @@ -2058,20 +2416,56 @@ exports.cursor = { } }; +function showDiff(err) { + return ( + err && + err.showDiff !== false && + sameType(err.actual, err.expected) && + err.expected !== undefined + ); +} + +function stringifyDiffObjs(err) { + if (!utils.isString(err.actual) || !utils.isString(err.expected)) { + err.actual = utils.stringify(err.actual); + err.expected = utils.stringify(err.expected); + } +} + /** - * Outut the given `failures` as a list. + * Returns a diff between 2 strings with coloured ANSI output. * - * @param {Array} failures - * @api public + * @description + * The diff will be either inline or unified dependent on the value + * of `Base.inlineDiff`. + * + * @param {string} actual + * @param {string} expected + * @return {string} Diff */ +var generateDiff = (exports.generateDiff = function(actual, expected) { + return exports.inlineDiffs + ? inlineDiff(actual, expected) + : unifiedDiff(actual, expected); +}); +/** + * Outputs the given `failures` as a list. + * + * @public + * @memberof Mocha.reporters.Base + * @variation 1 + * @param {Object[]} failures - Each is Test instance with corresponding + * Error property + */ exports.list = function(failures) { console.log(); failures.forEach(function(test, i) { // format - var fmt = color('error title', ' %s) %s:\n') - + color('error message', ' %s') - + color('error stack', '\n%s\n'); + var fmt = + color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); // msg var msg; @@ -2086,9 +2480,6 @@ exports.list = function(failures) { } var stack = err.stack || message; var index = message ? stack.indexOf(message) : -1; - var actual = err.actual; - var expected = err.expected; - var escape = true; if (index === -1) { msg = message; @@ -2104,71 +2495,58 @@ exports.list = function(failures) { msg = 'Uncaught ' + msg; } // explicitly show diff - if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { - escape = false; - if (!(utils.isString(actual) && utils.isString(expected))) { - err.actual = actual = utils.stringify(actual); - err.expected = expected = utils.stringify(expected); - } - - fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); + if (!exports.hideDiff && showDiff(err)) { + stringifyDiffObjs(err); + fmt = + color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); var match = message.match(/^([^:]+): expected/); msg = '\n ' + color('error message', match ? match[1] : msg); - if (exports.inlineDiffs) { - msg += inlineDiff(err, escape); - } else { - msg += unifiedDiff(err, escape); - } + msg += generateDiff(err.actual, err.expected); } // indent stack trace stack = stack.replace(/^/gm, ' '); - console.log(fmt, (i + 1), test.fullTitle(), msg, stack); + // indented test title + var testTitle = ''; + test.titlePath().forEach(function(str, index) { + if (index !== 0) { + testTitle += '\n '; + } + for (var i = 0; i < index; i++) { + testTitle += ' '; + } + testTitle += str; + }); + + console.log(fmt, i + 1, testTitle, msg, stack); }); }; /** - * Initialize a new `Base` reporter. + * Constructs a new `Base` reporter instance. * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. + * @description + * All other reporters generally inherit from this reporter. * - * @param {Runner} runner - * @api public + * @public + * @class + * @memberof Mocha.reporters + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ - -function Base(runner) { - var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; - var failures = this.failures = []; +function Base(runner, options) { + var failures = (this.failures = []); if (!runner) { - return; + throw new TypeError('Missing runner argument'); } + this.options = options || {}; this.runner = runner; + this.stats = runner.stats; // assigned so Reporters keep a closer reference - runner.stats = stats; - - runner.on('start', function() { - stats.start = new Date(); - }); - - runner.on('suite', function(suite) { - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function() { - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test) { - stats.passes = stats.passes || 0; - + runner.on(EVENT_TEST_PASS, function(test) { if (test.duration > test.slow()) { test.speed = 'slow'; } else if (test.duration > test.slow() / 2) { @@ -2176,32 +2554,22 @@ function Base(runner) { } else { test.speed = 'fast'; } - - stats.passes++; }); - runner.on('fail', function(test, err) { - stats.failures = stats.failures || 0; - stats.failures++; + runner.on(EVENT_TEST_FAIL, function(test, err) { + if (showDiff(err)) { + stringifyDiffObjs(err); + } test.err = err; failures.push(test); }); - - runner.on('end', function() { - stats.end = new Date(); - stats.duration = new Date() - stats.start; - }); - - runner.on('pending', function() { - stats.pending++; - }); } /** - * Output common epilogue used by many of - * the bundled reporters. + * Outputs common epilogue used by many of the bundled reporters. * - * @api public + * @public + * @memberof Mocha.reporters.Base */ Base.prototype.epilogue = function() { var stats = this.stats; @@ -2210,18 +2578,16 @@ Base.prototype.epilogue = function() { console.log(); // passes - fmt = color('bright pass', ' ') - + color('green', ' %d passing') - + color('light', ' (%s)'); + fmt = + color('bright pass', ' ') + + color('green', ' %d passing') + + color('light', ' (%s)'); - console.log(fmt, - stats.passes || 0, - ms(stats.duration)); + console.log(fmt, stats.passes || 0, milliseconds(stats.duration)); // pending if (stats.pending) { - fmt = color('pending', ' ') - + color('pending', ' %d pending'); + fmt = color('pending', ' ') + color('pending', ' %d pending'); console.log(fmt, stats.pending); } @@ -2240,9 +2606,9 @@ Base.prototype.epilogue = function() { }; /** - * Pad the given `str` to `len`. + * Pads the given `str` to `len`. * - * @api private + * @private * @param {string} str * @param {string} len * @return {string} @@ -2253,33 +2619,36 @@ function pad(str, len) { } /** - * Returns an inline diff between 2 strings with coloured ANSI output + * Returns inline diff between 2 strings with coloured ANSI output. * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape + * @private + * @param {String} actual + * @param {String} expected * @return {string} Diff */ -function inlineDiff(err, escape) { - var msg = errorDiff(err, 'WordsWithSpace', escape); +function inlineDiff(actual, expected) { + var msg = errorDiff(actual, expected); // linenos var lines = msg.split('\n'); if (lines.length > 4) { var width = String(lines.length).length; - msg = lines.map(function(str, i) { - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); + msg = lines + .map(function(str, i) { + return pad(++i, width) + ' |' + ' ' + str; + }) + .join('\n'); } // legend - msg = '\n' - + color('diff removed', 'actual') - + ' ' - + color('diff added', 'expected') - + '\n\n' - + msg - + '\n'; + msg = + '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; // indent msg = msg.replace(/^/gm, ' '); @@ -2287,27 +2656,24 @@ function inlineDiff(err, escape) { } /** - * Returns a unified diff between two strings. + * Returns unified diff between two strings with coloured ANSI output. * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape + * @private + * @param {String} actual + * @param {String} expected * @return {string} The diff. */ -function unifiedDiff(err, escape) { +function unifiedDiff(actual, expected) { var indent = ' '; function cleanUp(line) { - if (escape) { - line = escapeInvisibles(line); - } if (line[0] === '+') { return indent + colorLines('diff added', line); } if (line[0] === '-') { return indent + colorLines('diff removed', line); } - if (line.match(/\@\@/)) { - return null; + if (line.match(/@@/)) { + return '--'; } if (line.match(/\\ No newline/)) { return null; @@ -2317,63 +2683,59 @@ function unifiedDiff(err, escape) { function notBlank(line) { return typeof line !== 'undefined' && line !== null; } - var msg = diff.createPatch('string', err.actual, err.expected); - var lines = msg.split('\n').splice(4); - return '\n ' - + colorLines('diff added', '+ expected') + ' ' - + colorLines('diff removed', '- actual') - + '\n\n' - + lines.map(cleanUp).filter(notBlank).join('\n'); -} - -/** - * Return a character diff for `err`. - * - * @api private - * @param {Error} err - * @param {string} type - * @param {boolean} escape - * @return {string} - */ -function errorDiff(err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; - var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function(str) { - if (str.added) { - return colorLines('diff added', str.value); - } - if (str.removed) { - return colorLines('diff removed', str.value); - } - return str.value; - }).join(''); + var msg = diff.createPatch('string', actual, expected); + var lines = msg.split('\n').splice(5); + return ( + '\n ' + + colorLines('diff added', '+ expected') + + ' ' + + colorLines('diff removed', '- actual') + + '\n\n' + + lines + .map(cleanUp) + .filter(notBlank) + .join('\n') + ); } /** - * Returns a string with all invisible characters in plain text + * Returns character diff for `err`. * - * @api private - * @param {string} line - * @return {string} - */ -function escapeInvisibles(line) { - return line.replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); + * @private + * @param {String} actual + * @param {String} expected + * @return {string} the diff + */ +function errorDiff(actual, expected) { + return diff + .diffWordsWithSpace(actual, expected) + .map(function(str) { + if (str.added) { + return colorLines('diff added', str.value); + } + if (str.removed) { + return colorLines('diff removed', str.value); + } + return str.value; + }) + .join(''); } /** - * Color lines for `str`, using the color `name`. + * Colors lines for `str`, using the color `name`. * - * @api private + * @private * @param {string} name * @param {string} str * @return {string} */ function colorLines(name, str) { - return str.split('\n').map(function(str) { - return color(name, str); - }).join('\n'); + return str + .split('\n') + .map(function(str) { + return color(name, str); + }) + .join('\n'); } /** @@ -2382,9 +2744,9 @@ function colorLines(name, str) { var objToString = Object.prototype.toString; /** - * Check that a / b have the same type. + * Checks that a / b have the same type. * - * @api private + * @private * @param {Object} a * @param {Object} b * @return {boolean} @@ -2393,14 +2755,25 @@ function sameType(a, b) { return objToString.call(a) === objToString.call(b); } -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../ms":15,"../utils":38,"_process":67,"diff":46,"supports-color":42,"tty":5}],18:[function(require,module,exports){ +Base.abstract = true; + +}).call(this,require('_process')) +},{"../runner":34,"../utils":38,"_process":69,"diff":48,"ms":60,"supports-color":42,"tty":4}],18:[function(require,module,exports){ +'use strict'; +/** + * @module Doc + */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; /** * Expose `Doc`. @@ -2409,13 +2782,17 @@ var utils = require('../utils'); exports = module.exports = Doc; /** - * Initialize a new `Doc` reporter. + * Constructs a new `Doc` reporter instance. * - * @param {Runner} runner - * @api public + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Doc(runner) { - Base.call(this, runner); +function Doc(runner, options) { + Base.call(this, runner, options); var indents = 2; @@ -2423,7 +2800,7 @@ function Doc(runner) { return Array(indents).join(' '); } - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { if (suite.root) { return; } @@ -2434,7 +2811,7 @@ function Doc(runner) { console.log('%s
', indent()); }); - runner.on('suite end', function(suite) { + runner.on(EVENT_SUITE_END, function(suite) { if (suite.root) { return; } @@ -2444,29 +2821,48 @@ function Doc(runner) { --indents; }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { console.log('%s
%s
', indent(), utils.escape(test.title)); var code = utils.escape(utils.clean(test.body)); console.log('%s
%s
', indent(), code); }); - runner.on('fail', function(test, err) { - console.log('%s
%s
', indent(), utils.escape(test.title)); + runner.on(EVENT_TEST_FAIL, function(test, err) { + console.log( + '%s
%s
', + indent(), + utils.escape(test.title) + ); var code = utils.escape(utils.clean(test.body)); - console.log('%s
%s
', indent(), code); + console.log( + '%s
%s
', + indent(), + code + ); console.log('%s
%s
', indent(), utils.escape(err)); }); } -},{"../utils":38,"./base":17}],19:[function(require,module,exports){ +Doc.description = 'HTML documentation'; + +},{"../runner":34,"../utils":38,"./base":17}],19:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Dot + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; -var color = Base.color; +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_RUN_END = constants.EVENT_RUN_END; /** * Expose `Dot`. @@ -2475,48 +2871,52 @@ var color = Base.color; exports = module.exports = Dot; /** - * Initialize a new `Dot` matrix test reporter. + * Constructs a new `Dot` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Dot(runner) { - Base.call(this, runner); +function Dot(runner, options) { + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .75 | 0; + var width = (Base.window.width * 0.75) | 0; var n = -1; - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { process.stdout.write('\n'); }); - runner.on('pending', function() { + runner.on(EVENT_TEST_PENDING, function() { if (++n % width === 0) { process.stdout.write('\n '); } - process.stdout.write(color('pending', Base.symbols.comma)); + process.stdout.write(Base.color('pending', Base.symbols.comma)); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { if (++n % width === 0) { process.stdout.write('\n '); } if (test.speed === 'slow') { - process.stdout.write(color('bright yellow', Base.symbols.dot)); + process.stdout.write(Base.color('bright yellow', Base.symbols.dot)); } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); + process.stdout.write(Base.color(test.speed, Base.symbols.dot)); } }); - runner.on('fail', function() { + runner.on(EVENT_TEST_FAIL, function() { if (++n % width === 0) { process.stdout.write('\n '); } - process.stdout.write(color('fail', Base.symbols.bang)); + process.stdout.write(Base.color('fail', Base.symbols.bang)); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { console.log(); self.epilogue(); }); @@ -2527,11 +2927,17 @@ function Dot(runner) { */ inherits(Dot, Base); +Dot.description = 'dot matrix representation'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],20:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],20:[function(require,module,exports){ (function (global){ -/* eslint-env browser */ +'use strict'; +/* eslint-env browser */ +/** + * @module HTML + */ /** * Module dependencies. */ @@ -2540,19 +2946,19 @@ var Base = require('./base'); var utils = require('../utils'); var Progress = require('../browser/progress'); var escapeRe = require('escape-string-regexp'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ -/* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `HTML`. @@ -2564,21 +2970,28 @@ exports = module.exports = HTML; * Stats template. */ -var statsTemplate = ''; +var statsTemplate = + ''; + +var playIcon = '‣'; /** - * Initialize a new `HTML` reporter. + * Constructs a new `HTML` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function HTML(runner) { - Base.call(this, runner); +function HTML(runner, options) { + Base.call(this, runner, options); var self = this; var stats = this.stats; @@ -2615,7 +3028,7 @@ function HTML(runner) { on(passesLink, 'click', function(evt) { evt.preventDefault(); unhide(); - var name = (/pass/).test(report.className) ? '' : ' pass'; + var name = /pass/.test(report.className) ? '' : ' pass'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test pass'); @@ -2626,7 +3039,7 @@ function HTML(runner) { on(failuresLink, 'click', function(evt) { evt.preventDefault(); unhide(); - var name = (/fail/).test(report.className) ? '' : ' fail'; + var name = /fail/.test(report.className) ? '' : ' fail'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test fail'); @@ -2640,14 +3053,18 @@ function HTML(runner) { progress.size(40); } - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { if (suite.root) { return; } // suite var url = self.suiteURL(suite); - var el = fragment('
  • %s

  • ', url, escape(suite.title)); + var el = fragment( + '
  • %s

  • ', + url, + escape(suite.title) + ); // container stack[0].appendChild(el); @@ -2655,7 +3072,7 @@ function HTML(runner) { el.appendChild(stack[0]); }); - runner.on('suite end', function(suite) { + runner.on(EVENT_SUITE_END, function(suite) { if (suite.root) { updateStats(); return; @@ -2663,19 +3080,27 @@ function HTML(runner) { stack.shift(); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { var url = self.testURL(test); - var markup = '
  • %e%ems ' - + '

  • '; + var markup = + '
  • %e%ems ' + + '' + + playIcon + + '

  • '; var el = fragment(markup, test.speed, test.title, test.duration, url); self.addCodeToggle(el, test.body); appendToStack(el); updateStats(); }); - runner.on('fail', function(test) { - var el = fragment('
  • %e

  • ', - test.title, self.testURL(test)); + runner.on(EVENT_TEST_FAIL, function(test) { + var el = fragment( + '
  • %e ' + + playIcon + + '

  • ', + test.title, + self.testURL(test) + ); var stackString; // Note: Includes leading newline var message = test.err.toString(); @@ -2690,7 +3115,9 @@ function HTML(runner) { if (indexOfMessage === -1) { stackString = test.err.stack; } else { - stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); + stackString = test.err.stack.substr( + test.err.message.length + indexOfMessage + ); } } else if (test.err.sourceURL && test.err.line !== undefined) { // Safari doesn't give you a stack. Let's at least provide a source line. @@ -2700,12 +3127,21 @@ function HTML(runner) { stackString = stackString || ''; if (test.err.htmlMessage && stackString) { - el.appendChild(fragment('
    %s\n
    %e
    ', - test.err.htmlMessage, stackString)); + el.appendChild( + fragment( + '
    %s\n
    %e
    ', + test.err.htmlMessage, + stackString + ) + ); } else if (test.err.htmlMessage) { - el.appendChild(fragment('
    %s
    ', test.err.htmlMessage)); + el.appendChild( + fragment('
    %s
    ', test.err.htmlMessage) + ); } else { - el.appendChild(fragment('
    %e%e
    ', message, stackString)); + el.appendChild( + fragment('
    %e%e
    ', message, stackString) + ); } self.addCodeToggle(el, test.body); @@ -2713,8 +3149,11 @@ function HTML(runner) { updateStats(); }); - runner.on('pending', function(test) { - var el = fragment('
  • %e

  • ', test.title); + runner.on(EVENT_TEST_PENDING, function(test) { + var el = fragment( + '
  • %e

  • ', + test.title + ); appendToStack(el); updateStats(); }); @@ -2728,7 +3167,7 @@ function HTML(runner) { function updateStats() { // TODO: add to stats - var percent = stats.tests / runner.total * 100 | 0; + var percent = ((stats.tests / runner.total) * 100) | 0; if (progress) { progress.update(percent).draw(ctx); } @@ -2755,7 +3194,12 @@ function makeUrl(s) { search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?'); } - return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeRe(s)); + return ( + window.location.pathname + + (search ? search + '&' : '?') + + 'grep=' + + encodeURIComponent(escapeRe(s)) + ); } /** @@ -2815,8 +3259,10 @@ function fragment(html) { div.innerHTML = html.replace(/%([se])/g, function(_, type) { switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); + case 's': + return String(args[i++]); + case 'e': + return escape(args[i++]); // no default } }); @@ -2875,8 +3321,12 @@ function on(el, event, fn) { } } +HTML.browserOnly = true; + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../browser/progress":4,"../utils":38,"./base":17,"escape-string-regexp":47}],21:[function(require,module,exports){ +},{"../browser/progress":3,"../runner":34,"../utils":38,"./base":17,"escape-string-regexp":49}],21:[function(require,module,exports){ +'use strict'; + // Alias exports to a their normalized format Mocha#reporter to prevent a need // for dynamic (try/catch) requires, which Browserify doesn't handle. exports.Base = exports.base = require('./base'); @@ -2897,58 +3347,85 @@ exports.JSONStream = exports['json-stream'] = require('./json-stream'); },{"./base":17,"./doc":18,"./dot":19,"./html":20,"./json":23,"./json-stream":22,"./landing":24,"./list":25,"./markdown":26,"./min":27,"./nyan":28,"./progress":29,"./spec":30,"./tap":31,"./xunit":32}],22:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module JSONStream + */ /** * Module dependencies. */ var Base = require('./base'); -var JSON = require('json3'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; /** - * Expose `List`. + * Expose `JSONStream`. */ -exports = module.exports = List; +exports = module.exports = JSONStream; /** - * Initialize a new `List` test reporter. + * Constructs a new `JSONStream` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function List(runner) { - Base.call(this, runner); +function JSONStream(runner, options) { + Base.call(this, runner, options); var self = this; var total = runner.total; - runner.on('start', function() { - console.log(JSON.stringify(['start', { total: total }])); + runner.once(EVENT_RUN_BEGIN, function() { + writeEvent(['start', {total: total}]); }); - runner.on('pass', function(test) { - console.log(JSON.stringify(['pass', clean(test)])); + runner.on(EVENT_TEST_PASS, function(test) { + writeEvent(['pass', clean(test)]); }); - runner.on('fail', function(test, err) { + runner.on(EVENT_TEST_FAIL, function(test, err) { test = clean(test); test.err = err.message; test.stack = err.stack || null; - console.log(JSON.stringify(['fail', test])); + writeEvent(['fail', test]); }); - runner.on('end', function() { - process.stdout.write(JSON.stringify(['end', self.stats])); + runner.once(EVENT_RUN_END, function() { + writeEvent(['end', self.stats]); }); } /** - * Return a plain-object representation of `test` - * free of cyclic properties etc. + * Mocha event to be written to the output stream. + * @typedef {Array} JSONStream~MochaEvent + */ + +/** + * Writes Mocha event to reporter output stream. * - * @api private - * @param {Object} test - * @return {Object} + * @private + * @param {JSONStream~MochaEvent} event - Mocha event to be output. + */ +function writeEvent(event) { + process.stdout.write(JSON.stringify(event) + '\n'); +} + +/** + * Returns an object literal representation of `test` + * free of cyclic properties, etc. + * + * @private + * @param {Test} test - Instance used as data source. + * @return {Object} object containing pared-down test instance data */ function clean(test) { return { @@ -2959,14 +3436,26 @@ function clean(test) { }; } +JSONStream.description = 'newline delimited JSON events'; + }).call(this,require('_process')) -},{"./base":17,"_process":67,"json3":54}],23:[function(require,module,exports){ +},{"../runner":34,"./base":17,"_process":69}],23:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module JSON + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; /** * Expose `JSON`. @@ -2975,13 +3464,17 @@ var Base = require('./base'); exports = module.exports = JSONReporter; /** - * Initialize a new `JSON` reporter. + * Constructs a new `JSON` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class JSON + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function JSONReporter(runner) { - Base.call(this, runner); +function JSONReporter(runner, options) { + Base.call(this, runner, options); var self = this; var tests = []; @@ -2989,23 +3482,23 @@ function JSONReporter(runner) { var failures = []; var passes = []; - runner.on('test end', function(test) { + runner.on(EVENT_TEST_END, function(test) { tests.push(test); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { passes.push(test); }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { failures.push(test); }); - runner.on('pending', function(test) { + runner.on(EVENT_TEST_PENDING, function(test) { pending.push(test); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { var obj = { stats: self.stats, tests: tests.map(clean), @@ -3024,24 +3517,53 @@ function JSONReporter(runner) { * Return a plain-object representation of `test` * free of cyclic properties etc. * - * @api private + * @private * @param {Object} test * @return {Object} */ function clean(test) { + var err = test.err || {}; + if (err instanceof Error) { + err = errorJSON(err); + } + return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, currentRetry: test.currentRetry(), - err: errorJSON(test.err || {}) + err: cleanCycles(err) }; } /** - * Transform `error` into a JSON object. + * Replaces any circular references inside `obj` with '[object Object]' * - * @api private + * @private + * @param {Object} obj + * @return {Object} + */ +function cleanCycles(obj) { + var cache = []; + return JSON.parse( + JSON.stringify(obj, function(key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Instead of going in a circle, we'll print [object Object] + return '' + value; + } + cache.push(value); + } + + return value; + }) + ); +} + +/** + * Transform an Error object into a JSON object. + * + * @private * @param {Error} err * @return {Object} */ @@ -3053,15 +3575,27 @@ function errorJSON(err) { return res; } +JSONReporter.description = 'single JSON object'; + }).call(this,require('_process')) -},{"./base":17,"_process":67}],24:[function(require,module,exports){ +},{"../runner":34,"./base":17,"_process":69}],24:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Landing + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var STATE_FAILED = require('../runnable').constants.STATE_FAILED; + var cursor = Base.cursor; var color = Base.color; @@ -3090,16 +3624,20 @@ Base.colors['plane crash'] = 31; Base.colors.runway = 90; /** - * Initialize a new `Landing` reporter. + * Constructs a new `Landing` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Landing(runner) { - Base.call(this, runner); +function Landing(runner, options) { + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .75 | 0; + var width = (Base.window.width * 0.75) | 0; var total = runner.total; var stream = process.stdout; var plane = color('plane', '✈'); @@ -3111,17 +3649,17 @@ function Landing(runner) { return ' ' + color('runway', buf); } - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { stream.write('\n\n\n '); cursor.hide(); }); - runner.on('test end', function(test) { + runner.on(EVENT_TEST_END, function(test) { // check if the plane crashed - var col = crashed === -1 ? width * ++n / total | 0 : crashed; + var col = crashed === -1 ? ((width * ++n) / total) | 0 : crashed; // show the crash - if (test.state === 'failed') { + if (test.state === STATE_FAILED) { plane = color('plane crash', '✈'); crashed = col; } @@ -3137,7 +3675,7 @@ function Landing(runner) { stream.write('\u001b[0m'); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { cursor.show(); console.log(); self.epilogue(); @@ -3149,15 +3687,28 @@ function Landing(runner) { */ inherits(Landing, Base); +Landing.description = 'Unicode landing strip'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],25:[function(require,module,exports){ +},{"../runnable":33,"../runner":34,"../utils":38,"./base":17,"_process":69}],25:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module List + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_BEGIN = constants.EVENT_TEST_BEGIN; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; var color = Base.color; var cursor = Base.cursor; @@ -3168,45 +3719,49 @@ var cursor = Base.cursor; exports = module.exports = List; /** - * Initialize a new `List` test reporter. + * Constructs a new `List` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function List(runner) { - Base.call(this, runner); +function List(runner, options) { + Base.call(this, runner, options); var self = this; var n = 0; - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { console.log(); }); - runner.on('test', function(test) { + runner.on(EVENT_TEST_BEGIN, function(test) { process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); }); - runner.on('pending', function(test) { - var fmt = color('checkmark', ' -') - + color('pending', ' %s'); + runner.on(EVENT_TEST_PENDING, function(test) { + var fmt = color('checkmark', ' -') + color('pending', ' %s'); console.log(fmt, test.fullTitle()); }); - runner.on('pass', function(test) { - var fmt = color('checkmark', ' ' + Base.symbols.dot) - + color('pass', ' %s: ') - + color(test.speed, '%dms'); + runner.on(EVENT_TEST_PASS, function(test) { + var fmt = + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s: ') + + color(test.speed, '%dms'); cursor.CR(); console.log(fmt, test.fullTitle(), test.duration); }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { cursor.CR(); console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); - runner.on('end', self.epilogue.bind(self)); + runner.once(EVENT_RUN_END, self.epilogue.bind(self)); } /** @@ -3214,15 +3769,26 @@ function List(runner) { */ inherits(List, Base); +List.description = 'like "spec" reporter but flat'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],26:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],26:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Markdown + */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); +var constants = require('../runner').constants; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; /** * Constants @@ -3237,13 +3803,17 @@ var SUITE_PREFIX = '$'; exports = module.exports = Markdown; /** - * Initialize a new `Markdown` reporter. + * Constructs a new `Markdown` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Markdown(runner) { - Base.call(this, runner); +function Markdown(runner, options) { + Base.call(this, runner, options); var level = 0; var buf = ''; @@ -3256,7 +3826,7 @@ function Markdown(runner) { var ret = obj; var key = SUITE_PREFIX + suite.title; - obj = obj[key] = obj[key] || { suite: suite }; + obj = obj[key] = obj[key] || {suite: suite}; suite.suites.forEach(function(suite) { mapTOC(suite, obj); }); @@ -3289,18 +3859,18 @@ function Markdown(runner) { generateTOC(runner.suite); - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { ++level; var slug = utils.slug(suite.fullTitle()); buf += '' + '\n'; buf += title(suite.title) + '\n'; }); - runner.on('suite end', function() { + runner.on(EVENT_SUITE_END, function() { --level; }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { var code = utils.clean(test.body); buf += test.title + '.\n'; buf += '\n```js\n'; @@ -3308,22 +3878,31 @@ function Markdown(runner) { buf += '```\n\n'; }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { process.stdout.write('# TOC\n'); process.stdout.write(generateTOC(runner.suite)); process.stdout.write(buf); }); } +Markdown.description = 'GitHub Flavored Markdown'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],27:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],27:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Min + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; +var constants = require('../runner').constants; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; /** * Expose `Min`. @@ -3332,22 +3911,29 @@ var inherits = require('../utils').inherits; exports = module.exports = Min; /** - * Initialize a new `Min` minimal test reporter (best used with --watch). + * Constructs a new `Min` reporter instance. * - * @api public - * @param {Runner} runner + * @description + * This minimal test reporter is best used with '--watch'. + * + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Min(runner) { - Base.call(this, runner); +function Min(runner, options) { + Base.call(this, runner, options); - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { // clear screen process.stdout.write('\u001b[2J'); // set cursor position process.stdout.write('\u001b[1;3H'); }); - runner.on('end', this.epilogue.bind(this)); + runner.once(EVENT_RUN_END, this.epilogue.bind(this)); } /** @@ -3355,15 +3941,27 @@ function Min(runner) { */ inherits(Min, Base); +Min.description = 'essentially just a summary'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],28:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],28:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Nyan + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; var inherits = require('../utils').inherits; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; /** * Expose `Dot`. @@ -3372,18 +3970,21 @@ var inherits = require('../utils').inherits; exports = module.exports = NyanCat; /** - * Initialize a new `Dot` matrix test reporter. + * Constructs a new `Nyan` reporter instance. * - * @param {Runner} runner - * @api public + * @public + * @class Nyan + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ - -function NyanCat(runner) { - Base.call(this, runner); +function NyanCat(runner, options) { + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .75 | 0; - var nyanCatWidth = this.nyanCatWidth = 11; + var width = (Base.window.width * 0.75) | 0; + var nyanCatWidth = (this.nyanCatWidth = 11); this.colorIndex = 0; this.numberOfLines = 4; @@ -3391,26 +3992,26 @@ function NyanCat(runner) { this.scoreboardWidth = 5; this.tick = 0; this.trajectories = [[], [], [], []]; - this.trajectoryWidthMax = (width - nyanCatWidth); + this.trajectoryWidthMax = width - nyanCatWidth; - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { Base.cursor.hide(); self.draw(); }); - runner.on('pending', function() { + runner.on(EVENT_TEST_PENDING, function() { self.draw(); }); - runner.on('pass', function() { + runner.on(EVENT_TEST_PASS, function() { self.draw(); }); - runner.on('fail', function() { + runner.on(EVENT_TEST_FAIL, function() { self.draw(); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { Base.cursor.show(); for (var i = 0; i < self.numberOfLines; i++) { write('\n'); @@ -3427,7 +4028,7 @@ inherits(NyanCat, Base); /** * Draw the nyan cat * - * @api private + * @private */ NyanCat.prototype.draw = function() { @@ -3442,7 +4043,7 @@ NyanCat.prototype.draw = function() { * Draw the "scoreboard" showing the number * of passes, failures and pending tests. * - * @api private + * @private */ NyanCat.prototype.drawScoreboard = function() { @@ -3465,7 +4066,7 @@ NyanCat.prototype.drawScoreboard = function() { /** * Append the rainbow. * - * @api private + * @private */ NyanCat.prototype.appendRainbow = function() { @@ -3484,7 +4085,7 @@ NyanCat.prototype.appendRainbow = function() { /** * Draw the rainbow. * - * @api private + * @private */ NyanCat.prototype.drawRainbow = function() { @@ -3502,7 +4103,7 @@ NyanCat.prototype.drawRainbow = function() { /** * Draw the nyan cat * - * @api private + * @private */ NyanCat.prototype.drawNyanCat = function() { var self = this; @@ -3536,7 +4137,7 @@ NyanCat.prototype.drawNyanCat = function() { /** * Draw nyan cat face. * - * @api private + * @private * @return {string} */ @@ -3555,7 +4156,7 @@ NyanCat.prototype.face = function() { /** * Move cursor up `n`. * - * @api private + * @private * @param {number} n */ @@ -3566,7 +4167,7 @@ NyanCat.prototype.cursorUp = function(n) { /** * Move cursor down `n`. * - * @api private + * @private * @param {number} n */ @@ -3577,15 +4178,15 @@ NyanCat.prototype.cursorDown = function(n) { /** * Generate rainbow colors. * - * @api private + * @private * @return {Array} */ NyanCat.prototype.generateColors = function() { var colors = []; - for (var i = 0; i < (6 * 7); i++) { + for (var i = 0; i < 6 * 7; i++) { var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); + var n = i * (1.0 / 6); var r = Math.floor(3 * Math.sin(n) + 3); var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); @@ -3598,7 +4199,7 @@ NyanCat.prototype.generateColors = function() { /** * Apply rainbow to the given `str`. * - * @api private + * @private * @param {string} str * @return {string} */ @@ -3620,14 +4221,24 @@ function write(string) { process.stdout.write(string); } +NyanCat.description = '"nyan cat"'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],29:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],29:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Progress + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var EVENT_RUN_END = constants.EVENT_RUN_END; var inherits = require('../utils').inherits; var color = Base.color; var cursor = Base.cursor; @@ -3645,41 +4256,46 @@ exports = module.exports = Progress; Base.colors.progress = 90; /** - * Initialize a new `Progress` bar test reporter. + * Constructs a new `Progress` reporter instance. * - * @api public - * @param {Runner} runner - * @param {Object} options + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ function Progress(runner, options) { - Base.call(this, runner); + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .50 | 0; + var width = (Base.window.width * 0.5) | 0; var total = runner.total; var complete = 0; var lastN = -1; // default chars options = options || {}; - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; + var reporterOptions = options.reporterOptions || {}; + + options.open = reporterOptions.open || '['; + options.complete = reporterOptions.complete || '▬'; + options.incomplete = reporterOptions.incomplete || Base.symbols.dot; + options.close = reporterOptions.close || ']'; + options.verbose = reporterOptions.verbose || false; // tests started - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { console.log(); cursor.hide(); }); // tests complete - runner.on('test end', function() { + runner.on(EVENT_TEST_END, function() { complete++; var percent = complete / total; - var n = width * percent | 0; + var n = (width * percent) | 0; var i = width - n; if (n === lastN && !options.verbose) { @@ -3701,7 +4317,7 @@ function Progress(runner, options) { // tests are complete, output some stats // and the failures if any - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { cursor.show(); console.log(); self.epilogue(); @@ -3713,13 +4329,27 @@ function Progress(runner, options) { */ inherits(Progress, Base); +Progress.description = 'a progress bar'; + }).call(this,require('_process')) -},{"../utils":38,"./base":17,"_process":67}],30:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],30:[function(require,module,exports){ +'use strict'; +/** + * @module Spec + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; var inherits = require('../utils').inherits; var color = Base.color; @@ -3730,13 +4360,17 @@ var color = Base.color; exports = module.exports = Spec; /** - * Initialize a new `Spec` test reporter. + * Constructs a new `Spec` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Spec(runner) { - Base.call(this, runner); +function Spec(runner, options) { + Base.call(this, runner, options); var self = this; var indents = 0; @@ -3746,48 +4380,50 @@ function Spec(runner) { return Array(indents).join(' '); } - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { console.log(); }); - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { ++indents; console.log(color('suite', '%s%s'), indent(), suite.title); }); - runner.on('suite end', function() { + runner.on(EVENT_SUITE_END, function() { --indents; if (indents === 1) { console.log(); } }); - runner.on('pending', function(test) { + runner.on(EVENT_TEST_PENDING, function(test) { var fmt = indent() + color('pending', ' - %s'); console.log(fmt, test.title); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { var fmt; if (test.speed === 'fast') { - fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s'); + fmt = + indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s'); console.log(fmt, test.title); } else { - fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s') - + color(test.speed, ' (%dms)'); + fmt = + indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s') + + color(test.speed, ' (%dms)'); console.log(fmt, test.title, test.duration); } }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); }); - runner.on('end', self.epilogue.bind(self)); + runner.once(EVENT_RUN_END, self.epilogue.bind(self)); } /** @@ -3795,12 +4431,29 @@ function Spec(runner) { */ inherits(Spec, Base); -},{"../utils":38,"./base":17}],31:[function(require,module,exports){ +Spec.description = 'hierarchical & verbose [default]'; + +},{"../runner":34,"../utils":38,"./base":17}],31:[function(require,module,exports){ +(function (process){ +'use strict'; +/** + * @module TAP + */ /** * Module dependencies. */ +var util = require('util'); var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var inherits = require('../utils').inherits; +var sprintf = util.format; /** * Expose `TAP`. @@ -3809,87 +4462,305 @@ var Base = require('./base'); exports = module.exports = TAP; /** - * Initialize a new `TAP` reporter. + * Constructs a new `TAP` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function TAP(runner) { - Base.call(this, runner); +function TAP(runner, options) { + Base.call(this, runner, options); + var self = this; var n = 1; - var passes = 0; - var failures = 0; - runner.on('start', function() { - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); + var tapVersion = '12'; + if (options && options.reporterOptions) { + if (options.reporterOptions.tapVersion) { + tapVersion = options.reporterOptions.tapVersion.toString(); + } + } + + this._producer = createProducer(tapVersion); + + runner.once(EVENT_RUN_BEGIN, function() { + var ntests = runner.grepTotal(runner.suite); + self._producer.writeVersion(); + self._producer.writePlan(ntests); }); - runner.on('test end', function() { + runner.on(EVENT_TEST_END, function() { ++n; }); - runner.on('pending', function(test) { - console.log('ok %d %s # SKIP -', n, title(test)); + runner.on(EVENT_TEST_PENDING, function(test) { + self._producer.writePending(n, test); }); - runner.on('pass', function(test) { - passes++; - console.log('ok %d %s', n, title(test)); + runner.on(EVENT_TEST_PASS, function(test) { + self._producer.writePass(n, test); }); - runner.on('fail', function(test, err) { - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) { - console.log(err.stack.replace(/^/gm, ' ')); - } + runner.on(EVENT_TEST_FAIL, function(test, err) { + self._producer.writeFail(n, test, err); }); - runner.on('end', function() { - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); + runner.once(EVENT_RUN_END, function() { + self._producer.writeEpilogue(runner.stats); }); } /** - * Return a TAP-safe title of `test` + * Inherit from `Base.prototype`. + */ +inherits(TAP, Base); + +/** + * Returns a TAP-safe title of `test`. * - * @api private - * @param {Object} test - * @return {String} + * @private + * @param {Test} test - Test instance. + * @return {String} title with any hash character removed */ function title(test) { return test.fullTitle().replace(/#/g, ''); } -},{"./base":17}],32:[function(require,module,exports){ +/** + * Writes newline-terminated formatted string to reporter output stream. + * + * @private + * @param {string} format - `printf`-like format string + * @param {...*} [varArgs] - Format string arguments + */ +function println(format, varArgs) { + var vargs = Array.from(arguments); + vargs[0] += '\n'; + process.stdout.write(sprintf.apply(null, vargs)); +} + +/** + * Returns a `tapVersion`-appropriate TAP producer instance, if possible. + * + * @private + * @param {string} tapVersion - Version of TAP specification to produce. + * @returns {TAPProducer} specification-appropriate instance + * @throws {Error} if specification version has no associated producer. + */ +function createProducer(tapVersion) { + var producers = { + '12': new TAP12Producer(), + '13': new TAP13Producer() + }; + var producer = producers[tapVersion]; + + if (!producer) { + throw new Error( + 'invalid or unsupported TAP version: ' + JSON.stringify(tapVersion) + ); + } + + return producer; +} + +/** + * @summary + * Constructs a new TAPProducer. + * + * @description + * Only to be used as an abstract base class. + * + * @private + * @constructor + */ +function TAPProducer() {} + +/** + * Writes the TAP version to reporter output stream. + * + * @abstract + */ +TAPProducer.prototype.writeVersion = function() {}; + +/** + * Writes the plan to reporter output stream. + * + * @abstract + * @param {number} ntests - Number of tests that are planned to run. + */ +TAPProducer.prototype.writePlan = function(ntests) { + println('%d..%d', 1, ntests); +}; + +/** + * Writes that test passed to reporter output stream. + * + * @abstract + * @param {number} n - Index of test that passed. + * @param {Test} test - Instance containing test information. + */ +TAPProducer.prototype.writePass = function(n, test) { + println('ok %d %s', n, title(test)); +}; + +/** + * Writes that test was skipped to reporter output stream. + * + * @abstract + * @param {number} n - Index of test that was skipped. + * @param {Test} test - Instance containing test information. + */ +TAPProducer.prototype.writePending = function(n, test) { + println('ok %d %s # SKIP -', n, title(test)); +}; + +/** + * Writes that test failed to reporter output stream. + * + * @abstract + * @param {number} n - Index of test that failed. + * @param {Test} test - Instance containing test information. + * @param {Error} err - Reason the test failed. + */ +TAPProducer.prototype.writeFail = function(n, test, err) { + println('not ok %d %s', n, title(test)); +}; + +/** + * Writes the summary epilogue to reporter output stream. + * + * @abstract + * @param {Object} stats - Object containing run statistics. + */ +TAPProducer.prototype.writeEpilogue = function(stats) { + // :TBD: Why is this not counting pending tests? + println('# tests ' + (stats.passes + stats.failures)); + println('# pass ' + stats.passes); + // :TBD: Why are we not showing pending results? + println('# fail ' + stats.failures); +}; + +/** + * @summary + * Constructs a new TAP12Producer. + * + * @description + * Produces output conforming to the TAP12 specification. + * + * @private + * @constructor + * @extends TAPProducer + * @see {@link https://testanything.org/tap-specification.html|Specification} + */ +function TAP12Producer() { + /** + * Writes that test failed to reporter output stream, with error formatting. + * @override + */ + this.writeFail = function(n, test, err) { + TAPProducer.prototype.writeFail.call(this, n, test, err); + if (err.message) { + println(err.message.replace(/^/gm, ' ')); + } + if (err.stack) { + println(err.stack.replace(/^/gm, ' ')); + } + }; +} + +/** + * Inherit from `TAPProducer.prototype`. + */ +inherits(TAP12Producer, TAPProducer); + +/** + * @summary + * Constructs a new TAP13Producer. + * + * @description + * Produces output conforming to the TAP13 specification. + * + * @private + * @constructor + * @extends TAPProducer + * @see {@link https://testanything.org/tap-version-13-specification.html|Specification} + */ +function TAP13Producer() { + /** + * Writes the TAP version to reporter output stream. + * @override + */ + this.writeVersion = function() { + println('TAP version 13'); + }; + + /** + * Writes that test failed to reporter output stream, with error formatting. + * @override + */ + this.writeFail = function(n, test, err) { + TAPProducer.prototype.writeFail.call(this, n, test, err); + var emitYamlBlock = err.message != null || err.stack != null; + if (emitYamlBlock) { + println(indent(1) + '---'); + if (err.message) { + println(indent(2) + 'message: |-'); + println(err.message.replace(/^/gm, indent(3))); + } + if (err.stack) { + println(indent(2) + 'stack: |-'); + println(err.stack.replace(/^/gm, indent(3))); + } + println(indent(1) + '...'); + } + }; + + function indent(level) { + return Array(level + 1).join(' '); + } +} + +/** + * Inherit from `TAPProducer.prototype`. + */ +inherits(TAP13Producer, TAPProducer); + +TAP.description = 'TAP-compatible output'; + +}).call(this,require('_process')) +},{"../runner":34,"../utils":38,"./base":17,"_process":69,"util":89}],32:[function(require,module,exports){ (function (process,global){ +'use strict'; +/** + * @module XUnit + */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); -var inherits = utils.inherits; var fs = require('fs'); -var escape = utils.escape; var mkdirp = require('mkdirp'); var path = require('path'); +var errors = require('../errors'); +var createUnsupportedError = errors.createUnsupportedError; +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var STATE_FAILED = require('../runnable').constants.STATE_FAILED; +var inherits = utils.inherits; +var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ - -/* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `XUnit`. @@ -3898,48 +4769,73 @@ var clearInterval = global.clearInterval; exports = module.exports = XUnit; /** - * Initialize a new `XUnit` reporter. + * Constructs a new `XUnit` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ function XUnit(runner, options) { - Base.call(this, runner); + Base.call(this, runner, options); var stats = this.stats; var tests = []; var self = this; - if (options.reporterOptions && options.reporterOptions.output) { - if (!fs.createWriteStream) { - throw new Error('file output not supported in browser'); + // the name of the test suite, as it will appear in the resulting XML file + var suiteName; + + // the default name of the test suite if none is provided + var DEFAULT_SUITE_NAME = 'Mocha Tests'; + + if (options && options.reporterOptions) { + if (options.reporterOptions.output) { + if (!fs.createWriteStream) { + throw createUnsupportedError('file output not supported in browser'); + } + + mkdirp.sync(path.dirname(options.reporterOptions.output)); + self.fileStream = fs.createWriteStream(options.reporterOptions.output); } - mkdirp.sync(path.dirname(options.reporterOptions.output)); - self.fileStream = fs.createWriteStream(options.reporterOptions.output); + + // get the suite name from the reporter options (if provided) + suiteName = options.reporterOptions.suiteName; } - runner.on('pending', function(test) { + // fall back to the default suite name + suiteName = suiteName || DEFAULT_SUITE_NAME; + + runner.on(EVENT_TEST_PENDING, function(test) { tests.push(test); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { tests.push(test); }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { tests.push(test); }); - runner.on('end', function() { - self.write(tag('testsuite', { - name: 'Mocha Tests', - tests: stats.tests, - failures: stats.failures, - errors: stats.failures, - skipped: stats.tests - stats.failures - stats.passes, - timestamp: (new Date()).toUTCString(), - time: (stats.duration / 1000) || 0 - }, false)); + runner.once(EVENT_RUN_END, function() { + self.write( + tag( + 'testsuite', + { + name: suiteName, + tests: stats.tests, + failures: 0, + errors: stats.failures, + skipped: stats.tests - stats.failures - stats.passes, + timestamp: new Date().toUTCString(), + time: stats.duration / 1000 || 0 + }, + false + ) + ); tests.forEach(function(t) { self.test(t); @@ -3991,15 +4887,33 @@ XUnit.prototype.write = function(line) { * @param {Test} test */ XUnit.prototype.test = function(test) { + Base.useColors = false; + var attrs = { classname: test.parent.fullTitle(), name: test.title, - time: (test.duration / 1000) || 0 + time: test.duration / 1000 || 0 }; - if (test.state === 'failed') { + if (test.state === STATE_FAILED) { var err = test.err; - this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack)))); + var diff = + Base.hideDiff || !err.actual || !err.expected + ? '' + : '\n' + Base.generateDiff(err.actual, err.expected); + this.write( + tag( + 'testcase', + attrs, + false, + tag( + 'failure', + {}, + false, + escape(err.message) + escape(diff) + '\n' + escape(err.stack) + ) + ) + ); } else if (test.isPending()) { this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); } else { @@ -4034,53 +4948,39 @@ function tag(name, attrs, close, content) { return tag; } +XUnit.description = 'XUnit-compatible XML output'; + }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../utils":38,"./base":17,"_process":67,"fs":42,"mkdirp":64,"path":42}],33:[function(require,module,exports){ +},{"../errors":6,"../runnable":33,"../runner":34,"../utils":38,"./base":17,"_process":69,"fs":42,"mkdirp":59,"path":42}],33:[function(require,module,exports){ (function (global){ -/** - * Module dependencies. - */ +'use strict'; var EventEmitter = require('events').EventEmitter; -var JSON = require('json3'); var Pending = require('./pending'); var debug = require('debug')('mocha:runnable'); -var milliseconds = require('./ms'); +var milliseconds = require('ms'); var utils = require('./utils'); -var create = require('lodash.create'); +var createInvalidExceptionError = require('./errors') + .createInvalidExceptionError; /** * Save timer references to avoid Sinon interfering (see GH-237). */ - -/* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; -var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** - * Object#toString(). - */ - var toString = Object.prototype.toString; -/** - * Expose `Runnable`. - */ - module.exports = Runnable; /** * Initialize a new `Runnable` with the given `title` and callback `fn`. * + * @class + * @extends external:EventEmitter + * @public * @param {String} title * @param {Function} fn - * @api private - * @param {string} title - * @param {Function} fn */ function Runnable(title, fn) { this.title = title; @@ -4092,7 +4992,6 @@ function Runnable(title, fn) { this._slow = 75; this._enableTimeouts = true; this.timedOut = false; - this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; this.pending = false; @@ -4101,28 +5000,46 @@ function Runnable(title, fn) { /** * Inherit from `EventEmitter.prototype`. */ -Runnable.prototype = create(EventEmitter.prototype, { - constructor: Runnable -}); +utils.inherits(Runnable, EventEmitter); /** - * Set & get timeout `ms`. + * Get current timeout value in msecs. * - * @api private - * @param {number|string} ms - * @return {Runnable|number} ms or Runnable instance. + * @private + * @returns {number} current timeout threshold value + */ +/** + * @summary + * Set timeout threshold value (msecs). + * + * @description + * A string argument can use shorthand (e.g., "2s") and will be converted. + * The value will be clamped to range [0, 2^31-1]. + * If clamped value matches either range endpoint, timeouts will be disabled. + * + * @private + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value} + * @param {number|string} ms - Timeout threshold value. + * @returns {Runnable} this + * @chainable */ Runnable.prototype.timeout = function(ms) { if (!arguments.length) { return this._timeout; } - // see #1652 for reasoning - if (ms === 0 || ms > Math.pow(2, 31)) { - this._enableTimeouts = false; - } if (typeof ms === 'string') { ms = milliseconds(ms); } + + // Clamp to range + var INT_MAX = Math.pow(2, 31) - 1; + var range = [0, INT_MAX]; + ms = utils.clamp(ms, range); + + // see #1652 for reasoning + if (ms === range[0] || ms === range[1]) { + this._enableTimeouts = false; + } debug('timeout %d', ms); this._timeout = ms; if (this.timer) { @@ -4132,20 +5049,20 @@ Runnable.prototype.timeout = function(ms) { }; /** - * Set & get slow `ms`. + * Set or get slow `ms`. * - * @api private + * @private * @param {number|string} ms * @return {Runnable|number} ms or Runnable instance. */ Runnable.prototype.slow = function(ms) { - if (typeof ms === 'undefined') { + if (!arguments.length || typeof ms === 'undefined') { return this._slow; } if (typeof ms === 'string') { ms = milliseconds(ms); } - debug('timeout %d', ms); + debug('slow %d', ms); this._slow = ms; return this; }; @@ -4153,7 +5070,7 @@ Runnable.prototype.slow = function(ms) { /** * Set and get whether timeout is `enabled`. * - * @api private + * @private * @param {boolean} enabled * @return {Runnable|boolean} enabled or Runnable instance. */ @@ -4169,7 +5086,8 @@ Runnable.prototype.enableTimeouts = function(enabled) { /** * Halt and mark as pending. * - * @api public + * @memberof Mocha.Runnable + * @public */ Runnable.prototype.skip = function() { throw new Pending('sync skip'); @@ -4178,16 +5096,34 @@ Runnable.prototype.skip = function() { /** * Check if this runnable or its parent suite is marked as pending. * - * @api private + * @private */ Runnable.prototype.isPending = function() { return this.pending || (this.parent && this.parent.isPending()); }; /** - * Set number of retries. + * Return `true` if this Runnable has failed. + * @return {boolean} + * @private + */ +Runnable.prototype.isFailed = function() { + return !this.isPending() && this.state === constants.STATE_FAILED; +}; + +/** + * Return `true` if this Runnable has passed. + * @return {boolean} + * @private + */ +Runnable.prototype.isPassed = function() { + return !this.isPending() && this.state === constants.STATE_PASSED; +}; + +/** + * Set or get number of retries. * - * @api private + * @private */ Runnable.prototype.retries = function(n) { if (!arguments.length) { @@ -4197,9 +5133,9 @@ Runnable.prototype.retries = function(n) { }; /** - * Get current retry + * Set or get current retry * - * @api private + * @private */ Runnable.prototype.currentRetry = function(n) { if (!arguments.length) { @@ -4212,17 +5148,29 @@ Runnable.prototype.currentRetry = function(n) { * Return the full title generated by recursively concatenating the parent's * full title. * - * @api public + * @memberof Mocha.Runnable + * @public * @return {string} */ Runnable.prototype.fullTitle = function() { - return this.parent.fullTitle() + ' ' + this.title; + return this.titlePath().join(' '); +}; + +/** + * Return the title path generated by concatenating the parent's title path with the title. + * + * @memberof Mocha.Runnable + * @public + * @return {string} + */ +Runnable.prototype.titlePath = function() { + return this.parent.titlePath().concat([this.title]); }; /** * Clear the timeout. * - * @api private + * @private */ Runnable.prototype.clearTimeout = function() { clearTimeout(this.timer); @@ -4231,28 +5179,32 @@ Runnable.prototype.clearTimeout = function() { /** * Inspect the runnable void of private properties. * - * @api private + * @private * @return {string} */ Runnable.prototype.inspect = function() { - return JSON.stringify(this, function(key, val) { - if (key[0] === '_') { - return; - } - if (key === 'parent') { - return '#'; - } - if (key === 'ctx') { - return '#'; - } - return val; - }, 2); + return JSON.stringify( + this, + function(key, val) { + if (key[0] === '_') { + return; + } + if (key === 'parent') { + return '#'; + } + if (key === 'ctx') { + return '#'; + } + return val; + }, + 2 + ); }; /** * Reset the timeout. * - * @api private + * @private */ Runnable.prototype.resetTimeout = function() { var self = this; @@ -4266,15 +5218,15 @@ Runnable.prototype.resetTimeout = function() { if (!self._enableTimeouts) { return; } - self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.')); + self.callback(self._timeoutError(ms)); self.timedOut = true; }, ms); }; /** - * Whitelist a list of globals for this test run. + * Set or get a list of whitelisted globals for this test run. * - * @api private + * @private * @param {string[]} globals */ Runnable.prototype.globals = function(globals) { @@ -4288,7 +5240,7 @@ Runnable.prototype.globals = function(globals) { * Run the test and invoke `fn(err)`. * * @param {Function} fn - * @api private + * @private */ Runnable.prototype.run = function(fn) { var self = this; @@ -4308,7 +5260,13 @@ Runnable.prototype.run = function(fn) { return; } emitted = true; - self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); + var msg = 'done() called multiple times'; + if (err && err.message) { + err.message += " (and Mocha's " + msg + ')'; + self.emit('error', err); + } else { + self.emit('error', new Error(msg)); + } } // finished @@ -4317,15 +5275,16 @@ Runnable.prototype.run = function(fn) { if (self.timedOut) { return; } + if (finished) { - return multiple(err || self._trace); + return multiple(err); } self.clearTimeout(); self.duration = new Date() - start; finished = true; if (!err && self.duration > ms && self._enableTimeouts) { - err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'); + err = self._timeoutError(ms); } fn(err); } @@ -4352,18 +5311,22 @@ Runnable.prototype.run = function(fn) { try { callFnAsync(this.fn); } catch (err) { - done(utils.getError(err)); + emitted = true; + done(Runnable.toValueOrError(err)); } return; } if (this.allowUncaught) { - callFn(this.fn); - done(); - return; - } - - // sync or promise-returning + if (this.isPending()) { + done(); + } else { + callFn(this.fn); + } + return; + } + + // sync or promise-returning try { if (this.isPending()) { done(); @@ -4371,15 +5334,16 @@ Runnable.prototype.run = function(fn) { callFn(this.fn); } } catch (err) { - done(utils.getError(err)); + emitted = true; + done(Runnable.toValueOrError(err)); } function callFn(fn) { var result = fn.call(ctx); if (result && typeof result.then === 'function') { self.resetTimeout(); - result - .then(function() { + result.then( + function() { done(); // Return null so libraries like bluebird do not warn about // subsequently constructed Promises. @@ -4387,10 +5351,15 @@ Runnable.prototype.run = function(fn) { }, function(reason) { done(reason || new Error('Promise rejected with no or falsy reason')); - }); + } + ); } else { if (self.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()` or returning a promise')); + return done( + new Error( + '--async-only option in use without declaring `done()` or returning a promise' + ) + ); } done(); @@ -4404,13 +5373,18 @@ Runnable.prototype.run = function(fn) { } if (err) { if (Object.prototype.toString.call(err) === '[object Object]') { - return done(new Error('done() invoked with non-Error: ' - + JSON.stringify(err))); + return done( + new Error('done() invoked with non-Error: ' + JSON.stringify(err)) + ); } return done(new Error('done() invoked with non-Error: ' + err)); } if (result && utils.isPromise(result)) { - return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.')); + return done( + new Error( + 'Resolution method is overspecified. Specify a callback *or* return a Promise; not both.' + ) + ); } done(); @@ -4418,33 +5392,100 @@ Runnable.prototype.run = function(fn) { } }; +/** + * Instantiates a "timeout" error + * + * @param {number} ms - Timeout (in milliseconds) + * @returns {Error} a "timeout" error + * @private + */ +Runnable.prototype._timeoutError = function(ms) { + var msg = + 'Timeout of ' + + ms + + 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.'; + if (this.file) { + msg += ' (' + this.file + ')'; + } + return new Error(msg); +}; + +var constants = utils.defineConstants( + /** + * {@link Runnable}-related constants. + * @public + * @memberof Runnable + * @readonly + * @static + * @alias constants + * @enum {string} + */ + { + /** + * Value of `state` prop when a `Runnable` has failed + */ + STATE_FAILED: 'failed', + /** + * Value of `state` prop when a `Runnable` has passed + */ + STATE_PASSED: 'passed' + } +); + +/** + * Given `value`, return identity if truthy, otherwise create an "invalid exception" error and return that. + * @param {*} [value] - Value to return, if present + * @returns {*|Error} `value`, otherwise an `Error` + * @private + */ +Runnable.toValueOrError = function(value) { + return ( + value || + createInvalidExceptionError( + 'Runnable failed with falsy or undefined exception. Please throw an Error instead.', + value + ) + ); +}; + +Runnable.constants = constants; + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./ms":15,"./pending":16,"./utils":38,"debug":2,"events":3,"json3":54,"lodash.create":60}],34:[function(require,module,exports){ +},{"./errors":6,"./pending":16,"./utils":38,"debug":45,"events":50,"ms":60}],34:[function(require,module,exports){ (function (process,global){ +'use strict'; + /** * Module dependencies. */ - +var util = require('util'); var EventEmitter = require('events').EventEmitter; var Pending = require('./pending'); var utils = require('./utils'); var inherits = utils.inherits; var debug = require('debug')('mocha:runner'); var Runnable = require('./runnable'); -var filter = utils.filter; -var indexOf = utils.indexOf; -var some = utils.some; -var keys = utils.keys; +var Suite = require('./suite'); +var HOOK_TYPE_BEFORE_EACH = Suite.constants.HOOK_TYPE_BEFORE_EACH; +var HOOK_TYPE_AFTER_EACH = Suite.constants.HOOK_TYPE_AFTER_EACH; +var HOOK_TYPE_AFTER_ALL = Suite.constants.HOOK_TYPE_AFTER_ALL; +var HOOK_TYPE_BEFORE_ALL = Suite.constants.HOOK_TYPE_BEFORE_ALL; +var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN; +var STATE_FAILED = Runnable.constants.STATE_FAILED; +var STATE_PASSED = Runnable.constants.STATE_PASSED; +var dQuote = utils.dQuote; +var ngettext = utils.ngettext; +var sQuote = utils.sQuote; var stackFilter = utils.stackTraceFilter(); var stringify = utils.stringify; var type = utils.type; -var undefinedError = utils.undefinedError; -var isArray = utils.isArray; +var createInvalidExceptionError = require('./errors') + .createInvalidExceptionError; /** * Non-enumerable globals. + * @readonly */ - var globals = [ 'setTimeout', 'clearTimeout', @@ -4456,30 +5497,84 @@ var globals = [ 'clearImmediate' ]; -/** - * Expose `Runner`. - */ +var constants = utils.defineConstants( + /** + * {@link Runner}-related constants. + * @public + * @memberof Runner + * @readonly + * @alias constants + * @static + * @enum {string} + */ + { + /** + * Emitted when {@link Hook} execution begins + */ + EVENT_HOOK_BEGIN: 'hook', + /** + * Emitted when {@link Hook} execution ends + */ + EVENT_HOOK_END: 'hook end', + /** + * Emitted when Root {@link Suite} execution begins (all files have been parsed and hooks/tests are ready for execution) + */ + EVENT_RUN_BEGIN: 'start', + /** + * Emitted when Root {@link Suite} execution has been delayed via `delay` option + */ + EVENT_DELAY_BEGIN: 'waiting', + /** + * Emitted when delayed Root {@link Suite} execution is triggered by user via `global.run()` + */ + EVENT_DELAY_END: 'ready', + /** + * Emitted when Root {@link Suite} execution ends + */ + EVENT_RUN_END: 'end', + /** + * Emitted when {@link Suite} execution begins + */ + EVENT_SUITE_BEGIN: 'suite', + /** + * Emitted when {@link Suite} execution ends + */ + EVENT_SUITE_END: 'suite end', + /** + * Emitted when {@link Test} execution begins + */ + EVENT_TEST_BEGIN: 'test', + /** + * Emitted when {@link Test} execution ends + */ + EVENT_TEST_END: 'test end', + /** + * Emitted when {@link Test} execution fails + */ + EVENT_TEST_FAIL: 'fail', + /** + * Emitted when {@link Test} execution succeeds + */ + EVENT_TEST_PASS: 'pass', + /** + * Emitted when {@link Test} becomes pending + */ + EVENT_TEST_PENDING: 'pending', + /** + * Emitted when {@link Test} execution has failed, but will retry + */ + EVENT_TEST_RETRY: 'retry' + } +); module.exports = Runner; /** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending + * Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}. * - * @api public + * @extends external:EventEmitter + * @public + * @class * @param {Suite} suite Root suite * @param {boolean} [delay] Whether or not to delay execution of root suite * until ready. @@ -4493,10 +5588,10 @@ function Runner(suite, delay) { this.started = false; this.total = suite.total(); this.failures = 0; - this.on('test end', function(test) { + this.on(constants.EVENT_TEST_END, function(test) { self.checkGlobals(test); }); - this.on('hook end', function(hook) { + this.on(constants.EVENT_HOOK_END, function(hook) { self.checkGlobals(hook); }); this._defaultGrep = /.*/; @@ -4508,7 +5603,7 @@ function Runner(suite, delay) { * Wrapper for setImmediate, process.nextTick, or browser polyfill. * * @param {Function} fn - * @api private + * @private */ Runner.immediately = global.setImmediate || process.nextTick; @@ -4521,10 +5616,8 @@ inherits(Runner, EventEmitter); * Run tests with full titles matching `re`. Updates runner.total * with number of tests matched. * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public + * @public + * @memberof Runner * @param {RegExp} re * @param {boolean} invert * @return {Runner} Runner instance. @@ -4541,9 +5634,8 @@ Runner.prototype.grep = function(re, invert) { * Returns the number of tests matching the grep search for the * given suite. * - * @param {Suite} suite - * @return {Number} - * @api public + * @memberof Runner + * @public * @param {Suite} suite * @return {number} */ @@ -4568,14 +5660,14 @@ Runner.prototype.grepTotal = function(suite) { * Return a list of global properties. * * @return {Array} - * @api private + * @private */ Runner.prototype.globalProps = function() { - var props = keys(global); + var props = Object.keys(global); // non-enumerables for (var i = 0; i < globals.length; ++i) { - if (~indexOf(props, globals[i])) { + if (~props.indexOf(globals[i])) { continue; } props.push(globals[i]); @@ -4587,9 +5679,8 @@ Runner.prototype.globalProps = function() { /** * Allow the given `arr` of globals. * - * @param {Array} arr - * @return {Runner} for chaining - * @api public + * @public + * @memberof Runner * @param {Array} arr * @return {Runner} Runner instance. */ @@ -4605,7 +5696,7 @@ Runner.prototype.globals = function(arr) { /** * Check for global variable leaks. * - * @api private + * @private */ Runner.prototype.checkGlobals = function(test) { if (this.ignoreLeaks) { @@ -4628,17 +5719,21 @@ Runner.prototype.checkGlobals = function(test) { leaks = filterLeaks(ok, globals); this._globals = this._globals.concat(leaks); - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); + if (leaks.length) { + var format = ngettext( + leaks.length, + 'global leak detected: %s', + 'global leaks detected: %s' + ); + var error = new Error(util.format(format, leaks.map(sQuote).join(', '))); + this.fail(test, error); } }; /** * Fail the given `test`. * - * @api private + * @private * @param {Test} test * @param {Error} err */ @@ -4648,24 +5743,28 @@ Runner.prototype.fail = function(test, err) { } ++this.failures; - test.state = 'failed'; + test.state = STATE_FAILED; - if (!(err instanceof Error || err && typeof err.message === 'string')) { - err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); + if (!isError(err)) { + err = thrown2Error(err); } - err.stack = (this.fullStackTrace || !err.stack) - ? err.stack - : stackFilter(err.stack); + try { + err.stack = + this.fullStackTrace || !err.stack ? err.stack : stackFilter(err.stack); + } catch (ignore) { + // some environments do not take kindly to monkeying with the stack + } - this.emit('fail', test, err); + this.emit(constants.EVENT_TEST_FAIL, test, err); }; /** * Fail the given `hook` with `err`. * * Hook failures work in the following pattern: - * - If bail, then exit + * - If bail, run corresponding `after each` and `after` hooks, + * then exit * - Failed `before` hook skips all tests in a suite and subsuites, * but jumps to corresponding `after` hook * - Failed `before each` hook skips remaining tests in a @@ -4677,33 +5776,39 @@ Runner.prototype.fail = function(test, err) { * suite and subsuites, but executes other `after each` * hooks * - * @api private + * @private * @param {Hook} hook * @param {Error} err */ Runner.prototype.failHook = function(hook, err) { + hook.originalTitle = hook.originalTitle || hook.title; if (hook.ctx && hook.ctx.currentTest) { - hook.originalTitle = hook.originalTitle || hook.title; - hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"'; + hook.title = + hook.originalTitle + ' for ' + dQuote(hook.ctx.currentTest.title); + } else { + var parentTitle; + if (hook.parent.title) { + parentTitle = hook.parent.title; + } else { + parentTitle = hook.parent.root ? '{root}' : ''; + } + hook.title = hook.originalTitle + ' in ' + dQuote(parentTitle); } this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } }; /** * Run hook `name` callbacks and then invoke `fn()`. * - * @api private + * @private * @param {string} name * @param {Function} fn */ Runner.prototype.hook = function(name, fn) { var suite = this.suite; - var hooks = suite['_' + name]; + var hooks = suite.getHooks(name); var self = this; function next(i) { @@ -4713,9 +5818,17 @@ Runner.prototype.hook = function(name, fn) { } self.currentRunnable = hook; - hook.ctx.currentTest = self.test; + if (name === HOOK_TYPE_BEFORE_ALL) { + hook.ctx.currentTest = hook.parent.tests[0]; + } else if (name === HOOK_TYPE_AFTER_ALL) { + hook.ctx.currentTest = hook.parent.tests[hook.parent.tests.length - 1]; + } else { + hook.ctx.currentTest = self.test; + } + + hook.allowUncaught = self.allowUncaught; - self.emit('hook', hook); + self.emit(constants.EVENT_HOOK_BEGIN, hook); if (!hook.listeners('error').length) { hook.on('error', function(err) { @@ -4730,12 +5843,23 @@ Runner.prototype.hook = function(name, fn) { } if (err) { if (err instanceof Pending) { - if (name === 'beforeEach' || name === 'afterEach') { - self.test.pending = true; + if (name === HOOK_TYPE_AFTER_ALL) { + utils.deprecate( + 'Skipping a test within an "after all" hook is DEPRECATED and will throw an exception in a future version of Mocha. ' + + 'Use a return statement or other means to abort hook execution.' + ); + } + if (name === HOOK_TYPE_BEFORE_EACH || name === HOOK_TYPE_AFTER_EACH) { + if (self.test) { + self.test.pending = true; + } } else { - utils.forEach(suite.tests, function(test) { + suite.tests.forEach(function(test) { test.pending = true; }); + suite.suites.forEach(function(suite) { + suite.pending = true; + }); // a pending hook won't be executed twice. hook.pending = true; } @@ -4746,7 +5870,7 @@ Runner.prototype.hook = function(name, fn) { return fn(err); } } - self.emit('hook end', hook); + self.emit(constants.EVENT_HOOK_END, hook); delete hook.ctx.currentTest; next(++i); }); @@ -4761,7 +5885,7 @@ Runner.prototype.hook = function(name, fn) { * Run hook `name` for the given array of `suites` * in order, and callback `fn(err, errSuite)`. * - * @api private + * @private * @param {string} name * @param {Array} suites * @param {Function} fn @@ -4797,7 +5921,7 @@ Runner.prototype.hooks = function(name, suites, fn) { * * @param {String} name * @param {Function} fn - * @api private + * @private */ Runner.prototype.hookUp = function(name, fn) { var suites = [this.suite].concat(this.parents()).reverse(); @@ -4809,7 +5933,7 @@ Runner.prototype.hookUp = function(name, fn) { * * @param {String} name * @param {Function} fn - * @api private + * @private */ Runner.prototype.hookDown = function(name, fn) { var suites = [this.suite].concat(this.parents()); @@ -4821,7 +5945,7 @@ Runner.prototype.hookDown = function(name, fn) { * closest to furthest. * * @return {Array} - * @api private + * @private */ Runner.prototype.parents = function() { var suite = this.suite; @@ -4837,7 +5961,7 @@ Runner.prototype.parents = function() { * Run the current test and callback `fn(err)`. * * @param {Function} fn - * @api private + * @private */ Runner.prototype.runTest = function(fn) { var self = this; @@ -4846,18 +5970,23 @@ Runner.prototype.runTest = function(fn) { if (!test) { return; } + + var suite = this.parents().reverse()[0] || this.suite; + if (this.forbidOnly && suite.hasOnly()) { + fn(new Error('`.only` forbidden')); + return; + } if (this.asyncOnly) { test.asyncOnly = true; } - + test.on('error', function(err) { + self.fail(test, err); + }); if (this.allowUncaught) { test.allowUncaught = true; return test.run(fn); } try { - test.on('error', function(err) { - self.fail(test, err); - }); test.run(fn); } catch (err) { fn(err); @@ -4867,7 +5996,7 @@ Runner.prototype.runTest = function(fn) { /** * Run tests in the given `suite` and invoke the callback `fn()` when complete. * - * @api private + * @private * @param {Suite} suite * @param {Function} fn */ @@ -4886,7 +6015,7 @@ Runner.prototype.runTests = function(suite, fn) { if (self.suite) { // call hookUp afterEach - self.hookUp('afterEach', function(err2, errSuite2) { + self.hookUp(HOOK_TYPE_AFTER_EACH, function(err2, errSuite2) { self.suite = orig; // some hooks may fail even now if (err2) { @@ -4905,7 +6034,7 @@ Runner.prototype.runTests = function(suite, fn) { function next(err, errSuite) { // if we bail after first err if (self.failures && suite._bail) { - return fn(); + tests = []; } if (self._abort) { @@ -4947,17 +6076,29 @@ Runner.prototype.runTests = function(suite, fn) { } if (test.isPending()) { - self.emit('pending', test); - self.emit('test end', test); + if (self.forbidPending) { + test.isPending = alwaysFalse; + self.fail(test, new Error('Pending test forbidden')); + delete test.isPending; + } else { + self.emit(constants.EVENT_TEST_PENDING, test); + } + self.emit(constants.EVENT_TEST_END, test); return next(); } // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite) { + self.emit(constants.EVENT_TEST_BEGIN, (self.test = test)); + self.hookDown(HOOK_TYPE_BEFORE_EACH, function(err, errSuite) { if (test.isPending()) { - self.emit('pending', test); - self.emit('test end', test); + if (self.forbidPending) { + test.isPending = alwaysFalse; + self.fail(test, new Error('Pending test forbidden')); + delete test.isPending; + } else { + self.emit(constants.EVENT_TEST_PENDING, test); + } + self.emit(constants.EVENT_TEST_END, test); return next(); } if (err) { @@ -4968,33 +6109,37 @@ Runner.prototype.runTests = function(suite, fn) { test = self.test; if (err) { var retry = test.currentRetry(); - if (err instanceof Pending) { + if (err instanceof Pending && self.forbidPending) { + self.fail(test, new Error('Pending test forbidden')); + } else if (err instanceof Pending) { test.pending = true; - self.emit('pending', test); + self.emit(constants.EVENT_TEST_PENDING, test); } else if (retry < test.retries()) { var clonedTest = test.clone(); clonedTest.currentRetry(retry + 1); tests.unshift(clonedTest); + self.emit(constants.EVENT_TEST_RETRY, test, err); + // Early return + hook trigger so that it doesn't // increment the count wrong - return self.hookUp('afterEach', next); + return self.hookUp(HOOK_TYPE_AFTER_EACH, next); } else { self.fail(test, err); } - self.emit('test end', test); + self.emit(constants.EVENT_TEST_END, test); if (err instanceof Pending) { return next(); } - return self.hookUp('afterEach', next); + return self.hookUp(HOOK_TYPE_AFTER_EACH, next); } - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); + test.state = STATE_PASSED; + self.emit(constants.EVENT_TEST_PASS, test); + self.emit(constants.EVENT_TEST_END, test); + self.hookUp(HOOK_TYPE_AFTER_EACH, next); }); }); } @@ -5004,10 +6149,14 @@ Runner.prototype.runTests = function(suite, fn) { next(); }; +function alwaysFalse() { + return false; +} + /** * Run the given `suite` and invoke the callback `fn()` when complete. * - * @api private + * @private * @param {Suite} suite * @param {Function} fn */ @@ -5023,7 +6172,7 @@ Runner.prototype.runSuite = function(suite, fn) { return fn(); } - this.emit('suite', this.suite = suite); + this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite)); function next(errSuite) { if (errSuite) { @@ -5073,8 +6222,8 @@ Runner.prototype.runSuite = function(suite, fn) { // remove reference to test delete self.test; - self.hook('afterAll', function() { - self.emit('suite end', suite); + self.hook(HOOK_TYPE_AFTER_ALL, function() { + self.emit(constants.EVENT_SUITE_END, suite); fn(errSuite); }); } @@ -5082,7 +6231,7 @@ Runner.prototype.runSuite = function(suite, fn) { this.nextSuite = next; - this.hook('beforeAll', function(err) { + this.hook(HOOK_TYPE_BEFORE_ALL, function(err) { if (err) { return done(); } @@ -5094,16 +6243,24 @@ Runner.prototype.runSuite = function(suite, fn) { * Handle uncaught exceptions. * * @param {Error} err - * @api private + * @private */ Runner.prototype.uncaught = function(err) { + if (err instanceof Pending) { + return; + } if (err) { - debug('uncaught exception %s', err !== function() { - return this; - }.call(err) ? err : (err.message || err)); + debug('uncaught exception %O', err); } else { - debug('uncaught undefined exception'); - err = undefinedError(); + debug('uncaught undefined/falsy exception'); + err = createInvalidExceptionError( + 'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger', + err + ); + } + + if (!isError(err)) { + err = thrown2Error(err); } err.uncaught = true; @@ -5117,9 +6274,9 @@ Runner.prototype.uncaught = function(err) { this.fail(runnable, err); } else { // Can't recover from this failure - this.emit('start'); + this.emit(constants.EVENT_RUN_BEGIN); this.fail(runnable, err); - this.emit('end'); + this.emit(constants.EVENT_RUN_END); } return; @@ -5127,22 +6284,29 @@ Runner.prototype.uncaught = function(err) { runnable.clearTimeout(); - // Ignore errors if complete or pending - if (runnable.state || runnable.isPending()) { + // Ignore errors if already failed or pending + // See #3226 + if (runnable.isFailed() || runnable.isPending()) { return; } + // we cannot recover gracefully if a Runnable has already passed + // then fails asynchronously + var alreadyPassed = runnable.isPassed(); + // this will change the state to "failed" regardless of the current value this.fail(runnable, err); + if (!alreadyPassed) { + // recover from test + if (runnable.type === constants.EVENT_TEST_BEGIN) { + this.emit(constants.EVENT_TEST_END, runnable); + this.hookUp(HOOK_TYPE_AFTER_EACH, this.next); + return; + } + debug(runnable); - // recover from test - if (runnable.type === 'test') { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // recover from hooks - if (runnable.type === 'hook') { + // recover from hooks var errSuite = this.suite; + + // XXX how about a less awful way to determine this? // if hook failure is in afterEach block if (runnable.fullTitle().indexOf('after each') > -1) { return this.hookErr(err, errSuite, true); @@ -5156,54 +6320,15 @@ Runner.prototype.uncaught = function(err) { } // bail - this.emit('end'); + this.emit(constants.EVENT_RUN_END); }; -/** - * Cleans up the references to all the deferred functions - * (before/after/beforeEach/afterEach) and tests of a Suite. - * These must be deleted otherwise a memory leak can happen, - * as those functions may reference variables from closures, - * thus those variables can never be garbage collected as long - * as the deferred functions exist. - * - * @param {Suite} suite - */ -function cleanSuiteReferences(suite) { - function cleanArrReferences(arr) { - for (var i = 0; i < arr.length; i++) { - delete arr[i].fn; - } - } - - if (isArray(suite._beforeAll)) { - cleanArrReferences(suite._beforeAll); - } - - if (isArray(suite._beforeEach)) { - cleanArrReferences(suite._beforeEach); - } - - if (isArray(suite._afterAll)) { - cleanArrReferences(suite._afterAll); - } - - if (isArray(suite._afterEach)) { - cleanArrReferences(suite._afterEach); - } - - for (var i = 0; i < suite.tests.length; i++) { - delete suite.tests[i].fn; - } -} - /** * Run the root suite and invoke `fn(failures)` * on completion. * - * @param {Function} fn - * @return {Runner} for chaining - * @api public + * @public + * @memberof Runner * @param {Function} fn * @return {Runner} Runner instance. */ @@ -5211,11 +6336,6 @@ Runner.prototype.run = function(fn) { var self = this; var rootSuite = this.suite; - // If there is an `only` filter - if (this.hasOnly) { - filterOnly(rootSuite); - } - fn = fn || function() {}; function uncaught(err) { @@ -5223,22 +6343,32 @@ Runner.prototype.run = function(fn) { } function start() { + // If there is an `only` filter + if (rootSuite.hasOnly()) { + rootSuite.filterOnly(); + } self.started = true; - self.emit('start'); + if (self._delay) { + self.emit(constants.EVENT_DELAY_END); + } + self.emit(constants.EVENT_RUN_BEGIN); + self.runSuite(rootSuite, function() { debug('finished running'); - self.emit('end'); + self.emit(constants.EVENT_RUN_END); }); } - debug('start'); + debug(constants.EVENT_RUN_BEGIN); // references cleanup to avoid memory leaks - this.on('suite end', cleanSuiteReferences); + this.on(constants.EVENT_SUITE_END, function(suite) { + suite.cleanReferences(); + }); // callback - this.on('end', function() { - debug('end'); + this.on(constants.EVENT_RUN_END, function() { + debug(constants.EVENT_RUN_END); process.removeListener('uncaughtException', uncaught); fn(self.failures); }); @@ -5249,8 +6379,8 @@ Runner.prototype.run = function(fn) { if (this._delay) { // for reporters, I guess. // might be nice to debounce some dots while we wait. - this.emit('waiting', rootSuite); - rootSuite.once('run', start); + this.emit(constants.EVENT_DELAY_BEGIN, rootSuite); + rootSuite.once(EVENT_ROOT_SUITE_RUN, start); } else { start(); } @@ -5261,7 +6391,8 @@ Runner.prototype.run = function(fn) { /** * Cleanly abort execution. * - * @api public + * @memberof Runner + * @public * @return {Runner} Runner instance. */ Runner.prototype.abort = function() { @@ -5271,58 +6402,16 @@ Runner.prototype.abort = function() { return this; }; -/** - * Filter suites based on `isOnly` logic. - * - * @param {Array} suite - * @returns {Boolean} - * @api private - */ -function filterOnly(suite) { - if (suite._onlyTests.length) { - // If the suite contains `only` tests, run those and ignore any nested suites. - suite.tests = suite._onlyTests; - suite.suites = []; - } else { - // Otherwise, do not run any of the tests in this suite. - suite.tests = []; - utils.forEach(suite._onlySuites, function(onlySuite) { - // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite. - // Otherwise, all of the tests on this `only` suite should be run, so don't filter it. - if (hasOnly(onlySuite)) { - filterOnly(onlySuite); - } - }); - // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants. - suite.suites = filter(suite.suites, function(childSuite) { - return indexOf(suite._onlySuites, childSuite) !== -1 || filterOnly(childSuite); - }); - } - // Keep the suite only if there is something to run - return suite.tests.length || suite.suites.length; -} - -/** - * Determines whether a suite has an `only` test or suite as a descendant. - * - * @param {Array} suite - * @returns {Boolean} - * @api private - */ -function hasOnly(suite) { - return suite._onlyTests.length || suite._onlySuites.length || some(suite.suites, hasOnly); -} - /** * Filter leaks with the given globals flagged as `ok`. * - * @api private + * @private * @param {Array} ok * @param {Array} globals * @return {Array} */ function filterLeaks(ok, globals) { - return filter(globals, function(key) { + return globals.filter(function(key) { // Firefox and Chrome exposes iframes as index inside the window object if (/^\d+/.test(key)) { return false; @@ -5331,13 +6420,13 @@ function filterLeaks(ok, globals) { // in firefox // if runner runs in an iframe, this iframe's window.getInterface method // not init at first it is assigned in some seconds - if (global.navigator && (/^getInterface/).test(key)) { + if (global.navigator && /^getInterface/.test(key)) { return false; } // an iframe could be approached by window[iframeIndex] // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && (/^\d+/).test(key)) { + if (global.navigator && /^\d+/.test(key)) { return false; } @@ -5346,7 +6435,7 @@ function filterLeaks(ok, globals) { return false; } - var matched = filter(ok, function(ok) { + var matched = ok.filter(function(ok) { if (~ok.indexOf('*')) { return key.indexOf(ok.split('*')[0]) === 0; } @@ -5356,22 +6445,49 @@ function filterLeaks(ok, globals) { }); } +/** + * Check if argument is an instance of Error object or a duck-typed equivalent. + * + * @private + * @param {Object} err - object to check + * @param {string} err.message - error message + * @returns {boolean} + */ +function isError(err) { + return err instanceof Error || (err && typeof err.message === 'string'); +} + +/** + * + * Converts thrown non-extensible type into proper Error. + * + * @private + * @param {*} thrown - Non-extensible type thrown by code + * @return {Error} + */ +function thrown2Error(err) { + return new Error( + 'the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)' + ); +} + /** * Array of globals dependent on the environment. * * @return {Array} - * @api private + * @deprecated + * @todo remove; long since unsupported + * @private */ function extraGlobals() { if (typeof process === 'object' && typeof process.version === 'string') { var parts = process.version.split('.'); - var nodeVersion = utils.reduce(parts, function(a, v) { - return a << 8 | v; + var nodeVersion = parts.reduce(function(a, v) { + return (a << 8) | v; }); // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { + if (nodeVersion < 0x00090b) { return ['errno']; } } @@ -5379,53 +6495,159 @@ function extraGlobals() { return []; } -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./pending":16,"./runnable":33,"./utils":38,"_process":67,"debug":2,"events":3}],35:[function(require,module,exports){ +Runner.constants = constants; + /** - * Module dependencies. + * Node.js' `EventEmitter` + * @external EventEmitter + * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter} */ -var EventEmitter = require('events').EventEmitter; -var Hook = require('./hook'); -var utils = require('./utils'); -var inherits = utils.inherits; -var debug = require('debug')('mocha:suite'); -var milliseconds = require('./ms'); +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./errors":6,"./pending":16,"./runnable":33,"./suite":36,"./utils":38,"_process":69,"debug":45,"events":50,"util":89}],35:[function(require,module,exports){ +(function (global){ +'use strict'; /** - * Expose `Suite`. + * Provides a factory function for a {@link StatsCollector} object. + * @module */ -exports = module.exports = Suite; +var constants = require('./runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_END = constants.EVENT_TEST_END; /** - * Create a new `Suite` with the given `title` and parent `Suite`. When a suite - * with the same title is already present, that suite is returned to provide - * nicer reporter and more flexible meta-testing. + * Test statistics collector. * - * @api public - * @param {Suite} parent - * @param {string} title - * @return {Suite} + * @public + * @typedef {Object} StatsCollector + * @property {number} suites - integer count of suites run. + * @property {number} tests - integer count of tests run. + * @property {number} passes - integer count of passing tests. + * @property {number} pending - integer count of pending tests. + * @property {number} failures - integer count of failed tests. + * @property {Date} start - time when testing began. + * @property {Date} end - time when testing concluded. + * @property {number} duration - number of msecs that testing took. */ -exports.create = function(parent, title) { - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; -}; + +var Date = global.Date; /** - * Initialize a new `Suite` with the given `title` and `ctx`. + * Provides stats such as test duration, number of tests passed / failed etc., by listening for events emitted by `runner`. * - * @api private - * @param {string} title - * @param {Context} parentContext - */ -function Suite(title, parentContext) { + * @private + * @param {Runner} runner - Runner instance + * @throws {TypeError} If falsy `runner` + */ +function createStatsCollector(runner) { + /** + * @type StatsCollector + */ + var stats = { + suites: 0, + tests: 0, + passes: 0, + pending: 0, + failures: 0 + }; + + if (!runner) { + throw new TypeError('Missing runner argument'); + } + + runner.stats = stats; + + runner.once(EVENT_RUN_BEGIN, function() { + stats.start = new Date(); + }); + runner.on(EVENT_SUITE_BEGIN, function(suite) { + suite.root || stats.suites++; + }); + runner.on(EVENT_TEST_PASS, function() { + stats.passes++; + }); + runner.on(EVENT_TEST_FAIL, function() { + stats.failures++; + }); + runner.on(EVENT_TEST_PENDING, function() { + stats.pending++; + }); + runner.on(EVENT_TEST_END, function() { + stats.tests++; + }); + runner.once(EVENT_RUN_END, function() { + stats.end = new Date(); + stats.duration = stats.end - stats.start; + }); +} + +module.exports = createStatsCollector; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./runner":34}],36:[function(require,module,exports){ +'use strict'; + +/** + * Module dependencies. + */ +var EventEmitter = require('events').EventEmitter; +var Hook = require('./hook'); +var utils = require('./utils'); +var inherits = utils.inherits; +var debug = require('debug')('mocha:suite'); +var milliseconds = require('ms'); +var errors = require('./errors'); +var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError; + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` and parent `Suite`. + * + * @public + * @param {Suite} parent - Parent suite (required!) + * @param {string} title - Title + * @return {Suite} + */ +Suite.create = function(parent, title) { + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Constructs a new `Suite` instance with the given `title`, `ctx`, and `isRoot`. + * + * @public + * @class + * @extends EventEmitter + * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter|EventEmitter} + * @param {string} title - Suite title. + * @param {Context} parentContext - Parent context instance. + * @param {boolean} [isRoot=false] - Whether this is the root suite. + */ +function Suite(title, parentContext, isRoot) { if (!utils.isString(title)) { - throw new Error('Suite `title` should be a "string" but "' + typeof title + '" was given instead.'); + throw createInvalidArgumentTypeError( + 'Suite argument "title" must be a string. Received type "' + + typeof title + + '"', + 'title', + 'string' + ); } this.title = title; function Context() {} @@ -5438,7 +6660,7 @@ function Suite(title, parentContext) { this._beforeAll = []; this._afterEach = []; this._afterAll = []; - this.root = !title; + this.root = isRoot === true; this._timeout = 2000; this._enableTimeouts = true; this._slow = 75; @@ -5447,6 +6669,16 @@ function Suite(title, parentContext) { this._onlyTests = []; this._onlySuites = []; this.delayed = false; + + this.on('newListener', function(event) { + if (deprecatedEvents[event]) { + utils.deprecate( + 'Event "' + + event + + '" is deprecated. Please let the Mocha team know about your use case: https://git.io/v6Lwm' + ); + } + }); } /** @@ -5457,13 +6689,14 @@ inherits(Suite, EventEmitter); /** * Return a clone of this `Suite`. * - * @api private + * @private * @return {Suite} */ Suite.prototype.clone = function() { var suite = new Suite(this.title); debug('clone'); suite.ctx = this.ctx; + suite.root = this.root; suite.timeout(this.timeout()); suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); @@ -5473,9 +6706,10 @@ Suite.prototype.clone = function() { }; /** - * Set timeout `ms` or short-hand such as "2s". + * Set or get timeout `ms` or short-hand such as "2s". * - * @api private + * @private + * @todo Do not attempt to set value if `ms` is undefined * @param {number|string} ms * @return {Suite|number} for chaining */ @@ -5495,9 +6729,9 @@ Suite.prototype.timeout = function(ms) { }; /** - * Set number of times to retry a failed test. + * Set or get number of times to retry a failed test. * - * @api private + * @private * @param {number|string} n * @return {Suite|number} for chaining */ @@ -5511,12 +6745,12 @@ Suite.prototype.retries = function(n) { }; /** - * Set timeout to `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Suite|boolean} self or enabled - */ + * Set or get timeout to `enabled`. + * + * @private + * @param {boolean} enabled + * @return {Suite|boolean} self or enabled + */ Suite.prototype.enableTimeouts = function(enabled) { if (!arguments.length) { return this._enableTimeouts; @@ -5527,9 +6761,9 @@ Suite.prototype.enableTimeouts = function(enabled) { }; /** - * Set slow `ms` or short-hand such as "2s". + * Set or get slow `ms` or short-hand such as "2s". * - * @api private + * @private * @param {number|string} ms * @return {Suite|number} for chaining */ @@ -5546,9 +6780,9 @@ Suite.prototype.slow = function(ms) { }; /** - * Sets whether to bail after first error. + * Set or get whether to bail after first error. * - * @api private + * @private * @param {boolean} bail * @return {Suite|number} for chaining */ @@ -5564,16 +6798,35 @@ Suite.prototype.bail = function(bail) { /** * Check if this suite or its parent suite is marked as pending. * - * @api private + * @private */ Suite.prototype.isPending = function() { return this.pending || (this.parent && this.parent.isPending()); }; +/** + * Generic hook-creator. + * @private + * @param {string} title - Title of hook + * @param {Function} fn - Hook callback + * @returns {Hook} A new hook + */ +Suite.prototype._createHook = function(title, fn) { + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.retries(this.retries()); + hook.enableTimeouts(this.enableTimeouts()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + hook.file = this.file; + return hook; +}; + /** * Run `fn(test[, done])` before running tests. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5588,22 +6841,16 @@ Suite.prototype.beforeAll = function(title, fn) { } title = '"before all" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._beforeAll.push(hook); - this.emit('beforeAll', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_ALL, hook); return this; }; /** * Run `fn(test[, done])` after running tests. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5618,22 +6865,16 @@ Suite.prototype.afterAll = function(title, fn) { } title = '"after all" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._afterAll.push(hook); - this.emit('afterAll', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_ALL, hook); return this; }; /** * Run `fn(test[, done])` before each test case. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5648,22 +6889,16 @@ Suite.prototype.beforeEach = function(title, fn) { } title = '"before each" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._beforeEach.push(hook); - this.emit('beforeEach', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_EACH, hook); return this; }; /** * Run `fn(test[, done])` after each test case. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5678,41 +6913,36 @@ Suite.prototype.afterEach = function(title, fn) { } title = '"after each" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._afterEach.push(hook); - this.emit('afterEach', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_EACH, hook); return this; }; /** * Add a test `suite`. * - * @api private + * @private * @param {Suite} suite * @return {Suite} for chaining */ Suite.prototype.addSuite = function(suite) { suite.parent = this; + suite.root = false; suite.timeout(this.timeout()); suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); this.suites.push(suite); - this.emit('suite', suite); + this.emit(constants.EVENT_SUITE_ADD_SUITE, suite); return this; }; /** * Add a `test` to this suite. * - * @api private + * @private * @param {Test} test * @return {Suite} for chaining */ @@ -5724,7 +6954,7 @@ Suite.prototype.addTest = function(test) { test.slow(this.slow()); test.ctx = this.ctx; this.tests.push(test); - this.emit('test', test); + this.emit(constants.EVENT_SUITE_ADD_TEST, test); return this; }; @@ -5732,42 +6962,59 @@ Suite.prototype.addTest = function(test) { * Return the full title generated by recursively concatenating the parent's * full title. * - * @api public + * @memberof Suite + * @public * @return {string} */ Suite.prototype.fullTitle = function() { + return this.titlePath().join(' '); +}; + +/** + * Return the title path generated by recursively concatenating the parent's + * title path. + * + * @memberof Suite + * @public + * @return {string} + */ +Suite.prototype.titlePath = function() { + var result = []; if (this.parent) { - var full = this.parent.fullTitle(); - if (full) { - return full + ' ' + this.title; - } + result = result.concat(this.parent.titlePath()); + } + if (!this.root) { + result.push(this.title); } - return this.title; + return result; }; /** * Return the total number of tests. * - * @api public + * @memberof Suite + * @public * @return {number} */ Suite.prototype.total = function() { - return utils.reduce(this.suites, function(sum, suite) { - return sum + suite.total(); - }, 0) + this.tests.length; + return ( + this.suites.reduce(function(sum, suite) { + return sum + suite.total(); + }, 0) + this.tests.length + ); }; /** * Iterates through each suite recursively to find all tests. Applies a * function in the format `fn(test)`. * - * @api private + * @private * @param {Function} fn * @return {Suite} */ Suite.prototype.eachTest = function(fn) { - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite) { + this.tests.forEach(fn); + this.suites.forEach(function(suite) { suite.eachTest(fn); }); return this; @@ -5775,297 +7022,343 @@ Suite.prototype.eachTest = function(fn) { /** * This will run the root suite if we happen to be running in delayed mode. + * @private */ Suite.prototype.run = function run() { if (this.root) { - this.emit('run'); + this.emit(constants.EVENT_ROOT_SUITE_RUN); } }; -},{"./hook":7,"./ms":15,"./utils":38,"debug":2,"events":3}],36:[function(require,module,exports){ -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); -var create = require('lodash.create'); -var isString = require('./utils').isString; - /** - * Expose `Test`. + * Determines whether a suite has an `only` test or suite as a descendant. + * + * @private + * @returns {Boolean} */ - -module.exports = Test; +Suite.prototype.hasOnly = function hasOnly() { + return ( + this._onlyTests.length > 0 || + this._onlySuites.length > 0 || + this.suites.some(function(suite) { + return suite.hasOnly(); + }) + ); +}; /** - * Initialize a new `Test` with the given `title` and callback `fn`. + * Filter suites based on `isOnly` logic. * - * @api private - * @param {String} title - * @param {Function} fn + * @private + * @returns {Boolean} */ -function Test(title, fn) { - if (!isString(title)) { - throw new Error('Test `title` should be a "string" but "' + typeof title + '" was given instead.'); +Suite.prototype.filterOnly = function filterOnly() { + if (this._onlyTests.length) { + // If the suite contains `only` tests, run those and ignore any nested suites. + this.tests = this._onlyTests; + this.suites = []; + } else { + // Otherwise, do not run any of the tests in this suite. + this.tests = []; + this._onlySuites.forEach(function(onlySuite) { + // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite. + // Otherwise, all of the tests on this `only` suite should be run, so don't filter it. + if (onlySuite.hasOnly()) { + onlySuite.filterOnly(); + } + }); + // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants. + var onlySuites = this._onlySuites; + this.suites = this.suites.filter(function(childSuite) { + return onlySuites.indexOf(childSuite) !== -1 || childSuite.filterOnly(); + }); } - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ -Test.prototype = create(Runnable.prototype, { - constructor: Test -}); - -Test.prototype.clone = function() { - var test = new Test(this.title, this.fn); - test.timeout(this.timeout()); - test.slow(this.slow()); - test.enableTimeouts(this.enableTimeouts()); - test.retries(this.retries()); - test.currentRetry(this.currentRetry()); - test.globals(this.globals()); - test.parent = this.parent; - test.file = this.file; - test.ctx = this.ctx; - return test; + // Keep the suite only if there is something to run + return this.tests.length > 0 || this.suites.length > 0; }; -},{"./runnable":33,"./utils":38,"lodash.create":60}],37:[function(require,module,exports){ -'use strict'; - /** - * Pad a `number` with a ten's place zero. + * Adds a suite to the list of subsuites marked `only`. * - * @param {number} number - * @return {string} + * @private + * @param {Suite} suite */ -function pad(number) { - var n = number.toString(); - return n.length === 1 ? '0' + n : n; -} +Suite.prototype.appendOnlySuite = function(suite) { + this._onlySuites.push(suite); +}; /** - * Turn a `date` into an ISO string. - * - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString + * Adds a test to the list of tests marked `only`. * - * @param {Date} date - * @return {string} + * @private + * @param {Test} test */ -function toISOString(date) { - return date.getUTCFullYear() - + '-' + pad(date.getUTCMonth() + 1) - + '-' + pad(date.getUTCDate()) - + 'T' + pad(date.getUTCHours()) - + ':' + pad(date.getUTCMinutes()) - + ':' + pad(date.getUTCSeconds()) - + '.' + String((date.getUTCMilliseconds()/1000).toFixed(3)).slice(2, 5) - + 'Z'; -} +Suite.prototype.appendOnlyTest = function(test) { + this._onlyTests.push(test); +}; -/* - * Exports. +/** + * Returns the array of hooks by hook name; see `HOOK_TYPE_*` constants. + * @private */ - -module.exports = toISOString; - -},{}],38:[function(require,module,exports){ -(function (process,Buffer){ -/* eslint-env browser */ +Suite.prototype.getHooks = function getHooks(name) { + return this['_' + name]; +}; /** - * Module dependencies. + * Cleans up the references to all the deferred functions + * (before/after/beforeEach/afterEach) and tests of a Suite. + * These must be deleted otherwise a memory leak can happen, + * as those functions may reference variables from closures, + * thus those variables can never be garbage collected as long + * as the deferred functions exist. + * + * @private */ +Suite.prototype.cleanReferences = function cleanReferences() { + function cleanArrReferences(arr) { + for (var i = 0; i < arr.length; i++) { + delete arr[i].fn; + } + } -var JSON = require('json3'); -var basename = require('path').basename; -var debug = require('debug')('mocha:watch'); -var exists = require('fs').existsSync || require('path').existsSync; -var glob = require('glob'); -var path = require('path'); -var join = path.join; -var readdirSync = require('fs').readdirSync; -var statSync = require('fs').statSync; -var watchFile = require('fs').watchFile; -var toISOString = require('./to-iso-string'); + if (Array.isArray(this._beforeAll)) { + cleanArrReferences(this._beforeAll); + } -/** - * Ignored directories. - */ + if (Array.isArray(this._beforeEach)) { + cleanArrReferences(this._beforeEach); + } -var ignore = ['node_modules', '.git']; + if (Array.isArray(this._afterAll)) { + cleanArrReferences(this._afterAll); + } -exports.inherits = require('util').inherits; + if (Array.isArray(this._afterEach)) { + cleanArrReferences(this._afterEach); + } -/** - * Escape special characters in the given string of html. - * - * @api private - * @param {string} html - * @return {string} - */ -exports.escape = function(html) { - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); + for (var i = 0; i < this.tests.length; i++) { + delete this.tests[i].fn; + } }; -/** - * Array#forEach (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} scope - */ -exports.forEach = function(arr, fn, scope) { - for (var i = 0, l = arr.length; i < l; i++) { - fn.call(scope, arr[i], i); +var constants = utils.defineConstants( + /** + * {@link Suite}-related constants. + * @public + * @memberof Suite + * @alias constants + * @readonly + * @static + * @enum {string} + */ + { + /** + * Event emitted after a test file has been loaded Not emitted in browser. + */ + EVENT_FILE_POST_REQUIRE: 'post-require', + /** + * Event emitted before a test file has been loaded. In browser, this is emitted once an interface has been selected. + */ + EVENT_FILE_PRE_REQUIRE: 'pre-require', + /** + * Event emitted immediately after a test file has been loaded. Not emitted in browser. + */ + EVENT_FILE_REQUIRE: 'require', + /** + * Event emitted when `global.run()` is called (use with `delay` option) + */ + EVENT_ROOT_SUITE_RUN: 'run', + + /** + * Namespace for collection of a `Suite`'s "after all" hooks + */ + HOOK_TYPE_AFTER_ALL: 'afterAll', + /** + * Namespace for collection of a `Suite`'s "after each" hooks + */ + HOOK_TYPE_AFTER_EACH: 'afterEach', + /** + * Namespace for collection of a `Suite`'s "before all" hooks + */ + HOOK_TYPE_BEFORE_ALL: 'beforeAll', + /** + * Namespace for collection of a `Suite`'s "before all" hooks + */ + HOOK_TYPE_BEFORE_EACH: 'beforeEach', + + // the following events are all deprecated + + /** + * Emitted after an "after all" `Hook` has been added to a `Suite`. Deprecated + */ + EVENT_SUITE_ADD_HOOK_AFTER_ALL: 'afterAll', + /** + * Emitted after an "after each" `Hook` has been added to a `Suite` Deprecated + */ + EVENT_SUITE_ADD_HOOK_AFTER_EACH: 'afterEach', + /** + * Emitted after an "before all" `Hook` has been added to a `Suite` Deprecated + */ + EVENT_SUITE_ADD_HOOK_BEFORE_ALL: 'beforeAll', + /** + * Emitted after an "before each" `Hook` has been added to a `Suite` Deprecated + */ + EVENT_SUITE_ADD_HOOK_BEFORE_EACH: 'beforeEach', + /** + * Emitted after a child `Suite` has been added to a `Suite`. Deprecated + */ + EVENT_SUITE_ADD_SUITE: 'suite', + /** + * Emitted after a `Test` has been added to a `Suite`. Deprecated + */ + EVENT_SUITE_ADD_TEST: 'test' } -}; +); /** - * Test if the given obj is type of string. - * - * @api private - * @param {Object} obj - * @return {boolean} + * @summary There are no known use cases for these events. + * @desc This is a `Set`-like object having all keys being the constant's string value and the value being `true`. + * @todo Remove eventually + * @type {Object} + * @ignore */ -exports.isString = function(obj) { - return typeof obj === 'string'; -}; +var deprecatedEvents = Object.keys(constants) + .filter(function(constant) { + return constant.substring(0, 15) === 'EVENT_SUITE_ADD'; + }) + .reduce(function(acc, constant) { + acc[constants[constant]] = true; + return acc; + }, utils.createMap()); + +Suite.constants = constants; + +},{"./errors":6,"./hook":7,"./utils":38,"debug":45,"events":50,"ms":60}],37:[function(require,module,exports){ +'use strict'; +var Runnable = require('./runnable'); +var utils = require('./utils'); +var errors = require('./errors'); +var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError; +var isString = utils.isString; + +module.exports = Test; /** - * Array#map (<=IE8) + * Initialize a new `Test` with the given `title` and callback `fn`. * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} scope - * @return {Array} + * @public + * @class + * @extends Runnable + * @param {String} title - Test title (required) + * @param {Function} [fn] - Test callback. If omitted, the Test is considered "pending" */ -exports.map = function(arr, fn, scope) { - var result = []; - for (var i = 0, l = arr.length; i < l; i++) { - result.push(fn.call(scope, arr[i], i, arr)); +function Test(title, fn) { + if (!isString(title)) { + throw createInvalidArgumentTypeError( + 'Test argument "title" should be a string. Received type "' + + typeof title + + '"', + 'title', + 'string' + ); } - return result; -}; + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} /** - * Array#indexOf (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Object} obj to find index of - * @param {number} start - * @return {number} + * Inherit from `Runnable.prototype`. */ -var indexOf = exports.indexOf = function(arr, obj, start) { - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) { - return i; - } - } - return -1; +utils.inherits(Test, Runnable); + +Test.prototype.clone = function() { + var test = new Test(this.title, this.fn); + test.timeout(this.timeout()); + test.slow(this.slow()); + test.enableTimeouts(this.enableTimeouts()); + test.retries(this.retries()); + test.currentRetry(this.currentRetry()); + test.globals(this.globals()); + test.parent = this.parent; + test.file = this.file; + test.ctx = this.ctx; + return test; }; +},{"./errors":6,"./runnable":33,"./utils":38}],38:[function(require,module,exports){ +(function (process,Buffer){ +'use strict'; + /** - * Array#reduce (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} val Initial value. - * @return {*} + * Various utility functions used throughout Mocha's codebase. + * @module utils */ -var reduce = exports.reduce = function(arr, fn, val) { - var rval = val; - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } +/** + * Module dependencies. + */ - return rval; -}; +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var glob = require('glob'); +var he = require('he'); +var errors = require('./errors'); +var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError; +var createMissingArgumentError = errors.createMissingArgumentError; + +var assign = (exports.assign = require('object.assign').getPolyfill()); /** - * Array#filter (<=IE8) + * Inherit the prototype methods from one constructor into another. * - * @api private - * @param {Array} arr - * @param {Function} fn - * @return {Array} + * @param {function} ctor - Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor - Constructor function to inherit prototype from. + * @throws {TypeError} if either constructor is null, or if super constructor + * lacks a prototype. */ -exports.filter = function(arr, fn) { - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) { - ret.push(val); - } - } - - return ret; -}; +exports.inherits = util.inherits; /** - * Array#some (<=IE8) + * Escape special characters in the given string of html. * - * @api private - * @param {Array} arr - * @param {Function} fn - * @return {Array} + * @private + * @param {string} html + * @return {string} */ -exports.some = function(arr, fn) { - for (var i = 0, l = arr.length; i < l; i++) { - if (fn(arr[i])) { - return true; - } - } - return false; +exports.escape = function(html) { + return he.encode(String(html), {useNamedReferences: false}); }; /** - * Object.keys (<=IE8) + * Test if the given obj is type of string. * - * @api private + * @private * @param {Object} obj - * @return {Array} keys + * @return {boolean} */ -exports.keys = typeof Object.keys === 'function' ? Object.keys : function(obj) { - var keys = []; - var has = Object.prototype.hasOwnProperty; // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; +exports.isString = function(obj) { + return typeof obj === 'string'; }; /** * Watch the given `files` for changes * and invoke `fn(file)` on modification. * - * @api private + * @private * @param {Array} files * @param {Function} fn */ exports.watch = function(files, fn) { - var options = { interval: 100 }; + var options = {interval: 100}; + var debug = require('debug')('mocha:watch'); files.forEach(function(file) { debug('file %s', file); - watchFile(file, options, function(curr, prev) { + fs.watchFile(file, options, function(curr, prev) { if (prev.mtime < curr.mtime) { fn(file); } @@ -6074,63 +7367,52 @@ exports.watch = function(files, fn) { }; /** - * Array.isArray (<=IE8) + * Predicate to screen `pathname` for further consideration. * - * @api private - * @param {Object} obj - * @return {Boolean} - */ -var isArray = typeof Array.isArray === 'function' ? Array.isArray : function(obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; -}; - -exports.isArray = isArray; - -/** - * Buffer.prototype.toJSON polyfill. + * @description + * Returns false for pathname referencing: + *
      + *
    • 'npm' package installation directory + *
    • 'git' version control directory + *
    * - * @type {Function} + * @private + * @param {string} pathname - File or directory name to screen + * @return {boolean} whether pathname should be further considered + * @example + * ['node_modules', 'test.js'].filter(considerFurther); // => ['test.js'] */ -if (typeof Buffer !== 'undefined' && Buffer.prototype) { - Buffer.prototype.toJSON = Buffer.prototype.toJSON || function() { - return Array.prototype.slice.call(this, 0); - }; -} +function considerFurther(pathname) { + var ignore = ['node_modules', '.git']; -/** - * Ignored files. - * - * @api private - * @param {string} path - * @return {boolean} - */ -function ignored(path) { - return !~ignore.indexOf(path); + return !~ignore.indexOf(pathname); } /** * Lookup files in the given `dir`. * - * @api private + * @description + * Filenames are returned in _traversal_ order by the OS/filesystem. + * **Make no assumption that the names will be sorted in any fashion.** + * + * @private * @param {string} dir - * @param {string[]} [ext=['.js']] + * @param {string[]} [exts=['js']] * @param {Array} [ret=[]] * @return {Array} */ -exports.files = function(dir, ext, ret) { +exports.files = function(dir, exts, ret) { ret = ret || []; - ext = ext || ['js']; - - var re = new RegExp('\\.(' + ext.join('|') + ')$'); - - readdirSync(dir) - .filter(ignored) - .forEach(function(path) { - path = join(dir, path); - if (statSync(path).isDirectory()) { - exports.files(path, ext, ret); - } else if (path.match(re)) { - ret.push(path); + exts = exts || ['js']; + + fs.readdirSync(dir) + .filter(considerFurther) + .forEach(function(dirent) { + var pathname = path.join(dir, dirent); + if (fs.lstatSync(pathname).isDirectory()) { + exports.files(pathname, exts, ret); + } else if (hasMatchingExtname(pathname, exts)) { + ret.push(pathname); } }); @@ -6140,7 +7422,7 @@ exports.files = function(dir, ext, ret) { /** * Compute a slug from the given `str`. * - * @api private + * @private * @param {string} str * @return {string} */ @@ -6159,52 +7441,53 @@ exports.slug = function(str) { */ exports.clean = function(str) { str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') + .replace(/\r\n?|[\n\u2028\u2029]/g, '\n') + .replace(/^\uFEFF/, '') // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content - .replace(/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, '$1$2$3'); + .replace( + /^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, + '$1$2$3' + ); var spaces = str.match(/^\n?( *)/)[1].length; var tabs = str.match(/^\n?(\t*)/)[1].length; - var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); + var re = new RegExp( + '^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}', + 'gm' + ); str = str.replace(re, ''); - return exports.trim(str); -}; - -/** - * Trim the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ -exports.trim = function(str) { - return str.replace(/^\s+|\s+$/g, ''); + return str.trim(); }; /** * Parse the given `qs`. * - * @api private + * @private * @param {string} qs * @return {Object} */ exports.parseQuery = function(qs) { - return reduce(qs.replace('?', '').split('&'), function(obj, pair) { - var i = pair.indexOf('='); - var key = pair.slice(0, i); - var val = pair.slice(++i); - - obj[key] = decodeURIComponent(val); - return obj; - }, {}); + return qs + .replace('?', '') + .split('&') + .reduce(function(obj, pair) { + var i = pair.indexOf('='); + var key = pair.slice(0, i); + var val = pair.slice(++i); + + // Due to how the URLSearchParams API treats spaces + obj[key] = decodeURIComponent(val.replace(/\+/g, '%20')); + + return obj; + }, {}); }; /** * Highlight the given string of `js`. * - * @api private + * @private * @param {string} js * @return {string} */ @@ -6216,14 +7499,20 @@ function highlight(js) { .replace(/('.*?')/gm, '$1') .replace(/(\d+\.\d+)/gm, '$1') .replace(/(\d+)/gm, '$1') - .replace(/\bnew[ \t]+(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1'); + .replace( + /\bnew[ \t]+(\w+)/gm, + 'new $1' + ) + .replace( + /\b(function|new|throw|return|var|if|else)\b/gm, + '$1' + ); } /** * Highlight the contents of tag `name`. * - * @api private + * @private * @param {string} name */ exports.highlightTags = function(name) { @@ -6242,7 +7531,7 @@ exports.highlightTags = function(name) { * Objects w/ no properties return `'{}'` * All else: return result of `value.toString()` * - * @api private + * @private * @param {*} value The value to inspect. * @param {string} typeHint The type of the value * @returns {string} @@ -6264,7 +7553,7 @@ function emptyRepresentation(value, typeHint) { * Takes some variable and asks `Object.prototype.toString()` what it thinks it * is. * - * @api private + * @private * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString * @param {*} value The value to test. * @returns {string} Computed type @@ -6281,18 +7570,19 @@ function emptyRepresentation(value, typeHint) { * type(global) // 'global' * type(new String('foo') // 'object' */ -var type = exports.type = function type(value) { +var type = (exports.type = function type(value) { if (value === undefined) { return 'undefined'; } else if (value === null) { return 'null'; - } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + } else if (Buffer.isBuffer(value)) { return 'buffer'; } - return Object.prototype.toString.call(value) - .replace(/^\[.+\s(.+?)\]$/, '$1') + return Object.prototype.toString + .call(value) + .replace(/^\[.+\s(.+?)]$/, '$1') .toLowerCase(); -}; +}); /** * Stringify `value`. Different behavior depending on type of value: @@ -6304,7 +7594,7 @@ var type = exports.type = function type(value) { * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of * JSON.stringify(). * - * @api private + * @private * @see exports.type * @param {*} value * @return {string} @@ -6312,18 +7602,20 @@ var type = exports.type = function type(value) { exports.stringify = function(value) { var typeHint = type(value); - if (!~indexOf(['object', 'array', 'function'], typeHint)) { + if (!~['object', 'array', 'function'].indexOf(typeHint)) { if (typeHint === 'buffer') { - var json = value.toJSON(); + var json = Buffer.prototype.toJSON.call(value); // Based on the toJSON result - return jsonStringify(json.data && json.type ? json.data : json, 2) - .replace(/,(\n|$)/g, '$1'); + return jsonStringify( + json.data && json.type ? json.data : json, + 2 + ).replace(/,(\n|$)/g, '$1'); } // IE7/IE8 has a bizarre String constructor; needs to be coerced // into an array and back to obj. if (typeHint === 'string' && typeof value === 'object') { - value = reduce(value.split(''), function(acc, char, idx) { + value = value.split('').reduce(function(acc, char, idx) { acc[idx] = char; return acc; }, {}); @@ -6335,7 +7627,10 @@ exports.stringify = function(value) { for (var prop in value) { if (Object.prototype.hasOwnProperty.call(value, prop)) { - return jsonStringify(exports.canonicalize(value, null, typeHint), 2).replace(/,(\n|$)/g, '$1'); + return jsonStringify( + exports.canonicalize(value, null, typeHint), + 2 + ).replace(/,(\n|$)/g, '$1'); } } @@ -6345,7 +7640,7 @@ exports.stringify = function(value) { /** * like JSON.stringify but more sense. * - * @api private + * @private * @param {Object} object * @param {number=} spaces * @param {number=} depth @@ -6359,9 +7654,12 @@ function jsonStringify(object, spaces, depth) { depth = depth || 1; var space = spaces * depth; - var str = isArray(object) ? '[' : '{'; - var end = isArray(object) ? ']' : '}'; - var length = typeof object.length === 'number' ? object.length : exports.keys(object).length; + var str = Array.isArray(object) ? '[' : '{'; + var end = Array.isArray(object) ? ']' : '}'; + var length = + typeof object.length === 'number' + ? object.length + : Object.keys(object).length; // `.repeat()` polyfill function repeat(s, n) { return new Array(n).join(s); @@ -6381,17 +7679,13 @@ function jsonStringify(object, spaces, depth) { case 'regexp': case 'symbol': case 'number': - val = val === 0 && (1 / val) === -Infinity // `-0` - ? '-0' - : val.toString(); + val = + val === 0 && 1 / val === -Infinity // `-0` + ? '-0' + : val.toString(); break; case 'date': - var sDate; - if (isNaN(val.getTime())) { // Invalid date - sDate = val.toString(); - } else { - sDate = val.toISOString ? val.toISOString() : toISOString(val); - } + var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString(); val = '[Date: ' + sDate + ']'; break; case 'buffer': @@ -6401,9 +7695,10 @@ function jsonStringify(object, spaces, depth) { val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']'; break; default: - val = (val === '[Function]' || val === '[Circular]') - ? val - : JSON.stringify(val); // string + val = + val === '[Function]' || val === '[Circular]' + ? val + : JSON.stringify(val); // string } return val; } @@ -6413,28 +7708,21 @@ function jsonStringify(object, spaces, depth) { continue; // not my business } --length; - str += '\n ' + repeat(' ', space) - + (isArray(object) ? '' : '"' + i + '": ') // key - + _stringify(object[i]) // value - + (length ? ',' : ''); // comma + str += + '\n ' + + repeat(' ', space) + + (Array.isArray(object) ? '' : '"' + i + '": ') + // key + _stringify(object[i]) + // value + (length ? ',' : ''); // comma } - return str + return ( + str + // [], {} - + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end); + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end) + ); } -/** - * Test if a value is a buffer. - * - * @api private - * @param {*} value The value to test. - * @return {boolean} True if `value` is a buffer, otherwise false - */ -exports.isBuffer = function(value) { - return typeof Buffer !== 'undefined' && Buffer.isBuffer(value); -}; - /** * Return a new Thing that has the keys in sorted order. Recursive. * @@ -6447,7 +7735,7 @@ exports.isBuffer = function(value) { * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again. * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()` * - * @api private + * @private * @see {@link exports.stringify} * @param {*} value Thing to inspect. May or may not have properties. * @param {Array} [stack=[]] Stack of seen values @@ -6468,7 +7756,7 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) { stack = stack || []; - if (indexOf(stack, value) !== -1) { + if (stack.indexOf(value) !== -1) { return '[Circular]'; } @@ -6480,7 +7768,7 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) { break; case 'array': withStack(value, function() { - canonicalizedObj = exports.map(value, function(item) { + canonicalizedObj = value.map(function(item) { return exports.canonicalize(item, stack); }); }); @@ -6500,9 +7788,11 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) { case 'object': canonicalizedObj = canonicalizedObj || {}; withStack(value, function() { - exports.forEach(exports.keys(value).sort(), function(key) { - canonicalizedObj[key] = exports.canonicalize(value[key], stack); - }); + Object.keys(value) + .sort() + .forEach(function(key) { + canonicalizedObj[key] = exports.canonicalize(value[key], stack); + }); }); break; case 'date': @@ -6519,48 +7809,100 @@ exports.canonicalize = function canonicalize(value, stack, typeHint) { return canonicalizedObj; }; +/** + * Determines if pathname has a matching file extension. + * + * @private + * @param {string} pathname - Pathname to check for match. + * @param {string[]} exts - List of file extensions (sans period). + * @return {boolean} whether file extension matches. + * @example + * hasMatchingExtname('foo.html', ['js', 'css']); // => false + */ +function hasMatchingExtname(pathname, exts) { + var suffix = path.extname(pathname).slice(1); + return exts.some(function(element) { + return suffix === element; + }); +} + +/** + * Determines if pathname would be a "hidden" file (or directory) on UN*X. + * + * @description + * On UN*X, pathnames beginning with a full stop (aka dot) are hidden during + * typical usage. Dotfiles, plain-text configuration files, are prime examples. + * + * @see {@link http://xahlee.info/UnixResource_dir/writ/unix_origin_of_dot_filename.html|Origin of Dot File Names} + * + * @private + * @param {string} pathname - Pathname to check for match. + * @return {boolean} whether pathname would be considered a hidden file. + * @example + * isHiddenOnUnix('.profile'); // => true + */ +function isHiddenOnUnix(pathname) { + return path.basename(pathname)[0] === '.'; +} + /** * Lookup file names at the given `path`. * - * @api public - * @param {string} path Base path to start searching from. - * @param {string[]} extensions File extensions to look for. - * @param {boolean} recursive Whether or not to recurse into subdirectories. + * @description + * Filenames are returned in _traversal_ order by the OS/filesystem. + * **Make no assumption that the names will be sorted in any fashion.** + * + * @public + * @memberof Mocha.utils + * @todo Fix extension handling + * @param {string} filepath - Base path to start searching from. + * @param {string[]} extensions - File extensions to look for. + * @param {boolean} recursive - Whether to recurse into subdirectories. * @return {string[]} An array of paths. + * @throws {Error} if no files match pattern. + * @throws {TypeError} if `filepath` is directory and `extensions` not provided. */ -exports.lookupFiles = function lookupFiles(path, extensions, recursive) { +exports.lookupFiles = function lookupFiles(filepath, extensions, recursive) { var files = []; - var re = new RegExp('\\.(' + extensions.join('|') + ')$'); + var stat; - if (!exists(path)) { - if (exists(path + '.js')) { - path += '.js'; + if (!fs.existsSync(filepath)) { + if (fs.existsSync(filepath + '.js')) { + filepath += '.js'; } else { - files = glob.sync(path); + // Handle glob + files = glob.sync(filepath); if (!files.length) { - throw new Error("cannot resolve path (or pattern) '" + path + "'"); + throw createNoFilesMatchPatternError( + 'Cannot find any files matching pattern ' + exports.dQuote(filepath), + filepath + ); } return files; } } + // Handle file try { - var stat = statSync(path); + stat = fs.statSync(filepath); if (stat.isFile()) { - return path; + return filepath; } } catch (err) { // ignore error return; } - readdirSync(path).forEach(function(file) { - file = join(path, file); + // Handle directory + fs.readdirSync(filepath).forEach(function(dirent) { + var pathname = path.join(filepath, dirent); + var stat; + try { - var stat = statSync(file); + stat = fs.statSync(pathname); if (stat.isDirectory()) { if (recursive) { - files = files.concat(lookupFiles(file, extensions, recursive)); + files = files.concat(lookupFiles(pathname, extensions, recursive)); } return; } @@ -6568,34 +7910,73 @@ exports.lookupFiles = function lookupFiles(path, extensions, recursive) { // ignore error return; } - if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') { + if (!extensions) { + throw createMissingArgumentError( + util.format( + 'Argument %s required when argument %s is a directory', + exports.sQuote('extensions'), + exports.sQuote('filepath') + ), + 'extensions', + 'array' + ); + } + + if ( + !stat.isFile() || + !hasMatchingExtname(pathname, extensions) || + isHiddenOnUnix(pathname) + ) { return; } - files.push(file); + files.push(pathname); }); return files; }; /** - * Generate an undefined error with a message warning the user. - * - * @return {Error} + * process.emitWarning or a polyfill + * @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options + * @ignore */ +function emitWarning(msg, type) { + if (process.emitWarning) { + process.emitWarning(msg, type); + } else { + process.nextTick(function() { + console.warn(type + ': ' + msg); + }); + } +} -exports.undefinedError = function() { - return new Error('Caught undefined error, did you throw without specifying what?'); +/** + * Show a deprecation warning. Each distinct message is only displayed once. + * Ignores empty messages. + * + * @param {string} [msg] - Warning to print + * @private + */ +exports.deprecate = function deprecate(msg) { + msg = String(msg); + if (msg && !deprecate.cache[msg]) { + deprecate.cache[msg] = true; + emitWarning(msg, 'DeprecationWarning'); + } }; +exports.deprecate.cache = {}; /** - * Generate an undefined error if `err` is not defined. + * Show a generic warning. + * Ignores empty messages. * - * @param {Error} err - * @return {Error} + * @param {string} [msg] - Warning to print + * @private */ - -exports.getError = function(err) { - return err || exports.undefinedError(); +exports.warn = function warn(msg) { + if (msg) { + emitWarning(msg); + } }; /** @@ -6609,36 +7990,41 @@ exports.getError = function(err) { */ exports.stackTraceFilter = function() { // TODO: Replace with `process.browser` - var is = typeof document === 'undefined' ? { node: true } : { browser: true }; + var is = typeof document === 'undefined' ? {node: true} : {browser: true}; var slash = path.sep; var cwd; if (is.node) { cwd = process.cwd() + slash; } else { - cwd = (typeof location === 'undefined' ? window.location : location).href.replace(/\/[^\/]*$/, '/'); + cwd = (typeof location === 'undefined' + ? window.location + : location + ).href.replace(/\/[^/]*$/, '/'); slash = '/'; } function isMochaInternal(line) { - return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) - || (~line.indexOf('node_modules' + slash + 'mocha.js')) - || (~line.indexOf('bower_components' + slash + 'mocha.js')) - || (~line.indexOf(slash + 'mocha.js')); + return ( + ~line.indexOf('node_modules' + slash + 'mocha' + slash) || + ~line.indexOf(slash + 'mocha.js') + ); } function isNodeInternal(line) { - return (~line.indexOf('(timers.js:')) - || (~line.indexOf('(events.js:')) - || (~line.indexOf('(node.js:')) - || (~line.indexOf('(module.js:')) - || (~line.indexOf('GeneratorFunctionPrototype.next (native)')) - || false; + return ( + ~line.indexOf('(timers.js:') || + ~line.indexOf('(events.js:') || + ~line.indexOf('(node.js:') || + ~line.indexOf('(module.js:') || + ~line.indexOf('GeneratorFunctionPrototype.next (native)') || + false + ); } return function(stack) { stack = stack.split('\n'); - stack = reduce(stack, function(list, line) { + stack = stack.reduce(function(list, line) { if (isMochaInternal(line)) { return list; } @@ -6648,8 +8034,8 @@ exports.stackTraceFilter = function() { } // Clean up cwd(absolute) - if (/\(?.+:\d+:\d+\)?$/.test(line)) { - line = line.replace(cwd, ''); + if (/:\d+:\d+\)?$/.test(line)) { + line = line.replace('(' + cwd, '('); } list.push(line); @@ -6662,89 +8048,260 @@ exports.stackTraceFilter = function() { /** * Crude, but effective. - * @api + * @public * @param {*} value * @returns {boolean} Whether or not `value` is a Promise */ exports.isPromise = function isPromise(value) { - return typeof value === 'object' && typeof value.then === 'function'; + return ( + typeof value === 'object' && + value !== null && + typeof value.then === 'function' + ); }; -}).call(this,require('_process'),require("buffer").Buffer) -},{"./to-iso-string":37,"_process":67,"buffer":44,"debug":2,"fs":42,"glob":42,"json3":54,"path":42,"util":84}],39:[function(require,module,exports){ -'use strict' - -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray +/** + * Clamps a numeric value to an inclusive range. + * + * @param {number} value - Value to be clamped. + * @param {numer[]} range - Two element array specifying [min, max] range. + * @returns {number} clamped value + */ +exports.clamp = function clamp(value, range) { + return Math.min(Math.max(value, range[0]), range[1]); +}; + +/** + * Single quote text by combining with undirectional ASCII quotation marks. + * + * @description + * Provides a simple means of markup for quoting text to be used in output. + * Use this to quote names of variables, methods, and packages. + * + * package 'foo' cannot be found + * + * @private + * @param {string} str - Value to be quoted. + * @returns {string} quoted value + * @example + * sQuote('n') // => 'n' + */ +exports.sQuote = function(str) { + return "'" + str + "'"; +}; + +/** + * Double quote text by combining with undirectional ASCII quotation marks. + * + * @description + * Provides a simple means of markup for quoting text to be used in output. + * Use this to quote names of datatypes, classes, pathnames, and strings. + * + * argument 'value' must be "string" or "number" + * + * @private + * @param {string} str - Value to be quoted. + * @returns {string} quoted value + * @example + * dQuote('number') // => "number" + */ +exports.dQuote = function(str) { + return '"' + str + '"'; +}; + +/** + * Provides simplistic message translation for dealing with plurality. + * + * @description + * Use this to create messages which need to be singular or plural. + * Some languages have several plural forms, so _complete_ message clauses + * are preferable to generating the message on the fly. + * + * @private + * @param {number} n - Non-negative integer + * @param {string} msg1 - Message to be used in English for `n = 1` + * @param {string} msg2 - Message to be used in English for `n = 0, 2, 3, ...` + * @returns {string} message corresponding to value of `n` + * @example + * var sprintf = require('util').format; + * var pkgs = ['one', 'two']; + * var msg = sprintf( + * ngettext( + * pkgs.length, + * 'cannot load package: %s', + * 'cannot load packages: %s' + * ), + * pkgs.map(sQuote).join(', ') + * ); + * console.log(msg); // => cannot load packages: 'one', 'two' + */ +exports.ngettext = function(n, msg1, msg2) { + if (typeof n === 'number' && n >= 0) { + return n === 1 ? msg1 : msg2; + } +}; + +/** + * It's a noop. + * @public + */ +exports.noop = function() {}; + +/** + * Creates a map-like object. + * + * @description + * A "map" is an object with no prototype, for our purposes. In some cases + * this would be more appropriate than a `Map`, especially if your environment + * doesn't support it. Recommended for use in Mocha's public APIs. + * + * @public + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map|MDN:Map} + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects} + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign|MDN:Object.assign} + * @param {...*} [obj] - Arguments to `Object.assign()`. + * @returns {Object} An object with no prototype, having `...obj` properties + */ +exports.createMap = function(obj) { + return assign.apply( + null, + [Object.create(null)].concat(Array.prototype.slice.call(arguments)) + ); +}; + +/** + * Creates a read-only map-like object. + * + * @description + * This differs from {@link module:utils.createMap createMap} only in that + * the argument must be non-empty, because the result is frozen. + * + * @see {@link module:utils.createMap createMap} + * @param {...*} [obj] - Arguments to `Object.assign()`. + * @returns {Object} A frozen object with no prototype, having `...obj` properties + * @throws {TypeError} if argument is not a non-empty object. + */ +exports.defineConstants = function(obj) { + if (type(obj) !== 'object' || !Object.keys(obj).length) { + throw new TypeError('Invalid argument; expected a non-empty object'); + } + return Object.freeze(exports.createMap(obj)); +}; + +}).call(this,require('_process'),require("buffer").Buffer) +},{"./errors":6,"_process":69,"buffer":43,"debug":45,"fs":42,"glob":42,"he":54,"object.assign":65,"path":42,"util":89}],39:[function(require,module,exports){ +'use strict' + +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray var lookup = [] var revLookup = [] var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array -function init () { - var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i - } - - revLookup['-'.charCodeAt(0)] = 62 - revLookup['_'.charCodeAt(0)] = 63 +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i } -init() +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 -function toByteArray (b64) { - var i, j, l, tmp, placeHolders, arr +function getLens (b64) { var len = b64.length if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(len * 3 / 4 - placeHolders) + var curByte = 0 // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen - var L = 0 + for (var i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF } - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF } return arr } function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp var output = [] for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) output.push(tripletToBase64(tmp)) } return output.join('') @@ -6754,31 +8311,34 @@ function fromByteArray (uint8) { var tmp var len = uint8.length var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' var parts = [] var maxChunkLength = 16383 // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + parts.push(encodeChunk( + uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) + )) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) } - parts.push(output) - return parts.join('') } @@ -6813,126 +8373,14 @@ BrowserStdout.prototype._write = function(chunks, encoding, cb) { } }).call(this,require('_process')) -},{"_process":67,"stream":79,"util":84}],42:[function(require,module,exports){ +},{"_process":69,"stream":84,"util":89}],42:[function(require,module,exports){ arguments[4][40][0].apply(exports,arguments) },{"dup":40}],43:[function(require,module,exports){ -(function (global){ -'use strict'; - -var buffer = require('buffer'); -var Buffer = buffer.Buffer; -var SlowBuffer = buffer.SlowBuffer; -var MAX_LEN = buffer.kMaxLength || 2147483647; -exports.alloc = function alloc(size, fill, encoding) { - if (typeof Buffer.alloc === 'function') { - return Buffer.alloc(size, fill, encoding); - } - if (typeof encoding === 'number') { - throw new TypeError('encoding must not be number'); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size > MAX_LEN) { - throw new RangeError('size is too large'); - } - var enc = encoding; - var _fill = fill; - if (_fill === undefined) { - enc = undefined; - _fill = 0; - } - var buf = new Buffer(size); - if (typeof _fill === 'string') { - var fillBuf = new Buffer(_fill, enc); - var flen = fillBuf.length; - var i = -1; - while (++i < size) { - buf[i] = fillBuf[i % flen]; - } - } else { - buf.fill(_fill); - } - return buf; -} -exports.allocUnsafe = function allocUnsafe(size) { - if (typeof Buffer.allocUnsafe === 'function') { - return Buffer.allocUnsafe(size); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size > MAX_LEN) { - throw new RangeError('size is too large'); - } - return new Buffer(size); -} -exports.from = function from(value, encodingOrOffset, length) { - if (typeof Buffer.from === 'function' && (!global.Uint8Array || Uint8Array.from !== Buffer.from)) { - return Buffer.from(value, encodingOrOffset, length); - } - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number'); - } - if (typeof value === 'string') { - return new Buffer(value, encodingOrOffset); - } - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - var offset = encodingOrOffset; - if (arguments.length === 1) { - return new Buffer(value); - } - if (typeof offset === 'undefined') { - offset = 0; - } - var len = length; - if (typeof len === 'undefined') { - len = value.byteLength - offset; - } - if (offset >= value.byteLength) { - throw new RangeError('\'offset\' is out of bounds'); - } - if (len > value.byteLength - offset) { - throw new RangeError('\'length\' is out of bounds'); - } - return new Buffer(value.slice(offset, offset + len)); - } - if (Buffer.isBuffer(value)) { - var out = new Buffer(value.length); - value.copy(out, 0, 0, value.length); - return out; - } - if (value) { - if (Array.isArray(value) || (typeof ArrayBuffer !== 'undefined' && value.buffer instanceof ArrayBuffer) || 'length' in value) { - return new Buffer(value); - } - if (value.type === 'Buffer' && Array.isArray(value.data)) { - return new Buffer(value.data); - } - } - - throw new TypeError('First argument must be a string, Buffer, ' + 'ArrayBuffer, Array, or array-like object.'); -} -exports.allocUnsafeSlow = function allocUnsafeSlow(size) { - if (typeof Buffer.allocUnsafeSlow === 'function') { - return Buffer.allocUnsafeSlow(size); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size >= MAX_LEN) { - throw new RangeError('size is too large'); - } - return new SlowBuffer(size); -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"buffer":44}],44:[function(require,module,exports){ -(function (global){ +(function (Buffer){ /*! * The buffer module from node.js, for the browser. * - * @author Feross Aboukhadijeh + * @author Feross Aboukhadijeh * @license MIT */ /* eslint-disable no-proto */ @@ -6941,80 +8389,73 @@ exports.allocUnsafeSlow = function allocUnsafeSlow(size) { var base64 = require('base64-js') var ieee754 = require('ieee754') -var isArray = require('isarray') exports.Buffer = Buffer exports.SlowBuffer = SlowBuffer exports.INSPECT_MAX_BYTES = 50 +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + /** * If `Buffer.TYPED_ARRAY_SUPPORT`: * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) * * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, * Opera 11.6+, iOS 4.2+. * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} function typedArraySupport () { + // Can typed array instances can be augmented? try { var arr = new Uint8Array(1) - arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 } catch (e) { return false } } -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} - -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset } +}) - return that +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf } /** @@ -7028,44 +8469,77 @@ function createBuffer (that, length) { */ function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } - // Common case. if (typeof arg === 'number') { if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' + throw new TypeError( + 'The "string" argument must be of type string. Received type number' ) } - return allocUnsafe(this, arg) + return allocUnsafe(arg) } - return from(this, arg, encodingOrOffset, length) + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) } Buffer.poolSize = 8192 // not used by this implementation -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } -function from (that, value, encodingOrOffset, length) { if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) } - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) } - if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) } - return fromObject(that, value) + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) } /** @@ -7077,44 +8551,36 @@ function from (that, value, encodingOrOffset, length) { * Buffer.from(arrayBuffer[, byteOffset[, length]]) **/ Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) -} - -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } + return from(value, encodingOrOffset, length) } +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array + function assertSize (size) { if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') + throw new TypeError('"size" argument must be of type number') } else if (size < 0) { - throw new RangeError('"size" argument must not be negative') + throw new RangeError('The value "' + size + '" is invalid for option "size"') } } -function alloc (that, size, fill, encoding) { +function alloc (size, fill, encoding) { assertSize(size) if (size <= 0) { - return createBuffer(that, size) + return createBuffer(size) } if (fill !== undefined) { // Only pay attention to encoding if it's a string. This // prevents accidentally sending in a number that would // be interpretted as a start offset. return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) } - return createBuffer(that, size) + return createBuffer(size) } /** @@ -7122,132 +8588,114 @@ function alloc (that, size, fill, encoding) { * alloc(size[, fill[, encoding]]) **/ Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) + return alloc(size, fill, encoding) } -function allocUnsafe (that, size) { +function allocUnsafe (size) { assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; ++i) { - that[i] = 0 - } - } - return that + return createBuffer(size < 0 ? 0 : checked(size) | 0) } /** * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. * */ Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) + return allocUnsafe(size) } /** * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. */ Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) + return allocUnsafe(size) } -function fromString (that, string, encoding) { +function fromString (string, encoding) { if (typeof encoding !== 'string' || encoding === '') { encoding = 'utf8' } if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') + throw new TypeError('Unknown encoding: ' + encoding) } var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) + var buf = createBuffer(length) - var actual = that.write(string, encoding) + var actual = buf.write(string, encoding) if (actual !== length) { // Writing a hex string, for example, that contains invalid characters will // cause everything after the first invalid character to be ignored. (e.g. // 'abxxcd' will be treated as 'ab') - that = that.slice(0, actual) + buf = buf.slice(0, actual) } - return that + return buf } -function fromArrayLike (that, array) { +function fromArrayLike (array) { var length = array.length < 0 ? 0 : checked(array.length) | 0 - that = createBuffer(that, length) + var buf = createBuffer(length) for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 + buf[i] = array[i] & 255 } - return that + return buf } -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer - +function fromArrayBuffer (array, byteOffset, length) { if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') + throw new RangeError('"offset" is outside of buffer bounds') } if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') + throw new RangeError('"length" is outside of buffer bounds') } + var buf if (byteOffset === undefined && length === undefined) { - array = new Uint8Array(array) + buf = new Uint8Array(array) } else if (length === undefined) { - array = new Uint8Array(array, byteOffset) + buf = new Uint8Array(array, byteOffset) } else { - array = new Uint8Array(array, byteOffset, length) + buf = new Uint8Array(array, byteOffset, length) } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf } -function fromObject (that, obj) { +function fromObject (obj) { if (Buffer.isBuffer(obj)) { var len = checked(obj.length) | 0 - that = createBuffer(that, len) + var buf = createBuffer(len) - if (that.length === 0) { - return that + if (buf.length === 0) { + return buf } - obj.copy(that, 0, 0, len) - return that + obj.copy(buf, 0, 0, len) + return buf } - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) - } - - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) } + return fromArrayLike(obj) } - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } } function checked (length) { - // Note: cannot use `length < kMaxLength()` here because that fails when + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { + if (length >= K_MAX_LENGTH) { throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') } return length | 0 } @@ -7260,12 +8708,17 @@ function SlowBuffer (length) { } Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false } Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) } if (a === b) return 0 @@ -7306,7 +8759,7 @@ Buffer.isEncoding = function isEncoding (encoding) { } Buffer.concat = function concat (list, length) { - if (!isArray(list)) { + if (!Array.isArray(list)) { throw new TypeError('"list" argument must be an Array of Buffers') } @@ -7326,6 +8779,9 @@ Buffer.concat = function concat (list, length) { var pos = 0 for (i = 0; i < list.length; ++i) { var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) + } if (!Buffer.isBuffer(buf)) { throw new TypeError('"list" argument must be an Array of Buffers') } @@ -7339,16 +8795,19 @@ function byteLength (string, encoding) { if (Buffer.isBuffer(string)) { return string.length } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { return string.byteLength } if (typeof string !== 'string') { - string = '' + string + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) } var len = string.length - if (len === 0) return 0 + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 // Use a for loop to avoid recursion var loweredCase = false @@ -7360,7 +8819,6 @@ function byteLength (string, encoding) { return len case 'utf8': case 'utf-8': - case undefined: return utf8ToBytes(string).length case 'ucs2': case 'ucs-2': @@ -7372,7 +8830,9 @@ function byteLength (string, encoding) { case 'base64': return base64ToBytes(string).length default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } encoding = ('' + encoding).toLowerCase() loweredCase = true } @@ -7450,8 +8910,12 @@ function slowToString (encoding, start, end) { } } -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 Buffer.prototype._isBuffer = true function swap (b, n, m) { @@ -7498,12 +8962,14 @@ Buffer.prototype.swap64 = function swap64 () { } Buffer.prototype.toString = function toString () { - var length = this.length | 0 + var length = this.length if (length === 0) return '' if (arguments.length === 0) return utf8Slice(this, 0, length) return slowToString.apply(this, arguments) } +Buffer.prototype.toLocaleString = Buffer.prototype.toString + Buffer.prototype.equals = function equals (b) { if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') if (this === b) return true @@ -7513,16 +8979,20 @@ Buffer.prototype.equals = function equals (b) { Buffer.prototype.inspect = function inspect () { var str = '' var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' return '' } Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) } if (start === undefined) { @@ -7601,8 +9071,8 @@ function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { } else if (byteOffset < -0x80000000) { byteOffset = -0x80000000 } - byteOffset = +byteOffset // Coerce to Number. - if (isNaN(byteOffset)) { + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer byteOffset = dir ? 0 : (buffer.length - 1) } @@ -7631,8 +9101,7 @@ function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { return arrayIndexOf(buffer, val, byteOffset, encoding, dir) } else if (typeof val === 'number') { val = val & 0xFF // Search for a byte value [0-255] - if (Buffer.TYPED_ARRAY_SUPPORT && - typeof Uint8Array.prototype.indexOf === 'function') { + if (typeof Uint8Array.prototype.indexOf === 'function') { if (dir) { return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) } else { @@ -7725,16 +9194,14 @@ function hexWrite (buf, string, offset, length) { } } - // must be an even number of digits var strLen = string.length - if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') if (length > strLen / 2) { length = strLen / 2 } for (var i = 0; i < length; ++i) { var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i + if (numberIsNaN(parsed)) return i buf[offset + i] = parsed } return i @@ -7773,15 +9240,14 @@ Buffer.prototype.write = function write (string, offset, length, encoding) { offset = 0 // Buffer#write(string, offset[, length][, encoding]) } else if (isFinite(offset)) { - offset = offset | 0 + offset = offset >>> 0 if (isFinite(length)) { - length = length | 0 + length = length >>> 0 if (encoding === undefined) encoding = 'utf8' } else { encoding = length length = undefined } - // legacy write(string, encoding, offset, length) - remove in v0.13 } else { throw new Error( 'Buffer.write(string, encoding, offset[, length]) is no longer supported' @@ -7857,8 +9323,8 @@ function utf8Slice (buf, start, end) { var codePoint = null var bytesPerSequence = (firstByte > 0xEF) ? 4 : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 + : (firstByte > 0xBF) ? 2 + : 1 if (i + bytesPerSequence <= end) { var secondByte, thirdByte, fourthByte, tempCodePoint @@ -7980,7 +9446,7 @@ function utf16leSlice (buf, start, end) { var bytes = buf.slice(start, end) var res = '' for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) } return res } @@ -8006,18 +9472,9 @@ Buffer.prototype.slice = function slice (start, end) { if (end < start) end = start - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; ++i) { - newBuf[i] = this[i + start] - } - } - + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype return newBuf } @@ -8030,8 +9487,8 @@ function checkOffset (offset, ext, length) { } Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] @@ -8045,8 +9502,8 @@ Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) } Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) { checkOffset(offset, byteLength, this.length) } @@ -8061,21 +9518,25 @@ Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) } Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 1, this.length) return this[offset] } Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) return this[offset] | (this[offset + 1] << 8) } Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) return (this[offset] << 8) | this[offset + 1] } Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ((this[offset]) | @@ -8085,6 +9546,7 @@ Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { } Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] * 0x1000000) + @@ -8094,8 +9556,8 @@ Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { } Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] @@ -8112,8 +9574,8 @@ Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { } Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var i = byteLength @@ -8130,24 +9592,28 @@ Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { } Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 1, this.length) if (!(this[offset] & 0x80)) return (this[offset]) return ((0xff - this[offset] + 1) * -1) } Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset] | (this[offset + 1] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset + 1] | (this[offset] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset]) | @@ -8157,6 +9623,7 @@ Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { } Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] << 24) | @@ -8166,21 +9633,25 @@ Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { } Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, true, 23, 4) } Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, false, 23, 4) } Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, true, 52, 8) } Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, false, 52, 8) } @@ -8193,8 +9664,8 @@ function checkInt (buf, value, offset, ext, max, min) { Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1 checkInt(this, value, offset, byteLength, maxBytes, 0) @@ -8212,8 +9683,8 @@ Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1 checkInt(this, value, offset, byteLength, maxBytes, 0) @@ -8231,89 +9702,57 @@ Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) this[offset] = (value & 0xff) return offset + 1 } -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} - Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) return offset + 2 } Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) return offset + 2 } -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} - Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) return offset + 4 } Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) return offset + 4 } Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) + var limit = Math.pow(2, (8 * byteLength) - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } @@ -8334,9 +9773,9 @@ Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, no Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) + var limit = Math.pow(2, (8 * byteLength) - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } @@ -8357,9 +9796,8 @@ Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, no Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) if (value < 0) value = 0xff + value + 1 this[offset] = (value & 0xff) return offset + 1 @@ -8367,58 +9805,42 @@ Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) return offset + 2 } Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) return offset + 2 } Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) return offset + 4 } Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) return offset + 4 } @@ -8428,6 +9850,8 @@ function checkIEEE754 (buf, value, offset, ext, max, min) { } function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 if (!noAssert) { checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) } @@ -8444,6 +9868,8 @@ Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) } function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 if (!noAssert) { checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) } @@ -8461,6 +9887,7 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') if (!start) start = 0 if (!end && end !== 0) end = this.length if (targetStart >= target.length) targetStart = target.length @@ -8475,7 +9902,7 @@ Buffer.prototype.copy = function copy (target, targetStart, start, end) { if (targetStart < 0) { throw new RangeError('targetStart out of bounds') } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') if (end < 0) throw new RangeError('sourceEnd out of bounds') // Are we oob? @@ -8485,22 +9912,19 @@ Buffer.prototype.copy = function copy (target, targetStart, start, end) { } var len = end - start - var i - if (this === target && start < targetStart && targetStart < end) { + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; ++i) { + for (var i = len - 1; i >= 0; --i) { target[i + targetStart] = this[i + start] } } else { Uint8Array.prototype.set.call( target, - this.subarray(start, start + len), + this.subarray(start, end), targetStart ) } @@ -8523,18 +9947,20 @@ Buffer.prototype.fill = function fill (val, start, end, encoding) { encoding = end end = this.length } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } if (encoding !== undefined && typeof encoding !== 'string') { throw new TypeError('encoding must be a string') } if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { throw new TypeError('Unknown encoding: ' + encoding) } + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } } else if (typeof val === 'number') { val = val & 255 } @@ -8561,8 +9987,12 @@ Buffer.prototype.fill = function fill (val, start, end, encoding) { } else { var bytes = Buffer.isBuffer(val) ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) + : Buffer.from(val, encoding) var len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } for (i = 0; i < end - start; ++i) { this[i + start] = bytes[i % len] } @@ -8574,11 +10004,13 @@ Buffer.prototype.fill = function fill (val, start, end, encoding) { // HELPER FUNCTIONS // ================ -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') + str = str.trim().replace(INVALID_BASE64_RE, '') // Node converts strings with length < 2 to '' if (str.length < 2) return '' // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not @@ -8588,11 +10020,6 @@ function base64clean (str) { return str } -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} - function toHex (n) { if (n < 16) return '0' + n.toString(16) return n.toString(16) @@ -8715,12 +10142,21 @@ function blitBuffer (src, dst, offset, length) { return i } -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare } -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":39,"ieee754":50,"isarray":53}],45:[function(require,module,exports){ +}).call(this,require("buffer").Buffer) +},{"base64-js":39,"buffer":43,"ieee754":55}],44:[function(require,module,exports){ (function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // @@ -8831,3389 +10267,3477 @@ function objectToString(o) { } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":52}],46:[function(require,module,exports){ -/* See LICENSE file for terms of use */ +},{"../../is-buffer/index.js":57}],45:[function(require,module,exports){ +(function (process){ +"use strict"; -/* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +/* eslint-env browser */ + +/** + * This is the web browser implementation of `debug()`. + */ +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = localstorage(); +/** + * Colors. + */ + +exports.colors = ['#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33']; +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. * - * JsDiff.diffCss: Diff targeted at CSS content + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ +// eslint-disable-next-line complexity + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { + return true; + } // Internet Explorer and Edge do not support colors. + + + if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { + return false; + } // Is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + + + return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773 + typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker + typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/); +} +/** + * Colorize log arguments if enabled. * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + * @api public */ -(function(global, undefined) { - var objectPrototypeToString = Object.prototype.toString; - /*istanbul ignore next*/ - function map(arr, mapper, that) { - if (Array.prototype.map) { - return Array.prototype.map.call(arr, mapper, that); - } - var other = new Array(arr.length); +function formatArgs(args) { + args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff); - for (var i = 0, n = arr.length; i < n; i++) { - other[i] = mapper.call(that, arr[i], i, arr); - } - return other; - } - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; - } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; + if (!this.useColors) { + return; } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(//g, '>'); - n = n.replace(/"/g, '"'); - return n; - } + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit'); // The final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into - // This function handles the presence of circular references by bailing out when encountering an - // object that is already on the "stack" of items being processed. - function canonicalize(obj, stack, replacementStack) { - stack = stack || []; - replacementStack = replacementStack || []; + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function (match) { + if (match === '%%') { + return; + } - var i; + index++; - for (i = 0; i < stack.length; i += 1) { - if (stack[i] === obj) { - return replacementStack[i]; - } + if (match === '%c') { + // We only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; } + }); + args.splice(lastC, 0, c); +} +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ - var canonicalizedObj; - if ('[object Array]' === objectPrototypeToString.call(obj)) { - stack.push(obj); - canonicalizedObj = new Array(obj.length); - replacementStack.push(canonicalizedObj); - for (i = 0; i < obj.length; i += 1) { - canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); - } else if (typeof obj === 'object' && obj !== null) { - stack.push(obj); - canonicalizedObj = {}; - replacementStack.push(canonicalizedObj); - var sortedKeys = [], - key; - for (key in obj) { - sortedKeys.push(key); - } - sortedKeys.sort(); - for (i = 0; i < sortedKeys.length; i += 1) { - key = sortedKeys[i]; - canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); +function log() { + var _console; + + // This hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return (typeof console === "undefined" ? "undefined" : _typeof(console)) === 'object' && console.log && (_console = console).log.apply(_console, arguments); +} +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + + +function save(namespaces) { + try { + if (namespaces) { + exports.storage.setItem('debug', namespaces); } else { - canonicalizedObj = obj; + exports.storage.removeItem('debug'); } - return canonicalizedObj; + } catch (error) {// Swallow + // XXX (@Qix-) should we be logging these? } +} +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ - function buildValues(components, newString, oldString, useLongestToken) { - var componentPos = 0, - componentLen = components.length, - newPos = 0, - oldPos = 0; - for (; componentPos < componentLen; componentPos++) { - var component = components[componentPos]; - if (!component.removed) { - if (!component.added && useLongestToken) { - var value = newString.slice(newPos, newPos + component.count); - value = map(value, function(value, i) { - var oldValue = oldString[oldPos + i]; - return oldValue.length > value.length ? oldValue : value; - }); +function load() { + var r; - component.value = value.join(''); - } else { - component.value = newString.slice(newPos, newPos + component.count).join(''); - } - newPos += component.count; + try { + r = exports.storage.getItem('debug'); + } catch (error) {} // Swallow + // XXX (@Qix-) should we be logging these? + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - // Common case - if (!component.added) { - oldPos += component.count; - } - } else { - component.value = oldString.slice(oldPos, oldPos + component.count).join(''); - oldPos += component.count; - - // Reverse add and remove so removes are output first to match common convention - // The diffing algorithm is tied to add then remove output and this is the simplest - // route to get the desired output with minimal overhead. - if (componentPos && components[componentPos - 1].added) { - var tmp = components[componentPos - 1]; - components[componentPos - 1] = components[componentPos]; - components[componentPos] = tmp; - } - } - } - return components; + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; } - function Diff(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - } - Diff.prototype = { - diff: function(oldString, newString, callback) { - var self = this; + return r; +} +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ - function done(value) { - if (callback) { - setTimeout(function() { callback(undefined, value); }, 0); - return true; - } else { - return value; - } - } - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString === oldString) { - return done([{ value: newString }]); - } - if (!newString) { - return done([{ value: oldString, removed: true }]); - } - if (!oldString) { - return done([{ value: newString, added: true }]); - } +function localstorage() { + try { + // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context + // The Browser also has localStorage in the global context. + return localStorage; + } catch (error) {// Swallow + // XXX (@Qix-) should we be logging these? + } +} - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); +module.exports = require('./common')(exports); +var formatters = module.exports.formatters; +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ - var newLen = newString.length, oldLen = oldString.length; - var editLength = 1; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; +formatters.j = function (v) { + try { + return JSON.stringify(v); + } catch (error) { + return '[UnexpectedJSONParseError]: ' + error.message; + } +}; - // Seed editLength = 0, i.e. the content starts with the same values - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - // Identity per the equality and tokenizer - return done([{value: newString.join('')}]); - } - // Main worker method. checks all permutations of a given edit length for acceptance. - function execEditLength() { - for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { - var basePath; - var addPath = bestPath[diagonalPath - 1], - removePath = bestPath[diagonalPath + 1], - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath - 1] = undefined; - } +}).call(this,require('_process')) +},{"./common":46,"_process":69}],46:[function(require,module,exports){ +"use strict"; + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + */ +function setup(env) { + createDebug.debug = createDebug; + createDebug.default = createDebug; + createDebug.coerce = coerce; + createDebug.disable = disable; + createDebug.enable = enable; + createDebug.enabled = enabled; + createDebug.humanize = require('ms'); + Object.keys(env).forEach(function (key) { + createDebug[key] = env[key]; + }); + /** + * Active `debug` instances. + */ - var canAdd = addPath && addPath.newPos + 1 < newLen, - canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - // If this path is a terminal then prune - bestPath[diagonalPath] = undefined; - continue; - } + createDebug.instances = []; + /** + * The currently active debug mode names, and names to skip. + */ - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - self.pushComponent(basePath.components, undefined, true); - } else { - basePath = addPath; // No need to clone, we've pulled it from the list - basePath.newPos++; - self.pushComponent(basePath.components, true, undefined); - } + createDebug.names = []; + createDebug.skips = []; + /** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ - oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); + createDebug.formatters = {}; + /** + * Selects a color for a debug namespace + * @param {String} namespace The namespace string for the for the debug instance to be colored + * @return {Number|String} An ANSI color code for the given namespace + * @api private + */ - // If we have hit the end of both strings, then we are done - if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - return done(buildValues(basePath.components, newString, oldString, self.useLongestToken)); - } else { - // Otherwise track this path as a potential candidate and continue. - bestPath[diagonalPath] = basePath; - } - } + function selectColor(namespace) { + var hash = 0; - editLength++; - } + for (var i = 0; i < namespace.length; i++) { + hash = (hash << 5) - hash + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } - // Performs the length of edit iteration. Is a bit fugly as this has to support the - // sync and async mode which is never fun. Loops over execEditLength until a value - // is produced. - if (callback) { - (function exec() { - setTimeout(function() { - // This should not happen, but we want to be safe. - /*istanbul ignore next */ - if (editLength > maxEditLength) { - return callback(); - } + return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; + } - if (!execEditLength()) { - exec(); - } - }, 0); - }()); - } else { - while (editLength <= maxEditLength) { - var ret = execEditLength(); - if (ret) { - return ret; - } - } - } - }, + createDebug.selectColor = selectColor; + /** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ - pushComponent: function(components, added, removed) { - var last = components[components.length - 1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length - 1] = {count: last.count + 1, added: added, removed: removed }; - } else { - components.push({count: 1, added: added, removed: removed }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath, - - commonCount = 0; - while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { - newPos++; - oldPos++; - commonCount++; - } + function createDebug(namespace) { + var prevTime; - if (commonCount) { - basePath.components.push({count: commonCount}); + function debug() { + // Disabled? + if (!debug.enabled) { + return; } - basePath.newPos = newPos; - return oldPos; - }, + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } - equals: function(left, right) { - var reWhitespace = /\S/; - return left === right || (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)); - }, - tokenize: function(value) { - return value.split(''); - } - }; + var self = debug; // Set `diff` timestamp - var CharDiff = new Diff(); + var curr = Number(new Date()); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + args[0] = createDebug.coerce(args[0]); - var WordDiff = new Diff(true); - var WordWithSpaceDiff = new Diff(); - WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; + if (typeof args[0] !== 'string') { + // Anything else let's inspect with %O + args.unshift('%O'); + } // Apply any `formatters` transformations - var CssDiff = new Diff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; - var LineDiff = new Diff(); + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function (match, format) { + // If we encounter an escaped % then don't increase the array index + if (match === '%%') { + return match; + } - var TrimmedLineDiff = new Diff(); - TrimmedLineDiff.ignoreTrim = true; + index++; + var formatter = createDebug.formatters[format]; - LineDiff.tokenize = TrimmedLineDiff.tokenize = function(value) { - var retLines = [], - lines = value.split(/^/m); - for (var i = 0; i < lines.length; i++) { - var line = lines[i], - lastLine = lines[i - 1], - lastLineLastChar = lastLine && lastLine[lastLine.length - 1]; + if (typeof formatter === 'function') { + var val = args[index]; + match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format` - // Merge lines that may contain windows new lines - if (line === '\n' && lastLineLastChar === '\r') { - retLines[retLines.length - 1] = retLines[retLines.length - 1].slice(0, -1) + '\r\n'; - } else { - if (this.ignoreTrim) { - line = line.trim(); - // add a newline unless this is the last line. - if (i < lines.length - 1) { - line += '\n'; - } + args.splice(index, 1); + index--; } - retLines.push(line); - } - } - - return retLines; - }; - var PatchDiff = new Diff(); - PatchDiff.tokenize = function(value) { - var ret = [], - linesAndNewlines = value.split(/(\n|\r\n)/); + return match; + }); // Apply env-specific formatting (colors, etc.) - // Ignore the final empty token that occurs if the string ends with a new line - if (!linesAndNewlines[linesAndNewlines.length - 1]) { - linesAndNewlines.pop(); + createDebug.formatArgs.call(self, args); + var logFn = self.log || createDebug.log; + logFn.apply(self, args); } - // Merge the content and line separators into single tokens - for (var i = 0; i < linesAndNewlines.length; i++) { - var line = linesAndNewlines[i]; + debug.namespace = namespace; + debug.enabled = createDebug.enabled(namespace); + debug.useColors = createDebug.useColors(); + debug.color = selectColor(namespace); + debug.destroy = destroy; + debug.extend = extend; // Debug.formatArgs = formatArgs; + // debug.rawLog = rawLog; + // env-specific initialization logic for debug instances - if (i % 2) { - ret[ret.length - 1] += line; - } else { - ret.push(line); - } + if (typeof createDebug.init === 'function') { + createDebug.init(debug); } - return ret; - }; - var SentenceDiff = new Diff(); - SentenceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\S.+?[.!?])(?=\s+|$)/)); - }; - - var JsonDiff = new Diff(); - // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a - // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: - JsonDiff.useLongestToken = true; - JsonDiff.tokenize = LineDiff.tokenize; - JsonDiff.equals = function(left, right) { - return LineDiff.equals(left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')); - }; - - var JsDiff = { - Diff: Diff, + createDebug.instances.push(debug); + return debug; + } - diffChars: function(oldStr, newStr, callback) { return CharDiff.diff(oldStr, newStr, callback); }, - diffWords: function(oldStr, newStr, callback) { return WordDiff.diff(oldStr, newStr, callback); }, - diffWordsWithSpace: function(oldStr, newStr, callback) { return WordWithSpaceDiff.diff(oldStr, newStr, callback); }, - diffLines: function(oldStr, newStr, callback) { return LineDiff.diff(oldStr, newStr, callback); }, - diffTrimmedLines: function(oldStr, newStr, callback) { return TrimmedLineDiff.diff(oldStr, newStr, callback); }, + function destroy() { + var index = createDebug.instances.indexOf(this); - diffSentences: function(oldStr, newStr, callback) { return SentenceDiff.diff(oldStr, newStr, callback); }, + if (index !== -1) { + createDebug.instances.splice(index, 1); + return true; + } - diffCss: function(oldStr, newStr, callback) { return CssDiff.diff(oldStr, newStr, callback); }, - diffJson: function(oldObj, newObj, callback) { - return JsonDiff.diff( - typeof oldObj === 'string' ? oldObj : JSON.stringify(canonicalize(oldObj), undefined, ' '), - typeof newObj === 'string' ? newObj : JSON.stringify(canonicalize(newObj), undefined, ' '), - callback - ); - }, + return false; + } - createTwoFilesPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; + function extend(namespace, delimiter) { + return createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); + } + /** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ - if (oldFileName == newFileName) { - ret.push('Index: ' + oldFileName); - } - ret.push('==================================================================='); - ret.push('--- ' + oldFileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + newFileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - var diff = PatchDiff.diff(oldStr, newStr); - diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier + function enable(namespaces) { + createDebug.save(namespaces); + createDebug.names = []; + createDebug.skips = []; + var i; + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; - // Formats a given set of lines for printing as context lines in a patch - function contextLines(lines) { - return map(lines, function(entry) { return ' ' + entry; }); + for (i = 0; i < len; i++) { + if (!split[i]) { + // ignore empty strings + continue; } - // Outputs the no newline at end of file warning if needed - function eofNL(curRange, i, current) { - var last = diff[diff.length - 2], - isLast = i === diff.length - 2, - isLastOfType = i === diff.length - 3 && current.added !== last.added; + namespaces = split[i].replace(/\*/g, '.*?'); - // Figure out if this is the last line for the given file and missing NL - if (!(/\n$/.test(current.value)) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } + if (namespaces[0] === '-') { + createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + createDebug.names.push(new RegExp('^' + namespaces + '$')); } + } - var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; - - if (current.added || current.removed) { - // If we have previous context, start with that - if (!oldRangeStart) { - var prev = diff[i - 1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } + for (i = 0; i < createDebug.instances.length; i++) { + var instance = createDebug.instances[i]; + instance.enabled = createDebug.enabled(instance.namespace); + } + } + /** + * Disable debug output. + * + * @api public + */ - // Output our changes - curRange.push.apply(curRange, map(lines, function(entry) { - return (current.added ? '+' : '-') + entry; - })); - eofNL(curRange, i, current); - // Track the updated file position - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - // Identical context lines. Track line changes - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length - 2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize) - + ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - - oldRangeStart = 0; - newRangeStart = 0; - curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } + function disable() { + createDebug.enable(''); + } + /** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ - return ret.join('\n') + '\n'; - }, - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - return JsDiff.createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader); - }, + function enabled(name) { + if (name[name.length - 1] === '*') { + return true; + } - applyPatch: function(oldStr, uniDiff) { - var diffstr = uniDiff.split('\n'), - hunks = [], - i = 0, - remEOFNL = false, - addEOFNL = false; + var i; + var len; - // Skip to the first change hunk - while (i < diffstr.length && !(/^@@/.test(diffstr[i]))) { - i++; + for (i = 0, len = createDebug.skips.length; i < len; i++) { + if (createDebug.skips[i].test(name)) { + return false; } + } - // Parse the unified diff - for (; i < diffstr.length; i++) { - if (diffstr[i][0] === '@') { - var chnukHeader = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - hunks.unshift({ - start: chnukHeader[3], - oldlength: +chnukHeader[2], - removed: [], - newlength: chnukHeader[4], - added: [] - }); - } else if (diffstr[i][0] === '+') { - hunks[0].added.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === '-') { - hunks[0].removed.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === ' ') { - hunks[0].added.push(diffstr[i].substr(1)); - hunks[0].removed.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === '\\') { - if (diffstr[i - 1][0] === '+') { - remEOFNL = true; - } else if (diffstr[i - 1][0] === '-') { - addEOFNL = true; - } - } + for (i = 0, len = createDebug.names.length; i < len; i++) { + if (createDebug.names[i].test(name)) { + return true; } + } - // Apply the diff to the input - var lines = oldStr.split('\n'); - for (i = hunks.length - 1; i >= 0; i--) { - var hunk = hunks[i]; - // Sanity check the input string. Bail if we don't match. - for (var j = 0; j < hunk.oldlength; j++) { - if (lines[hunk.start - 1 + j] !== hunk.removed[j]) { - return false; - } - } - Array.prototype.splice.apply(lines, [hunk.start - 1, hunk.oldlength].concat(hunk.added)); - } + return false; + } + /** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ - // Handle EOFNL insertion/removal - if (remEOFNL) { - while (!lines[lines.length - 1]) { - lines.pop(); - } - } else if (addEOFNL) { - lines.push(''); - } - return lines.join('\n'); - }, - convertChangesToXML: function(changes) { - var ret = []; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } + function coerce(val) { + if (val instanceof Error) { + return val.stack || val.message; + } - ret.push(escapeHTML(change.value)); + return val; + } - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - } - return ret.join(''); - }, + createDebug.enable(createDebug.load()); + return createDebug; +} - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - convertChangesToDMP: function(changes) { - var ret = [], - change, - operation; - for (var i = 0; i < changes.length; i++) { - change = changes[i]; - if (change.added) { - operation = 1; - } else if (change.removed) { - operation = -1; - } else { - operation = 0; - } +module.exports = setup; - ret.push([operation, change.value]); - } - return ret; - }, - canonicalize: canonicalize - }; +},{"ms":60}],47:[function(require,module,exports){ +'use strict'; - /*istanbul ignore next */ - /*global module */ - if (typeof module !== 'undefined' && module.exports) { - module.exports = JsDiff; - } else if (false) { - /*global define */ - define([], function() { return JsDiff; }); - } else if (typeof global.JsDiff === 'undefined') { - global.JsDiff = JsDiff; - } -}(this)); +var keys = require('object-keys'); +var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol'; -},{}],47:[function(require,module,exports){ -'use strict'; +var toStr = Object.prototype.toString; +var concat = Array.prototype.concat; +var origDefineProperty = Object.defineProperty; -var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; +var isFunction = function (fn) { + return typeof fn === 'function' && toStr.call(fn) === '[object Function]'; +}; -module.exports = function (str) { - if (typeof str !== 'string') { - throw new TypeError('Expected a string'); +var arePropertyDescriptorsSupported = function () { + var obj = {}; + try { + origDefineProperty(obj, 'x', { enumerable: false, value: obj }); + // eslint-disable-next-line no-unused-vars, no-restricted-syntax + for (var _ in obj) { // jscs:ignore disallowUnusedVariables + return false; + } + return obj.x === obj; + } catch (e) { /* this is IE 8. */ + return false; } +}; +var supportsDescriptors = origDefineProperty && arePropertyDescriptorsSupported(); - return str.replace(matchOperatorsRe, '\\$&'); +var defineProperty = function (object, name, value, predicate) { + if (name in object && (!isFunction(predicate) || !predicate())) { + return; + } + if (supportsDescriptors) { + origDefineProperty(object, name, { + configurable: true, + enumerable: false, + value: value, + writable: true + }); + } else { + object[name] = value; + } }; -},{}],48:[function(require,module,exports){ -// 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 defineProperties = function (object, map) { + var predicates = arguments.length > 2 ? arguments[2] : {}; + var props = keys(map); + if (hasSymbols) { + props = concat.call(props, Object.getOwnPropertySymbols(map)); + } + for (var i = 0; i < props.length; i += 1) { + defineProperty(object, props[i], map[props[i]], predicates[props[i]]); + } +}; -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; +defineProperties.supportsDescriptors = !!supportsDescriptors; -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; +module.exports = defineProperties; -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; +},{"object-keys":62}],48:[function(require,module,exports){ +/*! -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; + diff v3.5.0 -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; +Software License Agreement (BSD License) -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; +Copyright (c) 2009-2015, Kevin Decker - if (!this._events) - this._events = {}; +All rights reserved. - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); - err.context = er; - throw err; - } - } - } +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: - handler = this._events[type]; +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. - if (isUndefined(handler)) - return false; +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } +* Neither the name of Kevin Decker nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission. - return true; -}; +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +@license +*/ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(false) + define([], factory); + else if(typeof exports === 'object') + exports["JsDiff"] = factory(); + else + root["JsDiff"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; -EventEmitter.prototype.addListener = function(type, listener) { - var m; +/******/ // The require function +/******/ function __webpack_require__(moduleId) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; - if (!this._events) - this._events = {}; +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); +/******/ // Flag the module as loaded +/******/ module.loaded = true; - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } - return this; -}; -EventEmitter.prototype.on = EventEmitter.prototype.addListener; +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; - var fired = false; +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; - function g() { - this.removeListener(type, g); +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } + /*istanbul ignore start*/'use strict'; - g.listener = listener; - this.on(type, g); + exports.__esModule = true; + exports.canonicalize = exports.convertChangesToXML = exports.convertChangesToDMP = exports.merge = exports.parsePatch = exports.applyPatches = exports.applyPatch = exports.createPatch = exports.createTwoFilesPatch = exports.structuredPatch = exports.diffArrays = exports.diffJson = exports.diffCss = exports.diffSentences = exports.diffTrimmedLines = exports.diffLines = exports.diffWordsWithSpace = exports.diffWords = exports.diffChars = exports.Diff = undefined; - return this; -}; + /*istanbul ignore end*/var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + /*istanbul ignore end*/var /*istanbul ignore start*/_character = __webpack_require__(2) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_word = __webpack_require__(3) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_sentence = __webpack_require__(6) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_css = __webpack_require__(7) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_json = __webpack_require__(8) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_array = __webpack_require__(9) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_apply = __webpack_require__(10) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_merge = __webpack_require__(13) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_create = __webpack_require__(14) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_dmp = __webpack_require__(16) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_xml = __webpack_require__(17) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /* See LICENSE file for terms of use */ + + /* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ + exports. /*istanbul ignore end*/Diff = _base2['default']; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffChars = _character.diffChars; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWords = _word.diffWords; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = _word.diffWordsWithSpace; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffLines = _line.diffLines; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = _line.diffTrimmedLines; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffSentences = _sentence.diffSentences; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffCss = _css.diffCss; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffJson = _json.diffJson; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffArrays = _array.diffArrays; + /*istanbul ignore start*/exports. /*istanbul ignore end*/structuredPatch = _create.structuredPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = _create.createTwoFilesPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = _create.createPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatch = _apply.applyPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = _apply.applyPatches; + /*istanbul ignore start*/exports. /*istanbul ignore end*/parsePatch = _parse.parsePatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/merge = _merge.merge; + /*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToDMP = _dmp.convertChangesToDMP; + /*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToXML = _xml.convertChangesToXML; + /*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = _json.canonicalize; + + + +/***/ }), +/* 1 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports['default'] = /*istanbul ignore end*/Diff; + function Diff() {} + + Diff.prototype = { + /*istanbul ignore start*/ /*istanbul ignore end*/diff: function diff(oldString, newString) { + /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var callback = options.callback; + if (typeof options === 'function') { + callback = options; + options = {}; + } + this.options = options; + + var self = this; + + function done(value) { + if (callback) { + setTimeout(function () { + callback(undefined, value); + }, 0); + return true; + } else { + return value; + } + } + + // Allow subclasses to massage the input prior to running + oldString = this.castInput(oldString); + newString = this.castInput(newString); + + oldString = this.removeEmpty(this.tokenize(oldString)); + newString = this.removeEmpty(this.tokenize(newString)); + + var newLen = newString.length, + oldLen = oldString.length; + var editLength = 1; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0, i.e. the content starts with the same values + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { + // Identity per the equality and tokenizer + return done([{ value: this.join(newString), count: newString.length }]); + } + + // Main worker method. checks all permutations of a given edit length for acceptance. + function execEditLength() { + for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { + var basePath = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + var addPath = bestPath[diagonalPath - 1], + removePath = bestPath[diagonalPath + 1], + _oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath - 1] = undefined; + } + + var canAdd = addPath && addPath.newPos + 1 < newLen, + canRemove = removePath && 0 <= _oldPos && _oldPos < oldLen; + if (!canAdd && !canRemove) { + // If this path is a terminal then prune + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || canRemove && addPath.newPos < removePath.newPos) { + basePath = clonePath(removePath); + self.pushComponent(basePath.components, undefined, true); + } else { + basePath = addPath; // No need to clone, we've pulled it from the list + basePath.newPos++; + self.pushComponent(basePath.components, true, undefined); + } + + _oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); + + // If we have hit the end of both strings, then we are done + if (basePath.newPos + 1 >= newLen && _oldPos + 1 >= oldLen) { + return done(buildValues(self, basePath.components, newString, oldString, self.useLongestToken)); + } else { + // Otherwise track this path as a potential candidate and continue. + bestPath[diagonalPath] = basePath; + } + } + + editLength++; + } + + // Performs the length of edit iteration. Is a bit fugly as this has to support the + // sync and async mode which is never fun. Loops over execEditLength until a value + // is produced. + if (callback) { + (function exec() { + setTimeout(function () { + // This should not happen, but we want to be safe. + /* istanbul ignore next */ + if (editLength > maxEditLength) { + return callback(); + } + + if (!execEditLength()) { + exec(); + } + }, 0); + })(); + } else { + while (editLength <= maxEditLength) { + var ret = execEditLength(); + if (ret) { + return ret; + } + } + } + }, + /*istanbul ignore start*/ /*istanbul ignore end*/pushComponent: function pushComponent(components, added, removed) { + var last = components[components.length - 1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length - 1] = { count: last.count + 1, added: added, removed: removed }; + } else { + components.push({ count: 1, added: added, removed: removed }); + } + }, + /*istanbul ignore start*/ /*istanbul ignore end*/extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath, + commonCount = 0; + while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { + newPos++; + oldPos++; + commonCount++; + } + + if (commonCount) { + basePath.components.push({ count: commonCount }); + } + + basePath.newPos = newPos; + return oldPos; + }, + /*istanbul ignore start*/ /*istanbul ignore end*/equals: function equals(left, right) { + if (this.options.comparator) { + return this.options.comparator(left, right); + } else { + return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase(); + } + }, + /*istanbul ignore start*/ /*istanbul ignore end*/removeEmpty: function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + }, + /*istanbul ignore start*/ /*istanbul ignore end*/castInput: function castInput(value) { + return value; + }, + /*istanbul ignore start*/ /*istanbul ignore end*/tokenize: function tokenize(value) { + return value.split(''); + }, + /*istanbul ignore start*/ /*istanbul ignore end*/join: function join(chars) { + return chars.join(''); + } + }; + + function buildValues(diff, components, newString, oldString, useLongestToken) { + var componentPos = 0, + componentLen = components.length, + newPos = 0, + oldPos = 0; + + for (; componentPos < componentLen; componentPos++) { + var component = components[componentPos]; + if (!component.removed) { + if (!component.added && useLongestToken) { + var value = newString.slice(newPos, newPos + component.count); + value = value.map(function (value, i) { + var oldValue = oldString[oldPos + i]; + return oldValue.length > value.length ? oldValue : value; + }); + + component.value = diff.join(value); + } else { + component.value = diff.join(newString.slice(newPos, newPos + component.count)); + } + newPos += component.count; + + // Common case + if (!component.added) { + oldPos += component.count; + } + } else { + component.value = diff.join(oldString.slice(oldPos, oldPos + component.count)); + oldPos += component.count; + + // Reverse add and remove so removes are output first to match common convention + // The diffing algorithm is tied to add then remove output and this is the simplest + // route to get the desired output with minimal overhead. + if (componentPos && components[componentPos - 1].added) { + var tmp = components[componentPos - 1]; + components[componentPos - 1] = components[componentPos]; + components[componentPos] = tmp; + } + } + } + + // Special case handle for when one terminal is ignored (i.e. whitespace). + // For this case we merge the terminal into the prior string and drop the change. + // This is only available for string mode. + var lastComponent = components[componentLen - 1]; + if (componentLen > 1 && typeof lastComponent.value === 'string' && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) { + components[componentLen - 2].value += lastComponent.value; + components.pop(); + } + + return components; + } - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } - if (!this._events || !this._events[type]) - return this; - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - if (position < 0) - return this; +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } + /*istanbul ignore start*/'use strict'; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } + exports.__esModule = true; + exports.characterDiff = undefined; + exports. /*istanbul ignore end*/diffChars = diffChars; - return this; -}; + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - if (!this._events) - return this; + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } + /*istanbul ignore end*/var characterDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/characterDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + function diffChars(oldStr, newStr, options) { + return characterDiff.diff(oldStr, newStr, options); + } - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - listeners = this._events[type]; - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.wordDiff = undefined; + exports. /*istanbul ignore end*/diffWords = diffWords; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = diffWordsWithSpace; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + /*istanbul ignore end*/var /*istanbul ignore start*/_params = __webpack_require__(4) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/ // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode + // + // Ranges and exceptions: + // Latin-1 Supplement, 0080–00FF + // - U+00D7 × Multiplication sign + // - U+00F7 ÷ Division sign + // Latin Extended-A, 0100–017F + // Latin Extended-B, 0180–024F + // IPA Extensions, 0250–02AF + // Spacing Modifier Letters, 02B0–02FF + // - U+02C7 ˇ ˇ Caron + // - U+02D8 ˘ ˘ Breve + // - U+02D9 ˙ ˙ Dot Above + // - U+02DA ˚ ˚ Ring Above + // - U+02DB ˛ ˛ Ogonek + // - U+02DC ˜ ˜ Small Tilde + // - U+02DD ˝ ˝ Double Acute Accent + // Latin Extended Additional, 1E00–1EFF + var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/; + + var reWhitespace = /\S/; + + var wordDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/wordDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + wordDiff.equals = function (left, right) { + if (this.options.ignoreCase) { + left = left.toLowerCase(); + right = right.toLowerCase(); + } + return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right); + }; + wordDiff.tokenize = function (value) { + var tokens = value.split(/(\s+|\b)/); + + // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set. + for (var i = 0; i < tokens.length - 1; i++) { + // If we have an empty string in the next field and we have only word chars before and after, merge + if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) { + tokens[i] += tokens[i + 2]; + tokens.splice(i + 1, 2); + i--; + } + } + + return tokens; + }; + + function diffWords(oldStr, newStr, options) { + options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(options, { ignoreWhitespace: true }); + return wordDiff.diff(oldStr, newStr, options); + } - return this; -}; + function diffWordsWithSpace(oldStr, newStr, options) { + return wordDiff.diff(oldStr, newStr, options); + } -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; +/***/ }), +/* 4 */ +/***/ (function(module, exports) { -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; + /*istanbul ignore start*/'use strict'; -function isFunction(arg) { - return typeof arg === 'function'; -} + exports.__esModule = true; + exports. /*istanbul ignore end*/generateOptions = generateOptions; + function generateOptions(options, defaults) { + if (typeof options === 'function') { + defaults.callback = options; + } else if (options) { + for (var name in options) { + /* istanbul ignore else */ + if (options.hasOwnProperty(name)) { + defaults[name] = options[name]; + } + } + } + return defaults; + } -function isNumber(arg) { - return typeof arg === 'number'; -} -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -function isUndefined(arg) { - return arg === void 0; -} +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { -},{}],49:[function(require,module,exports){ -(function (process){ -// Growl - Copyright TJ Holowaychuk (MIT Licensed) + /*istanbul ignore start*/'use strict'; -/** - * Module dependencies. - */ + exports.__esModule = true; + exports.lineDiff = undefined; + exports. /*istanbul ignore end*/diffLines = diffLines; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = diffTrimmedLines; -var exec = require('child_process').exec - , fs = require('fs') - , path = require('path') - , exists = fs.existsSync || path.existsSync - , os = require('os') - , quote = JSON.stringify - , cmd; - -function which(name) { - var paths = process.env.PATH.split(':'); - var loc; - - for (var i = 0, len = paths.length; i < len; ++i) { - loc = path.join(paths[i], name); - if (exists(loc)) return loc; - } -} - -switch(os.type()) { - case 'Darwin': - if (which('terminal-notifier')) { - cmd = { - type: "Darwin-NotificationCenter" - , pkg: "terminal-notifier" - , msg: '-message' - , title: '-title' - , subtitle: '-subtitle' - , icon: '-appIcon' - , sound: '-sound' - , url: '-open' - , priority: { - cmd: '-execute' - , range: [] - } - }; - } else { - cmd = { - type: "Darwin-Growl" - , pkg: "growlnotify" - , msg: '-m' - , sticky: '--sticky' - , priority: { - cmd: '--priority' - , range: [ - -2 - , -1 - , 0 - , 1 - , 2 - , "Very Low" - , "Moderate" - , "Normal" - , "High" - , "Emergency" - ] - } - }; - } - break; - case 'Linux': - if (which('growl')) { - cmd = { - type: "Linux-Growl" - , pkg: "growl" - , msg: '-m' - , title: '-title' - , subtitle: '-subtitle' - , host: { - cmd: '-H' - , hostname: '192.168.33.1' - } - }; - } else { - cmd = { - type: "Linux" - , pkg: "notify-send" - , msg: '' - , sticky: '-t 0' - , icon: '-i' - , priority: { - cmd: '-u' - , range: [ - "low" - , "normal" - , "critical" - ] - } - }; - } - break; - case 'Windows_NT': - cmd = { - type: "Windows" - , pkg: "growlnotify" - , msg: '' - , sticky: '/s:true' - , title: '/t:' - , icon: '/i:' - , url: '/cu:' - , priority: { - cmd: '/p:' - , range: [ - -2 - , -1 - , 0 - , 1 - , 2 - ] - } - }; - break; -} + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; -/** - * Expose `growl`. - */ + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); -exports = module.exports = growl; + /*istanbul ignore end*/var /*istanbul ignore start*/_params = __webpack_require__(4) /*istanbul ignore end*/; -/** - * Node-growl version. - */ + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } -exports.version = '1.4.1' + /*istanbul ignore end*/var lineDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/lineDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + lineDiff.tokenize = function (value) { + var retLines = [], + linesAndNewlines = value.split(/(\n|\r\n)/); -/** - * Send growl notification _msg_ with _options_. - * - * Options: - * - * - title Notification title - * - sticky Make the notification stick (defaults to false) - * - priority Specify an int or named key (default is 0) - * - name Application name (defaults to growlnotify) - * - sound Sound efect ( in OSx defined in preferences -> sound -> effects) * works only in OSX > 10.8x - * - image - * - path to an icon sets --iconpath - * - path to an image sets --image - * - capitalized word sets --appIcon - * - filename uses extname as --icon - * - otherwise treated as --icon - * - * Examples: - * - * growl('New email') - * growl('5 new emails', { title: 'Thunderbird' }) - * growl('5 new emails', { title: 'Thunderbird', sound: 'Purr' }) - * growl('Email sent', function(){ - * // ... notification sent - * }) - * - * @param {string} msg - * @param {object} options - * @param {function} fn - * @api public - */ + // Ignore the final empty token that occurs if the string ends with a new line + if (!linesAndNewlines[linesAndNewlines.length - 1]) { + linesAndNewlines.pop(); + } -function growl(msg, options, fn) { - var image - , args - , options = options || {} - , fn = fn || function(){}; + // Merge the content and line separators into single tokens + for (var i = 0; i < linesAndNewlines.length; i++) { + var line = linesAndNewlines[i]; - if (options.exec) { - cmd = { - type: "Custom" - , pkg: options.exec - , range: [] - }; - } + if (i % 2 && !this.options.newlineIsToken) { + retLines[retLines.length - 1] += line; + } else { + if (this.options.ignoreWhitespace) { + line = line.trim(); + } + retLines.push(line); + } + } - // noop - if (!cmd) return fn(new Error('growl not supported on this platform')); - args = [cmd.pkg]; - - // image - if (image = options.image) { - switch(cmd.type) { - case 'Darwin-Growl': - var flag, ext = path.extname(image).substr(1) - flag = flag || ext == 'icns' && 'iconpath' - flag = flag || /^[A-Z]/.test(image) && 'appIcon' - flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' - flag = flag || ext && (image = ext) && 'icon' - flag = flag || 'icon' - args.push('--' + flag, quote(image)) - break; - case 'Darwin-NotificationCenter': - args.push(cmd.icon, quote(image)); - break; - case 'Linux': - args.push(cmd.icon, quote(image)); - // libnotify defaults to sticky, set a hint for transient notifications - if (!options.sticky) args.push('--hint=int:transient:1'); - break; - case 'Windows': - args.push(cmd.icon + quote(image)); - break; - } - } + return retLines; + }; - // sticky - if (options.sticky) args.push(cmd.sticky); + function diffLines(oldStr, newStr, callback) { + return lineDiff.diff(oldStr, newStr, callback); + } + function diffTrimmedLines(oldStr, newStr, callback) { + var options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(callback, { ignoreWhitespace: true }); + return lineDiff.diff(oldStr, newStr, options); + } - // priority - if (options.priority) { - var priority = options.priority + ''; - var checkindexOf = cmd.priority.range.indexOf(priority); - if (~cmd.priority.range.indexOf(priority)) { - args.push(cmd.priority, options.priority); - } - } - //sound - if(options.sound && cmd.type === 'Darwin-NotificationCenter'){ - args.push(cmd.sound, options.sound) - } - // name - if (options.name && cmd.type === "Darwin-Growl") { - args.push('--name', options.name); - } +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { - switch(cmd.type) { - case 'Darwin-Growl': - args.push(cmd.msg); - args.push(quote(msg).replace(/\\n/g, '\n')); - if (options.title) args.push(quote(options.title)); - break; - case 'Darwin-NotificationCenter': - args.push(cmd.msg); - var stringifiedMsg = quote(msg); - var escapedMsg = stringifiedMsg.replace(/\\n/g, '\n'); - args.push(escapedMsg); - if (options.title) { - args.push(cmd.title); - args.push(quote(options.title)); - } - if (options.subtitle) { - args.push(cmd.subtitle); - args.push(quote(options.subtitle)); - } - if (options.url) { - args.push(cmd.url); - args.push(quote(options.url)); - } - break; - case 'Linux-Growl': - args.push(cmd.msg); - args.push(quote(msg).replace(/\\n/g, '\n')); - if (options.title) args.push(quote(options.title)); - if (cmd.host) { - args.push(cmd.host.cmd, cmd.host.hostname) - } - break; - case 'Linux': - if (options.title) { - args.push(quote(options.title)); - args.push(cmd.msg); - args.push(quote(msg).replace(/\\n/g, '\n')); - } else { - args.push(quote(msg).replace(/\\n/g, '\n')); - } - break; - case 'Windows': - args.push(quote(msg).replace(/\\n/g, '\n')); - if (options.title) args.push(cmd.title + quote(options.title)); - if (options.url) args.push(cmd.url + quote(options.url)); - break; - case 'Custom': - args[0] = (function(origCommand) { - var message = options.title - ? options.title + ': ' + msg - : msg; - var command = origCommand.replace(/(^|[^%])%s/g, '$1' + quote(message)); - if (command === origCommand) args.push(quote(message)); - return command; - })(args[0]); - break; - } + /*istanbul ignore start*/'use strict'; - // execute - exec(args.join(' '), fn); -}; + exports.__esModule = true; + exports.sentenceDiff = undefined; + exports. /*istanbul ignore end*/diffSentences = diffSentences; -}).call(this,require('_process')) -},{"_process":67,"child_process":42,"fs":42,"os":65,"path":42}],50:[function(require,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - i += d + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + /*istanbul ignore end*/var sentenceDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/sentenceDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + sentenceDiff.tokenize = function (value) { + return value.split(/(\S.+?[.!?])(?=\s+|$)/); + }; - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} + function diffSentences(oldStr, newStr, callback) { + return sentenceDiff.diff(oldStr, newStr, callback); + } -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - value = Math.abs(value) - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } + /*istanbul ignore start*/'use strict'; - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + exports.__esModule = true; + exports.cssDiff = undefined; + exports. /*istanbul ignore end*/diffCss = diffCss; - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - buffer[offset + i - d] |= s * 128 -} + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); -},{}],51:[function(require,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 - } -} + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } -},{}],52:[function(require,module,exports){ -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ + /*istanbul ignore end*/var cssDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/cssDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + cssDiff.tokenize = function (value) { + return value.split(/([{}:;,]|\s+)/); + }; -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} + function diffCss(oldStr, newStr, callback) { + return cssDiff.diff(oldStr, newStr, callback); + } -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} -},{}],53:[function(require,module,exports){ -var toString = {}.toString; +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; + /*istanbul ignore start*/'use strict'; -},{}],54:[function(require,module,exports){ -(function (global){ -/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */ -;(function () { - // Detect the `define` function exposed by asynchronous module loaders. The - // strict `define` check is necessary for compatibility with `r.js`. - var isLoader = false; - - // A set of types used to distinguish objects from primitives. - var objectTypes = { - "function": true, - "object": true - }; + exports.__esModule = true; + exports.jsonDiff = undefined; - // Detect the `exports` object exposed by CommonJS implementations. - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - - // Use the `global` object exposed by Node (including Browserify via - // `insert-module-globals`), Narwhal, and Ringo as the default context, - // and the `window` object in browsers. Rhino exports a `global` function - // instead. - var root = objectTypes[typeof window] && window || this, - freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global; - - if (freeGlobal && (freeGlobal["global"] === freeGlobal || freeGlobal["window"] === freeGlobal || freeGlobal["self"] === freeGlobal)) { - root = freeGlobal; - } - - // Public: Initializes JSON 3 using the given `context` object, attaching the - // `stringify` and `parse` functions to the specified `exports` object. - function runInContext(context, exports) { - context || (context = root["Object"]()); - exports || (exports = root["Object"]()); - - // Native constructor aliases. - var Number = context["Number"] || root["Number"], - String = context["String"] || root["String"], - Object = context["Object"] || root["Object"], - Date = context["Date"] || root["Date"], - SyntaxError = context["SyntaxError"] || root["SyntaxError"], - TypeError = context["TypeError"] || root["TypeError"], - Math = context["Math"] || root["Math"], - nativeJSON = context["JSON"] || root["JSON"]; - - // Delegate to the native `stringify` and `parse` implementations. - if (typeof nativeJSON == "object" && nativeJSON) { - exports.stringify = nativeJSON.stringify; - exports.parse = nativeJSON.parse; - } - - // Convenience aliases. - var objectProto = Object.prototype, - getClass = objectProto.toString, - isProperty, forEach, undef; - - // Test the `Date#getUTC*` methods. Based on work by @Yaffle. - var isExtended = new Date(-3509827334573292); - try { - // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical - // results for certain dates in Opera >= 10.53. - isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && - // Safari < 2.0.2 stores the internal millisecond time value correctly, - // but clips the values returned by the date methods to the range of - // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]). - isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; - } catch (exception) {} - - // Internal: Determines whether the native `JSON.stringify` and `parse` - // implementations are spec-compliant. Based on work by Ken Snyder. - function has(name) { - if (has[name] !== undef) { - // Return cached feature test result. - return has[name]; - } - var isSupported; - if (name == "bug-string-char-index") { - // IE <= 7 doesn't support accessing string characters using square - // bracket notation. IE 8 only supports this for primitives. - isSupported = "a"[0] != "a"; - } else if (name == "json") { - // Indicates whether both `JSON.stringify` and `JSON.parse` are - // supported. - isSupported = has("json-stringify") && has("json-parse"); - } else { - var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; - // Test `JSON.stringify`. - if (name == "json-stringify") { - var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended; - if (stringifySupported) { - // A test function object with a custom `toJSON` method. - (value = function () { - return 1; - }).toJSON = value; - try { - stringifySupported = - // Firefox 3.1b1 and b2 serialize string, number, and boolean - // primitives as object literals. - stringify(0) === "0" && - // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object - // literals. - stringify(new Number()) === "0" && - stringify(new String()) == '""' && - // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or - // does not define a canonical JSON representation (this applies to - // objects with `toJSON` properties as well, *unless* they are nested - // within an object or array). - stringify(getClass) === undef && - // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and - // FF 3.1b3 pass this test. - stringify(undef) === undef && - // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s, - // respectively, if the value is omitted entirely. - stringify() === undef && - // FF 3.1b1, 2 throw an error if the given value is not a number, - // string, array, object, Boolean, or `null` literal. This applies to - // objects with custom `toJSON` methods as well, unless they are nested - // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON` - // methods entirely. - stringify(value) === "1" && - stringify([value]) == "[1]" && - // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of - // `"[null]"`. - stringify([undef]) == "[null]" && - // YUI 3.0.0b1 fails to serialize `null` literals. - stringify(null) == "null" && - // FF 3.1b1, 2 halts serialization if an array contains a function: - // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3 - // elides non-JSON values from objects and arrays, unless they - // define custom `toJSON` methods. - stringify([undef, getClass, null]) == "[null,null,null]" && - // Simple serialization test. FF 3.1b1 uses Unicode escape sequences - // where character escape codes are expected (e.g., `\b` => `\u0008`). - stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && - // FF 3.1b1 and b2 ignore the `filter` and `width` arguments. - stringify(null, value) === "1" && - stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && - // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly - // serialize extended years. - stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && - // The milliseconds are optional in ES 5, but required in 5.1. - stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && - // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative - // four-digit years instead of six-digit years. Credits: @Yaffle. - stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && - // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond - // values less than 1000. Credits: @Yaffle. - stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; - } catch (exception) { - stringifySupported = false; - } - } - isSupported = stringifySupported; - } - // Test `JSON.parse`. - if (name == "json-parse") { - var parse = exports.parse; - if (typeof parse == "function") { - try { - // FF 3.1b1, b2 will throw an exception if a bare literal is provided. - // Conforming implementations should also coerce the initial argument to - // a string prior to parsing. - if (parse("0") === 0 && !parse(false)) { - // Simple parsing test. - value = parse(serialized); - var parseSupported = value["a"].length == 5 && value["a"][0] === 1; - if (parseSupported) { - try { - // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings. - parseSupported = !parse('"\t"'); - } catch (exception) {} - if (parseSupported) { - try { - // FF 4.0 and 4.0.1 allow leading `+` signs and leading - // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow - // certain octal literals. - parseSupported = parse("01") !== 1; - } catch (exception) {} - } - if (parseSupported) { - try { - // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal - // points. These environments, along with FF 3.1b1 and 2, - // also allow trailing commas in JSON objects and arrays. - parseSupported = parse("1.") !== 1; - } catch (exception) {} - } - } - } - } catch (exception) { - parseSupported = false; - } - } - isSupported = parseSupported; - } - } - return has[name] = !!isSupported; - } - - if (!has("json")) { - // Common `[[Class]]` name aliases. - var functionClass = "[object Function]", - dateClass = "[object Date]", - numberClass = "[object Number]", - stringClass = "[object String]", - arrayClass = "[object Array]", - booleanClass = "[object Boolean]"; - - // Detect incomplete support for accessing string characters by index. - var charIndexBuggy = has("bug-string-char-index"); - - // Define additional utility methods if the `Date` methods are buggy. - if (!isExtended) { - var floor = Math.floor; - // A mapping between the months of the year and the number of days between - // January 1st and the first of the respective month. - var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; - // Internal: Calculates the number of days between the Unix epoch and the - // first day of the given month. - var getDay = function (year, month) { - return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); - }; - } + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - // Internal: Determines if a property is a direct property of the given - // object. Delegates to the native `Object#hasOwnProperty` method. - if (!(isProperty = objectProto.hasOwnProperty)) { - isProperty = function (property) { - var members = {}, constructor; - if ((members.__proto__ = null, members.__proto__ = { - // The *proto* property cannot be set multiple times in recent - // versions of Firefox and SeaMonkey. - "toString": 1 - }, members).toString != getClass) { - // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but - // supports the mutable *proto* property. - isProperty = function (property) { - // Capture and break the object's prototype chain (see section 8.6.2 - // of the ES 5.1 spec). The parenthesized expression prevents an - // unsafe transformation by the Closure Compiler. - var original = this.__proto__, result = property in (this.__proto__ = null, this); - // Restore the original prototype chain. - this.__proto__ = original; - return result; - }; - } else { - // Capture a reference to the top-level `Object` constructor. - constructor = members.constructor; - // Use the `constructor` property to simulate `Object#hasOwnProperty` in - // other environments. - isProperty = function (property) { - var parent = (this.constructor || constructor).prototype; - return property in this && !(property in parent && this[property] === parent[property]); - }; - } - members = null; - return isProperty.call(this, property); - }; - } + exports. /*istanbul ignore end*/diffJson = diffJson; + /*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = canonicalize; - // Internal: Normalizes the `for...in` iteration algorithm across - // environments. Each enumerated key is yielded to a `callback` function. - forEach = function (object, callback) { - var size = 0, Properties, members, property; - - // Tests for bugs in the current environment's `for...in` algorithm. The - // `valueOf` property inherits the non-enumerable flag from - // `Object.prototype` in older versions of IE, Netscape, and Mozilla. - (Properties = function () { - this.valueOf = 0; - }).prototype.valueOf = 0; - - // Iterate over a new instance of the `Properties` class. - members = new Properties(); - for (property in members) { - // Ignore all properties inherited from `Object.prototype`. - if (isProperty.call(members, property)) { - size++; - } - } - Properties = members = null; - - // Normalize the iteration algorithm. - if (!size) { - // A list of non-enumerable properties inherited from `Object.prototype`. - members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; - // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable - // properties. - forEach = function (object, callback) { - var isFunction = getClass.call(object) == functionClass, property, length; - var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty; - for (property in object) { - // Gecko <= 1.0 enumerates the `prototype` property of functions under - // certain conditions; IE does not. - if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { - callback(property); - } - } - // Manually invoke the callback for each non-enumerable property. - for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); - }; - } else if (size == 2) { - // Safari <= 2.0.4 enumerates shadowed properties twice. - forEach = function (object, callback) { - // Create a set of iterated properties. - var members = {}, isFunction = getClass.call(object) == functionClass, property; - for (property in object) { - // Store each property name to prevent double enumeration. The - // `prototype` property of functions is not enumerated due to cross- - // environment inconsistencies. - if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { - callback(property); - } - } - }; - } else { - // No bugs detected; use the standard `for...in` algorithm. - forEach = function (object, callback) { - var isFunction = getClass.call(object) == functionClass, property, isConstructor; - for (property in object) { - if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { - callback(property); - } - } - // Manually invoke the callback for the `constructor` property due to - // cross-environment inconsistencies. - if (isConstructor || isProperty.call(object, (property = "constructor"))) { - callback(property); - } - }; - } - return forEach(object, callback); - }; + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - // Public: Serializes a JavaScript `value` as a JSON string. The optional - // `filter` argument may specify either a function that alters how object and - // array members are serialized, or an array of strings and numbers that - // indicates which properties should be serialized. The optional `width` - // argument may be either a string or number that specifies the indentation - // level of the output. - if (!has("json-stringify")) { - // Internal: A map of control characters and their escaped equivalents. - var Escapes = { - 92: "\\\\", - 34: '\\"', - 8: "\\b", - 12: "\\f", - 10: "\\n", - 13: "\\r", - 9: "\\t" - }; + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - // Internal: Converts `value` into a zero-padded string such that its - // length is at least equal to `width`. The `width` must be <= 6. - var leadingZeroes = "000000"; - var toPaddedString = function (width, value) { - // The `|| 0` expression is necessary to work around a bug in - // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`. - return (leadingZeroes + (value || 0)).slice(-width); - }; + /*istanbul ignore end*/var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; - // Internal: Double-quotes a string `value`, replacing all ASCII control - // characters (characters with code unit values between 0 and 31) with - // their escaped equivalents. This is an implementation of the - // `Quote(value)` operation defined in ES 5.1 section 15.12.3. - var unicodePrefix = "\\u00"; - var quote = function (value) { - var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10; - var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value); - for (; index < length; index++) { - var charCode = value.charCodeAt(index); - // If the character is a control character, append its Unicode or - // shorthand escape sequence; otherwise, append the character as-is. - switch (charCode) { - case 8: case 9: case 10: case 12: case 13: case 34: case 92: - result += Escapes[charCode]; - break; - default: - if (charCode < 32) { - result += unicodePrefix + toPaddedString(2, charCode.toString(16)); - break; - } - result += useCharIndex ? symbols[index] : value.charAt(index); - } - } - return result + '"'; - }; + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - // Internal: Recursively serializes an object. Implements the - // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations. - var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { - var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; - try { - // Necessary for host object support. - value = object[property]; - } catch (exception) {} - if (typeof value == "object" && value) { - className = getClass.call(value); - if (className == dateClass && !isProperty.call(value, "toJSON")) { - if (value > -1 / 0 && value < 1 / 0) { - // Dates are serialized according to the `Date#toJSON` method - // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15 - // for the ISO 8601 date time string format. - if (getDay) { - // Manually compute the year, month, date, hours, minutes, - // seconds, and milliseconds if the `getUTC*` methods are - // buggy. Adapted from @Yaffle's `date-shim` project. - date = floor(value / 864e5); - for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); - for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); - date = 1 + date - getDay(year, month); - // The `time` value specifies the time within the day (see ES - // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used - // to compute `A modulo B`, as the `%` operator does not - // correspond to the `modulo` operation for negative numbers. - time = (value % 864e5 + 864e5) % 864e5; - // The hours, minutes, seconds, and milliseconds are obtained by - // decomposing the time within the day. See section 15.9.1.10. - hours = floor(time / 36e5) % 24; - minutes = floor(time / 6e4) % 60; - seconds = floor(time / 1e3) % 60; - milliseconds = time % 1e3; - } else { - year = value.getUTCFullYear(); - month = value.getUTCMonth(); - date = value.getUTCDate(); - hours = value.getUTCHours(); - minutes = value.getUTCMinutes(); - seconds = value.getUTCSeconds(); - milliseconds = value.getUTCMilliseconds(); - } - // Serialize extended years correctly. - value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + - "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + - // Months, dates, hours, minutes, and seconds should have two - // digits; milliseconds should have three. - "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + - // Milliseconds are optional in ES 5.0, but required in 5.1. - "." + toPaddedString(3, milliseconds) + "Z"; - } else { - value = null; - } - } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { - // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the - // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3 - // ignores all `toJSON` methods on these objects unless they are - // defined directly on an instance. - value = value.toJSON(property); - } - } - if (callback) { - // If a replacement function was provided, call it to obtain the value - // for serialization. - value = callback.call(object, property, value); - } - if (value === null) { - return "null"; - } - className = getClass.call(value); - if (className == booleanClass) { - // Booleans are represented literally. - return "" + value; - } else if (className == numberClass) { - // JSON numbers must be finite. `Infinity` and `NaN` are serialized as - // `"null"`. - return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; - } else if (className == stringClass) { - // Strings are double-quoted and escaped. - return quote("" + value); - } - // Recursively serialize objects and arrays. - if (typeof value == "object") { - // Check for cyclic structures. This is a linear search; performance - // is inversely proportional to the number of unique nested objects. - for (length = stack.length; length--;) { - if (stack[length] === value) { - // Cyclic structures cannot be serialized by `JSON.stringify`. - throw TypeError(); - } - } - // Add the object to the stack of traversed objects. - stack.push(value); - results = []; - // Save the current indentation level and indent one additional level. - prefix = indentation; - indentation += whitespace; - if (className == arrayClass) { - // Recursively serialize array elements. - for (index = 0, length = value.length; index < length; index++) { - element = serialize(index, value, callback, properties, whitespace, indentation, stack); - results.push(element === undef ? "null" : element); - } - result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; - } else { - // Recursively serialize object members. Members are selected from - // either a user-specified list of property names, or the object - // itself. - forEach(properties || value, function (property) { - var element = serialize(property, value, callback, properties, whitespace, indentation, stack); - if (element !== undef) { - // According to ES 5.1 section 15.12.3: "If `gap` {whitespace} - // is not the empty string, let `member` {quote(property) + ":"} - // be the concatenation of `member` and the `space` character." - // The "`space` character" refers to the literal space - // character, not the `space` {width} argument provided to - // `JSON.stringify`. - results.push(quote(property) + ":" + (whitespace ? " " : "") + element); - } - }); - result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; - } - // Remove the object from the traversed object stack. - stack.pop(); - return result; - } - }; + /*istanbul ignore end*/var objectPrototypeToString = Object.prototype.toString; - // Public: `JSON.stringify`. See ES 5.1 section 15.12.3. - exports.stringify = function (source, filter, width) { - var whitespace, callback, properties, className; - if (objectTypes[typeof filter] && filter) { - if ((className = getClass.call(filter)) == functionClass) { - callback = filter; - } else if (className == arrayClass) { - // Convert the property names array into a makeshift set. - properties = {}; - for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); - } - } - if (width) { - if ((className = getClass.call(width)) == numberClass) { - // Convert the `width` to an integer and create a string containing - // `width` number of space characters. - if ((width -= width % 1) > 0) { - for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); - } - } else if (className == stringClass) { - whitespace = width.length <= 10 ? width : width.slice(0, 10); - } - } - // Opera <= 7.54u2 discards the values associated with empty string keys - // (`""`) only if they are used directly within an object member list - // (e.g., `!("" in { "": 1})`). - return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); - }; - } + var jsonDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/jsonDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a + // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: + jsonDiff.useLongestToken = true; - // Public: Parses a JSON source string. - if (!has("json-parse")) { - var fromCharCode = String.fromCharCode; - - // Internal: A map of escaped control characters and their unescaped - // equivalents. - var Unescapes = { - 92: "\\", - 34: '"', - 47: "/", - 98: "\b", - 116: "\t", - 110: "\n", - 102: "\f", - 114: "\r" - }; + jsonDiff.tokenize = /*istanbul ignore start*/_line.lineDiff /*istanbul ignore end*/.tokenize; + jsonDiff.castInput = function (value) { + /*istanbul ignore start*/var _options = /*istanbul ignore end*/this.options, + undefinedReplacement = _options.undefinedReplacement, + _options$stringifyRep = _options.stringifyReplacer, + stringifyReplacer = _options$stringifyRep === undefined ? function (k, v) /*istanbul ignore start*/{ + return (/*istanbul ignore end*/typeof v === 'undefined' ? undefinedReplacement : v + ); + } : _options$stringifyRep; - // Internal: Stores the parser state. - var Index, Source; - // Internal: Resets the parser state and throws a `SyntaxError`. - var abort = function () { - Index = Source = null; - throw SyntaxError(); - }; + return typeof value === 'string' ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, ' '); + }; + jsonDiff.equals = function (left, right) { + return (/*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')) + ); + }; - // Internal: Returns the next token, or `"$"` if the parser has reached - // the end of the source string. A token may be a string, number, `null` - // literal, or Boolean literal. - var lex = function () { - var source = Source, length = source.length, value, begin, position, isSigned, charCode; - while (Index < length) { - charCode = source.charCodeAt(Index); - switch (charCode) { - case 9: case 10: case 13: case 32: - // Skip whitespace tokens, including tabs, carriage returns, line - // feeds, and space characters. - Index++; - break; - case 123: case 125: case 91: case 93: case 58: case 44: - // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at - // the current position. - value = charIndexBuggy ? source.charAt(Index) : source[Index]; - Index++; - return value; - case 34: - // `"` delimits a JSON string; advance to the next character and - // begin parsing the string. String tokens are prefixed with the - // sentinel `@` character to distinguish them from punctuators and - // end-of-string tokens. - for (value = "@", Index++; Index < length;) { - charCode = source.charCodeAt(Index); - if (charCode < 32) { - // Unescaped ASCII control characters (those with a code unit - // less than the space character) are not permitted. - abort(); - } else if (charCode == 92) { - // A reverse solidus (`\`) marks the beginning of an escaped - // control character (including `"`, `\`, and `/`) or Unicode - // escape sequence. - charCode = source.charCodeAt(++Index); - switch (charCode) { - case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: - // Revive escaped control characters. - value += Unescapes[charCode]; - Index++; - break; - case 117: - // `\u` marks the beginning of a Unicode escape sequence. - // Advance to the first character and validate the - // four-digit code point. - begin = ++Index; - for (position = Index + 4; Index < position; Index++) { - charCode = source.charCodeAt(Index); - // A valid sequence comprises four hexdigits (case- - // insensitive) that form a single hexadecimal value. - if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { - // Invalid Unicode escape sequence. - abort(); - } - } - // Revive the escaped character. - value += fromCharCode("0x" + source.slice(begin, Index)); - break; - default: - // Invalid escape sequence. - abort(); - } - } else { - if (charCode == 34) { - // An unescaped double-quote character marks the end of the - // string. - break; - } - charCode = source.charCodeAt(Index); - begin = Index; - // Optimize for the common case where a string is valid. - while (charCode >= 32 && charCode != 92 && charCode != 34) { - charCode = source.charCodeAt(++Index); - } - // Append the string as-is. - value += source.slice(begin, Index); - } - } - if (source.charCodeAt(Index) == 34) { - // Advance to the next character and return the revived string. - Index++; - return value; - } - // Unterminated string. - abort(); - default: - // Parse numbers and literals. - begin = Index; - // Advance past the negative sign, if one is specified. - if (charCode == 45) { - isSigned = true; - charCode = source.charCodeAt(++Index); - } - // Parse an integer or floating-point value. - if (charCode >= 48 && charCode <= 57) { - // Leading zeroes are interpreted as octal literals. - if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { - // Illegal octal literal. - abort(); - } - isSigned = false; - // Parse the integer component. - for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); - // Floats cannot contain a leading decimal point; however, this - // case is already accounted for by the parser. - if (source.charCodeAt(Index) == 46) { - position = ++Index; - // Parse the decimal component. - for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); - if (position == Index) { - // Illegal trailing decimal. - abort(); - } - Index = position; - } - // Parse exponents. The `e` denoting the exponent is - // case-insensitive. - charCode = source.charCodeAt(Index); - if (charCode == 101 || charCode == 69) { - charCode = source.charCodeAt(++Index); - // Skip past the sign following the exponent, if one is - // specified. - if (charCode == 43 || charCode == 45) { - Index++; - } - // Parse the exponential component. - for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); - if (position == Index) { - // Illegal empty exponent. - abort(); - } - Index = position; - } - // Coerce the parsed value to a JavaScript number. - return +source.slice(begin, Index); - } - // A negative sign may only precede numbers. - if (isSigned) { - abort(); - } - // `true`, `false`, and `null` literals. - if (source.slice(Index, Index + 4) == "true") { - Index += 4; - return true; - } else if (source.slice(Index, Index + 5) == "false") { - Index += 5; - return false; - } else if (source.slice(Index, Index + 4) == "null") { - Index += 4; - return null; - } - // Unrecognized token. - abort(); - } - } - // Return the sentinel `$` character if the parser has reached the end - // of the source string. - return "$"; - }; + function diffJson(oldObj, newObj, options) { + return jsonDiff.diff(oldObj, newObj, options); + } - // Internal: Parses a JSON `value` token. - var get = function (value) { - var results, hasMembers; - if (value == "$") { - // Unexpected end of input. - abort(); - } - if (typeof value == "string") { - if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { - // Remove the sentinel `@` character. - return value.slice(1); - } - // Parse object and array literals. - if (value == "[") { - // Parses a JSON array, returning a new JavaScript array. - results = []; - for (;; hasMembers || (hasMembers = true)) { - value = lex(); - // A closing square bracket marks the end of the array literal. - if (value == "]") { - break; - } - // If the array literal contains elements, the current token - // should be a comma separating the previous element from the - // next. - if (hasMembers) { - if (value == ",") { - value = lex(); - if (value == "]") { - // Unexpected trailing `,` in array literal. - abort(); - } - } else { - // A `,` must separate each array element. - abort(); - } - } - // Elisions and leading commas are not permitted. - if (value == ",") { - abort(); - } - results.push(get(value)); - } - return results; - } else if (value == "{") { - // Parses a JSON object, returning a new JavaScript object. - results = {}; - for (;; hasMembers || (hasMembers = true)) { - value = lex(); - // A closing curly brace marks the end of the object literal. - if (value == "}") { - break; - } - // If the object literal contains members, the current token - // should be a comma separator. - if (hasMembers) { - if (value == ",") { - value = lex(); - if (value == "}") { - // Unexpected trailing `,` in object literal. - abort(); - } - } else { - // A `,` must separate each object member. - abort(); - } - } - // Leading commas are not permitted, object property names must be - // double-quoted strings, and a `:` must separate each property - // name and value. - if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { - abort(); - } - results[value.slice(1)] = get(lex()); - } - return results; - } - // Unexpected token encountered. - abort(); - } - return value; - }; + // This function handles the presence of circular references by bailing out when encountering an + // object that is already on the "stack" of items being processed. Accepts an optional replacer + function canonicalize(obj, stack, replacementStack, replacer, key) { + stack = stack || []; + replacementStack = replacementStack || []; + + if (replacer) { + obj = replacer(key, obj); + } + + var i = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + + for (i = 0; i < stack.length; i += 1) { + if (stack[i] === obj) { + return replacementStack[i]; + } + } + + var canonicalizedObj = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + + if ('[object Array]' === objectPrototypeToString.call(obj)) { + stack.push(obj); + canonicalizedObj = new Array(obj.length); + replacementStack.push(canonicalizedObj); + for (i = 0; i < obj.length; i += 1) { + canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key); + } + stack.pop(); + replacementStack.pop(); + return canonicalizedObj; + } + + if (obj && obj.toJSON) { + obj = obj.toJSON(); + } + + if ( /*istanbul ignore start*/(typeof /*istanbul ignore end*/obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null) { + stack.push(obj); + canonicalizedObj = {}; + replacementStack.push(canonicalizedObj); + var sortedKeys = [], + _key = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + for (_key in obj) { + /* istanbul ignore else */ + if (obj.hasOwnProperty(_key)) { + sortedKeys.push(_key); + } + } + sortedKeys.sort(); + for (i = 0; i < sortedKeys.length; i += 1) { + _key = sortedKeys[i]; + canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key); + } + stack.pop(); + replacementStack.pop(); + } else { + canonicalizedObj = obj; + } + return canonicalizedObj; + } - // Internal: Updates a traversed object member. - var update = function (source, property, callback) { - var element = walk(source, property, callback); - if (element === undef) { - delete source[property]; - } else { - source[property] = element; - } - }; - // Internal: Recursively traverses a parsed JSON object, invoking the - // `callback` function for each value. This is an implementation of the - // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2. - var walk = function (source, property, callback) { - var value = source[property], length; - if (typeof value == "object" && value) { - // `forEach` can't be used to traverse an array in Opera <= 8.54 - // because its `Object#hasOwnProperty` implementation returns `false` - // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`). - if (getClass.call(value) == arrayClass) { - for (length = value.length; length--;) { - update(value, length, callback); - } - } else { - forEach(value, function (property) { - update(value, property, callback); - }); - } - } - return callback.call(source, property, value); - }; - // Public: `JSON.parse`. See ES 5.1 section 15.12.2. - exports.parse = function (source, callback) { - var result, value; - Index = 0; - Source = "" + source; - result = get(lex()); - // If a JSON string contains multiple tokens, it is invalid. - if (lex() != "$") { - abort(); - } - // Reset the parser state. - Index = Source = null; - return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; - }; - } - } +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { - exports["runInContext"] = runInContext; - return exports; - } + /*istanbul ignore start*/'use strict'; - if (freeExports && !isLoader) { - // Export for CommonJS environments. - runInContext(root, freeExports); - } else { - // Export for web browsers and JavaScript engines. - var nativeJSON = root.JSON, - previousJSON = root["JSON3"], - isRestored = false; - - var JSON3 = runInContext(root, (root["JSON3"] = { - // Public: Restores the original value of the global `JSON` object and - // returns a reference to the `JSON3` object. - "noConflict": function () { - if (!isRestored) { - isRestored = true; - root.JSON = nativeJSON; - root["JSON3"] = previousJSON; - nativeJSON = previousJSON = null; - } - return JSON3; - } - })); + exports.__esModule = true; + exports.arrayDiff = undefined; + exports. /*istanbul ignore end*/diffArrays = diffArrays; - root.JSON = { - "parse": JSON3.parse, - "stringify": JSON3.stringify - }; - } + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - // Export for asynchronous module loaders. - if (isLoader) { - define(function () { - return JSON3; - }); - } -}).call(this); + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],55:[function(require,module,exports){ -/** - * lodash 3.2.0 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var baseCopy = require('lodash._basecopy'), - keys = require('lodash.keys'); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } -/** - * The base implementation of `_.assign` without support for argument juggling, - * multiple sources, and `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ -function baseAssign(object, source) { - return source == null - ? object - : baseCopy(source, keys(source), object); -} + /*istanbul ignore end*/var arrayDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + arrayDiff.tokenize = function (value) { + return value.slice(); + }; + arrayDiff.join = arrayDiff.removeEmpty = function (value) { + return value; + }; -module.exports = baseAssign; + function diffArrays(oldArr, newArr, callback) { + return arrayDiff.diff(oldArr, newArr, callback); + } -},{"lodash._basecopy":56,"lodash.keys":63}],56:[function(require,module,exports){ -/** - * lodash 3.0.1 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -/** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property names to copy. - * @param {Object} [object={}] The object to copy properties to. - * @returns {Object} Returns `object`. - */ -function baseCopy(source, props, object) { - object || (object = {}); - var index = -1, - length = props.length; +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/applyPatch = applyPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = applyPatches; + + var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_distanceIterator = __webpack_require__(12) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _distanceIterator2 = _interopRequireDefault(_distanceIterator); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/function applyPatch(source, uniDiff) { + /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + if (typeof uniDiff === 'string') { + uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff); + } + + if (Array.isArray(uniDiff)) { + if (uniDiff.length > 1) { + throw new Error('applyPatch only works with a single input.'); + } + + uniDiff = uniDiff[0]; + } + + // Apply the diff to the input + var lines = source.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [], + hunks = uniDiff.hunks, + compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) /*istanbul ignore start*/{ + return (/*istanbul ignore end*/line === patchContent + ); + }, + errorCount = 0, + fuzzFactor = options.fuzzFactor || 0, + minLine = 0, + offset = 0, + removeEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/, + addEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + + /** + * Checks if the hunk exactly fits on the provided location + */ + function hunkFits(hunk, toPos) { + for (var j = 0; j < hunk.lines.length; j++) { + var line = hunk.lines[j], + operation = line.length > 0 ? line[0] : ' ', + content = line.length > 0 ? line.substr(1) : line; + + if (operation === ' ' || operation === '-') { + // Context sanity check + if (!compareLine(toPos + 1, lines[toPos], operation, content)) { + errorCount++; + + if (errorCount > fuzzFactor) { + return false; + } + } + toPos++; + } + } + + return true; + } + + // Search best fit offsets for each hunk based on the previous ones + for (var i = 0; i < hunks.length; i++) { + var hunk = hunks[i], + maxLine = lines.length - hunk.oldLines, + localOffset = 0, + toPos = offset + hunk.oldStart - 1; + + var iterator = /*istanbul ignore start*/(0, _distanceIterator2['default']) /*istanbul ignore end*/(toPos, minLine, maxLine); + + for (; localOffset !== undefined; localOffset = iterator()) { + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + break; + } + } + + if (localOffset === undefined) { + return false; + } + + // Set lower text limit to end of the current hunk, so next ones don't try + // to fit over already patched text + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; + } + + // Apply patch hunks + var diffOffset = 0; + for (var _i = 0; _i < hunks.length; _i++) { + var _hunk = hunks[_i], + _toPos = _hunk.oldStart + _hunk.offset + diffOffset - 1; + diffOffset += _hunk.newLines - _hunk.oldLines; + + if (_toPos < 0) { + // Creating a new file + _toPos = 0; + } + + for (var j = 0; j < _hunk.lines.length; j++) { + var line = _hunk.lines[j], + operation = line.length > 0 ? line[0] : ' ', + content = line.length > 0 ? line.substr(1) : line, + delimiter = _hunk.linedelimiters[j]; + + if (operation === ' ') { + _toPos++; + } else if (operation === '-') { + lines.splice(_toPos, 1); + delimiters.splice(_toPos, 1); + /* istanbul ignore else */ + } else if (operation === '+') { + lines.splice(_toPos, 0, content); + delimiters.splice(_toPos, 0, delimiter); + _toPos++; + } else if (operation === '\\') { + var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null; + if (previousOperation === '+') { + removeEOFNL = true; + } else if (previousOperation === '-') { + addEOFNL = true; + } + } + } + } + + // Handle EOFNL insertion/removal + if (removeEOFNL) { + while (!lines[lines.length - 1]) { + lines.pop(); + delimiters.pop(); + } + } else if (addEOFNL) { + lines.push(''); + delimiters.push('\n'); + } + for (var _k = 0; _k < lines.length - 1; _k++) { + lines[_k] = lines[_k] + delimiters[_k]; + } + return lines.join(''); + } - while (++index < length) { - var key = props[index]; - object[key] = source[key]; - } - return object; -} + // Wrapper that supports multiple file patches via callbacks. + function applyPatches(uniDiff, options) { + if (typeof uniDiff === 'string') { + uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff); + } + + var currentIndex = 0; + function processIndex() { + var index = uniDiff[currentIndex++]; + if (!index) { + return options.complete(); + } + + options.loadFile(index, function (err, data) { + if (err) { + return options.complete(err); + } + + var updatedContent = applyPatch(data, index, options); + options.patched(index, updatedContent, function (err) { + if (err) { + return options.complete(err); + } + + processIndex(); + }); + }); + } + processIndex(); + } -module.exports = baseCopy; -},{}],57:[function(require,module,exports){ -/** - * lodash 3.0.3 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -/** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ -var baseCreate = (function() { - function object() {} - return function(prototype) { - if (isObject(prototype)) { - object.prototype = prototype; - var result = new object; - object.prototype = undefined; - } - return result || {}; - }; -}()); +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/parsePatch = parsePatch; + function parsePatch(uniDiff) { + /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [], + list = [], + i = 0; + + function parseIndex() { + var index = {}; + list.push(index); + + // Parse diff metadata + while (i < diffstr.length) { + var line = diffstr[i]; + + // File header found, end parsing diff metadata + if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) { + break; + } + + // Diff index + var header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line); + if (header) { + index.index = header[1]; + } + + i++; + } + + // Parse file headers if they are defined. Unified diff requires them, but + // there's no technical issues to have an isolated hunk without file header + parseFileHeader(index); + parseFileHeader(index); + + // Parse hunks + index.hunks = []; + + while (i < diffstr.length) { + var _line = diffstr[i]; + + if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(_line)) { + break; + } else if (/^@@/.test(_line)) { + index.hunks.push(parseHunk()); + } else if (_line && options.strict) { + // Ignore unexpected content unless in strict mode + throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line)); + } else { + i++; + } + } + } + + // Parses the --- and +++ headers, if none are found, no lines + // are consumed. + function parseFileHeader(index) { + var fileHeader = /^(---|\+\+\+)\s+(.*)$/.exec(diffstr[i]); + if (fileHeader) { + var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; + var data = fileHeader[2].split('\t', 2); + var fileName = data[0].replace(/\\\\/g, '\\'); + if (/^".*"$/.test(fileName)) { + fileName = fileName.substr(1, fileName.length - 2); + } + index[keyPrefix + 'FileName'] = fileName; + index[keyPrefix + 'Header'] = (data[1] || '').trim(); + + i++; + } + } + + // Parses a hunk + // This assumes that we are at the start of a hunk. + function parseHunk() { + var chunkHeaderIndex = i, + chunkHeaderLine = diffstr[i++], + chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/); + + var hunk = { + oldStart: +chunkHeader[1], + oldLines: +chunkHeader[2] || 1, + newStart: +chunkHeader[3], + newLines: +chunkHeader[4] || 1, + lines: [], + linedelimiters: [] + }; + + var addCount = 0, + removeCount = 0; + for (; i < diffstr.length; i++) { + // Lines starting with '---' could be mistaken for the "remove line" operation + // But they could be the header for the next file. Therefore prune such cases out. + if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) { + break; + } + var operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? ' ' : diffstr[i][0]; + + if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') { + hunk.lines.push(diffstr[i]); + hunk.linedelimiters.push(delimiters[i] || '\n'); + + if (operation === '+') { + addCount++; + } else if (operation === '-') { + removeCount++; + } else if (operation === ' ') { + addCount++; + removeCount++; + } + } else { + break; + } + } + + // Handle the empty block count case + if (!addCount && hunk.newLines === 1) { + hunk.newLines = 0; + } + if (!removeCount && hunk.oldLines === 1) { + hunk.oldLines = 0; + } + + // Perform optional sanity checking + if (options.strict) { + if (addCount !== hunk.newLines) { + throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); + } + if (removeCount !== hunk.oldLines) { + throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); + } + } + + return hunk; + } + + while (i < diffstr.length) { + parseIndex(); + } + + return list; + } -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} -module.exports = baseCreate; -},{}],58:[function(require,module,exports){ -/** - * lodash 3.9.1 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ +/***/ }), +/* 12 */ +/***/ (function(module, exports) { -/** `Object#toString` result references. */ -var funcTag = '[object Function]'; + /*istanbul ignore start*/"use strict"; -/** Used to detect host constructors (Safari > 5). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; + exports.__esModule = true; -/** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} + exports["default"] = /*istanbul ignore end*/function (start, minLine, maxLine) { + var wantForward = true, + backwardExhausted = false, + forwardExhausted = false, + localOffset = 1; -/** Used for native method references. */ -var objectProto = Object.prototype; + return function iterator() { + if (wantForward && !forwardExhausted) { + if (backwardExhausted) { + localOffset++; + } else { + wantForward = false; + } -/** Used to resolve the decompiled source of functions. */ -var fnToString = Function.prototype.toString; + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (start + localOffset <= maxLine) { + return localOffset; + } -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; + forwardExhausted = true; + } -/** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) - * of values. - */ -var objToString = objectProto.toString; + if (!backwardExhausted) { + if (!forwardExhausted) { + wantForward = true; + } -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (minLine <= start - localOffset) { + return -localOffset++; + } -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; -} + backwardExhausted = true; + return iterator(); + } -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; -} + // We tried to fit hunk before text beginning and beyond text length, then + // hunk can't fit on the text. Return undefined + }; + }; -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} -/** - * Checks if `value` is a native function. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ -function isNative(value) { - if (value == null) { - return false; - } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); -} -module.exports = getNative; +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { -},{}],59:[function(require,module,exports){ -/** - * lodash 3.0.9 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ + /*istanbul ignore start*/'use strict'; -/** Used to detect unsigned integer values. */ -var reIsUint = /^\d+$/; + exports.__esModule = true; + exports. /*istanbul ignore end*/calcLineCount = calcLineCount; + /*istanbul ignore start*/exports. /*istanbul ignore end*/merge = merge; -/** - * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) - * of an array-like value. - */ -var MAX_SAFE_INTEGER = 9007199254740991; + var /*istanbul ignore start*/_create = __webpack_require__(14) /*istanbul ignore end*/; -/** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ -function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; -} + var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; -/** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. - * - * @private - * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. - */ -var getLength = baseProperty('length'); + var /*istanbul ignore start*/_array = __webpack_require__(15) /*istanbul ignore end*/; -/** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ -function isArrayLike(value) { - return value != null && isLength(getLength(value)); -} + /*istanbul ignore start*/function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } -/** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ -function isIndex(value, length) { - value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; -} + /*istanbul ignore end*/function calcLineCount(hunk) { + /*istanbul ignore start*/var _calcOldNewLineCount = /*istanbul ignore end*/calcOldNewLineCount(hunk.lines), + oldLines = _calcOldNewLineCount.oldLines, + newLines = _calcOldNewLineCount.newLines; -/** - * Checks if the provided arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. - */ -function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object)) { - var other = object[index]; - return value === value ? (value === other) : (other !== other); - } - return false; -} + if (oldLines !== undefined) { + hunk.oldLines = oldLines; + } else { + delete hunk.oldLines; + } -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} + if (newLines !== undefined) { + hunk.newLines = newLines; + } else { + delete hunk.newLines; + } + } -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} + function merge(mine, theirs, base) { + mine = loadPatch(mine, base); + theirs = loadPatch(theirs, base); + + var ret = {}; + + // For index we just let it pass through as it doesn't have any necessary meaning. + // Leaving sanity checks on this to the API consumer that may know more about the + // meaning in their own context. + if (mine.index || theirs.index) { + ret.index = mine.index || theirs.index; + } + + if (mine.newFileName || theirs.newFileName) { + if (!fileNameChanged(mine)) { + // No header or no change in ours, use theirs (and ours if theirs does not exist) + ret.oldFileName = theirs.oldFileName || mine.oldFileName; + ret.newFileName = theirs.newFileName || mine.newFileName; + ret.oldHeader = theirs.oldHeader || mine.oldHeader; + ret.newHeader = theirs.newHeader || mine.newHeader; + } else if (!fileNameChanged(theirs)) { + // No header or no change in theirs, use ours + ret.oldFileName = mine.oldFileName; + ret.newFileName = mine.newFileName; + ret.oldHeader = mine.oldHeader; + ret.newHeader = mine.newHeader; + } else { + // Both changed... figure it out + ret.oldFileName = selectField(ret, mine.oldFileName, theirs.oldFileName); + ret.newFileName = selectField(ret, mine.newFileName, theirs.newFileName); + ret.oldHeader = selectField(ret, mine.oldHeader, theirs.oldHeader); + ret.newHeader = selectField(ret, mine.newHeader, theirs.newHeader); + } + } + + ret.hunks = []; + + var mineIndex = 0, + theirsIndex = 0, + mineOffset = 0, + theirsOffset = 0; + + while (mineIndex < mine.hunks.length || theirsIndex < theirs.hunks.length) { + var mineCurrent = mine.hunks[mineIndex] || { oldStart: Infinity }, + theirsCurrent = theirs.hunks[theirsIndex] || { oldStart: Infinity }; + + if (hunkBefore(mineCurrent, theirsCurrent)) { + // This patch does not overlap with any of the others, yay. + ret.hunks.push(cloneHunk(mineCurrent, mineOffset)); + mineIndex++; + theirsOffset += mineCurrent.newLines - mineCurrent.oldLines; + } else if (hunkBefore(theirsCurrent, mineCurrent)) { + // This patch does not overlap with any of the others, yay. + ret.hunks.push(cloneHunk(theirsCurrent, theirsOffset)); + theirsIndex++; + mineOffset += theirsCurrent.newLines - theirsCurrent.oldLines; + } else { + // Overlap, merge as best we can + var mergedHunk = { + oldStart: Math.min(mineCurrent.oldStart, theirsCurrent.oldStart), + oldLines: 0, + newStart: Math.min(mineCurrent.newStart + mineOffset, theirsCurrent.oldStart + theirsOffset), + newLines: 0, + lines: [] + }; + mergeLines(mergedHunk, mineCurrent.oldStart, mineCurrent.lines, theirsCurrent.oldStart, theirsCurrent.lines); + theirsIndex++; + mineIndex++; + + ret.hunks.push(mergedHunk); + } + } + + return ret; + } -module.exports = isIterateeCall; + function loadPatch(param, base) { + if (typeof param === 'string') { + if (/^@@/m.test(param) || /^Index:/m.test(param)) { + return (/*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(param)[0] + ); + } + + if (!base) { + throw new Error('Must provide a base reference or pass in a patch'); + } + return (/*istanbul ignore start*/(0, _create.structuredPatch) /*istanbul ignore end*/(undefined, undefined, base, param) + ); + } + + return param; + } -},{}],60:[function(require,module,exports){ -/** - * lodash 3.1.1 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var baseAssign = require('lodash._baseassign'), - baseCreate = require('lodash._basecreate'), - isIterateeCall = require('lodash._isiterateecall'); + function fileNameChanged(patch) { + return patch.newFileName && patch.newFileName !== patch.oldFileName; + } -/** - * Creates an object that inherits from the given `prototype` object. If a - * `properties` object is provided its own enumerable properties are assigned - * to the created object. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ -function create(prototype, properties, guard) { - var result = baseCreate(prototype); - if (guard && isIterateeCall(prototype, properties, guard)) { - properties = undefined; - } - return properties ? baseAssign(result, properties) : result; -} + function selectField(index, mine, theirs) { + if (mine === theirs) { + return mine; + } else { + index.conflict = true; + return { mine: mine, theirs: theirs }; + } + } -module.exports = create; + function hunkBefore(test, check) { + return test.oldStart < check.oldStart && test.oldStart + test.oldLines < check.oldStart; + } -},{"lodash._baseassign":55,"lodash._basecreate":57,"lodash._isiterateecall":59}],61:[function(require,module,exports){ -/** - * lodash (Custom Build) - * Build: `lodash modularize exports="npm" -o ./` - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ + function cloneHunk(hunk, offset) { + return { + oldStart: hunk.oldStart, oldLines: hunk.oldLines, + newStart: hunk.newStart + offset, newLines: hunk.newLines, + lines: hunk.lines + }; + } -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER = 9007199254740991; + function mergeLines(hunk, mineOffset, mineLines, theirOffset, theirLines) { + // This will generally result in a conflicted hunk, but there are cases where the context + // is the only overlap where we can successfully merge the content here. + var mine = { offset: mineOffset, lines: mineLines, index: 0 }, + their = { offset: theirOffset, lines: theirLines, index: 0 }; + + // Handle any leading content + insertLeading(hunk, mine, their); + insertLeading(hunk, their, mine); + + // Now in the overlap content. Scan through and select the best changes from each. + while (mine.index < mine.lines.length && their.index < their.lines.length) { + var mineCurrent = mine.lines[mine.index], + theirCurrent = their.lines[their.index]; + + if ((mineCurrent[0] === '-' || mineCurrent[0] === '+') && (theirCurrent[0] === '-' || theirCurrent[0] === '+')) { + // Both modified ... + mutualChange(hunk, mine, their); + } else if (mineCurrent[0] === '+' && theirCurrent[0] === ' ') { + /*istanbul ignore start*/var _hunk$lines; + + /*istanbul ignore end*/ // Mine inserted + /*istanbul ignore start*/(_hunk$lines = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/collectChange(mine))); + } else if (theirCurrent[0] === '+' && mineCurrent[0] === ' ') { + /*istanbul ignore start*/var _hunk$lines2; + + /*istanbul ignore end*/ // Theirs inserted + /*istanbul ignore start*/(_hunk$lines2 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/collectChange(their))); + } else if (mineCurrent[0] === '-' && theirCurrent[0] === ' ') { + // Mine removed or edited + removal(hunk, mine, their); + } else if (theirCurrent[0] === '-' && mineCurrent[0] === ' ') { + // Their removed or edited + removal(hunk, their, mine, true); + } else if (mineCurrent === theirCurrent) { + // Context identity + hunk.lines.push(mineCurrent); + mine.index++; + their.index++; + } else { + // Context mismatch + conflict(hunk, collectChange(mine), collectChange(their)); + } + } + + // Now push anything that may be remaining + insertTrailing(hunk, mine); + insertTrailing(hunk, their); + + calcLineCount(hunk); + } -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]'; + function mutualChange(hunk, mine, their) { + var myChanges = collectChange(mine), + theirChanges = collectChange(their); -/** Used for built-in method references. */ -var objectProto = Object.prototype; + if (allRemoves(myChanges) && allRemoves(theirChanges)) { + // Special case for remove changes that are supersets of one another + if ( /*istanbul ignore start*/(0, _array.arrayStartsWith) /*istanbul ignore end*/(myChanges, theirChanges) && skipRemoveSuperset(their, myChanges, myChanges.length - theirChanges.length)) { + /*istanbul ignore start*/var _hunk$lines3; -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines3 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/myChanges)); + return; + } else if ( /*istanbul ignore start*/(0, _array.arrayStartsWith) /*istanbul ignore end*/(theirChanges, myChanges) && skipRemoveSuperset(mine, theirChanges, theirChanges.length - myChanges.length)) { + /*istanbul ignore start*/var _hunk$lines4; -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var objectToString = objectProto.toString; + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines4 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines4 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/theirChanges)); + return; + } + } else if ( /*istanbul ignore start*/(0, _array.arrayEqual) /*istanbul ignore end*/(myChanges, theirChanges)) { + /*istanbul ignore start*/var _hunk$lines5; -/** Built-in value references. */ -var propertyIsEnumerable = objectProto.propertyIsEnumerable; + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines5 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines5 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/myChanges)); + return; + } -/** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ -function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); -} + conflict(hunk, myChanges, theirChanges); + } -/** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ -function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); -} + function removal(hunk, mine, their, swap) { + var myChanges = collectChange(mine), + theirChanges = collectContext(their, myChanges); + if (theirChanges.merged) { + /*istanbul ignore start*/var _hunk$lines6; -/** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ -function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); -} + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines6 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines6 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/theirChanges.merged)); + } else { + conflict(hunk, swap ? theirChanges : myChanges, swap ? myChanges : theirChanges); + } + } -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. - var tag = isObject(value) ? objectToString.call(value) : ''; - return tag == funcTag || tag == genTag; + function conflict(hunk, mine, their) { + hunk.conflict = true; + hunk.lines.push({ + conflict: true, + mine: mine, + theirs: their + }); + } + + function insertLeading(hunk, insert, their) { + while (insert.offset < their.offset && insert.index < insert.lines.length) { + var line = insert.lines[insert.index++]; + hunk.lines.push(line); + insert.offset++; + } + } + function insertTrailing(hunk, insert) { + while (insert.index < insert.lines.length) { + var line = insert.lines[insert.index++]; + hunk.lines.push(line); + } + } + + function collectChange(state) { + var ret = [], + operation = state.lines[state.index][0]; + while (state.index < state.lines.length) { + var line = state.lines[state.index]; + + // Group additions that are immediately after subtractions and treat them as one "atomic" modify change. + if (operation === '-' && line[0] === '+') { + operation = '+'; + } + + if (operation === line[0]) { + ret.push(line); + state.index++; + } else { + break; + } + } + + return ret; + } + function collectContext(state, matchChanges) { + var changes = [], + merged = [], + matchIndex = 0, + contextChanges = false, + conflicted = false; + while (matchIndex < matchChanges.length && state.index < state.lines.length) { + var change = state.lines[state.index], + match = matchChanges[matchIndex]; + + // Once we've hit our add, then we are done + if (match[0] === '+') { + break; + } + + contextChanges = contextChanges || change[0] !== ' '; + + merged.push(match); + matchIndex++; + + // Consume any additions in the other block as a conflict to attempt + // to pull in the remaining context after this + if (change[0] === '+') { + conflicted = true; + + while (change[0] === '+') { + changes.push(change); + change = state.lines[++state.index]; + } + } + + if (match.substr(1) === change.substr(1)) { + changes.push(change); + state.index++; + } else { + conflicted = true; + } + } + + if ((matchChanges[matchIndex] || '')[0] === '+' && contextChanges) { + conflicted = true; + } + + if (conflicted) { + return changes; + } + + while (matchIndex < matchChanges.length) { + merged.push(matchChanges[matchIndex++]); + } + + return { + merged: merged, + changes: changes + }; + } + + function allRemoves(changes) { + return changes.reduce(function (prev, change) { + return prev && change[0] === '-'; + }, true); + } + function skipRemoveSuperset(state, removeChanges, delta) { + for (var i = 0; i < delta; i++) { + var changeContent = removeChanges[removeChanges.length - delta + i].substr(1); + if (state.lines[state.index + i] !== ' ' + changeContent) { + return false; + } + } + + state.index += delta; + return true; + } + + function calcOldNewLineCount(lines) { + var oldLines = 0; + var newLines = 0; + + lines.forEach(function (line) { + if (typeof line !== 'string') { + var myCount = calcOldNewLineCount(line.mine); + var theirCount = calcOldNewLineCount(line.theirs); + + if (oldLines !== undefined) { + if (myCount.oldLines === theirCount.oldLines) { + oldLines += myCount.oldLines; + } else { + oldLines = undefined; + } + } + + if (newLines !== undefined) { + if (myCount.newLines === theirCount.newLines) { + newLines += myCount.newLines; + } else { + newLines = undefined; + } + } + } else { + if (newLines !== undefined && (line[0] === '+' || line[0] === ' ')) { + newLines++; + } + if (oldLines !== undefined && (line[0] === '-' || line[0] === ' ')) { + oldLines++; + } + } + }); + + return { oldLines: oldLines, newLines: newLines }; + } + + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/structuredPatch = structuredPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = createTwoFilesPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = createPatch; + + var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + + /*istanbul ignore end*/function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + if (!options) { + options = {}; + } + if (typeof options.context === 'undefined') { + options.context = 4; + } + + var diff = /*istanbul ignore start*/(0, _line.diffLines) /*istanbul ignore end*/(oldStr, newStr, options); + diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function (entry) { + return ' ' + entry; + }); + } + + var hunks = []; + var oldRangeStart = 0, + newRangeStart = 0, + curRange = [], + oldLine = 1, + newLine = 1; + + /*istanbul ignore start*/var _loop = function _loop( /*istanbul ignore end*/i) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; + + if (current.added || current.removed) { + /*istanbul ignore start*/var _curRange; + + /*istanbul ignore end*/ // If we have previous context, start with that + if (!oldRangeStart) { + var prev = diff[i - 1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : []; + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + + // Output our changes + /*istanbul ignore start*/(_curRange = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/lines.map(function (entry) { + return (current.added ? '+' : '-') + entry; + }))); + + // Track the updated file position + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + // Identical context lines. Track line changes + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= options.context * 2 && i < diff.length - 2) { + /*istanbul ignore start*/var _curRange2; + + /*istanbul ignore end*/ // Overlapping + /*istanbul ignore start*/(_curRange2 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines))); + } else { + /*istanbul ignore start*/var _curRange3; + + /*istanbul ignore end*/ // end the range and output + var contextSize = Math.min(lines.length, options.context); + /*istanbul ignore start*/(_curRange3 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines.slice(0, contextSize)))); + + var hunk = { + oldStart: oldRangeStart, + oldLines: oldLine - oldRangeStart + contextSize, + newStart: newRangeStart, + newLines: newLine - newRangeStart + contextSize, + lines: curRange + }; + if (i >= diff.length - 2 && lines.length <= options.context) { + // EOF is inside this hunk + var oldEOFNewline = /\n$/.test(oldStr); + var newEOFNewline = /\n$/.test(newStr); + if (lines.length == 0 && !oldEOFNewline) { + // special case: old has no eol and no trailing context; no-nl can end up before adds + curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file'); + } else if (!oldEOFNewline || !newEOFNewline) { + curRange.push('\\ No newline at end of file'); + } + } + hunks.push(hunk); + + oldRangeStart = 0; + newRangeStart = 0; + curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + }; + + for (var i = 0; i < diff.length; i++) { + /*istanbul ignore start*/_loop( /*istanbul ignore end*/i); + } + + return { + oldFileName: oldFileName, newFileName: newFileName, + oldHeader: oldHeader, newHeader: newHeader, + hunks: hunks + }; + } + + function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + var diff = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options); + + var ret = []; + if (oldFileName == newFileName) { + ret.push('Index: ' + oldFileName); + } + ret.push('==================================================================='); + ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader)); + ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader)); + + for (var i = 0; i < diff.hunks.length; i++) { + var hunk = diff.hunks[i]; + ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@'); + ret.push.apply(ret, hunk.lines); + } + + return ret.join('\n') + '\n'; + } + + function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) { + return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options); + } + + + +/***/ }), +/* 15 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/"use strict"; + + exports.__esModule = true; + exports. /*istanbul ignore end*/arrayEqual = arrayEqual; + /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayStartsWith = arrayStartsWith; + function arrayEqual(a, b) { + if (a.length !== b.length) { + return false; + } + + return arrayStartsWith(a, b); + } + + function arrayStartsWith(array, start) { + if (start.length > array.length) { + return false; + } + + for (var i = 0; i < start.length; i++) { + if (start[i] !== array[i]) { + return false; + } + } + + return true; + } + + + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/"use strict"; + + exports.__esModule = true; + exports. /*istanbul ignore end*/convertChangesToDMP = convertChangesToDMP; + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + function convertChangesToDMP(changes) { + var ret = [], + change = /*istanbul ignore start*/void 0 /*istanbul ignore end*/, + operation = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + for (var i = 0; i < changes.length; i++) { + change = changes[i]; + if (change.added) { + operation = 1; + } else if (change.removed) { + operation = -1; + } else { + operation = 0; + } + + ret.push([operation, change.value]); + } + return ret; + } + + + +/***/ }), +/* 17 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/convertChangesToXML = convertChangesToXML; + function convertChangesToXML(changes) { + var ret = []; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + } + return ret.join(''); + } + + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(//g, '>'); + n = n.replace(/"/g, '"'); + + return n; + } + + + +/***/ }) +/******/ ]) +}); +; +},{}],49:[function(require,module,exports){ +'use strict'; + +var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; + +module.exports = function (str) { + if (typeof str !== 'string') { + throw new TypeError('Expected a string'); + } + + return str.replace(matchOperatorsRe, '\\$&'); +}; + +},{}],50:[function(require,module,exports){ +// 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 objectCreate = Object.create || objectCreatePolyfill +var objectKeys = Object.keys || objectKeysPolyfill +var bind = Function.prototype.bind || functionBindPolyfill + +function EventEmitter() { + if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { + this._events = objectCreate(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; } +module.exports = EventEmitter; -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ -function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +var hasDefineProperty; +try { + var o = {}; + if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); + hasDefineProperty = o.x === 0; +} catch (err) { hasDefineProperty = false } +if (hasDefineProperty) { + Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + // check whether the input is a positive number (whose value is zero or + // greater and not a NaN). + if (typeof arg !== 'number' || arg < 0 || arg !== arg) + throw new TypeError('"defaultMaxListeners" must be a positive number'); + defaultMaxListeners = arg; + } + }); +} else { + EventEmitter.defaultMaxListeners = defaultMaxListeners; } -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || isNaN(n)) + throw new TypeError('"n" argument must be a positive number'); + this._maxListeners = n; + return this; +}; + +function $getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; } -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return $getMaxListeners(this); +}; + +// These standalone emit* functions are used to optimize calling of event +// handlers for fast cases because emit() itself often has a variable number of +// arguments and can be deoptimized because of that. These functions always have +// the same number of arguments and thus do not get deoptimized, so the code +// inside them can execute faster. +function emitNone(handler, isFn, self) { + if (isFn) + handler.call(self); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self); + } +} +function emitOne(handler, isFn, self, arg1) { + if (isFn) + handler.call(self, arg1); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1); + } +} +function emitTwo(handler, isFn, self, arg1, arg2) { + if (isFn) + handler.call(self, arg1, arg2); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2); + } +} +function emitThree(handler, isFn, self, arg1, arg2, arg3) { + if (isFn) + handler.call(self, arg1, arg2, arg3); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2, arg3); + } +} + +function emitMany(handler, isFn, self, args) { + if (isFn) + handler.apply(self, args); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].apply(self, args); + } +} + +EventEmitter.prototype.emit = function emit(type) { + var er, handler, len, args, i, events; + var doError = (type === 'error'); + + events = this._events; + if (events) + doError = (doError && events.error == null); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + if (arguments.length > 1) + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Unhandled "error" event. (' + er + ')'); + err.context = er; + throw err; + } + return false; + } + + handler = events[type]; + + if (!handler) + return false; + + var isFn = typeof handler === 'function'; + len = arguments.length; + switch (len) { + // fast cases + case 1: + emitNone(handler, isFn, this); + break; + case 2: + emitOne(handler, isFn, this, arguments[1]); + break; + case 3: + emitTwo(handler, isFn, this, arguments[1], arguments[2]); + break; + case 4: + emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); + break; + // slower + default: + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + emitMany(handler, isFn, this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + + events = target._events; + if (!events) { + events = target._events = objectCreate(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (!existing) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + } else { + // If we've already got an array, just append. + if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + } + + // Check for listener leak + if (!existing.warned) { + m = $getMaxListeners(target); + if (m && m > 0 && existing.length > m) { + existing.warned = true; + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' "' + String(type) + '" listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit.'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + if (typeof console === 'object' && console.warn) { + console.warn('%s: %s', w.name, w.message); + } + } + } + } + + return target; } -module.exports = isArguments; +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; -},{}],62:[function(require,module,exports){ -/** - * lodash 3.0.4 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ +EventEmitter.prototype.on = EventEmitter.prototype.addListener; -/** `Object#toString` result references. */ -var arrayTag = '[object Array]', - funcTag = '[object Function]'; +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; -/** Used to detect host constructors (Safari > 5). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + switch (arguments.length) { + case 0: + return this.listener.call(this.target); + case 1: + return this.listener.call(this.target, arguments[0]); + case 2: + return this.listener.call(this.target, arguments[0], arguments[1]); + case 3: + return this.listener.call(this.target, arguments[0], arguments[1], + arguments[2]); + default: + var args = new Array(arguments.length); + for (var i = 0; i < args.length; ++i) + args[i] = arguments[i]; + this.listener.apply(this.target, args); + } + } +} -/** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = bind.call(onceWrapper, state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; } -/** Used for native method references. */ -var objectProto = Object.prototype; +EventEmitter.prototype.once = function once(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; -/** Used to resolve the decompiled source of functions. */ -var fnToString = Function.prototype.toString; +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; -/** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) - * of values. - */ -var objToString = objectProto.toString; + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); + events = this._events; + if (!events) + return this; -/* Native method references for those with the same name as other `lodash` methods. */ -var nativeIsArray = getNative(Array, 'isArray'); + list = events[type]; + if (!list) + return this; -/** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. - */ -var MAX_SAFE_INTEGER = 9007199254740991; + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else + spliceOne(list, position); + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (!events) + return this; + + // not listening for removeListener, no need to emit + if (!events.removeListener) { + if (arguments.length === 0) { + this._events = objectCreate(null); + this._eventsCount = 0; + } else if (events[type]) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = objectKeys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = objectCreate(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (!events) + return []; + + var evlistener = events[type]; + if (!evlistener) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener) { + return evlistener.length; + } + } + + return 0; } -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(function() { return arguments; }()); - * // => false - */ -var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; }; -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; +// About 1.5x faster than the two-arg version of Array#splice(). +function spliceOne(list, index) { + for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) + list[i] = list[k]; + list.pop(); } -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; } -/** - * Checks if `value` is a native function. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ -function isNative(value) { - if (value == null) { - return false; +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); + return ret; +} + +function objectCreatePolyfill(proto) { + var F = function() {}; + F.prototype = proto; + return new F; +} +function objectKeysPolyfill(obj) { + var keys = []; + for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { + keys.push(k); } - return isObjectLike(value) && reIsHostCtor.test(value); + return k; +} +function functionBindPolyfill(context) { + var fn = this; + return function () { + return fn.apply(context, arguments); + }; } -module.exports = isArray; +},{}],51:[function(require,module,exports){ +'use strict'; -},{}],63:[function(require,module,exports){ -/** - * lodash 3.1.2 (Custom Build) - * Build: `lodash modern modularize exports="npm" -o ./` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var getNative = require('lodash._getnative'), - isArguments = require('lodash.isarguments'), - isArray = require('lodash.isarray'); +/* eslint no-invalid-this: 1 */ + +var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; +var slice = Array.prototype.slice; +var toStr = Object.prototype.toString; +var funcType = '[object Function]'; + +module.exports = function bind(that) { + var target = this; + if (typeof target !== 'function' || toStr.call(target) !== funcType) { + throw new TypeError(ERROR_MESSAGE + target); + } + var args = slice.call(arguments, 1); + + var bound; + var binder = function () { + if (this instanceof bound) { + var result = target.apply( + this, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return this; + } else { + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + } + }; -/** Used to detect unsigned integer values. */ -var reIsUint = /^\d+$/; + var boundLength = Math.max(0, target.length - args.length); + var boundArgs = []; + for (var i = 0; i < boundLength; i++) { + boundArgs.push('$' + i); + } -/** Used for native method references. */ -var objectProto = Object.prototype; + bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; + if (target.prototype) { + var Empty = function Empty() {}; + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; + } -/* Native method references for those with the same name as other `lodash` methods. */ -var nativeKeys = getNative(Object, 'keys'); + return bound; +}; -/** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. - */ -var MAX_SAFE_INTEGER = 9007199254740991; +},{}],52:[function(require,module,exports){ +'use strict'; -/** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ -function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; -} +var implementation = require('./implementation'); -/** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. - * - * @private - * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. - */ -var getLength = baseProperty('length'); +module.exports = Function.prototype.bind || implementation; -/** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ -function isArrayLike(value) { - return value != null && isLength(getLength(value)); -} +},{"./implementation":51}],53:[function(require,module,exports){ +'use strict'; -/** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ -function isIndex(value, length) { - value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; -} +/* eslint complexity: [2, 17], max-statements: [2, 33] */ +module.exports = function hasSymbols() { + if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } + if (typeof Symbol.iterator === 'symbol') { return true; } -/** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + var obj = {}; + var sym = Symbol('test'); + var symObj = Object(sym); + if (typeof sym === 'string') { return false; } + + if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } + if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } + + // temp disabled per https://github.com/ljharb/object.assign/issues/17 + // if (sym instanceof Symbol) { return false; } + // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 + // if (!(symObj instanceof Symbol)) { return false; } + + // if (typeof Symbol.prototype.toString !== 'function') { return false; } + // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } + + var symVal = 42; + obj[sym] = symVal; + for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax + if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } + + if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } + + var syms = Object.getOwnPropertySymbols(obj); + if (syms.length !== 1 || syms[0] !== sym) { return false; } + + if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } + + if (typeof Object.getOwnPropertyDescriptor === 'function') { + var descriptor = Object.getOwnPropertyDescriptor(obj, sym); + if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } + } + + return true; +}; + +},{}],54:[function(require,module,exports){ +(function (global){ +/*! https://mths.be/he v1.2.0 by @mathias | MIT license */ +;(function(root) { + + // Detect free variables `exports`. + var freeExports = typeof exports == 'object' && exports; + + // Detect free variable `module`. + var freeModule = typeof module == 'object' && module && + module.exports == freeExports && module; + + // Detect free variable `global`, from Node.js or Browserified code, + // and use it as `root`. + var freeGlobal = typeof global == 'object' && global; + if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { + root = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + // All astral symbols. + var regexAstralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; + // All ASCII symbols (not just printable ASCII) except those listed in the + // first column of the overrides table. + // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides + var regexAsciiWhitelist = /[\x01-\x7F]/g; + // All BMP symbols that are not ASCII newlines, printable ASCII symbols, or + // code points listed in the first column of the overrides table on + // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides. + var regexBmpWhitelist = /[\x01-\t\x0B\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g; + + var regexEncodeNonAscii = /<\u20D2|=\u20E5|>\u20D2|\u205F\u200A|\u219D\u0338|\u2202\u0338|\u2220\u20D2|\u2229\uFE00|\u222A\uFE00|\u223C\u20D2|\u223D\u0331|\u223E\u0333|\u2242\u0338|\u224B\u0338|\u224D\u20D2|\u224E\u0338|\u224F\u0338|\u2250\u0338|\u2261\u20E5|\u2264\u20D2|\u2265\u20D2|\u2266\u0338|\u2267\u0338|\u2268\uFE00|\u2269\uFE00|\u226A\u0338|\u226A\u20D2|\u226B\u0338|\u226B\u20D2|\u227F\u0338|\u2282\u20D2|\u2283\u20D2|\u228A\uFE00|\u228B\uFE00|\u228F\u0338|\u2290\u0338|\u2293\uFE00|\u2294\uFE00|\u22B4\u20D2|\u22B5\u20D2|\u22D8\u0338|\u22D9\u0338|\u22DA\uFE00|\u22DB\uFE00|\u22F5\u0338|\u22F9\u0338|\u2933\u0338|\u29CF\u0338|\u29D0\u0338|\u2A6D\u0338|\u2A70\u0338|\u2A7D\u0338|\u2A7E\u0338|\u2AA1\u0338|\u2AA2\u0338|\u2AAC\uFE00|\u2AAD\uFE00|\u2AAF\u0338|\u2AB0\u0338|\u2AC5\u0338|\u2AC6\u0338|\u2ACB\uFE00|\u2ACC\uFE00|\u2AFD\u20E5|[\xA0-\u0113\u0116-\u0122\u0124-\u012B\u012E-\u014D\u0150-\u017E\u0192\u01B5\u01F5\u0237\u02C6\u02C7\u02D8-\u02DD\u0311\u0391-\u03A1\u03A3-\u03A9\u03B1-\u03C9\u03D1\u03D2\u03D5\u03D6\u03DC\u03DD\u03F0\u03F1\u03F5\u03F6\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E\u045F\u2002-\u2005\u2007-\u2010\u2013-\u2016\u2018-\u201A\u201C-\u201E\u2020-\u2022\u2025\u2026\u2030-\u2035\u2039\u203A\u203E\u2041\u2043\u2044\u204F\u2057\u205F-\u2063\u20AC\u20DB\u20DC\u2102\u2105\u210A-\u2113\u2115-\u211E\u2122\u2124\u2127-\u2129\u212C\u212D\u212F-\u2131\u2133-\u2138\u2145-\u2148\u2153-\u215E\u2190-\u219B\u219D-\u21A7\u21A9-\u21AE\u21B0-\u21B3\u21B5-\u21B7\u21BA-\u21DB\u21DD\u21E4\u21E5\u21F5\u21FD-\u2205\u2207-\u2209\u220B\u220C\u220F-\u2214\u2216-\u2218\u221A\u221D-\u2238\u223A-\u2257\u2259\u225A\u225C\u225F-\u2262\u2264-\u228B\u228D-\u229B\u229D-\u22A5\u22A7-\u22B0\u22B2-\u22BB\u22BD-\u22DB\u22DE-\u22E3\u22E6-\u22F7\u22F9-\u22FE\u2305\u2306\u2308-\u2310\u2312\u2313\u2315\u2316\u231C-\u231F\u2322\u2323\u232D\u232E\u2336\u233D\u233F\u237C\u23B0\u23B1\u23B4-\u23B6\u23DC-\u23DF\u23E2\u23E7\u2423\u24C8\u2500\u2502\u250C\u2510\u2514\u2518\u251C\u2524\u252C\u2534\u253C\u2550-\u256C\u2580\u2584\u2588\u2591-\u2593\u25A1\u25AA\u25AB\u25AD\u25AE\u25B1\u25B3-\u25B5\u25B8\u25B9\u25BD-\u25BF\u25C2\u25C3\u25CA\u25CB\u25EC\u25EF\u25F8-\u25FC\u2605\u2606\u260E\u2640\u2642\u2660\u2663\u2665\u2666\u266A\u266D-\u266F\u2713\u2717\u2720\u2736\u2758\u2772\u2773\u27C8\u27C9\u27E6-\u27ED\u27F5-\u27FA\u27FC\u27FF\u2902-\u2905\u290C-\u2913\u2916\u2919-\u2920\u2923-\u292A\u2933\u2935-\u2939\u293C\u293D\u2945\u2948-\u294B\u294E-\u2976\u2978\u2979\u297B-\u297F\u2985\u2986\u298B-\u2996\u299A\u299C\u299D\u29A4-\u29B7\u29B9\u29BB\u29BC\u29BE-\u29C5\u29C9\u29CD-\u29D0\u29DC-\u29DE\u29E3-\u29E5\u29EB\u29F4\u29F6\u2A00-\u2A02\u2A04\u2A06\u2A0C\u2A0D\u2A10-\u2A17\u2A22-\u2A27\u2A29\u2A2A\u2A2D-\u2A31\u2A33-\u2A3C\u2A3F\u2A40\u2A42-\u2A4D\u2A50\u2A53-\u2A58\u2A5A-\u2A5D\u2A5F\u2A66\u2A6A\u2A6D-\u2A75\u2A77-\u2A9A\u2A9D-\u2AA2\u2AA4-\u2AB0\u2AB3-\u2AC8\u2ACB\u2ACC\u2ACF-\u2ADB\u2AE4\u2AE6-\u2AE9\u2AEB-\u2AF3\u2AFD\uFB00-\uFB04]|\uD835[\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDD6B]/g; + var encodeMap = {'\xAD':'shy','\u200C':'zwnj','\u200D':'zwj','\u200E':'lrm','\u2063':'ic','\u2062':'it','\u2061':'af','\u200F':'rlm','\u200B':'ZeroWidthSpace','\u2060':'NoBreak','\u0311':'DownBreve','\u20DB':'tdot','\u20DC':'DotDot','\t':'Tab','\n':'NewLine','\u2008':'puncsp','\u205F':'MediumSpace','\u2009':'thinsp','\u200A':'hairsp','\u2004':'emsp13','\u2002':'ensp','\u2005':'emsp14','\u2003':'emsp','\u2007':'numsp','\xA0':'nbsp','\u205F\u200A':'ThickSpace','\u203E':'oline','_':'lowbar','\u2010':'dash','\u2013':'ndash','\u2014':'mdash','\u2015':'horbar',',':'comma',';':'semi','\u204F':'bsemi',':':'colon','\u2A74':'Colone','!':'excl','\xA1':'iexcl','?':'quest','\xBF':'iquest','.':'period','\u2025':'nldr','\u2026':'mldr','\xB7':'middot','\'':'apos','\u2018':'lsquo','\u2019':'rsquo','\u201A':'sbquo','\u2039':'lsaquo','\u203A':'rsaquo','"':'quot','\u201C':'ldquo','\u201D':'rdquo','\u201E':'bdquo','\xAB':'laquo','\xBB':'raquo','(':'lpar',')':'rpar','[':'lsqb',']':'rsqb','{':'lcub','}':'rcub','\u2308':'lceil','\u2309':'rceil','\u230A':'lfloor','\u230B':'rfloor','\u2985':'lopar','\u2986':'ropar','\u298B':'lbrke','\u298C':'rbrke','\u298D':'lbrkslu','\u298E':'rbrksld','\u298F':'lbrksld','\u2990':'rbrkslu','\u2991':'langd','\u2992':'rangd','\u2993':'lparlt','\u2994':'rpargt','\u2995':'gtlPar','\u2996':'ltrPar','\u27E6':'lobrk','\u27E7':'robrk','\u27E8':'lang','\u27E9':'rang','\u27EA':'Lang','\u27EB':'Rang','\u27EC':'loang','\u27ED':'roang','\u2772':'lbbrk','\u2773':'rbbrk','\u2016':'Vert','\xA7':'sect','\xB6':'para','@':'commat','*':'ast','/':'sol','undefined':null,'&':'amp','#':'num','%':'percnt','\u2030':'permil','\u2031':'pertenk','\u2020':'dagger','\u2021':'Dagger','\u2022':'bull','\u2043':'hybull','\u2032':'prime','\u2033':'Prime','\u2034':'tprime','\u2057':'qprime','\u2035':'bprime','\u2041':'caret','`':'grave','\xB4':'acute','\u02DC':'tilde','^':'Hat','\xAF':'macr','\u02D8':'breve','\u02D9':'dot','\xA8':'die','\u02DA':'ring','\u02DD':'dblac','\xB8':'cedil','\u02DB':'ogon','\u02C6':'circ','\u02C7':'caron','\xB0':'deg','\xA9':'copy','\xAE':'reg','\u2117':'copysr','\u2118':'wp','\u211E':'rx','\u2127':'mho','\u2129':'iiota','\u2190':'larr','\u219A':'nlarr','\u2192':'rarr','\u219B':'nrarr','\u2191':'uarr','\u2193':'darr','\u2194':'harr','\u21AE':'nharr','\u2195':'varr','\u2196':'nwarr','\u2197':'nearr','\u2198':'searr','\u2199':'swarr','\u219D':'rarrw','\u219D\u0338':'nrarrw','\u219E':'Larr','\u219F':'Uarr','\u21A0':'Rarr','\u21A1':'Darr','\u21A2':'larrtl','\u21A3':'rarrtl','\u21A4':'mapstoleft','\u21A5':'mapstoup','\u21A6':'map','\u21A7':'mapstodown','\u21A9':'larrhk','\u21AA':'rarrhk','\u21AB':'larrlp','\u21AC':'rarrlp','\u21AD':'harrw','\u21B0':'lsh','\u21B1':'rsh','\u21B2':'ldsh','\u21B3':'rdsh','\u21B5':'crarr','\u21B6':'cularr','\u21B7':'curarr','\u21BA':'olarr','\u21BB':'orarr','\u21BC':'lharu','\u21BD':'lhard','\u21BE':'uharr','\u21BF':'uharl','\u21C0':'rharu','\u21C1':'rhard','\u21C2':'dharr','\u21C3':'dharl','\u21C4':'rlarr','\u21C5':'udarr','\u21C6':'lrarr','\u21C7':'llarr','\u21C8':'uuarr','\u21C9':'rrarr','\u21CA':'ddarr','\u21CB':'lrhar','\u21CC':'rlhar','\u21D0':'lArr','\u21CD':'nlArr','\u21D1':'uArr','\u21D2':'rArr','\u21CF':'nrArr','\u21D3':'dArr','\u21D4':'iff','\u21CE':'nhArr','\u21D5':'vArr','\u21D6':'nwArr','\u21D7':'neArr','\u21D8':'seArr','\u21D9':'swArr','\u21DA':'lAarr','\u21DB':'rAarr','\u21DD':'zigrarr','\u21E4':'larrb','\u21E5':'rarrb','\u21F5':'duarr','\u21FD':'loarr','\u21FE':'roarr','\u21FF':'hoarr','\u2200':'forall','\u2201':'comp','\u2202':'part','\u2202\u0338':'npart','\u2203':'exist','\u2204':'nexist','\u2205':'empty','\u2207':'Del','\u2208':'in','\u2209':'notin','\u220B':'ni','\u220C':'notni','\u03F6':'bepsi','\u220F':'prod','\u2210':'coprod','\u2211':'sum','+':'plus','\xB1':'pm','\xF7':'div','\xD7':'times','<':'lt','\u226E':'nlt','<\u20D2':'nvlt','=':'equals','\u2260':'ne','=\u20E5':'bne','\u2A75':'Equal','>':'gt','\u226F':'ngt','>\u20D2':'nvgt','\xAC':'not','|':'vert','\xA6':'brvbar','\u2212':'minus','\u2213':'mp','\u2214':'plusdo','\u2044':'frasl','\u2216':'setmn','\u2217':'lowast','\u2218':'compfn','\u221A':'Sqrt','\u221D':'prop','\u221E':'infin','\u221F':'angrt','\u2220':'ang','\u2220\u20D2':'nang','\u2221':'angmsd','\u2222':'angsph','\u2223':'mid','\u2224':'nmid','\u2225':'par','\u2226':'npar','\u2227':'and','\u2228':'or','\u2229':'cap','\u2229\uFE00':'caps','\u222A':'cup','\u222A\uFE00':'cups','\u222B':'int','\u222C':'Int','\u222D':'tint','\u2A0C':'qint','\u222E':'oint','\u222F':'Conint','\u2230':'Cconint','\u2231':'cwint','\u2232':'cwconint','\u2233':'awconint','\u2234':'there4','\u2235':'becaus','\u2236':'ratio','\u2237':'Colon','\u2238':'minusd','\u223A':'mDDot','\u223B':'homtht','\u223C':'sim','\u2241':'nsim','\u223C\u20D2':'nvsim','\u223D':'bsim','\u223D\u0331':'race','\u223E':'ac','\u223E\u0333':'acE','\u223F':'acd','\u2240':'wr','\u2242':'esim','\u2242\u0338':'nesim','\u2243':'sime','\u2244':'nsime','\u2245':'cong','\u2247':'ncong','\u2246':'simne','\u2248':'ap','\u2249':'nap','\u224A':'ape','\u224B':'apid','\u224B\u0338':'napid','\u224C':'bcong','\u224D':'CupCap','\u226D':'NotCupCap','\u224D\u20D2':'nvap','\u224E':'bump','\u224E\u0338':'nbump','\u224F':'bumpe','\u224F\u0338':'nbumpe','\u2250':'doteq','\u2250\u0338':'nedot','\u2251':'eDot','\u2252':'efDot','\u2253':'erDot','\u2254':'colone','\u2255':'ecolon','\u2256':'ecir','\u2257':'cire','\u2259':'wedgeq','\u225A':'veeeq','\u225C':'trie','\u225F':'equest','\u2261':'equiv','\u2262':'nequiv','\u2261\u20E5':'bnequiv','\u2264':'le','\u2270':'nle','\u2264\u20D2':'nvle','\u2265':'ge','\u2271':'nge','\u2265\u20D2':'nvge','\u2266':'lE','\u2266\u0338':'nlE','\u2267':'gE','\u2267\u0338':'ngE','\u2268\uFE00':'lvnE','\u2268':'lnE','\u2269':'gnE','\u2269\uFE00':'gvnE','\u226A':'ll','\u226A\u0338':'nLtv','\u226A\u20D2':'nLt','\u226B':'gg','\u226B\u0338':'nGtv','\u226B\u20D2':'nGt','\u226C':'twixt','\u2272':'lsim','\u2274':'nlsim','\u2273':'gsim','\u2275':'ngsim','\u2276':'lg','\u2278':'ntlg','\u2277':'gl','\u2279':'ntgl','\u227A':'pr','\u2280':'npr','\u227B':'sc','\u2281':'nsc','\u227C':'prcue','\u22E0':'nprcue','\u227D':'sccue','\u22E1':'nsccue','\u227E':'prsim','\u227F':'scsim','\u227F\u0338':'NotSucceedsTilde','\u2282':'sub','\u2284':'nsub','\u2282\u20D2':'vnsub','\u2283':'sup','\u2285':'nsup','\u2283\u20D2':'vnsup','\u2286':'sube','\u2288':'nsube','\u2287':'supe','\u2289':'nsupe','\u228A\uFE00':'vsubne','\u228A':'subne','\u228B\uFE00':'vsupne','\u228B':'supne','\u228D':'cupdot','\u228E':'uplus','\u228F':'sqsub','\u228F\u0338':'NotSquareSubset','\u2290':'sqsup','\u2290\u0338':'NotSquareSuperset','\u2291':'sqsube','\u22E2':'nsqsube','\u2292':'sqsupe','\u22E3':'nsqsupe','\u2293':'sqcap','\u2293\uFE00':'sqcaps','\u2294':'sqcup','\u2294\uFE00':'sqcups','\u2295':'oplus','\u2296':'ominus','\u2297':'otimes','\u2298':'osol','\u2299':'odot','\u229A':'ocir','\u229B':'oast','\u229D':'odash','\u229E':'plusb','\u229F':'minusb','\u22A0':'timesb','\u22A1':'sdotb','\u22A2':'vdash','\u22AC':'nvdash','\u22A3':'dashv','\u22A4':'top','\u22A5':'bot','\u22A7':'models','\u22A8':'vDash','\u22AD':'nvDash','\u22A9':'Vdash','\u22AE':'nVdash','\u22AA':'Vvdash','\u22AB':'VDash','\u22AF':'nVDash','\u22B0':'prurel','\u22B2':'vltri','\u22EA':'nltri','\u22B3':'vrtri','\u22EB':'nrtri','\u22B4':'ltrie','\u22EC':'nltrie','\u22B4\u20D2':'nvltrie','\u22B5':'rtrie','\u22ED':'nrtrie','\u22B5\u20D2':'nvrtrie','\u22B6':'origof','\u22B7':'imof','\u22B8':'mumap','\u22B9':'hercon','\u22BA':'intcal','\u22BB':'veebar','\u22BD':'barvee','\u22BE':'angrtvb','\u22BF':'lrtri','\u22C0':'Wedge','\u22C1':'Vee','\u22C2':'xcap','\u22C3':'xcup','\u22C4':'diam','\u22C5':'sdot','\u22C6':'Star','\u22C7':'divonx','\u22C8':'bowtie','\u22C9':'ltimes','\u22CA':'rtimes','\u22CB':'lthree','\u22CC':'rthree','\u22CD':'bsime','\u22CE':'cuvee','\u22CF':'cuwed','\u22D0':'Sub','\u22D1':'Sup','\u22D2':'Cap','\u22D3':'Cup','\u22D4':'fork','\u22D5':'epar','\u22D6':'ltdot','\u22D7':'gtdot','\u22D8':'Ll','\u22D8\u0338':'nLl','\u22D9':'Gg','\u22D9\u0338':'nGg','\u22DA\uFE00':'lesg','\u22DA':'leg','\u22DB':'gel','\u22DB\uFE00':'gesl','\u22DE':'cuepr','\u22DF':'cuesc','\u22E6':'lnsim','\u22E7':'gnsim','\u22E8':'prnsim','\u22E9':'scnsim','\u22EE':'vellip','\u22EF':'ctdot','\u22F0':'utdot','\u22F1':'dtdot','\u22F2':'disin','\u22F3':'isinsv','\u22F4':'isins','\u22F5':'isindot','\u22F5\u0338':'notindot','\u22F6':'notinvc','\u22F7':'notinvb','\u22F9':'isinE','\u22F9\u0338':'notinE','\u22FA':'nisd','\u22FB':'xnis','\u22FC':'nis','\u22FD':'notnivc','\u22FE':'notnivb','\u2305':'barwed','\u2306':'Barwed','\u230C':'drcrop','\u230D':'dlcrop','\u230E':'urcrop','\u230F':'ulcrop','\u2310':'bnot','\u2312':'profline','\u2313':'profsurf','\u2315':'telrec','\u2316':'target','\u231C':'ulcorn','\u231D':'urcorn','\u231E':'dlcorn','\u231F':'drcorn','\u2322':'frown','\u2323':'smile','\u232D':'cylcty','\u232E':'profalar','\u2336':'topbot','\u233D':'ovbar','\u233F':'solbar','\u237C':'angzarr','\u23B0':'lmoust','\u23B1':'rmoust','\u23B4':'tbrk','\u23B5':'bbrk','\u23B6':'bbrktbrk','\u23DC':'OverParenthesis','\u23DD':'UnderParenthesis','\u23DE':'OverBrace','\u23DF':'UnderBrace','\u23E2':'trpezium','\u23E7':'elinters','\u2423':'blank','\u2500':'boxh','\u2502':'boxv','\u250C':'boxdr','\u2510':'boxdl','\u2514':'boxur','\u2518':'boxul','\u251C':'boxvr','\u2524':'boxvl','\u252C':'boxhd','\u2534':'boxhu','\u253C':'boxvh','\u2550':'boxH','\u2551':'boxV','\u2552':'boxdR','\u2553':'boxDr','\u2554':'boxDR','\u2555':'boxdL','\u2556':'boxDl','\u2557':'boxDL','\u2558':'boxuR','\u2559':'boxUr','\u255A':'boxUR','\u255B':'boxuL','\u255C':'boxUl','\u255D':'boxUL','\u255E':'boxvR','\u255F':'boxVr','\u2560':'boxVR','\u2561':'boxvL','\u2562':'boxVl','\u2563':'boxVL','\u2564':'boxHd','\u2565':'boxhD','\u2566':'boxHD','\u2567':'boxHu','\u2568':'boxhU','\u2569':'boxHU','\u256A':'boxvH','\u256B':'boxVh','\u256C':'boxVH','\u2580':'uhblk','\u2584':'lhblk','\u2588':'block','\u2591':'blk14','\u2592':'blk12','\u2593':'blk34','\u25A1':'squ','\u25AA':'squf','\u25AB':'EmptyVerySmallSquare','\u25AD':'rect','\u25AE':'marker','\u25B1':'fltns','\u25B3':'xutri','\u25B4':'utrif','\u25B5':'utri','\u25B8':'rtrif','\u25B9':'rtri','\u25BD':'xdtri','\u25BE':'dtrif','\u25BF':'dtri','\u25C2':'ltrif','\u25C3':'ltri','\u25CA':'loz','\u25CB':'cir','\u25EC':'tridot','\u25EF':'xcirc','\u25F8':'ultri','\u25F9':'urtri','\u25FA':'lltri','\u25FB':'EmptySmallSquare','\u25FC':'FilledSmallSquare','\u2605':'starf','\u2606':'star','\u260E':'phone','\u2640':'female','\u2642':'male','\u2660':'spades','\u2663':'clubs','\u2665':'hearts','\u2666':'diams','\u266A':'sung','\u2713':'check','\u2717':'cross','\u2720':'malt','\u2736':'sext','\u2758':'VerticalSeparator','\u27C8':'bsolhsub','\u27C9':'suphsol','\u27F5':'xlarr','\u27F6':'xrarr','\u27F7':'xharr','\u27F8':'xlArr','\u27F9':'xrArr','\u27FA':'xhArr','\u27FC':'xmap','\u27FF':'dzigrarr','\u2902':'nvlArr','\u2903':'nvrArr','\u2904':'nvHarr','\u2905':'Map','\u290C':'lbarr','\u290D':'rbarr','\u290E':'lBarr','\u290F':'rBarr','\u2910':'RBarr','\u2911':'DDotrahd','\u2912':'UpArrowBar','\u2913':'DownArrowBar','\u2916':'Rarrtl','\u2919':'latail','\u291A':'ratail','\u291B':'lAtail','\u291C':'rAtail','\u291D':'larrfs','\u291E':'rarrfs','\u291F':'larrbfs','\u2920':'rarrbfs','\u2923':'nwarhk','\u2924':'nearhk','\u2925':'searhk','\u2926':'swarhk','\u2927':'nwnear','\u2928':'toea','\u2929':'tosa','\u292A':'swnwar','\u2933':'rarrc','\u2933\u0338':'nrarrc','\u2935':'cudarrr','\u2936':'ldca','\u2937':'rdca','\u2938':'cudarrl','\u2939':'larrpl','\u293C':'curarrm','\u293D':'cularrp','\u2945':'rarrpl','\u2948':'harrcir','\u2949':'Uarrocir','\u294A':'lurdshar','\u294B':'ldrushar','\u294E':'LeftRightVector','\u294F':'RightUpDownVector','\u2950':'DownLeftRightVector','\u2951':'LeftUpDownVector','\u2952':'LeftVectorBar','\u2953':'RightVectorBar','\u2954':'RightUpVectorBar','\u2955':'RightDownVectorBar','\u2956':'DownLeftVectorBar','\u2957':'DownRightVectorBar','\u2958':'LeftUpVectorBar','\u2959':'LeftDownVectorBar','\u295A':'LeftTeeVector','\u295B':'RightTeeVector','\u295C':'RightUpTeeVector','\u295D':'RightDownTeeVector','\u295E':'DownLeftTeeVector','\u295F':'DownRightTeeVector','\u2960':'LeftUpTeeVector','\u2961':'LeftDownTeeVector','\u2962':'lHar','\u2963':'uHar','\u2964':'rHar','\u2965':'dHar','\u2966':'luruhar','\u2967':'ldrdhar','\u2968':'ruluhar','\u2969':'rdldhar','\u296A':'lharul','\u296B':'llhard','\u296C':'rharul','\u296D':'lrhard','\u296E':'udhar','\u296F':'duhar','\u2970':'RoundImplies','\u2971':'erarr','\u2972':'simrarr','\u2973':'larrsim','\u2974':'rarrsim','\u2975':'rarrap','\u2976':'ltlarr','\u2978':'gtrarr','\u2979':'subrarr','\u297B':'suplarr','\u297C':'lfisht','\u297D':'rfisht','\u297E':'ufisht','\u297F':'dfisht','\u299A':'vzigzag','\u299C':'vangrt','\u299D':'angrtvbd','\u29A4':'ange','\u29A5':'range','\u29A6':'dwangle','\u29A7':'uwangle','\u29A8':'angmsdaa','\u29A9':'angmsdab','\u29AA':'angmsdac','\u29AB':'angmsdad','\u29AC':'angmsdae','\u29AD':'angmsdaf','\u29AE':'angmsdag','\u29AF':'angmsdah','\u29B0':'bemptyv','\u29B1':'demptyv','\u29B2':'cemptyv','\u29B3':'raemptyv','\u29B4':'laemptyv','\u29B5':'ohbar','\u29B6':'omid','\u29B7':'opar','\u29B9':'operp','\u29BB':'olcross','\u29BC':'odsold','\u29BE':'olcir','\u29BF':'ofcir','\u29C0':'olt','\u29C1':'ogt','\u29C2':'cirscir','\u29C3':'cirE','\u29C4':'solb','\u29C5':'bsolb','\u29C9':'boxbox','\u29CD':'trisb','\u29CE':'rtriltri','\u29CF':'LeftTriangleBar','\u29CF\u0338':'NotLeftTriangleBar','\u29D0':'RightTriangleBar','\u29D0\u0338':'NotRightTriangleBar','\u29DC':'iinfin','\u29DD':'infintie','\u29DE':'nvinfin','\u29E3':'eparsl','\u29E4':'smeparsl','\u29E5':'eqvparsl','\u29EB':'lozf','\u29F4':'RuleDelayed','\u29F6':'dsol','\u2A00':'xodot','\u2A01':'xoplus','\u2A02':'xotime','\u2A04':'xuplus','\u2A06':'xsqcup','\u2A0D':'fpartint','\u2A10':'cirfnint','\u2A11':'awint','\u2A12':'rppolint','\u2A13':'scpolint','\u2A14':'npolint','\u2A15':'pointint','\u2A16':'quatint','\u2A17':'intlarhk','\u2A22':'pluscir','\u2A23':'plusacir','\u2A24':'simplus','\u2A25':'plusdu','\u2A26':'plussim','\u2A27':'plustwo','\u2A29':'mcomma','\u2A2A':'minusdu','\u2A2D':'loplus','\u2A2E':'roplus','\u2A2F':'Cross','\u2A30':'timesd','\u2A31':'timesbar','\u2A33':'smashp','\u2A34':'lotimes','\u2A35':'rotimes','\u2A36':'otimesas','\u2A37':'Otimes','\u2A38':'odiv','\u2A39':'triplus','\u2A3A':'triminus','\u2A3B':'tritime','\u2A3C':'iprod','\u2A3F':'amalg','\u2A40':'capdot','\u2A42':'ncup','\u2A43':'ncap','\u2A44':'capand','\u2A45':'cupor','\u2A46':'cupcap','\u2A47':'capcup','\u2A48':'cupbrcap','\u2A49':'capbrcup','\u2A4A':'cupcup','\u2A4B':'capcap','\u2A4C':'ccups','\u2A4D':'ccaps','\u2A50':'ccupssm','\u2A53':'And','\u2A54':'Or','\u2A55':'andand','\u2A56':'oror','\u2A57':'orslope','\u2A58':'andslope','\u2A5A':'andv','\u2A5B':'orv','\u2A5C':'andd','\u2A5D':'ord','\u2A5F':'wedbar','\u2A66':'sdote','\u2A6A':'simdot','\u2A6D':'congdot','\u2A6D\u0338':'ncongdot','\u2A6E':'easter','\u2A6F':'apacir','\u2A70':'apE','\u2A70\u0338':'napE','\u2A71':'eplus','\u2A72':'pluse','\u2A73':'Esim','\u2A77':'eDDot','\u2A78':'equivDD','\u2A79':'ltcir','\u2A7A':'gtcir','\u2A7B':'ltquest','\u2A7C':'gtquest','\u2A7D':'les','\u2A7D\u0338':'nles','\u2A7E':'ges','\u2A7E\u0338':'nges','\u2A7F':'lesdot','\u2A80':'gesdot','\u2A81':'lesdoto','\u2A82':'gesdoto','\u2A83':'lesdotor','\u2A84':'gesdotol','\u2A85':'lap','\u2A86':'gap','\u2A87':'lne','\u2A88':'gne','\u2A89':'lnap','\u2A8A':'gnap','\u2A8B':'lEg','\u2A8C':'gEl','\u2A8D':'lsime','\u2A8E':'gsime','\u2A8F':'lsimg','\u2A90':'gsiml','\u2A91':'lgE','\u2A92':'glE','\u2A93':'lesges','\u2A94':'gesles','\u2A95':'els','\u2A96':'egs','\u2A97':'elsdot','\u2A98':'egsdot','\u2A99':'el','\u2A9A':'eg','\u2A9D':'siml','\u2A9E':'simg','\u2A9F':'simlE','\u2AA0':'simgE','\u2AA1':'LessLess','\u2AA1\u0338':'NotNestedLessLess','\u2AA2':'GreaterGreater','\u2AA2\u0338':'NotNestedGreaterGreater','\u2AA4':'glj','\u2AA5':'gla','\u2AA6':'ltcc','\u2AA7':'gtcc','\u2AA8':'lescc','\u2AA9':'gescc','\u2AAA':'smt','\u2AAB':'lat','\u2AAC':'smte','\u2AAC\uFE00':'smtes','\u2AAD':'late','\u2AAD\uFE00':'lates','\u2AAE':'bumpE','\u2AAF':'pre','\u2AAF\u0338':'npre','\u2AB0':'sce','\u2AB0\u0338':'nsce','\u2AB3':'prE','\u2AB4':'scE','\u2AB5':'prnE','\u2AB6':'scnE','\u2AB7':'prap','\u2AB8':'scap','\u2AB9':'prnap','\u2ABA':'scnap','\u2ABB':'Pr','\u2ABC':'Sc','\u2ABD':'subdot','\u2ABE':'supdot','\u2ABF':'subplus','\u2AC0':'supplus','\u2AC1':'submult','\u2AC2':'supmult','\u2AC3':'subedot','\u2AC4':'supedot','\u2AC5':'subE','\u2AC5\u0338':'nsubE','\u2AC6':'supE','\u2AC6\u0338':'nsupE','\u2AC7':'subsim','\u2AC8':'supsim','\u2ACB\uFE00':'vsubnE','\u2ACB':'subnE','\u2ACC\uFE00':'vsupnE','\u2ACC':'supnE','\u2ACF':'csub','\u2AD0':'csup','\u2AD1':'csube','\u2AD2':'csupe','\u2AD3':'subsup','\u2AD4':'supsub','\u2AD5':'subsub','\u2AD6':'supsup','\u2AD7':'suphsub','\u2AD8':'supdsub','\u2AD9':'forkv','\u2ADA':'topfork','\u2ADB':'mlcp','\u2AE4':'Dashv','\u2AE6':'Vdashl','\u2AE7':'Barv','\u2AE8':'vBar','\u2AE9':'vBarv','\u2AEB':'Vbar','\u2AEC':'Not','\u2AED':'bNot','\u2AEE':'rnmid','\u2AEF':'cirmid','\u2AF0':'midcir','\u2AF1':'topcir','\u2AF2':'nhpar','\u2AF3':'parsim','\u2AFD':'parsl','\u2AFD\u20E5':'nparsl','\u266D':'flat','\u266E':'natur','\u266F':'sharp','\xA4':'curren','\xA2':'cent','$':'dollar','\xA3':'pound','\xA5':'yen','\u20AC':'euro','\xB9':'sup1','\xBD':'half','\u2153':'frac13','\xBC':'frac14','\u2155':'frac15','\u2159':'frac16','\u215B':'frac18','\xB2':'sup2','\u2154':'frac23','\u2156':'frac25','\xB3':'sup3','\xBE':'frac34','\u2157':'frac35','\u215C':'frac38','\u2158':'frac45','\u215A':'frac56','\u215D':'frac58','\u215E':'frac78','\uD835\uDCB6':'ascr','\uD835\uDD52':'aopf','\uD835\uDD1E':'afr','\uD835\uDD38':'Aopf','\uD835\uDD04':'Afr','\uD835\uDC9C':'Ascr','\xAA':'ordf','\xE1':'aacute','\xC1':'Aacute','\xE0':'agrave','\xC0':'Agrave','\u0103':'abreve','\u0102':'Abreve','\xE2':'acirc','\xC2':'Acirc','\xE5':'aring','\xC5':'angst','\xE4':'auml','\xC4':'Auml','\xE3':'atilde','\xC3':'Atilde','\u0105':'aogon','\u0104':'Aogon','\u0101':'amacr','\u0100':'Amacr','\xE6':'aelig','\xC6':'AElig','\uD835\uDCB7':'bscr','\uD835\uDD53':'bopf','\uD835\uDD1F':'bfr','\uD835\uDD39':'Bopf','\u212C':'Bscr','\uD835\uDD05':'Bfr','\uD835\uDD20':'cfr','\uD835\uDCB8':'cscr','\uD835\uDD54':'copf','\u212D':'Cfr','\uD835\uDC9E':'Cscr','\u2102':'Copf','\u0107':'cacute','\u0106':'Cacute','\u0109':'ccirc','\u0108':'Ccirc','\u010D':'ccaron','\u010C':'Ccaron','\u010B':'cdot','\u010A':'Cdot','\xE7':'ccedil','\xC7':'Ccedil','\u2105':'incare','\uD835\uDD21':'dfr','\u2146':'dd','\uD835\uDD55':'dopf','\uD835\uDCB9':'dscr','\uD835\uDC9F':'Dscr','\uD835\uDD07':'Dfr','\u2145':'DD','\uD835\uDD3B':'Dopf','\u010F':'dcaron','\u010E':'Dcaron','\u0111':'dstrok','\u0110':'Dstrok','\xF0':'eth','\xD0':'ETH','\u2147':'ee','\u212F':'escr','\uD835\uDD22':'efr','\uD835\uDD56':'eopf','\u2130':'Escr','\uD835\uDD08':'Efr','\uD835\uDD3C':'Eopf','\xE9':'eacute','\xC9':'Eacute','\xE8':'egrave','\xC8':'Egrave','\xEA':'ecirc','\xCA':'Ecirc','\u011B':'ecaron','\u011A':'Ecaron','\xEB':'euml','\xCB':'Euml','\u0117':'edot','\u0116':'Edot','\u0119':'eogon','\u0118':'Eogon','\u0113':'emacr','\u0112':'Emacr','\uD835\uDD23':'ffr','\uD835\uDD57':'fopf','\uD835\uDCBB':'fscr','\uD835\uDD09':'Ffr','\uD835\uDD3D':'Fopf','\u2131':'Fscr','\uFB00':'fflig','\uFB03':'ffilig','\uFB04':'ffllig','\uFB01':'filig','fj':'fjlig','\uFB02':'fllig','\u0192':'fnof','\u210A':'gscr','\uD835\uDD58':'gopf','\uD835\uDD24':'gfr','\uD835\uDCA2':'Gscr','\uD835\uDD3E':'Gopf','\uD835\uDD0A':'Gfr','\u01F5':'gacute','\u011F':'gbreve','\u011E':'Gbreve','\u011D':'gcirc','\u011C':'Gcirc','\u0121':'gdot','\u0120':'Gdot','\u0122':'Gcedil','\uD835\uDD25':'hfr','\u210E':'planckh','\uD835\uDCBD':'hscr','\uD835\uDD59':'hopf','\u210B':'Hscr','\u210C':'Hfr','\u210D':'Hopf','\u0125':'hcirc','\u0124':'Hcirc','\u210F':'hbar','\u0127':'hstrok','\u0126':'Hstrok','\uD835\uDD5A':'iopf','\uD835\uDD26':'ifr','\uD835\uDCBE':'iscr','\u2148':'ii','\uD835\uDD40':'Iopf','\u2110':'Iscr','\u2111':'Im','\xED':'iacute','\xCD':'Iacute','\xEC':'igrave','\xCC':'Igrave','\xEE':'icirc','\xCE':'Icirc','\xEF':'iuml','\xCF':'Iuml','\u0129':'itilde','\u0128':'Itilde','\u0130':'Idot','\u012F':'iogon','\u012E':'Iogon','\u012B':'imacr','\u012A':'Imacr','\u0133':'ijlig','\u0132':'IJlig','\u0131':'imath','\uD835\uDCBF':'jscr','\uD835\uDD5B':'jopf','\uD835\uDD27':'jfr','\uD835\uDCA5':'Jscr','\uD835\uDD0D':'Jfr','\uD835\uDD41':'Jopf','\u0135':'jcirc','\u0134':'Jcirc','\u0237':'jmath','\uD835\uDD5C':'kopf','\uD835\uDCC0':'kscr','\uD835\uDD28':'kfr','\uD835\uDCA6':'Kscr','\uD835\uDD42':'Kopf','\uD835\uDD0E':'Kfr','\u0137':'kcedil','\u0136':'Kcedil','\uD835\uDD29':'lfr','\uD835\uDCC1':'lscr','\u2113':'ell','\uD835\uDD5D':'lopf','\u2112':'Lscr','\uD835\uDD0F':'Lfr','\uD835\uDD43':'Lopf','\u013A':'lacute','\u0139':'Lacute','\u013E':'lcaron','\u013D':'Lcaron','\u013C':'lcedil','\u013B':'Lcedil','\u0142':'lstrok','\u0141':'Lstrok','\u0140':'lmidot','\u013F':'Lmidot','\uD835\uDD2A':'mfr','\uD835\uDD5E':'mopf','\uD835\uDCC2':'mscr','\uD835\uDD10':'Mfr','\uD835\uDD44':'Mopf','\u2133':'Mscr','\uD835\uDD2B':'nfr','\uD835\uDD5F':'nopf','\uD835\uDCC3':'nscr','\u2115':'Nopf','\uD835\uDCA9':'Nscr','\uD835\uDD11':'Nfr','\u0144':'nacute','\u0143':'Nacute','\u0148':'ncaron','\u0147':'Ncaron','\xF1':'ntilde','\xD1':'Ntilde','\u0146':'ncedil','\u0145':'Ncedil','\u2116':'numero','\u014B':'eng','\u014A':'ENG','\uD835\uDD60':'oopf','\uD835\uDD2C':'ofr','\u2134':'oscr','\uD835\uDCAA':'Oscr','\uD835\uDD12':'Ofr','\uD835\uDD46':'Oopf','\xBA':'ordm','\xF3':'oacute','\xD3':'Oacute','\xF2':'ograve','\xD2':'Ograve','\xF4':'ocirc','\xD4':'Ocirc','\xF6':'ouml','\xD6':'Ouml','\u0151':'odblac','\u0150':'Odblac','\xF5':'otilde','\xD5':'Otilde','\xF8':'oslash','\xD8':'Oslash','\u014D':'omacr','\u014C':'Omacr','\u0153':'oelig','\u0152':'OElig','\uD835\uDD2D':'pfr','\uD835\uDCC5':'pscr','\uD835\uDD61':'popf','\u2119':'Popf','\uD835\uDD13':'Pfr','\uD835\uDCAB':'Pscr','\uD835\uDD62':'qopf','\uD835\uDD2E':'qfr','\uD835\uDCC6':'qscr','\uD835\uDCAC':'Qscr','\uD835\uDD14':'Qfr','\u211A':'Qopf','\u0138':'kgreen','\uD835\uDD2F':'rfr','\uD835\uDD63':'ropf','\uD835\uDCC7':'rscr','\u211B':'Rscr','\u211C':'Re','\u211D':'Ropf','\u0155':'racute','\u0154':'Racute','\u0159':'rcaron','\u0158':'Rcaron','\u0157':'rcedil','\u0156':'Rcedil','\uD835\uDD64':'sopf','\uD835\uDCC8':'sscr','\uD835\uDD30':'sfr','\uD835\uDD4A':'Sopf','\uD835\uDD16':'Sfr','\uD835\uDCAE':'Sscr','\u24C8':'oS','\u015B':'sacute','\u015A':'Sacute','\u015D':'scirc','\u015C':'Scirc','\u0161':'scaron','\u0160':'Scaron','\u015F':'scedil','\u015E':'Scedil','\xDF':'szlig','\uD835\uDD31':'tfr','\uD835\uDCC9':'tscr','\uD835\uDD65':'topf','\uD835\uDCAF':'Tscr','\uD835\uDD17':'Tfr','\uD835\uDD4B':'Topf','\u0165':'tcaron','\u0164':'Tcaron','\u0163':'tcedil','\u0162':'Tcedil','\u2122':'trade','\u0167':'tstrok','\u0166':'Tstrok','\uD835\uDCCA':'uscr','\uD835\uDD66':'uopf','\uD835\uDD32':'ufr','\uD835\uDD4C':'Uopf','\uD835\uDD18':'Ufr','\uD835\uDCB0':'Uscr','\xFA':'uacute','\xDA':'Uacute','\xF9':'ugrave','\xD9':'Ugrave','\u016D':'ubreve','\u016C':'Ubreve','\xFB':'ucirc','\xDB':'Ucirc','\u016F':'uring','\u016E':'Uring','\xFC':'uuml','\xDC':'Uuml','\u0171':'udblac','\u0170':'Udblac','\u0169':'utilde','\u0168':'Utilde','\u0173':'uogon','\u0172':'Uogon','\u016B':'umacr','\u016A':'Umacr','\uD835\uDD33':'vfr','\uD835\uDD67':'vopf','\uD835\uDCCB':'vscr','\uD835\uDD19':'Vfr','\uD835\uDD4D':'Vopf','\uD835\uDCB1':'Vscr','\uD835\uDD68':'wopf','\uD835\uDCCC':'wscr','\uD835\uDD34':'wfr','\uD835\uDCB2':'Wscr','\uD835\uDD4E':'Wopf','\uD835\uDD1A':'Wfr','\u0175':'wcirc','\u0174':'Wcirc','\uD835\uDD35':'xfr','\uD835\uDCCD':'xscr','\uD835\uDD69':'xopf','\uD835\uDD4F':'Xopf','\uD835\uDD1B':'Xfr','\uD835\uDCB3':'Xscr','\uD835\uDD36':'yfr','\uD835\uDCCE':'yscr','\uD835\uDD6A':'yopf','\uD835\uDCB4':'Yscr','\uD835\uDD1C':'Yfr','\uD835\uDD50':'Yopf','\xFD':'yacute','\xDD':'Yacute','\u0177':'ycirc','\u0176':'Ycirc','\xFF':'yuml','\u0178':'Yuml','\uD835\uDCCF':'zscr','\uD835\uDD37':'zfr','\uD835\uDD6B':'zopf','\u2128':'Zfr','\u2124':'Zopf','\uD835\uDCB5':'Zscr','\u017A':'zacute','\u0179':'Zacute','\u017E':'zcaron','\u017D':'Zcaron','\u017C':'zdot','\u017B':'Zdot','\u01B5':'imped','\xFE':'thorn','\xDE':'THORN','\u0149':'napos','\u03B1':'alpha','\u0391':'Alpha','\u03B2':'beta','\u0392':'Beta','\u03B3':'gamma','\u0393':'Gamma','\u03B4':'delta','\u0394':'Delta','\u03B5':'epsi','\u03F5':'epsiv','\u0395':'Epsilon','\u03DD':'gammad','\u03DC':'Gammad','\u03B6':'zeta','\u0396':'Zeta','\u03B7':'eta','\u0397':'Eta','\u03B8':'theta','\u03D1':'thetav','\u0398':'Theta','\u03B9':'iota','\u0399':'Iota','\u03BA':'kappa','\u03F0':'kappav','\u039A':'Kappa','\u03BB':'lambda','\u039B':'Lambda','\u03BC':'mu','\xB5':'micro','\u039C':'Mu','\u03BD':'nu','\u039D':'Nu','\u03BE':'xi','\u039E':'Xi','\u03BF':'omicron','\u039F':'Omicron','\u03C0':'pi','\u03D6':'piv','\u03A0':'Pi','\u03C1':'rho','\u03F1':'rhov','\u03A1':'Rho','\u03C3':'sigma','\u03A3':'Sigma','\u03C2':'sigmaf','\u03C4':'tau','\u03A4':'Tau','\u03C5':'upsi','\u03A5':'Upsilon','\u03D2':'Upsi','\u03C6':'phi','\u03D5':'phiv','\u03A6':'Phi','\u03C7':'chi','\u03A7':'Chi','\u03C8':'psi','\u03A8':'Psi','\u03C9':'omega','\u03A9':'ohm','\u0430':'acy','\u0410':'Acy','\u0431':'bcy','\u0411':'Bcy','\u0432':'vcy','\u0412':'Vcy','\u0433':'gcy','\u0413':'Gcy','\u0453':'gjcy','\u0403':'GJcy','\u0434':'dcy','\u0414':'Dcy','\u0452':'djcy','\u0402':'DJcy','\u0435':'iecy','\u0415':'IEcy','\u0451':'iocy','\u0401':'IOcy','\u0454':'jukcy','\u0404':'Jukcy','\u0436':'zhcy','\u0416':'ZHcy','\u0437':'zcy','\u0417':'Zcy','\u0455':'dscy','\u0405':'DScy','\u0438':'icy','\u0418':'Icy','\u0456':'iukcy','\u0406':'Iukcy','\u0457':'yicy','\u0407':'YIcy','\u0439':'jcy','\u0419':'Jcy','\u0458':'jsercy','\u0408':'Jsercy','\u043A':'kcy','\u041A':'Kcy','\u045C':'kjcy','\u040C':'KJcy','\u043B':'lcy','\u041B':'Lcy','\u0459':'ljcy','\u0409':'LJcy','\u043C':'mcy','\u041C':'Mcy','\u043D':'ncy','\u041D':'Ncy','\u045A':'njcy','\u040A':'NJcy','\u043E':'ocy','\u041E':'Ocy','\u043F':'pcy','\u041F':'Pcy','\u0440':'rcy','\u0420':'Rcy','\u0441':'scy','\u0421':'Scy','\u0442':'tcy','\u0422':'Tcy','\u045B':'tshcy','\u040B':'TSHcy','\u0443':'ucy','\u0423':'Ucy','\u045E':'ubrcy','\u040E':'Ubrcy','\u0444':'fcy','\u0424':'Fcy','\u0445':'khcy','\u0425':'KHcy','\u0446':'tscy','\u0426':'TScy','\u0447':'chcy','\u0427':'CHcy','\u045F':'dzcy','\u040F':'DZcy','\u0448':'shcy','\u0428':'SHcy','\u0449':'shchcy','\u0429':'SHCHcy','\u044A':'hardcy','\u042A':'HARDcy','\u044B':'ycy','\u042B':'Ycy','\u044C':'softcy','\u042C':'SOFTcy','\u044D':'ecy','\u042D':'Ecy','\u044E':'yucy','\u042E':'YUcy','\u044F':'yacy','\u042F':'YAcy','\u2135':'aleph','\u2136':'beth','\u2137':'gimel','\u2138':'daleth'}; + + var regexEscape = /["&'<>`]/g; + var escapeMap = { + '"': '"', + '&': '&', + '\'': ''', + '<': '<', + // See https://mathiasbynens.be/notes/ambiguous-ampersands: in HTML, the + // following is not strictly necessary unless it’s part of a tag or an + // unquoted attribute value. We’re only escaping it to support those + // situations, and for XML support. + '>': '>', + // In Internet Explorer ≤ 8, the backtick character can be used + // to break out of (un)quoted attribute values or HTML comments. + // See http://html5sec.org/#102, http://html5sec.org/#108, and + // http://html5sec.org/#133. + '`': '`' + }; + + var regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/; + var regexInvalidRawCodePoint = /[\0-\x08\x0B\x0E-\x1F\x7F-\x9F\uFDD0-\uFDEF\uFFFE\uFFFF]|[\uD83F\uD87F\uD8BF\uD8FF\uD93F\uD97F\uD9BF\uD9FF\uDA3F\uDA7F\uDABF\uDAFF\uDB3F\uDB7F\uDBBF\uDBFF][\uDFFE\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; + var regexDecode = /&(CounterClockwiseContourIntegral|DoubleLongLeftRightArrow|ClockwiseContourIntegral|NotNestedGreaterGreater|NotSquareSupersetEqual|DiacriticalDoubleAcute|NotRightTriangleEqual|NotSucceedsSlantEqual|NotPrecedesSlantEqual|CloseCurlyDoubleQuote|NegativeVeryThinSpace|DoubleContourIntegral|FilledVerySmallSquare|CapitalDifferentialD|OpenCurlyDoubleQuote|EmptyVerySmallSquare|NestedGreaterGreater|DoubleLongRightArrow|NotLeftTriangleEqual|NotGreaterSlantEqual|ReverseUpEquilibrium|DoubleLeftRightArrow|NotSquareSubsetEqual|NotDoubleVerticalBar|RightArrowLeftArrow|NotGreaterFullEqual|NotRightTriangleBar|SquareSupersetEqual|DownLeftRightVector|DoubleLongLeftArrow|leftrightsquigarrow|LeftArrowRightArrow|NegativeMediumSpace|blacktriangleright|RightDownVectorBar|PrecedesSlantEqual|RightDoubleBracket|SucceedsSlantEqual|NotLeftTriangleBar|RightTriangleEqual|SquareIntersection|RightDownTeeVector|ReverseEquilibrium|NegativeThickSpace|longleftrightarrow|Longleftrightarrow|LongLeftRightArrow|DownRightTeeVector|DownRightVectorBar|GreaterSlantEqual|SquareSubsetEqual|LeftDownVectorBar|LeftDoubleBracket|VerticalSeparator|rightleftharpoons|NotGreaterGreater|NotSquareSuperset|blacktriangleleft|blacktriangledown|NegativeThinSpace|LeftDownTeeVector|NotLessSlantEqual|leftrightharpoons|DoubleUpDownArrow|DoubleVerticalBar|LeftTriangleEqual|FilledSmallSquare|twoheadrightarrow|NotNestedLessLess|DownLeftTeeVector|DownLeftVectorBar|RightAngleBracket|NotTildeFullEqual|NotReverseElement|RightUpDownVector|DiacriticalTilde|NotSucceedsTilde|circlearrowright|NotPrecedesEqual|rightharpoondown|DoubleRightArrow|NotSucceedsEqual|NonBreakingSpace|NotRightTriangle|LessEqualGreater|RightUpTeeVector|LeftAngleBracket|GreaterFullEqual|DownArrowUpArrow|RightUpVectorBar|twoheadleftarrow|GreaterEqualLess|downharpoonright|RightTriangleBar|ntrianglerighteq|NotSupersetEqual|LeftUpDownVector|DiacriticalAcute|rightrightarrows|vartriangleright|UpArrowDownArrow|DiacriticalGrave|UnderParenthesis|EmptySmallSquare|LeftUpVectorBar|leftrightarrows|DownRightVector|downharpoonleft|trianglerighteq|ShortRightArrow|OverParenthesis|DoubleLeftArrow|DoubleDownArrow|NotSquareSubset|bigtriangledown|ntrianglelefteq|UpperRightArrow|curvearrowright|vartriangleleft|NotLeftTriangle|nleftrightarrow|LowerRightArrow|NotHumpDownHump|NotGreaterTilde|rightthreetimes|LeftUpTeeVector|NotGreaterEqual|straightepsilon|LeftTriangleBar|rightsquigarrow|ContourIntegral|rightleftarrows|CloseCurlyQuote|RightDownVector|LeftRightVector|nLeftrightarrow|leftharpoondown|circlearrowleft|SquareSuperset|OpenCurlyQuote|hookrightarrow|HorizontalLine|DiacriticalDot|NotLessGreater|ntriangleright|DoubleRightTee|InvisibleComma|InvisibleTimes|LowerLeftArrow|DownLeftVector|NotSubsetEqual|curvearrowleft|trianglelefteq|NotVerticalBar|TildeFullEqual|downdownarrows|NotGreaterLess|RightTeeVector|ZeroWidthSpace|looparrowright|LongRightArrow|doublebarwedge|ShortLeftArrow|ShortDownArrow|RightVectorBar|GreaterGreater|ReverseElement|rightharpoonup|LessSlantEqual|leftthreetimes|upharpoonright|rightarrowtail|LeftDownVector|Longrightarrow|NestedLessLess|UpperLeftArrow|nshortparallel|leftleftarrows|leftrightarrow|Leftrightarrow|LeftRightArrow|longrightarrow|upharpoonleft|RightArrowBar|ApplyFunction|LeftTeeVector|leftarrowtail|NotEqualTilde|varsubsetneqq|varsupsetneqq|RightTeeArrow|SucceedsEqual|SucceedsTilde|LeftVectorBar|SupersetEqual|hookleftarrow|DifferentialD|VerticalTilde|VeryThinSpace|blacktriangle|bigtriangleup|LessFullEqual|divideontimes|leftharpoonup|UpEquilibrium|ntriangleleft|RightTriangle|measuredangle|shortparallel|longleftarrow|Longleftarrow|LongLeftArrow|DoubleLeftTee|Poincareplane|PrecedesEqual|triangleright|DoubleUpArrow|RightUpVector|fallingdotseq|looparrowleft|PrecedesTilde|NotTildeEqual|NotTildeTilde|smallsetminus|Proportional|triangleleft|triangledown|UnderBracket|NotHumpEqual|exponentiale|ExponentialE|NotLessTilde|HilbertSpace|RightCeiling|blacklozenge|varsupsetneq|HumpDownHump|GreaterEqual|VerticalLine|LeftTeeArrow|NotLessEqual|DownTeeArrow|LeftTriangle|varsubsetneq|Intersection|NotCongruent|DownArrowBar|LeftUpVector|LeftArrowBar|risingdotseq|GreaterTilde|RoundImplies|SquareSubset|ShortUpArrow|NotSuperset|quaternions|precnapprox|backepsilon|preccurlyeq|OverBracket|blacksquare|MediumSpace|VerticalBar|circledcirc|circleddash|CircleMinus|CircleTimes|LessGreater|curlyeqprec|curlyeqsucc|diamondsuit|UpDownArrow|Updownarrow|RuleDelayed|Rrightarrow|updownarrow|RightVector|nRightarrow|nrightarrow|eqslantless|LeftCeiling|Equilibrium|SmallCircle|expectation|NotSucceeds|thickapprox|GreaterLess|SquareUnion|NotPrecedes|NotLessLess|straightphi|succnapprox|succcurlyeq|SubsetEqual|sqsupseteq|Proportion|Laplacetrf|ImaginaryI|supsetneqq|NotGreater|gtreqqless|NotElement|ThickSpace|TildeEqual|TildeTilde|Fouriertrf|rmoustache|EqualTilde|eqslantgtr|UnderBrace|LeftVector|UpArrowBar|nLeftarrow|nsubseteqq|subsetneqq|nsupseteqq|nleftarrow|succapprox|lessapprox|UpTeeArrow|upuparrows|curlywedge|lesseqqgtr|varepsilon|varnothing|RightFloor|complement|CirclePlus|sqsubseteq|Lleftarrow|circledast|RightArrow|Rightarrow|rightarrow|lmoustache|Bernoullis|precapprox|mapstoleft|mapstodown|longmapsto|dotsquare|downarrow|DoubleDot|nsubseteq|supsetneq|leftarrow|nsupseteq|subsetneq|ThinSpace|ngeqslant|subseteqq|HumpEqual|NotSubset|triangleq|NotCupCap|lesseqgtr|heartsuit|TripleDot|Leftarrow|Coproduct|Congruent|varpropto|complexes|gvertneqq|LeftArrow|LessTilde|supseteqq|MinusPlus|CircleDot|nleqslant|NotExists|gtreqless|nparallel|UnionPlus|LeftFloor|checkmark|CenterDot|centerdot|Mellintrf|gtrapprox|bigotimes|OverBrace|spadesuit|therefore|pitchfork|rationals|PlusMinus|Backslash|Therefore|DownBreve|backsimeq|backprime|DownArrow|nshortmid|Downarrow|lvertneqq|eqvparsl|imagline|imagpart|infintie|integers|Integral|intercal|LessLess|Uarrocir|intlarhk|sqsupset|angmsdaf|sqsubset|llcorner|vartheta|cupbrcap|lnapprox|Superset|SuchThat|succnsim|succneqq|angmsdag|biguplus|curlyvee|trpezium|Succeeds|NotTilde|bigwedge|angmsdah|angrtvbd|triminus|cwconint|fpartint|lrcorner|smeparsl|subseteq|urcorner|lurdshar|laemptyv|DDotrahd|approxeq|ldrushar|awconint|mapstoup|backcong|shortmid|triangle|geqslant|gesdotol|timesbar|circledR|circledS|setminus|multimap|naturals|scpolint|ncongdot|RightTee|boxminus|gnapprox|boxtimes|andslope|thicksim|angmsdaa|varsigma|cirfnint|rtriltri|angmsdab|rppolint|angmsdac|barwedge|drbkarow|clubsuit|thetasym|bsolhsub|capbrcup|dzigrarr|doteqdot|DotEqual|dotminus|UnderBar|NotEqual|realpart|otimesas|ulcorner|hksearow|hkswarow|parallel|PartialD|elinters|emptyset|plusacir|bbrktbrk|angmsdad|pointint|bigoplus|angmsdae|Precedes|bigsqcup|varkappa|notindot|supseteq|precneqq|precnsim|profalar|profline|profsurf|leqslant|lesdotor|raemptyv|subplus|notnivb|notnivc|subrarr|zigrarr|vzigzag|submult|subedot|Element|between|cirscir|larrbfs|larrsim|lotimes|lbrksld|lbrkslu|lozenge|ldrdhar|dbkarow|bigcirc|epsilon|simrarr|simplus|ltquest|Epsilon|luruhar|gtquest|maltese|npolint|eqcolon|npreceq|bigodot|ddagger|gtrless|bnequiv|harrcir|ddotseq|equivDD|backsim|demptyv|nsqsube|nsqsupe|Upsilon|nsubset|upsilon|minusdu|nsucceq|swarrow|nsupset|coloneq|searrow|boxplus|napprox|natural|asympeq|alefsym|congdot|nearrow|bigstar|diamond|supplus|tritime|LeftTee|nvinfin|triplus|NewLine|nvltrie|nvrtrie|nwarrow|nexists|Diamond|ruluhar|Implies|supmult|angzarr|suplarr|suphsub|questeq|because|digamma|Because|olcross|bemptyv|omicron|Omicron|rotimes|NoBreak|intprod|angrtvb|orderof|uwangle|suphsol|lesdoto|orslope|DownTee|realine|cudarrl|rdldhar|OverBar|supedot|lessdot|supdsub|topfork|succsim|rbrkslu|rbrksld|pertenk|cudarrr|isindot|planckh|lessgtr|pluscir|gesdoto|plussim|plustwo|lesssim|cularrp|rarrsim|Cayleys|notinva|notinvb|notinvc|UpArrow|Uparrow|uparrow|NotLess|dwangle|precsim|Product|curarrm|Cconint|dotplus|rarrbfs|ccupssm|Cedilla|cemptyv|notniva|quatint|frac35|frac38|frac45|frac56|frac58|frac78|tridot|xoplus|gacute|gammad|Gammad|lfisht|lfloor|bigcup|sqsupe|gbreve|Gbreve|lharul|sqsube|sqcups|Gcedil|apacir|llhard|lmidot|Lmidot|lmoust|andand|sqcaps|approx|Abreve|spades|circeq|tprime|divide|topcir|Assign|topbot|gesdot|divonx|xuplus|timesd|gesles|atilde|solbar|SOFTcy|loplus|timesb|lowast|lowbar|dlcorn|dlcrop|softcy|dollar|lparlt|thksim|lrhard|Atilde|lsaquo|smashp|bigvee|thinsp|wreath|bkarow|lsquor|lstrok|Lstrok|lthree|ltimes|ltlarr|DotDot|simdot|ltrPar|weierp|xsqcup|angmsd|sigmav|sigmaf|zeetrf|Zcaron|zcaron|mapsto|vsupne|thetav|cirmid|marker|mcomma|Zacute|vsubnE|there4|gtlPar|vsubne|bottom|gtrarr|SHCHcy|shchcy|midast|midcir|middot|minusb|minusd|gtrdot|bowtie|sfrown|mnplus|models|colone|seswar|Colone|mstpos|searhk|gtrsim|nacute|Nacute|boxbox|telrec|hairsp|Tcedil|nbumpe|scnsim|ncaron|Ncaron|ncedil|Ncedil|hamilt|Scedil|nearhk|hardcy|HARDcy|tcedil|Tcaron|commat|nequiv|nesear|tcaron|target|hearts|nexist|varrho|scedil|Scaron|scaron|hellip|Sacute|sacute|hercon|swnwar|compfn|rtimes|rthree|rsquor|rsaquo|zacute|wedgeq|homtht|barvee|barwed|Barwed|rpargt|horbar|conint|swarhk|roplus|nltrie|hslash|hstrok|Hstrok|rmoust|Conint|bprime|hybull|hyphen|iacute|Iacute|supsup|supsub|supsim|varphi|coprod|brvbar|agrave|Supset|supset|igrave|Igrave|notinE|Agrave|iiiint|iinfin|copysr|wedbar|Verbar|vangrt|becaus|incare|verbar|inodot|bullet|drcorn|intcal|drcrop|cularr|vellip|Utilde|bumpeq|cupcap|dstrok|Dstrok|CupCap|cupcup|cupdot|eacute|Eacute|supdot|iquest|easter|ecaron|Ecaron|ecolon|isinsv|utilde|itilde|Itilde|curarr|succeq|Bumpeq|cacute|ulcrop|nparsl|Cacute|nprcue|egrave|Egrave|nrarrc|nrarrw|subsup|subsub|nrtrie|jsercy|nsccue|Jsercy|kappav|kcedil|Kcedil|subsim|ulcorn|nsimeq|egsdot|veebar|kgreen|capand|elsdot|Subset|subset|curren|aacute|lacute|Lacute|emptyv|ntilde|Ntilde|lagran|lambda|Lambda|capcap|Ugrave|langle|subdot|emsp13|numero|emsp14|nvdash|nvDash|nVdash|nVDash|ugrave|ufisht|nvHarr|larrfs|nvlArr|larrhk|larrlp|larrpl|nvrArr|Udblac|nwarhk|larrtl|nwnear|oacute|Oacute|latail|lAtail|sstarf|lbrace|odblac|Odblac|lbrack|udblac|odsold|eparsl|lcaron|Lcaron|ograve|Ograve|lcedil|Lcedil|Aacute|ssmile|ssetmn|squarf|ldquor|capcup|ominus|cylcty|rharul|eqcirc|dagger|rfloor|rfisht|Dagger|daleth|equals|origof|capdot|equest|dcaron|Dcaron|rdquor|oslash|Oslash|otilde|Otilde|otimes|Otimes|urcrop|Ubreve|ubreve|Yacute|Uacute|uacute|Rcedil|rcedil|urcorn|parsim|Rcaron|Vdashl|rcaron|Tstrok|percnt|period|permil|Exists|yacute|rbrack|rbrace|phmmat|ccaron|Ccaron|planck|ccedil|plankv|tstrok|female|plusdo|plusdu|ffilig|plusmn|ffllig|Ccedil|rAtail|dfisht|bernou|ratail|Rarrtl|rarrtl|angsph|rarrpl|rarrlp|rarrhk|xwedge|xotime|forall|ForAll|Vvdash|vsupnE|preceq|bigcap|frac12|frac13|frac14|primes|rarrfs|prnsim|frac15|Square|frac16|square|lesdot|frac18|frac23|propto|prurel|rarrap|rangle|puncsp|frac25|Racute|qprime|racute|lesges|frac34|abreve|AElig|eqsim|utdot|setmn|urtri|Equal|Uring|seArr|uring|searr|dashv|Dashv|mumap|nabla|iogon|Iogon|sdote|sdotb|scsim|napid|napos|equiv|natur|Acirc|dblac|erarr|nbump|iprod|erDot|ucirc|awint|esdot|angrt|ncong|isinE|scnap|Scirc|scirc|ndash|isins|Ubrcy|nearr|neArr|isinv|nedot|ubrcy|acute|Ycirc|iukcy|Iukcy|xutri|nesim|caret|jcirc|Jcirc|caron|twixt|ddarr|sccue|exist|jmath|sbquo|ngeqq|angst|ccaps|lceil|ngsim|UpTee|delta|Delta|rtrif|nharr|nhArr|nhpar|rtrie|jukcy|Jukcy|kappa|rsquo|Kappa|nlarr|nlArr|TSHcy|rrarr|aogon|Aogon|fflig|xrarr|tshcy|ccirc|nleqq|filig|upsih|nless|dharl|nlsim|fjlig|ropar|nltri|dharr|robrk|roarr|fllig|fltns|roang|rnmid|subnE|subne|lAarr|trisb|Ccirc|acirc|ccups|blank|VDash|forkv|Vdash|langd|cedil|blk12|blk14|laquo|strns|diams|notin|vDash|larrb|blk34|block|disin|uplus|vdash|vBarv|aelig|starf|Wedge|check|xrArr|lates|lbarr|lBarr|notni|lbbrk|bcong|frasl|lbrke|frown|vrtri|vprop|vnsup|gamma|Gamma|wedge|xodot|bdquo|srarr|doteq|ldquo|boxdl|boxdL|gcirc|Gcirc|boxDl|boxDL|boxdr|boxdR|boxDr|TRADE|trade|rlhar|boxDR|vnsub|npart|vltri|rlarr|boxhd|boxhD|nprec|gescc|nrarr|nrArr|boxHd|boxHD|boxhu|boxhU|nrtri|boxHu|clubs|boxHU|times|colon|Colon|gimel|xlArr|Tilde|nsime|tilde|nsmid|nspar|THORN|thorn|xlarr|nsube|nsubE|thkap|xhArr|comma|nsucc|boxul|boxuL|nsupe|nsupE|gneqq|gnsim|boxUl|boxUL|grave|boxur|boxuR|boxUr|boxUR|lescc|angle|bepsi|boxvh|varpi|boxvH|numsp|Theta|gsime|gsiml|theta|boxVh|boxVH|boxvl|gtcir|gtdot|boxvL|boxVl|boxVL|crarr|cross|Cross|nvsim|boxvr|nwarr|nwArr|sqsup|dtdot|Uogon|lhard|lharu|dtrif|ocirc|Ocirc|lhblk|duarr|odash|sqsub|Hacek|sqcup|llarr|duhar|oelig|OElig|ofcir|boxvR|uogon|lltri|boxVr|csube|uuarr|ohbar|csupe|ctdot|olarr|olcir|harrw|oline|sqcap|omacr|Omacr|omega|Omega|boxVR|aleph|lneqq|lnsim|loang|loarr|rharu|lobrk|hcirc|operp|oplus|rhard|Hcirc|orarr|Union|order|ecirc|Ecirc|cuepr|szlig|cuesc|breve|reals|eDDot|Breve|hoarr|lopar|utrif|rdquo|Umacr|umacr|efDot|swArr|ultri|alpha|rceil|ovbar|swarr|Wcirc|wcirc|smtes|smile|bsemi|lrarr|aring|parsl|lrhar|bsime|uhblk|lrtri|cupor|Aring|uharr|uharl|slarr|rbrke|bsolb|lsime|rbbrk|RBarr|lsimg|phone|rBarr|rbarr|icirc|lsquo|Icirc|emacr|Emacr|ratio|simne|plusb|simlE|simgE|simeq|pluse|ltcir|ltdot|empty|xharr|xdtri|iexcl|Alpha|ltrie|rarrw|pound|ltrif|xcirc|bumpe|prcue|bumpE|asymp|amacr|cuvee|Sigma|sigma|iiint|udhar|iiota|ijlig|IJlig|supnE|imacr|Imacr|prime|Prime|image|prnap|eogon|Eogon|rarrc|mdash|mDDot|cuwed|imath|supne|imped|Amacr|udarr|prsim|micro|rarrb|cwint|raquo|infin|eplus|range|rangd|Ucirc|radic|minus|amalg|veeeq|rAarr|epsiv|ycirc|quest|sharp|quot|zwnj|Qscr|race|qscr|Qopf|qopf|qint|rang|Rang|Zscr|zscr|Zopf|zopf|rarr|rArr|Rarr|Pscr|pscr|prop|prod|prnE|prec|ZHcy|zhcy|prap|Zeta|zeta|Popf|popf|Zdot|plus|zdot|Yuml|yuml|phiv|YUcy|yucy|Yscr|yscr|perp|Yopf|yopf|part|para|YIcy|Ouml|rcub|yicy|YAcy|rdca|ouml|osol|Oscr|rdsh|yacy|real|oscr|xvee|andd|rect|andv|Xscr|oror|ordm|ordf|xscr|ange|aopf|Aopf|rHar|Xopf|opar|Oopf|xopf|xnis|rhov|oopf|omid|xmap|oint|apid|apos|ogon|ascr|Ascr|odot|odiv|xcup|xcap|ocir|oast|nvlt|nvle|nvgt|nvge|nvap|Wscr|wscr|auml|ntlg|ntgl|nsup|nsub|nsim|Nscr|nscr|nsce|Wopf|ring|npre|wopf|npar|Auml|Barv|bbrk|Nopf|nopf|nmid|nLtv|beta|ropf|Ropf|Beta|beth|nles|rpar|nleq|bnot|bNot|nldr|NJcy|rscr|Rscr|Vscr|vscr|rsqb|njcy|bopf|nisd|Bopf|rtri|Vopf|nGtv|ngtr|vopf|boxh|boxH|boxv|nges|ngeq|boxV|bscr|scap|Bscr|bsim|Vert|vert|bsol|bull|bump|caps|cdot|ncup|scnE|ncap|nbsp|napE|Cdot|cent|sdot|Vbar|nang|vBar|chcy|Mscr|mscr|sect|semi|CHcy|Mopf|mopf|sext|circ|cire|mldr|mlcp|cirE|comp|shcy|SHcy|vArr|varr|cong|copf|Copf|copy|COPY|malt|male|macr|lvnE|cscr|ltri|sime|ltcc|simg|Cscr|siml|csub|Uuml|lsqb|lsim|uuml|csup|Lscr|lscr|utri|smid|lpar|cups|smte|lozf|darr|Lopf|Uscr|solb|lopf|sopf|Sopf|lneq|uscr|spar|dArr|lnap|Darr|dash|Sqrt|LJcy|ljcy|lHar|dHar|Upsi|upsi|diam|lesg|djcy|DJcy|leqq|dopf|Dopf|dscr|Dscr|dscy|ldsh|ldca|squf|DScy|sscr|Sscr|dsol|lcub|late|star|Star|Uopf|Larr|lArr|larr|uopf|dtri|dzcy|sube|subE|Lang|lang|Kscr|kscr|Kopf|kopf|KJcy|kjcy|KHcy|khcy|DZcy|ecir|edot|eDot|Jscr|jscr|succ|Jopf|jopf|Edot|uHar|emsp|ensp|Iuml|iuml|eopf|isin|Iscr|iscr|Eopf|epar|sung|epsi|escr|sup1|sup2|sup3|Iota|iota|supe|supE|Iopf|iopf|IOcy|iocy|Escr|esim|Esim|imof|Uarr|QUOT|uArr|uarr|euml|IEcy|iecy|Idot|Euml|euro|excl|Hscr|hscr|Hopf|hopf|TScy|tscy|Tscr|hbar|tscr|flat|tbrk|fnof|hArr|harr|half|fopf|Fopf|tdot|gvnE|fork|trie|gtcc|fscr|Fscr|gdot|gsim|Gscr|gscr|Gopf|gopf|gneq|Gdot|tosa|gnap|Topf|topf|geqq|toea|GJcy|gjcy|tint|gesl|mid|Sfr|ggg|top|ges|gla|glE|glj|geq|gne|gEl|gel|gnE|Gcy|gcy|gap|Tfr|tfr|Tcy|tcy|Hat|Tau|Ffr|tau|Tab|hfr|Hfr|ffr|Fcy|fcy|icy|Icy|iff|ETH|eth|ifr|Ifr|Eta|eta|int|Int|Sup|sup|ucy|Ucy|Sum|sum|jcy|ENG|ufr|Ufr|eng|Jcy|jfr|els|ell|egs|Efr|efr|Jfr|uml|kcy|Kcy|Ecy|ecy|kfr|Kfr|lap|Sub|sub|lat|lcy|Lcy|leg|Dot|dot|lEg|leq|les|squ|div|die|lfr|Lfr|lgE|Dfr|dfr|Del|deg|Dcy|dcy|lne|lnE|sol|loz|smt|Cup|lrm|cup|lsh|Lsh|sim|shy|map|Map|mcy|Mcy|mfr|Mfr|mho|gfr|Gfr|sfr|cir|Chi|chi|nap|Cfr|vcy|Vcy|cfr|Scy|scy|ncy|Ncy|vee|Vee|Cap|cap|nfr|scE|sce|Nfr|nge|ngE|nGg|vfr|Vfr|ngt|bot|nGt|nis|niv|Rsh|rsh|nle|nlE|bne|Bfr|bfr|nLl|nlt|nLt|Bcy|bcy|not|Not|rlm|wfr|Wfr|npr|nsc|num|ocy|ast|Ocy|ofr|xfr|Xfr|Ofr|ogt|ohm|apE|olt|Rho|ape|rho|Rfr|rfr|ord|REG|ang|reg|orv|And|and|AMP|Rcy|amp|Afr|ycy|Ycy|yen|yfr|Yfr|rcy|par|pcy|Pcy|pfr|Pfr|phi|Phi|afr|Acy|acy|zcy|Zcy|piv|acE|acd|zfr|Zfr|pre|prE|psi|Psi|qfr|Qfr|zwj|Or|ge|Gg|gt|gg|el|oS|lt|Lt|LT|Re|lg|gl|eg|ne|Im|it|le|DD|wp|wr|nu|Nu|dd|lE|Sc|sc|pi|Pi|ee|af|ll|Ll|rx|gE|xi|pm|Xi|ic|pr|Pr|in|ni|mp|mu|ac|Mu|or|ap|Gt|GT|ii);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)(?!;)([=a-zA-Z0-9]?)|&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g; + var decodeMap = {'aacute':'\xE1','Aacute':'\xC1','abreve':'\u0103','Abreve':'\u0102','ac':'\u223E','acd':'\u223F','acE':'\u223E\u0333','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','acy':'\u0430','Acy':'\u0410','aelig':'\xE6','AElig':'\xC6','af':'\u2061','afr':'\uD835\uDD1E','Afr':'\uD835\uDD04','agrave':'\xE0','Agrave':'\xC0','alefsym':'\u2135','aleph':'\u2135','alpha':'\u03B1','Alpha':'\u0391','amacr':'\u0101','Amacr':'\u0100','amalg':'\u2A3F','amp':'&','AMP':'&','and':'\u2227','And':'\u2A53','andand':'\u2A55','andd':'\u2A5C','andslope':'\u2A58','andv':'\u2A5A','ang':'\u2220','ange':'\u29A4','angle':'\u2220','angmsd':'\u2221','angmsdaa':'\u29A8','angmsdab':'\u29A9','angmsdac':'\u29AA','angmsdad':'\u29AB','angmsdae':'\u29AC','angmsdaf':'\u29AD','angmsdag':'\u29AE','angmsdah':'\u29AF','angrt':'\u221F','angrtvb':'\u22BE','angrtvbd':'\u299D','angsph':'\u2222','angst':'\xC5','angzarr':'\u237C','aogon':'\u0105','Aogon':'\u0104','aopf':'\uD835\uDD52','Aopf':'\uD835\uDD38','ap':'\u2248','apacir':'\u2A6F','ape':'\u224A','apE':'\u2A70','apid':'\u224B','apos':'\'','ApplyFunction':'\u2061','approx':'\u2248','approxeq':'\u224A','aring':'\xE5','Aring':'\xC5','ascr':'\uD835\uDCB6','Ascr':'\uD835\uDC9C','Assign':'\u2254','ast':'*','asymp':'\u2248','asympeq':'\u224D','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','awconint':'\u2233','awint':'\u2A11','backcong':'\u224C','backepsilon':'\u03F6','backprime':'\u2035','backsim':'\u223D','backsimeq':'\u22CD','Backslash':'\u2216','Barv':'\u2AE7','barvee':'\u22BD','barwed':'\u2305','Barwed':'\u2306','barwedge':'\u2305','bbrk':'\u23B5','bbrktbrk':'\u23B6','bcong':'\u224C','bcy':'\u0431','Bcy':'\u0411','bdquo':'\u201E','becaus':'\u2235','because':'\u2235','Because':'\u2235','bemptyv':'\u29B0','bepsi':'\u03F6','bernou':'\u212C','Bernoullis':'\u212C','beta':'\u03B2','Beta':'\u0392','beth':'\u2136','between':'\u226C','bfr':'\uD835\uDD1F','Bfr':'\uD835\uDD05','bigcap':'\u22C2','bigcirc':'\u25EF','bigcup':'\u22C3','bigodot':'\u2A00','bigoplus':'\u2A01','bigotimes':'\u2A02','bigsqcup':'\u2A06','bigstar':'\u2605','bigtriangledown':'\u25BD','bigtriangleup':'\u25B3','biguplus':'\u2A04','bigvee':'\u22C1','bigwedge':'\u22C0','bkarow':'\u290D','blacklozenge':'\u29EB','blacksquare':'\u25AA','blacktriangle':'\u25B4','blacktriangledown':'\u25BE','blacktriangleleft':'\u25C2','blacktriangleright':'\u25B8','blank':'\u2423','blk12':'\u2592','blk14':'\u2591','blk34':'\u2593','block':'\u2588','bne':'=\u20E5','bnequiv':'\u2261\u20E5','bnot':'\u2310','bNot':'\u2AED','bopf':'\uD835\uDD53','Bopf':'\uD835\uDD39','bot':'\u22A5','bottom':'\u22A5','bowtie':'\u22C8','boxbox':'\u29C9','boxdl':'\u2510','boxdL':'\u2555','boxDl':'\u2556','boxDL':'\u2557','boxdr':'\u250C','boxdR':'\u2552','boxDr':'\u2553','boxDR':'\u2554','boxh':'\u2500','boxH':'\u2550','boxhd':'\u252C','boxhD':'\u2565','boxHd':'\u2564','boxHD':'\u2566','boxhu':'\u2534','boxhU':'\u2568','boxHu':'\u2567','boxHU':'\u2569','boxminus':'\u229F','boxplus':'\u229E','boxtimes':'\u22A0','boxul':'\u2518','boxuL':'\u255B','boxUl':'\u255C','boxUL':'\u255D','boxur':'\u2514','boxuR':'\u2558','boxUr':'\u2559','boxUR':'\u255A','boxv':'\u2502','boxV':'\u2551','boxvh':'\u253C','boxvH':'\u256A','boxVh':'\u256B','boxVH':'\u256C','boxvl':'\u2524','boxvL':'\u2561','boxVl':'\u2562','boxVL':'\u2563','boxvr':'\u251C','boxvR':'\u255E','boxVr':'\u255F','boxVR':'\u2560','bprime':'\u2035','breve':'\u02D8','Breve':'\u02D8','brvbar':'\xA6','bscr':'\uD835\uDCB7','Bscr':'\u212C','bsemi':'\u204F','bsim':'\u223D','bsime':'\u22CD','bsol':'\\','bsolb':'\u29C5','bsolhsub':'\u27C8','bull':'\u2022','bullet':'\u2022','bump':'\u224E','bumpe':'\u224F','bumpE':'\u2AAE','bumpeq':'\u224F','Bumpeq':'\u224E','cacute':'\u0107','Cacute':'\u0106','cap':'\u2229','Cap':'\u22D2','capand':'\u2A44','capbrcup':'\u2A49','capcap':'\u2A4B','capcup':'\u2A47','capdot':'\u2A40','CapitalDifferentialD':'\u2145','caps':'\u2229\uFE00','caret':'\u2041','caron':'\u02C7','Cayleys':'\u212D','ccaps':'\u2A4D','ccaron':'\u010D','Ccaron':'\u010C','ccedil':'\xE7','Ccedil':'\xC7','ccirc':'\u0109','Ccirc':'\u0108','Cconint':'\u2230','ccups':'\u2A4C','ccupssm':'\u2A50','cdot':'\u010B','Cdot':'\u010A','cedil':'\xB8','Cedilla':'\xB8','cemptyv':'\u29B2','cent':'\xA2','centerdot':'\xB7','CenterDot':'\xB7','cfr':'\uD835\uDD20','Cfr':'\u212D','chcy':'\u0447','CHcy':'\u0427','check':'\u2713','checkmark':'\u2713','chi':'\u03C7','Chi':'\u03A7','cir':'\u25CB','circ':'\u02C6','circeq':'\u2257','circlearrowleft':'\u21BA','circlearrowright':'\u21BB','circledast':'\u229B','circledcirc':'\u229A','circleddash':'\u229D','CircleDot':'\u2299','circledR':'\xAE','circledS':'\u24C8','CircleMinus':'\u2296','CirclePlus':'\u2295','CircleTimes':'\u2297','cire':'\u2257','cirE':'\u29C3','cirfnint':'\u2A10','cirmid':'\u2AEF','cirscir':'\u29C2','ClockwiseContourIntegral':'\u2232','CloseCurlyDoubleQuote':'\u201D','CloseCurlyQuote':'\u2019','clubs':'\u2663','clubsuit':'\u2663','colon':':','Colon':'\u2237','colone':'\u2254','Colone':'\u2A74','coloneq':'\u2254','comma':',','commat':'@','comp':'\u2201','compfn':'\u2218','complement':'\u2201','complexes':'\u2102','cong':'\u2245','congdot':'\u2A6D','Congruent':'\u2261','conint':'\u222E','Conint':'\u222F','ContourIntegral':'\u222E','copf':'\uD835\uDD54','Copf':'\u2102','coprod':'\u2210','Coproduct':'\u2210','copy':'\xA9','COPY':'\xA9','copysr':'\u2117','CounterClockwiseContourIntegral':'\u2233','crarr':'\u21B5','cross':'\u2717','Cross':'\u2A2F','cscr':'\uD835\uDCB8','Cscr':'\uD835\uDC9E','csub':'\u2ACF','csube':'\u2AD1','csup':'\u2AD0','csupe':'\u2AD2','ctdot':'\u22EF','cudarrl':'\u2938','cudarrr':'\u2935','cuepr':'\u22DE','cuesc':'\u22DF','cularr':'\u21B6','cularrp':'\u293D','cup':'\u222A','Cup':'\u22D3','cupbrcap':'\u2A48','cupcap':'\u2A46','CupCap':'\u224D','cupcup':'\u2A4A','cupdot':'\u228D','cupor':'\u2A45','cups':'\u222A\uFE00','curarr':'\u21B7','curarrm':'\u293C','curlyeqprec':'\u22DE','curlyeqsucc':'\u22DF','curlyvee':'\u22CE','curlywedge':'\u22CF','curren':'\xA4','curvearrowleft':'\u21B6','curvearrowright':'\u21B7','cuvee':'\u22CE','cuwed':'\u22CF','cwconint':'\u2232','cwint':'\u2231','cylcty':'\u232D','dagger':'\u2020','Dagger':'\u2021','daleth':'\u2138','darr':'\u2193','dArr':'\u21D3','Darr':'\u21A1','dash':'\u2010','dashv':'\u22A3','Dashv':'\u2AE4','dbkarow':'\u290F','dblac':'\u02DD','dcaron':'\u010F','Dcaron':'\u010E','dcy':'\u0434','Dcy':'\u0414','dd':'\u2146','DD':'\u2145','ddagger':'\u2021','ddarr':'\u21CA','DDotrahd':'\u2911','ddotseq':'\u2A77','deg':'\xB0','Del':'\u2207','delta':'\u03B4','Delta':'\u0394','demptyv':'\u29B1','dfisht':'\u297F','dfr':'\uD835\uDD21','Dfr':'\uD835\uDD07','dHar':'\u2965','dharl':'\u21C3','dharr':'\u21C2','DiacriticalAcute':'\xB4','DiacriticalDot':'\u02D9','DiacriticalDoubleAcute':'\u02DD','DiacriticalGrave':'`','DiacriticalTilde':'\u02DC','diam':'\u22C4','diamond':'\u22C4','Diamond':'\u22C4','diamondsuit':'\u2666','diams':'\u2666','die':'\xA8','DifferentialD':'\u2146','digamma':'\u03DD','disin':'\u22F2','div':'\xF7','divide':'\xF7','divideontimes':'\u22C7','divonx':'\u22C7','djcy':'\u0452','DJcy':'\u0402','dlcorn':'\u231E','dlcrop':'\u230D','dollar':'$','dopf':'\uD835\uDD55','Dopf':'\uD835\uDD3B','dot':'\u02D9','Dot':'\xA8','DotDot':'\u20DC','doteq':'\u2250','doteqdot':'\u2251','DotEqual':'\u2250','dotminus':'\u2238','dotplus':'\u2214','dotsquare':'\u22A1','doublebarwedge':'\u2306','DoubleContourIntegral':'\u222F','DoubleDot':'\xA8','DoubleDownArrow':'\u21D3','DoubleLeftArrow':'\u21D0','DoubleLeftRightArrow':'\u21D4','DoubleLeftTee':'\u2AE4','DoubleLongLeftArrow':'\u27F8','DoubleLongLeftRightArrow':'\u27FA','DoubleLongRightArrow':'\u27F9','DoubleRightArrow':'\u21D2','DoubleRightTee':'\u22A8','DoubleUpArrow':'\u21D1','DoubleUpDownArrow':'\u21D5','DoubleVerticalBar':'\u2225','downarrow':'\u2193','Downarrow':'\u21D3','DownArrow':'\u2193','DownArrowBar':'\u2913','DownArrowUpArrow':'\u21F5','DownBreve':'\u0311','downdownarrows':'\u21CA','downharpoonleft':'\u21C3','downharpoonright':'\u21C2','DownLeftRightVector':'\u2950','DownLeftTeeVector':'\u295E','DownLeftVector':'\u21BD','DownLeftVectorBar':'\u2956','DownRightTeeVector':'\u295F','DownRightVector':'\u21C1','DownRightVectorBar':'\u2957','DownTee':'\u22A4','DownTeeArrow':'\u21A7','drbkarow':'\u2910','drcorn':'\u231F','drcrop':'\u230C','dscr':'\uD835\uDCB9','Dscr':'\uD835\uDC9F','dscy':'\u0455','DScy':'\u0405','dsol':'\u29F6','dstrok':'\u0111','Dstrok':'\u0110','dtdot':'\u22F1','dtri':'\u25BF','dtrif':'\u25BE','duarr':'\u21F5','duhar':'\u296F','dwangle':'\u29A6','dzcy':'\u045F','DZcy':'\u040F','dzigrarr':'\u27FF','eacute':'\xE9','Eacute':'\xC9','easter':'\u2A6E','ecaron':'\u011B','Ecaron':'\u011A','ecir':'\u2256','ecirc':'\xEA','Ecirc':'\xCA','ecolon':'\u2255','ecy':'\u044D','Ecy':'\u042D','eDDot':'\u2A77','edot':'\u0117','eDot':'\u2251','Edot':'\u0116','ee':'\u2147','efDot':'\u2252','efr':'\uD835\uDD22','Efr':'\uD835\uDD08','eg':'\u2A9A','egrave':'\xE8','Egrave':'\xC8','egs':'\u2A96','egsdot':'\u2A98','el':'\u2A99','Element':'\u2208','elinters':'\u23E7','ell':'\u2113','els':'\u2A95','elsdot':'\u2A97','emacr':'\u0113','Emacr':'\u0112','empty':'\u2205','emptyset':'\u2205','EmptySmallSquare':'\u25FB','emptyv':'\u2205','EmptyVerySmallSquare':'\u25AB','emsp':'\u2003','emsp13':'\u2004','emsp14':'\u2005','eng':'\u014B','ENG':'\u014A','ensp':'\u2002','eogon':'\u0119','Eogon':'\u0118','eopf':'\uD835\uDD56','Eopf':'\uD835\uDD3C','epar':'\u22D5','eparsl':'\u29E3','eplus':'\u2A71','epsi':'\u03B5','epsilon':'\u03B5','Epsilon':'\u0395','epsiv':'\u03F5','eqcirc':'\u2256','eqcolon':'\u2255','eqsim':'\u2242','eqslantgtr':'\u2A96','eqslantless':'\u2A95','Equal':'\u2A75','equals':'=','EqualTilde':'\u2242','equest':'\u225F','Equilibrium':'\u21CC','equiv':'\u2261','equivDD':'\u2A78','eqvparsl':'\u29E5','erarr':'\u2971','erDot':'\u2253','escr':'\u212F','Escr':'\u2130','esdot':'\u2250','esim':'\u2242','Esim':'\u2A73','eta':'\u03B7','Eta':'\u0397','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','euro':'\u20AC','excl':'!','exist':'\u2203','Exists':'\u2203','expectation':'\u2130','exponentiale':'\u2147','ExponentialE':'\u2147','fallingdotseq':'\u2252','fcy':'\u0444','Fcy':'\u0424','female':'\u2640','ffilig':'\uFB03','fflig':'\uFB00','ffllig':'\uFB04','ffr':'\uD835\uDD23','Ffr':'\uD835\uDD09','filig':'\uFB01','FilledSmallSquare':'\u25FC','FilledVerySmallSquare':'\u25AA','fjlig':'fj','flat':'\u266D','fllig':'\uFB02','fltns':'\u25B1','fnof':'\u0192','fopf':'\uD835\uDD57','Fopf':'\uD835\uDD3D','forall':'\u2200','ForAll':'\u2200','fork':'\u22D4','forkv':'\u2AD9','Fouriertrf':'\u2131','fpartint':'\u2A0D','frac12':'\xBD','frac13':'\u2153','frac14':'\xBC','frac15':'\u2155','frac16':'\u2159','frac18':'\u215B','frac23':'\u2154','frac25':'\u2156','frac34':'\xBE','frac35':'\u2157','frac38':'\u215C','frac45':'\u2158','frac56':'\u215A','frac58':'\u215D','frac78':'\u215E','frasl':'\u2044','frown':'\u2322','fscr':'\uD835\uDCBB','Fscr':'\u2131','gacute':'\u01F5','gamma':'\u03B3','Gamma':'\u0393','gammad':'\u03DD','Gammad':'\u03DC','gap':'\u2A86','gbreve':'\u011F','Gbreve':'\u011E','Gcedil':'\u0122','gcirc':'\u011D','Gcirc':'\u011C','gcy':'\u0433','Gcy':'\u0413','gdot':'\u0121','Gdot':'\u0120','ge':'\u2265','gE':'\u2267','gel':'\u22DB','gEl':'\u2A8C','geq':'\u2265','geqq':'\u2267','geqslant':'\u2A7E','ges':'\u2A7E','gescc':'\u2AA9','gesdot':'\u2A80','gesdoto':'\u2A82','gesdotol':'\u2A84','gesl':'\u22DB\uFE00','gesles':'\u2A94','gfr':'\uD835\uDD24','Gfr':'\uD835\uDD0A','gg':'\u226B','Gg':'\u22D9','ggg':'\u22D9','gimel':'\u2137','gjcy':'\u0453','GJcy':'\u0403','gl':'\u2277','gla':'\u2AA5','glE':'\u2A92','glj':'\u2AA4','gnap':'\u2A8A','gnapprox':'\u2A8A','gne':'\u2A88','gnE':'\u2269','gneq':'\u2A88','gneqq':'\u2269','gnsim':'\u22E7','gopf':'\uD835\uDD58','Gopf':'\uD835\uDD3E','grave':'`','GreaterEqual':'\u2265','GreaterEqualLess':'\u22DB','GreaterFullEqual':'\u2267','GreaterGreater':'\u2AA2','GreaterLess':'\u2277','GreaterSlantEqual':'\u2A7E','GreaterTilde':'\u2273','gscr':'\u210A','Gscr':'\uD835\uDCA2','gsim':'\u2273','gsime':'\u2A8E','gsiml':'\u2A90','gt':'>','Gt':'\u226B','GT':'>','gtcc':'\u2AA7','gtcir':'\u2A7A','gtdot':'\u22D7','gtlPar':'\u2995','gtquest':'\u2A7C','gtrapprox':'\u2A86','gtrarr':'\u2978','gtrdot':'\u22D7','gtreqless':'\u22DB','gtreqqless':'\u2A8C','gtrless':'\u2277','gtrsim':'\u2273','gvertneqq':'\u2269\uFE00','gvnE':'\u2269\uFE00','Hacek':'\u02C7','hairsp':'\u200A','half':'\xBD','hamilt':'\u210B','hardcy':'\u044A','HARDcy':'\u042A','harr':'\u2194','hArr':'\u21D4','harrcir':'\u2948','harrw':'\u21AD','Hat':'^','hbar':'\u210F','hcirc':'\u0125','Hcirc':'\u0124','hearts':'\u2665','heartsuit':'\u2665','hellip':'\u2026','hercon':'\u22B9','hfr':'\uD835\uDD25','Hfr':'\u210C','HilbertSpace':'\u210B','hksearow':'\u2925','hkswarow':'\u2926','hoarr':'\u21FF','homtht':'\u223B','hookleftarrow':'\u21A9','hookrightarrow':'\u21AA','hopf':'\uD835\uDD59','Hopf':'\u210D','horbar':'\u2015','HorizontalLine':'\u2500','hscr':'\uD835\uDCBD','Hscr':'\u210B','hslash':'\u210F','hstrok':'\u0127','Hstrok':'\u0126','HumpDownHump':'\u224E','HumpEqual':'\u224F','hybull':'\u2043','hyphen':'\u2010','iacute':'\xED','Iacute':'\xCD','ic':'\u2063','icirc':'\xEE','Icirc':'\xCE','icy':'\u0438','Icy':'\u0418','Idot':'\u0130','iecy':'\u0435','IEcy':'\u0415','iexcl':'\xA1','iff':'\u21D4','ifr':'\uD835\uDD26','Ifr':'\u2111','igrave':'\xEC','Igrave':'\xCC','ii':'\u2148','iiiint':'\u2A0C','iiint':'\u222D','iinfin':'\u29DC','iiota':'\u2129','ijlig':'\u0133','IJlig':'\u0132','Im':'\u2111','imacr':'\u012B','Imacr':'\u012A','image':'\u2111','ImaginaryI':'\u2148','imagline':'\u2110','imagpart':'\u2111','imath':'\u0131','imof':'\u22B7','imped':'\u01B5','Implies':'\u21D2','in':'\u2208','incare':'\u2105','infin':'\u221E','infintie':'\u29DD','inodot':'\u0131','int':'\u222B','Int':'\u222C','intcal':'\u22BA','integers':'\u2124','Integral':'\u222B','intercal':'\u22BA','Intersection':'\u22C2','intlarhk':'\u2A17','intprod':'\u2A3C','InvisibleComma':'\u2063','InvisibleTimes':'\u2062','iocy':'\u0451','IOcy':'\u0401','iogon':'\u012F','Iogon':'\u012E','iopf':'\uD835\uDD5A','Iopf':'\uD835\uDD40','iota':'\u03B9','Iota':'\u0399','iprod':'\u2A3C','iquest':'\xBF','iscr':'\uD835\uDCBE','Iscr':'\u2110','isin':'\u2208','isindot':'\u22F5','isinE':'\u22F9','isins':'\u22F4','isinsv':'\u22F3','isinv':'\u2208','it':'\u2062','itilde':'\u0129','Itilde':'\u0128','iukcy':'\u0456','Iukcy':'\u0406','iuml':'\xEF','Iuml':'\xCF','jcirc':'\u0135','Jcirc':'\u0134','jcy':'\u0439','Jcy':'\u0419','jfr':'\uD835\uDD27','Jfr':'\uD835\uDD0D','jmath':'\u0237','jopf':'\uD835\uDD5B','Jopf':'\uD835\uDD41','jscr':'\uD835\uDCBF','Jscr':'\uD835\uDCA5','jsercy':'\u0458','Jsercy':'\u0408','jukcy':'\u0454','Jukcy':'\u0404','kappa':'\u03BA','Kappa':'\u039A','kappav':'\u03F0','kcedil':'\u0137','Kcedil':'\u0136','kcy':'\u043A','Kcy':'\u041A','kfr':'\uD835\uDD28','Kfr':'\uD835\uDD0E','kgreen':'\u0138','khcy':'\u0445','KHcy':'\u0425','kjcy':'\u045C','KJcy':'\u040C','kopf':'\uD835\uDD5C','Kopf':'\uD835\uDD42','kscr':'\uD835\uDCC0','Kscr':'\uD835\uDCA6','lAarr':'\u21DA','lacute':'\u013A','Lacute':'\u0139','laemptyv':'\u29B4','lagran':'\u2112','lambda':'\u03BB','Lambda':'\u039B','lang':'\u27E8','Lang':'\u27EA','langd':'\u2991','langle':'\u27E8','lap':'\u2A85','Laplacetrf':'\u2112','laquo':'\xAB','larr':'\u2190','lArr':'\u21D0','Larr':'\u219E','larrb':'\u21E4','larrbfs':'\u291F','larrfs':'\u291D','larrhk':'\u21A9','larrlp':'\u21AB','larrpl':'\u2939','larrsim':'\u2973','larrtl':'\u21A2','lat':'\u2AAB','latail':'\u2919','lAtail':'\u291B','late':'\u2AAD','lates':'\u2AAD\uFE00','lbarr':'\u290C','lBarr':'\u290E','lbbrk':'\u2772','lbrace':'{','lbrack':'[','lbrke':'\u298B','lbrksld':'\u298F','lbrkslu':'\u298D','lcaron':'\u013E','Lcaron':'\u013D','lcedil':'\u013C','Lcedil':'\u013B','lceil':'\u2308','lcub':'{','lcy':'\u043B','Lcy':'\u041B','ldca':'\u2936','ldquo':'\u201C','ldquor':'\u201E','ldrdhar':'\u2967','ldrushar':'\u294B','ldsh':'\u21B2','le':'\u2264','lE':'\u2266','LeftAngleBracket':'\u27E8','leftarrow':'\u2190','Leftarrow':'\u21D0','LeftArrow':'\u2190','LeftArrowBar':'\u21E4','LeftArrowRightArrow':'\u21C6','leftarrowtail':'\u21A2','LeftCeiling':'\u2308','LeftDoubleBracket':'\u27E6','LeftDownTeeVector':'\u2961','LeftDownVector':'\u21C3','LeftDownVectorBar':'\u2959','LeftFloor':'\u230A','leftharpoondown':'\u21BD','leftharpoonup':'\u21BC','leftleftarrows':'\u21C7','leftrightarrow':'\u2194','Leftrightarrow':'\u21D4','LeftRightArrow':'\u2194','leftrightarrows':'\u21C6','leftrightharpoons':'\u21CB','leftrightsquigarrow':'\u21AD','LeftRightVector':'\u294E','LeftTee':'\u22A3','LeftTeeArrow':'\u21A4','LeftTeeVector':'\u295A','leftthreetimes':'\u22CB','LeftTriangle':'\u22B2','LeftTriangleBar':'\u29CF','LeftTriangleEqual':'\u22B4','LeftUpDownVector':'\u2951','LeftUpTeeVector':'\u2960','LeftUpVector':'\u21BF','LeftUpVectorBar':'\u2958','LeftVector':'\u21BC','LeftVectorBar':'\u2952','leg':'\u22DA','lEg':'\u2A8B','leq':'\u2264','leqq':'\u2266','leqslant':'\u2A7D','les':'\u2A7D','lescc':'\u2AA8','lesdot':'\u2A7F','lesdoto':'\u2A81','lesdotor':'\u2A83','lesg':'\u22DA\uFE00','lesges':'\u2A93','lessapprox':'\u2A85','lessdot':'\u22D6','lesseqgtr':'\u22DA','lesseqqgtr':'\u2A8B','LessEqualGreater':'\u22DA','LessFullEqual':'\u2266','LessGreater':'\u2276','lessgtr':'\u2276','LessLess':'\u2AA1','lesssim':'\u2272','LessSlantEqual':'\u2A7D','LessTilde':'\u2272','lfisht':'\u297C','lfloor':'\u230A','lfr':'\uD835\uDD29','Lfr':'\uD835\uDD0F','lg':'\u2276','lgE':'\u2A91','lHar':'\u2962','lhard':'\u21BD','lharu':'\u21BC','lharul':'\u296A','lhblk':'\u2584','ljcy':'\u0459','LJcy':'\u0409','ll':'\u226A','Ll':'\u22D8','llarr':'\u21C7','llcorner':'\u231E','Lleftarrow':'\u21DA','llhard':'\u296B','lltri':'\u25FA','lmidot':'\u0140','Lmidot':'\u013F','lmoust':'\u23B0','lmoustache':'\u23B0','lnap':'\u2A89','lnapprox':'\u2A89','lne':'\u2A87','lnE':'\u2268','lneq':'\u2A87','lneqq':'\u2268','lnsim':'\u22E6','loang':'\u27EC','loarr':'\u21FD','lobrk':'\u27E6','longleftarrow':'\u27F5','Longleftarrow':'\u27F8','LongLeftArrow':'\u27F5','longleftrightarrow':'\u27F7','Longleftrightarrow':'\u27FA','LongLeftRightArrow':'\u27F7','longmapsto':'\u27FC','longrightarrow':'\u27F6','Longrightarrow':'\u27F9','LongRightArrow':'\u27F6','looparrowleft':'\u21AB','looparrowright':'\u21AC','lopar':'\u2985','lopf':'\uD835\uDD5D','Lopf':'\uD835\uDD43','loplus':'\u2A2D','lotimes':'\u2A34','lowast':'\u2217','lowbar':'_','LowerLeftArrow':'\u2199','LowerRightArrow':'\u2198','loz':'\u25CA','lozenge':'\u25CA','lozf':'\u29EB','lpar':'(','lparlt':'\u2993','lrarr':'\u21C6','lrcorner':'\u231F','lrhar':'\u21CB','lrhard':'\u296D','lrm':'\u200E','lrtri':'\u22BF','lsaquo':'\u2039','lscr':'\uD835\uDCC1','Lscr':'\u2112','lsh':'\u21B0','Lsh':'\u21B0','lsim':'\u2272','lsime':'\u2A8D','lsimg':'\u2A8F','lsqb':'[','lsquo':'\u2018','lsquor':'\u201A','lstrok':'\u0142','Lstrok':'\u0141','lt':'<','Lt':'\u226A','LT':'<','ltcc':'\u2AA6','ltcir':'\u2A79','ltdot':'\u22D6','lthree':'\u22CB','ltimes':'\u22C9','ltlarr':'\u2976','ltquest':'\u2A7B','ltri':'\u25C3','ltrie':'\u22B4','ltrif':'\u25C2','ltrPar':'\u2996','lurdshar':'\u294A','luruhar':'\u2966','lvertneqq':'\u2268\uFE00','lvnE':'\u2268\uFE00','macr':'\xAF','male':'\u2642','malt':'\u2720','maltese':'\u2720','map':'\u21A6','Map':'\u2905','mapsto':'\u21A6','mapstodown':'\u21A7','mapstoleft':'\u21A4','mapstoup':'\u21A5','marker':'\u25AE','mcomma':'\u2A29','mcy':'\u043C','Mcy':'\u041C','mdash':'\u2014','mDDot':'\u223A','measuredangle':'\u2221','MediumSpace':'\u205F','Mellintrf':'\u2133','mfr':'\uD835\uDD2A','Mfr':'\uD835\uDD10','mho':'\u2127','micro':'\xB5','mid':'\u2223','midast':'*','midcir':'\u2AF0','middot':'\xB7','minus':'\u2212','minusb':'\u229F','minusd':'\u2238','minusdu':'\u2A2A','MinusPlus':'\u2213','mlcp':'\u2ADB','mldr':'\u2026','mnplus':'\u2213','models':'\u22A7','mopf':'\uD835\uDD5E','Mopf':'\uD835\uDD44','mp':'\u2213','mscr':'\uD835\uDCC2','Mscr':'\u2133','mstpos':'\u223E','mu':'\u03BC','Mu':'\u039C','multimap':'\u22B8','mumap':'\u22B8','nabla':'\u2207','nacute':'\u0144','Nacute':'\u0143','nang':'\u2220\u20D2','nap':'\u2249','napE':'\u2A70\u0338','napid':'\u224B\u0338','napos':'\u0149','napprox':'\u2249','natur':'\u266E','natural':'\u266E','naturals':'\u2115','nbsp':'\xA0','nbump':'\u224E\u0338','nbumpe':'\u224F\u0338','ncap':'\u2A43','ncaron':'\u0148','Ncaron':'\u0147','ncedil':'\u0146','Ncedil':'\u0145','ncong':'\u2247','ncongdot':'\u2A6D\u0338','ncup':'\u2A42','ncy':'\u043D','Ncy':'\u041D','ndash':'\u2013','ne':'\u2260','nearhk':'\u2924','nearr':'\u2197','neArr':'\u21D7','nearrow':'\u2197','nedot':'\u2250\u0338','NegativeMediumSpace':'\u200B','NegativeThickSpace':'\u200B','NegativeThinSpace':'\u200B','NegativeVeryThinSpace':'\u200B','nequiv':'\u2262','nesear':'\u2928','nesim':'\u2242\u0338','NestedGreaterGreater':'\u226B','NestedLessLess':'\u226A','NewLine':'\n','nexist':'\u2204','nexists':'\u2204','nfr':'\uD835\uDD2B','Nfr':'\uD835\uDD11','nge':'\u2271','ngE':'\u2267\u0338','ngeq':'\u2271','ngeqq':'\u2267\u0338','ngeqslant':'\u2A7E\u0338','nges':'\u2A7E\u0338','nGg':'\u22D9\u0338','ngsim':'\u2275','ngt':'\u226F','nGt':'\u226B\u20D2','ngtr':'\u226F','nGtv':'\u226B\u0338','nharr':'\u21AE','nhArr':'\u21CE','nhpar':'\u2AF2','ni':'\u220B','nis':'\u22FC','nisd':'\u22FA','niv':'\u220B','njcy':'\u045A','NJcy':'\u040A','nlarr':'\u219A','nlArr':'\u21CD','nldr':'\u2025','nle':'\u2270','nlE':'\u2266\u0338','nleftarrow':'\u219A','nLeftarrow':'\u21CD','nleftrightarrow':'\u21AE','nLeftrightarrow':'\u21CE','nleq':'\u2270','nleqq':'\u2266\u0338','nleqslant':'\u2A7D\u0338','nles':'\u2A7D\u0338','nless':'\u226E','nLl':'\u22D8\u0338','nlsim':'\u2274','nlt':'\u226E','nLt':'\u226A\u20D2','nltri':'\u22EA','nltrie':'\u22EC','nLtv':'\u226A\u0338','nmid':'\u2224','NoBreak':'\u2060','NonBreakingSpace':'\xA0','nopf':'\uD835\uDD5F','Nopf':'\u2115','not':'\xAC','Not':'\u2AEC','NotCongruent':'\u2262','NotCupCap':'\u226D','NotDoubleVerticalBar':'\u2226','NotElement':'\u2209','NotEqual':'\u2260','NotEqualTilde':'\u2242\u0338','NotExists':'\u2204','NotGreater':'\u226F','NotGreaterEqual':'\u2271','NotGreaterFullEqual':'\u2267\u0338','NotGreaterGreater':'\u226B\u0338','NotGreaterLess':'\u2279','NotGreaterSlantEqual':'\u2A7E\u0338','NotGreaterTilde':'\u2275','NotHumpDownHump':'\u224E\u0338','NotHumpEqual':'\u224F\u0338','notin':'\u2209','notindot':'\u22F5\u0338','notinE':'\u22F9\u0338','notinva':'\u2209','notinvb':'\u22F7','notinvc':'\u22F6','NotLeftTriangle':'\u22EA','NotLeftTriangleBar':'\u29CF\u0338','NotLeftTriangleEqual':'\u22EC','NotLess':'\u226E','NotLessEqual':'\u2270','NotLessGreater':'\u2278','NotLessLess':'\u226A\u0338','NotLessSlantEqual':'\u2A7D\u0338','NotLessTilde':'\u2274','NotNestedGreaterGreater':'\u2AA2\u0338','NotNestedLessLess':'\u2AA1\u0338','notni':'\u220C','notniva':'\u220C','notnivb':'\u22FE','notnivc':'\u22FD','NotPrecedes':'\u2280','NotPrecedesEqual':'\u2AAF\u0338','NotPrecedesSlantEqual':'\u22E0','NotReverseElement':'\u220C','NotRightTriangle':'\u22EB','NotRightTriangleBar':'\u29D0\u0338','NotRightTriangleEqual':'\u22ED','NotSquareSubset':'\u228F\u0338','NotSquareSubsetEqual':'\u22E2','NotSquareSuperset':'\u2290\u0338','NotSquareSupersetEqual':'\u22E3','NotSubset':'\u2282\u20D2','NotSubsetEqual':'\u2288','NotSucceeds':'\u2281','NotSucceedsEqual':'\u2AB0\u0338','NotSucceedsSlantEqual':'\u22E1','NotSucceedsTilde':'\u227F\u0338','NotSuperset':'\u2283\u20D2','NotSupersetEqual':'\u2289','NotTilde':'\u2241','NotTildeEqual':'\u2244','NotTildeFullEqual':'\u2247','NotTildeTilde':'\u2249','NotVerticalBar':'\u2224','npar':'\u2226','nparallel':'\u2226','nparsl':'\u2AFD\u20E5','npart':'\u2202\u0338','npolint':'\u2A14','npr':'\u2280','nprcue':'\u22E0','npre':'\u2AAF\u0338','nprec':'\u2280','npreceq':'\u2AAF\u0338','nrarr':'\u219B','nrArr':'\u21CF','nrarrc':'\u2933\u0338','nrarrw':'\u219D\u0338','nrightarrow':'\u219B','nRightarrow':'\u21CF','nrtri':'\u22EB','nrtrie':'\u22ED','nsc':'\u2281','nsccue':'\u22E1','nsce':'\u2AB0\u0338','nscr':'\uD835\uDCC3','Nscr':'\uD835\uDCA9','nshortmid':'\u2224','nshortparallel':'\u2226','nsim':'\u2241','nsime':'\u2244','nsimeq':'\u2244','nsmid':'\u2224','nspar':'\u2226','nsqsube':'\u22E2','nsqsupe':'\u22E3','nsub':'\u2284','nsube':'\u2288','nsubE':'\u2AC5\u0338','nsubset':'\u2282\u20D2','nsubseteq':'\u2288','nsubseteqq':'\u2AC5\u0338','nsucc':'\u2281','nsucceq':'\u2AB0\u0338','nsup':'\u2285','nsupe':'\u2289','nsupE':'\u2AC6\u0338','nsupset':'\u2283\u20D2','nsupseteq':'\u2289','nsupseteqq':'\u2AC6\u0338','ntgl':'\u2279','ntilde':'\xF1','Ntilde':'\xD1','ntlg':'\u2278','ntriangleleft':'\u22EA','ntrianglelefteq':'\u22EC','ntriangleright':'\u22EB','ntrianglerighteq':'\u22ED','nu':'\u03BD','Nu':'\u039D','num':'#','numero':'\u2116','numsp':'\u2007','nvap':'\u224D\u20D2','nvdash':'\u22AC','nvDash':'\u22AD','nVdash':'\u22AE','nVDash':'\u22AF','nvge':'\u2265\u20D2','nvgt':'>\u20D2','nvHarr':'\u2904','nvinfin':'\u29DE','nvlArr':'\u2902','nvle':'\u2264\u20D2','nvlt':'<\u20D2','nvltrie':'\u22B4\u20D2','nvrArr':'\u2903','nvrtrie':'\u22B5\u20D2','nvsim':'\u223C\u20D2','nwarhk':'\u2923','nwarr':'\u2196','nwArr':'\u21D6','nwarrow':'\u2196','nwnear':'\u2927','oacute':'\xF3','Oacute':'\xD3','oast':'\u229B','ocir':'\u229A','ocirc':'\xF4','Ocirc':'\xD4','ocy':'\u043E','Ocy':'\u041E','odash':'\u229D','odblac':'\u0151','Odblac':'\u0150','odiv':'\u2A38','odot':'\u2299','odsold':'\u29BC','oelig':'\u0153','OElig':'\u0152','ofcir':'\u29BF','ofr':'\uD835\uDD2C','Ofr':'\uD835\uDD12','ogon':'\u02DB','ograve':'\xF2','Ograve':'\xD2','ogt':'\u29C1','ohbar':'\u29B5','ohm':'\u03A9','oint':'\u222E','olarr':'\u21BA','olcir':'\u29BE','olcross':'\u29BB','oline':'\u203E','olt':'\u29C0','omacr':'\u014D','Omacr':'\u014C','omega':'\u03C9','Omega':'\u03A9','omicron':'\u03BF','Omicron':'\u039F','omid':'\u29B6','ominus':'\u2296','oopf':'\uD835\uDD60','Oopf':'\uD835\uDD46','opar':'\u29B7','OpenCurlyDoubleQuote':'\u201C','OpenCurlyQuote':'\u2018','operp':'\u29B9','oplus':'\u2295','or':'\u2228','Or':'\u2A54','orarr':'\u21BB','ord':'\u2A5D','order':'\u2134','orderof':'\u2134','ordf':'\xAA','ordm':'\xBA','origof':'\u22B6','oror':'\u2A56','orslope':'\u2A57','orv':'\u2A5B','oS':'\u24C8','oscr':'\u2134','Oscr':'\uD835\uDCAA','oslash':'\xF8','Oslash':'\xD8','osol':'\u2298','otilde':'\xF5','Otilde':'\xD5','otimes':'\u2297','Otimes':'\u2A37','otimesas':'\u2A36','ouml':'\xF6','Ouml':'\xD6','ovbar':'\u233D','OverBar':'\u203E','OverBrace':'\u23DE','OverBracket':'\u23B4','OverParenthesis':'\u23DC','par':'\u2225','para':'\xB6','parallel':'\u2225','parsim':'\u2AF3','parsl':'\u2AFD','part':'\u2202','PartialD':'\u2202','pcy':'\u043F','Pcy':'\u041F','percnt':'%','period':'.','permil':'\u2030','perp':'\u22A5','pertenk':'\u2031','pfr':'\uD835\uDD2D','Pfr':'\uD835\uDD13','phi':'\u03C6','Phi':'\u03A6','phiv':'\u03D5','phmmat':'\u2133','phone':'\u260E','pi':'\u03C0','Pi':'\u03A0','pitchfork':'\u22D4','piv':'\u03D6','planck':'\u210F','planckh':'\u210E','plankv':'\u210F','plus':'+','plusacir':'\u2A23','plusb':'\u229E','pluscir':'\u2A22','plusdo':'\u2214','plusdu':'\u2A25','pluse':'\u2A72','PlusMinus':'\xB1','plusmn':'\xB1','plussim':'\u2A26','plustwo':'\u2A27','pm':'\xB1','Poincareplane':'\u210C','pointint':'\u2A15','popf':'\uD835\uDD61','Popf':'\u2119','pound':'\xA3','pr':'\u227A','Pr':'\u2ABB','prap':'\u2AB7','prcue':'\u227C','pre':'\u2AAF','prE':'\u2AB3','prec':'\u227A','precapprox':'\u2AB7','preccurlyeq':'\u227C','Precedes':'\u227A','PrecedesEqual':'\u2AAF','PrecedesSlantEqual':'\u227C','PrecedesTilde':'\u227E','preceq':'\u2AAF','precnapprox':'\u2AB9','precneqq':'\u2AB5','precnsim':'\u22E8','precsim':'\u227E','prime':'\u2032','Prime':'\u2033','primes':'\u2119','prnap':'\u2AB9','prnE':'\u2AB5','prnsim':'\u22E8','prod':'\u220F','Product':'\u220F','profalar':'\u232E','profline':'\u2312','profsurf':'\u2313','prop':'\u221D','Proportion':'\u2237','Proportional':'\u221D','propto':'\u221D','prsim':'\u227E','prurel':'\u22B0','pscr':'\uD835\uDCC5','Pscr':'\uD835\uDCAB','psi':'\u03C8','Psi':'\u03A8','puncsp':'\u2008','qfr':'\uD835\uDD2E','Qfr':'\uD835\uDD14','qint':'\u2A0C','qopf':'\uD835\uDD62','Qopf':'\u211A','qprime':'\u2057','qscr':'\uD835\uDCC6','Qscr':'\uD835\uDCAC','quaternions':'\u210D','quatint':'\u2A16','quest':'?','questeq':'\u225F','quot':'"','QUOT':'"','rAarr':'\u21DB','race':'\u223D\u0331','racute':'\u0155','Racute':'\u0154','radic':'\u221A','raemptyv':'\u29B3','rang':'\u27E9','Rang':'\u27EB','rangd':'\u2992','range':'\u29A5','rangle':'\u27E9','raquo':'\xBB','rarr':'\u2192','rArr':'\u21D2','Rarr':'\u21A0','rarrap':'\u2975','rarrb':'\u21E5','rarrbfs':'\u2920','rarrc':'\u2933','rarrfs':'\u291E','rarrhk':'\u21AA','rarrlp':'\u21AC','rarrpl':'\u2945','rarrsim':'\u2974','rarrtl':'\u21A3','Rarrtl':'\u2916','rarrw':'\u219D','ratail':'\u291A','rAtail':'\u291C','ratio':'\u2236','rationals':'\u211A','rbarr':'\u290D','rBarr':'\u290F','RBarr':'\u2910','rbbrk':'\u2773','rbrace':'}','rbrack':']','rbrke':'\u298C','rbrksld':'\u298E','rbrkslu':'\u2990','rcaron':'\u0159','Rcaron':'\u0158','rcedil':'\u0157','Rcedil':'\u0156','rceil':'\u2309','rcub':'}','rcy':'\u0440','Rcy':'\u0420','rdca':'\u2937','rdldhar':'\u2969','rdquo':'\u201D','rdquor':'\u201D','rdsh':'\u21B3','Re':'\u211C','real':'\u211C','realine':'\u211B','realpart':'\u211C','reals':'\u211D','rect':'\u25AD','reg':'\xAE','REG':'\xAE','ReverseElement':'\u220B','ReverseEquilibrium':'\u21CB','ReverseUpEquilibrium':'\u296F','rfisht':'\u297D','rfloor':'\u230B','rfr':'\uD835\uDD2F','Rfr':'\u211C','rHar':'\u2964','rhard':'\u21C1','rharu':'\u21C0','rharul':'\u296C','rho':'\u03C1','Rho':'\u03A1','rhov':'\u03F1','RightAngleBracket':'\u27E9','rightarrow':'\u2192','Rightarrow':'\u21D2','RightArrow':'\u2192','RightArrowBar':'\u21E5','RightArrowLeftArrow':'\u21C4','rightarrowtail':'\u21A3','RightCeiling':'\u2309','RightDoubleBracket':'\u27E7','RightDownTeeVector':'\u295D','RightDownVector':'\u21C2','RightDownVectorBar':'\u2955','RightFloor':'\u230B','rightharpoondown':'\u21C1','rightharpoonup':'\u21C0','rightleftarrows':'\u21C4','rightleftharpoons':'\u21CC','rightrightarrows':'\u21C9','rightsquigarrow':'\u219D','RightTee':'\u22A2','RightTeeArrow':'\u21A6','RightTeeVector':'\u295B','rightthreetimes':'\u22CC','RightTriangle':'\u22B3','RightTriangleBar':'\u29D0','RightTriangleEqual':'\u22B5','RightUpDownVector':'\u294F','RightUpTeeVector':'\u295C','RightUpVector':'\u21BE','RightUpVectorBar':'\u2954','RightVector':'\u21C0','RightVectorBar':'\u2953','ring':'\u02DA','risingdotseq':'\u2253','rlarr':'\u21C4','rlhar':'\u21CC','rlm':'\u200F','rmoust':'\u23B1','rmoustache':'\u23B1','rnmid':'\u2AEE','roang':'\u27ED','roarr':'\u21FE','robrk':'\u27E7','ropar':'\u2986','ropf':'\uD835\uDD63','Ropf':'\u211D','roplus':'\u2A2E','rotimes':'\u2A35','RoundImplies':'\u2970','rpar':')','rpargt':'\u2994','rppolint':'\u2A12','rrarr':'\u21C9','Rrightarrow':'\u21DB','rsaquo':'\u203A','rscr':'\uD835\uDCC7','Rscr':'\u211B','rsh':'\u21B1','Rsh':'\u21B1','rsqb':']','rsquo':'\u2019','rsquor':'\u2019','rthree':'\u22CC','rtimes':'\u22CA','rtri':'\u25B9','rtrie':'\u22B5','rtrif':'\u25B8','rtriltri':'\u29CE','RuleDelayed':'\u29F4','ruluhar':'\u2968','rx':'\u211E','sacute':'\u015B','Sacute':'\u015A','sbquo':'\u201A','sc':'\u227B','Sc':'\u2ABC','scap':'\u2AB8','scaron':'\u0161','Scaron':'\u0160','sccue':'\u227D','sce':'\u2AB0','scE':'\u2AB4','scedil':'\u015F','Scedil':'\u015E','scirc':'\u015D','Scirc':'\u015C','scnap':'\u2ABA','scnE':'\u2AB6','scnsim':'\u22E9','scpolint':'\u2A13','scsim':'\u227F','scy':'\u0441','Scy':'\u0421','sdot':'\u22C5','sdotb':'\u22A1','sdote':'\u2A66','searhk':'\u2925','searr':'\u2198','seArr':'\u21D8','searrow':'\u2198','sect':'\xA7','semi':';','seswar':'\u2929','setminus':'\u2216','setmn':'\u2216','sext':'\u2736','sfr':'\uD835\uDD30','Sfr':'\uD835\uDD16','sfrown':'\u2322','sharp':'\u266F','shchcy':'\u0449','SHCHcy':'\u0429','shcy':'\u0448','SHcy':'\u0428','ShortDownArrow':'\u2193','ShortLeftArrow':'\u2190','shortmid':'\u2223','shortparallel':'\u2225','ShortRightArrow':'\u2192','ShortUpArrow':'\u2191','shy':'\xAD','sigma':'\u03C3','Sigma':'\u03A3','sigmaf':'\u03C2','sigmav':'\u03C2','sim':'\u223C','simdot':'\u2A6A','sime':'\u2243','simeq':'\u2243','simg':'\u2A9E','simgE':'\u2AA0','siml':'\u2A9D','simlE':'\u2A9F','simne':'\u2246','simplus':'\u2A24','simrarr':'\u2972','slarr':'\u2190','SmallCircle':'\u2218','smallsetminus':'\u2216','smashp':'\u2A33','smeparsl':'\u29E4','smid':'\u2223','smile':'\u2323','smt':'\u2AAA','smte':'\u2AAC','smtes':'\u2AAC\uFE00','softcy':'\u044C','SOFTcy':'\u042C','sol':'/','solb':'\u29C4','solbar':'\u233F','sopf':'\uD835\uDD64','Sopf':'\uD835\uDD4A','spades':'\u2660','spadesuit':'\u2660','spar':'\u2225','sqcap':'\u2293','sqcaps':'\u2293\uFE00','sqcup':'\u2294','sqcups':'\u2294\uFE00','Sqrt':'\u221A','sqsub':'\u228F','sqsube':'\u2291','sqsubset':'\u228F','sqsubseteq':'\u2291','sqsup':'\u2290','sqsupe':'\u2292','sqsupset':'\u2290','sqsupseteq':'\u2292','squ':'\u25A1','square':'\u25A1','Square':'\u25A1','SquareIntersection':'\u2293','SquareSubset':'\u228F','SquareSubsetEqual':'\u2291','SquareSuperset':'\u2290','SquareSupersetEqual':'\u2292','SquareUnion':'\u2294','squarf':'\u25AA','squf':'\u25AA','srarr':'\u2192','sscr':'\uD835\uDCC8','Sscr':'\uD835\uDCAE','ssetmn':'\u2216','ssmile':'\u2323','sstarf':'\u22C6','star':'\u2606','Star':'\u22C6','starf':'\u2605','straightepsilon':'\u03F5','straightphi':'\u03D5','strns':'\xAF','sub':'\u2282','Sub':'\u22D0','subdot':'\u2ABD','sube':'\u2286','subE':'\u2AC5','subedot':'\u2AC3','submult':'\u2AC1','subne':'\u228A','subnE':'\u2ACB','subplus':'\u2ABF','subrarr':'\u2979','subset':'\u2282','Subset':'\u22D0','subseteq':'\u2286','subseteqq':'\u2AC5','SubsetEqual':'\u2286','subsetneq':'\u228A','subsetneqq':'\u2ACB','subsim':'\u2AC7','subsub':'\u2AD5','subsup':'\u2AD3','succ':'\u227B','succapprox':'\u2AB8','succcurlyeq':'\u227D','Succeeds':'\u227B','SucceedsEqual':'\u2AB0','SucceedsSlantEqual':'\u227D','SucceedsTilde':'\u227F','succeq':'\u2AB0','succnapprox':'\u2ABA','succneqq':'\u2AB6','succnsim':'\u22E9','succsim':'\u227F','SuchThat':'\u220B','sum':'\u2211','Sum':'\u2211','sung':'\u266A','sup':'\u2283','Sup':'\u22D1','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','supdot':'\u2ABE','supdsub':'\u2AD8','supe':'\u2287','supE':'\u2AC6','supedot':'\u2AC4','Superset':'\u2283','SupersetEqual':'\u2287','suphsol':'\u27C9','suphsub':'\u2AD7','suplarr':'\u297B','supmult':'\u2AC2','supne':'\u228B','supnE':'\u2ACC','supplus':'\u2AC0','supset':'\u2283','Supset':'\u22D1','supseteq':'\u2287','supseteqq':'\u2AC6','supsetneq':'\u228B','supsetneqq':'\u2ACC','supsim':'\u2AC8','supsub':'\u2AD4','supsup':'\u2AD6','swarhk':'\u2926','swarr':'\u2199','swArr':'\u21D9','swarrow':'\u2199','swnwar':'\u292A','szlig':'\xDF','Tab':'\t','target':'\u2316','tau':'\u03C4','Tau':'\u03A4','tbrk':'\u23B4','tcaron':'\u0165','Tcaron':'\u0164','tcedil':'\u0163','Tcedil':'\u0162','tcy':'\u0442','Tcy':'\u0422','tdot':'\u20DB','telrec':'\u2315','tfr':'\uD835\uDD31','Tfr':'\uD835\uDD17','there4':'\u2234','therefore':'\u2234','Therefore':'\u2234','theta':'\u03B8','Theta':'\u0398','thetasym':'\u03D1','thetav':'\u03D1','thickapprox':'\u2248','thicksim':'\u223C','ThickSpace':'\u205F\u200A','thinsp':'\u2009','ThinSpace':'\u2009','thkap':'\u2248','thksim':'\u223C','thorn':'\xFE','THORN':'\xDE','tilde':'\u02DC','Tilde':'\u223C','TildeEqual':'\u2243','TildeFullEqual':'\u2245','TildeTilde':'\u2248','times':'\xD7','timesb':'\u22A0','timesbar':'\u2A31','timesd':'\u2A30','tint':'\u222D','toea':'\u2928','top':'\u22A4','topbot':'\u2336','topcir':'\u2AF1','topf':'\uD835\uDD65','Topf':'\uD835\uDD4B','topfork':'\u2ADA','tosa':'\u2929','tprime':'\u2034','trade':'\u2122','TRADE':'\u2122','triangle':'\u25B5','triangledown':'\u25BF','triangleleft':'\u25C3','trianglelefteq':'\u22B4','triangleq':'\u225C','triangleright':'\u25B9','trianglerighteq':'\u22B5','tridot':'\u25EC','trie':'\u225C','triminus':'\u2A3A','TripleDot':'\u20DB','triplus':'\u2A39','trisb':'\u29CD','tritime':'\u2A3B','trpezium':'\u23E2','tscr':'\uD835\uDCC9','Tscr':'\uD835\uDCAF','tscy':'\u0446','TScy':'\u0426','tshcy':'\u045B','TSHcy':'\u040B','tstrok':'\u0167','Tstrok':'\u0166','twixt':'\u226C','twoheadleftarrow':'\u219E','twoheadrightarrow':'\u21A0','uacute':'\xFA','Uacute':'\xDA','uarr':'\u2191','uArr':'\u21D1','Uarr':'\u219F','Uarrocir':'\u2949','ubrcy':'\u045E','Ubrcy':'\u040E','ubreve':'\u016D','Ubreve':'\u016C','ucirc':'\xFB','Ucirc':'\xDB','ucy':'\u0443','Ucy':'\u0423','udarr':'\u21C5','udblac':'\u0171','Udblac':'\u0170','udhar':'\u296E','ufisht':'\u297E','ufr':'\uD835\uDD32','Ufr':'\uD835\uDD18','ugrave':'\xF9','Ugrave':'\xD9','uHar':'\u2963','uharl':'\u21BF','uharr':'\u21BE','uhblk':'\u2580','ulcorn':'\u231C','ulcorner':'\u231C','ulcrop':'\u230F','ultri':'\u25F8','umacr':'\u016B','Umacr':'\u016A','uml':'\xA8','UnderBar':'_','UnderBrace':'\u23DF','UnderBracket':'\u23B5','UnderParenthesis':'\u23DD','Union':'\u22C3','UnionPlus':'\u228E','uogon':'\u0173','Uogon':'\u0172','uopf':'\uD835\uDD66','Uopf':'\uD835\uDD4C','uparrow':'\u2191','Uparrow':'\u21D1','UpArrow':'\u2191','UpArrowBar':'\u2912','UpArrowDownArrow':'\u21C5','updownarrow':'\u2195','Updownarrow':'\u21D5','UpDownArrow':'\u2195','UpEquilibrium':'\u296E','upharpoonleft':'\u21BF','upharpoonright':'\u21BE','uplus':'\u228E','UpperLeftArrow':'\u2196','UpperRightArrow':'\u2197','upsi':'\u03C5','Upsi':'\u03D2','upsih':'\u03D2','upsilon':'\u03C5','Upsilon':'\u03A5','UpTee':'\u22A5','UpTeeArrow':'\u21A5','upuparrows':'\u21C8','urcorn':'\u231D','urcorner':'\u231D','urcrop':'\u230E','uring':'\u016F','Uring':'\u016E','urtri':'\u25F9','uscr':'\uD835\uDCCA','Uscr':'\uD835\uDCB0','utdot':'\u22F0','utilde':'\u0169','Utilde':'\u0168','utri':'\u25B5','utrif':'\u25B4','uuarr':'\u21C8','uuml':'\xFC','Uuml':'\xDC','uwangle':'\u29A7','vangrt':'\u299C','varepsilon':'\u03F5','varkappa':'\u03F0','varnothing':'\u2205','varphi':'\u03D5','varpi':'\u03D6','varpropto':'\u221D','varr':'\u2195','vArr':'\u21D5','varrho':'\u03F1','varsigma':'\u03C2','varsubsetneq':'\u228A\uFE00','varsubsetneqq':'\u2ACB\uFE00','varsupsetneq':'\u228B\uFE00','varsupsetneqq':'\u2ACC\uFE00','vartheta':'\u03D1','vartriangleleft':'\u22B2','vartriangleright':'\u22B3','vBar':'\u2AE8','Vbar':'\u2AEB','vBarv':'\u2AE9','vcy':'\u0432','Vcy':'\u0412','vdash':'\u22A2','vDash':'\u22A8','Vdash':'\u22A9','VDash':'\u22AB','Vdashl':'\u2AE6','vee':'\u2228','Vee':'\u22C1','veebar':'\u22BB','veeeq':'\u225A','vellip':'\u22EE','verbar':'|','Verbar':'\u2016','vert':'|','Vert':'\u2016','VerticalBar':'\u2223','VerticalLine':'|','VerticalSeparator':'\u2758','VerticalTilde':'\u2240','VeryThinSpace':'\u200A','vfr':'\uD835\uDD33','Vfr':'\uD835\uDD19','vltri':'\u22B2','vnsub':'\u2282\u20D2','vnsup':'\u2283\u20D2','vopf':'\uD835\uDD67','Vopf':'\uD835\uDD4D','vprop':'\u221D','vrtri':'\u22B3','vscr':'\uD835\uDCCB','Vscr':'\uD835\uDCB1','vsubne':'\u228A\uFE00','vsubnE':'\u2ACB\uFE00','vsupne':'\u228B\uFE00','vsupnE':'\u2ACC\uFE00','Vvdash':'\u22AA','vzigzag':'\u299A','wcirc':'\u0175','Wcirc':'\u0174','wedbar':'\u2A5F','wedge':'\u2227','Wedge':'\u22C0','wedgeq':'\u2259','weierp':'\u2118','wfr':'\uD835\uDD34','Wfr':'\uD835\uDD1A','wopf':'\uD835\uDD68','Wopf':'\uD835\uDD4E','wp':'\u2118','wr':'\u2240','wreath':'\u2240','wscr':'\uD835\uDCCC','Wscr':'\uD835\uDCB2','xcap':'\u22C2','xcirc':'\u25EF','xcup':'\u22C3','xdtri':'\u25BD','xfr':'\uD835\uDD35','Xfr':'\uD835\uDD1B','xharr':'\u27F7','xhArr':'\u27FA','xi':'\u03BE','Xi':'\u039E','xlarr':'\u27F5','xlArr':'\u27F8','xmap':'\u27FC','xnis':'\u22FB','xodot':'\u2A00','xopf':'\uD835\uDD69','Xopf':'\uD835\uDD4F','xoplus':'\u2A01','xotime':'\u2A02','xrarr':'\u27F6','xrArr':'\u27F9','xscr':'\uD835\uDCCD','Xscr':'\uD835\uDCB3','xsqcup':'\u2A06','xuplus':'\u2A04','xutri':'\u25B3','xvee':'\u22C1','xwedge':'\u22C0','yacute':'\xFD','Yacute':'\xDD','yacy':'\u044F','YAcy':'\u042F','ycirc':'\u0177','Ycirc':'\u0176','ycy':'\u044B','Ycy':'\u042B','yen':'\xA5','yfr':'\uD835\uDD36','Yfr':'\uD835\uDD1C','yicy':'\u0457','YIcy':'\u0407','yopf':'\uD835\uDD6A','Yopf':'\uD835\uDD50','yscr':'\uD835\uDCCE','Yscr':'\uD835\uDCB4','yucy':'\u044E','YUcy':'\u042E','yuml':'\xFF','Yuml':'\u0178','zacute':'\u017A','Zacute':'\u0179','zcaron':'\u017E','Zcaron':'\u017D','zcy':'\u0437','Zcy':'\u0417','zdot':'\u017C','Zdot':'\u017B','zeetrf':'\u2128','ZeroWidthSpace':'\u200B','zeta':'\u03B6','Zeta':'\u0396','zfr':'\uD835\uDD37','Zfr':'\u2128','zhcy':'\u0436','ZHcy':'\u0416','zigrarr':'\u21DD','zopf':'\uD835\uDD6B','Zopf':'\u2124','zscr':'\uD835\uDCCF','Zscr':'\uD835\uDCB5','zwj':'\u200D','zwnj':'\u200C'}; + var decodeMapLegacy = {'aacute':'\xE1','Aacute':'\xC1','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','aelig':'\xE6','AElig':'\xC6','agrave':'\xE0','Agrave':'\xC0','amp':'&','AMP':'&','aring':'\xE5','Aring':'\xC5','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','brvbar':'\xA6','ccedil':'\xE7','Ccedil':'\xC7','cedil':'\xB8','cent':'\xA2','copy':'\xA9','COPY':'\xA9','curren':'\xA4','deg':'\xB0','divide':'\xF7','eacute':'\xE9','Eacute':'\xC9','ecirc':'\xEA','Ecirc':'\xCA','egrave':'\xE8','Egrave':'\xC8','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','frac12':'\xBD','frac14':'\xBC','frac34':'\xBE','gt':'>','GT':'>','iacute':'\xED','Iacute':'\xCD','icirc':'\xEE','Icirc':'\xCE','iexcl':'\xA1','igrave':'\xEC','Igrave':'\xCC','iquest':'\xBF','iuml':'\xEF','Iuml':'\xCF','laquo':'\xAB','lt':'<','LT':'<','macr':'\xAF','micro':'\xB5','middot':'\xB7','nbsp':'\xA0','not':'\xAC','ntilde':'\xF1','Ntilde':'\xD1','oacute':'\xF3','Oacute':'\xD3','ocirc':'\xF4','Ocirc':'\xD4','ograve':'\xF2','Ograve':'\xD2','ordf':'\xAA','ordm':'\xBA','oslash':'\xF8','Oslash':'\xD8','otilde':'\xF5','Otilde':'\xD5','ouml':'\xF6','Ouml':'\xD6','para':'\xB6','plusmn':'\xB1','pound':'\xA3','quot':'"','QUOT':'"','raquo':'\xBB','reg':'\xAE','REG':'\xAE','sect':'\xA7','shy':'\xAD','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','szlig':'\xDF','thorn':'\xFE','THORN':'\xDE','times':'\xD7','uacute':'\xFA','Uacute':'\xDA','ucirc':'\xFB','Ucirc':'\xDB','ugrave':'\xF9','Ugrave':'\xD9','uml':'\xA8','uuml':'\xFC','Uuml':'\xDC','yacute':'\xFD','Yacute':'\xDD','yen':'\xA5','yuml':'\xFF'}; + var decodeMapNumeric = {'0':'\uFFFD','128':'\u20AC','130':'\u201A','131':'\u0192','132':'\u201E','133':'\u2026','134':'\u2020','135':'\u2021','136':'\u02C6','137':'\u2030','138':'\u0160','139':'\u2039','140':'\u0152','142':'\u017D','145':'\u2018','146':'\u2019','147':'\u201C','148':'\u201D','149':'\u2022','150':'\u2013','151':'\u2014','152':'\u02DC','153':'\u2122','154':'\u0161','155':'\u203A','156':'\u0153','158':'\u017E','159':'\u0178'}; + var invalidReferenceCodePoints = [1,2,3,4,5,6,7,8,11,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,64976,64977,64978,64979,64980,64981,64982,64983,64984,64985,64986,64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64998,64999,65000,65001,65002,65003,65004,65005,65006,65007,65534,65535,131070,131071,196606,196607,262142,262143,327678,327679,393214,393215,458750,458751,524286,524287,589822,589823,655358,655359,720894,720895,786430,786431,851966,851967,917502,917503,983038,983039,1048574,1048575,1114110,1114111]; + + /*--------------------------------------------------------------------------*/ + + var stringFromCharCode = String.fromCharCode; + + var object = {}; + var hasOwnProperty = object.hasOwnProperty; + var has = function(object, propertyName) { + return hasOwnProperty.call(object, propertyName); + }; + + var contains = function(array, value) { + var index = -1; + var length = array.length; + while (++index < length) { + if (array[index] == value) { + return true; + } + } + return false; + }; + + var merge = function(options, defaults) { + if (!options) { + return defaults; + } + var result = {}; + var key; + for (key in defaults) { + // A `hasOwnProperty` check is not needed here, since only recognized + // option names are used anyway. Any others are ignored. + result[key] = has(options, key) ? options[key] : defaults[key]; + } + return result; + }; + + // Modified version of `ucs2encode`; see https://mths.be/punycode. + var codePointToSymbol = function(codePoint, strict) { + var output = ''; + if ((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF) { + // See issue #4: + // “Otherwise, if the number is in the range 0xD800 to 0xDFFF or is + // greater than 0x10FFFF, then this is a parse error. Return a U+FFFD + // REPLACEMENT CHARACTER.” + if (strict) { + parseError('character reference outside the permissible Unicode range'); + } + return '\uFFFD'; + } + if (has(decodeMapNumeric, codePoint)) { + if (strict) { + parseError('disallowed character reference'); + } + return decodeMapNumeric[codePoint]; + } + if (strict && contains(invalidReferenceCodePoints, codePoint)) { + parseError('disallowed character reference'); + } + if (codePoint > 0xFFFF) { + codePoint -= 0x10000; + output += stringFromCharCode(codePoint >>> 10 & 0x3FF | 0xD800); + codePoint = 0xDC00 | codePoint & 0x3FF; + } + output += stringFromCharCode(codePoint); + return output; + }; + + var hexEscape = function(codePoint) { + return '&#x' + codePoint.toString(16).toUpperCase() + ';'; + }; + + var decEscape = function(codePoint) { + return '&#' + codePoint + ';'; + }; + + var parseError = function(message) { + throw Error('Parse error: ' + message); + }; + + /*--------------------------------------------------------------------------*/ + + var encode = function(string, options) { + options = merge(options, encode.options); + var strict = options.strict; + if (strict && regexInvalidRawCodePoint.test(string)) { + parseError('forbidden code point'); + } + var encodeEverything = options.encodeEverything; + var useNamedReferences = options.useNamedReferences; + var allowUnsafeSymbols = options.allowUnsafeSymbols; + var escapeCodePoint = options.decimal ? decEscape : hexEscape; + + var escapeBmpSymbol = function(symbol) { + return escapeCodePoint(symbol.charCodeAt(0)); + }; + + if (encodeEverything) { + // Encode ASCII symbols. + string = string.replace(regexAsciiWhitelist, function(symbol) { + // Use named references if requested & possible. + if (useNamedReferences && has(encodeMap, symbol)) { + return '&' + encodeMap[symbol] + ';'; + } + return escapeBmpSymbol(symbol); + }); + // Shorten a few escapes that represent two symbols, of which at least one + // is within the ASCII range. + if (useNamedReferences) { + string = string + .replace(/>\u20D2/g, '>⃒') + .replace(/<\u20D2/g, '<⃒') + .replace(/fj/g, 'fj'); + } + // Encode non-ASCII symbols. + if (useNamedReferences) { + // Encode non-ASCII symbols that can be replaced with a named reference. + string = string.replace(regexEncodeNonAscii, function(string) { + // Note: there is no need to check `has(encodeMap, string)` here. + return '&' + encodeMap[string] + ';'; + }); + } + // Note: any remaining non-ASCII symbols are handled outside of the `if`. + } else if (useNamedReferences) { + // Apply named character references. + // Encode `<>"'&` using named character references. + if (!allowUnsafeSymbols) { + string = string.replace(regexEscape, function(string) { + return '&' + encodeMap[string] + ';'; // no need to check `has()` here + }); + } + // Shorten escapes that represent two symbols, of which at least one is + // `<>"'&`. + string = string + .replace(/>\u20D2/g, '>⃒') + .replace(/<\u20D2/g, '<⃒'); + // Encode non-ASCII symbols that can be replaced with a named reference. + string = string.replace(regexEncodeNonAscii, function(string) { + // Note: there is no need to check `has(encodeMap, string)` here. + return '&' + encodeMap[string] + ';'; + }); + } else if (!allowUnsafeSymbols) { + // Encode `<>"'&` using hexadecimal escapes, now that they’re not handled + // using named character references. + string = string.replace(regexEscape, escapeBmpSymbol); + } + return string + // Encode astral symbols. + .replace(regexAstralSymbols, function($0) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + var high = $0.charCodeAt(0); + var low = $0.charCodeAt(1); + var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000; + return escapeCodePoint(codePoint); + }) + // Encode any remaining BMP symbols that are not printable ASCII symbols + // using a hexadecimal escape. + .replace(regexBmpWhitelist, escapeBmpSymbol); + }; + // Expose default options (so they can be overridden globally). + encode.options = { + 'allowUnsafeSymbols': false, + 'encodeEverything': false, + 'strict': false, + 'useNamedReferences': false, + 'decimal' : false + }; + + var decode = function(html, options) { + options = merge(options, decode.options); + var strict = options.strict; + if (strict && regexInvalidEntity.test(html)) { + parseError('malformed character reference'); + } + return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7, $8) { + var codePoint; + var semicolon; + var decDigits; + var hexDigits; + var reference; + var next; + + if ($1) { + reference = $1; + // Note: there is no need to check `has(decodeMap, reference)`. + return decodeMap[reference]; + } + + if ($2) { + // Decode named character references without trailing `;`, e.g. `&`. + // This is only a parse error if it gets converted to `&`, or if it is + // followed by `=` in an attribute context. + reference = $2; + next = $3; + if (next && options.isAttributeValue) { + if (strict && next == '=') { + parseError('`&` did not start a character reference'); + } + return $0; + } else { + if (strict) { + parseError( + 'named character reference was not terminated by a semicolon' + ); + } + // Note: there is no need to check `has(decodeMapLegacy, reference)`. + return decodeMapLegacy[reference] + (next || ''); + } + } + + if ($4) { + // Decode decimal escapes, e.g. `𝌆`. + decDigits = $4; + semicolon = $5; + if (strict && !semicolon) { + parseError('character reference was not terminated by a semicolon'); + } + codePoint = parseInt(decDigits, 10); + return codePointToSymbol(codePoint, strict); + } + + if ($6) { + // Decode hexadecimal escapes, e.g. `𝌆`. + hexDigits = $6; + semicolon = $7; + if (strict && !semicolon) { + parseError('character reference was not terminated by a semicolon'); + } + codePoint = parseInt(hexDigits, 16); + return codePointToSymbol(codePoint, strict); + } + + // If we’re still here, `if ($7)` is implied; it’s an ambiguous + // ampersand for sure. https://mths.be/notes/ambiguous-ampersands + if (strict) { + parseError( + 'named character reference was not terminated by a semicolon' + ); + } + return $0; + }); + }; + // Expose default options (so they can be overridden globally). + decode.options = { + 'isAttributeValue': false, + 'strict': false + }; + + var escape = function(string) { + return string.replace(regexEscape, function($0) { + // Note: there is no need to check `has(escapeMap, $0)` here. + return escapeMap[$0]; + }); + }; + + /*--------------------------------------------------------------------------*/ + + var he = { + 'version': '1.2.0', + 'encode': encode, + 'decode': decode, + 'escape': escape, + 'unescape': decode + }; + + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + false + ) { + define(function() { + return he; + }); + } else if (freeExports && !freeExports.nodeType) { + if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+ + freeModule.exports = he; + } else { // in Narwhal or RingoJS v0.7.0- + for (var key in he) { + has(he, key) && (freeExports[key] = he[key]); + } + } + } else { // in Rhino or a web browser + root.he = he; + } + +}(this)); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],55:[function(require,module,exports){ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } -/** - * A fallback implementation of `Object.keys` which creates an array of the - * own enumerable property names of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ -function shimKeys(object) { - var props = keysIn(object), - propsLength = props.length, - length = propsLength && object.length; +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } - var allowIndexes = !!length && isLength(length) && - (isArray(object) || isArguments(object)); + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - var index = -1, - result = []; + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - while (++index < propsLength) { - var key = props[index]; - if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; + buffer[offset + i - d] |= s * 128 } -/** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); +},{}],56:[function(require,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 + } } -/** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) - * for more details. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) +},{}],57:[function(require,module,exports){ +/*! + * Determine if an object is a Buffer * - * _.keys('hi'); - * // => ['0', '1'] + * @author Feross Aboukhadijeh + * @license MIT */ -var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; - if ((typeof Ctor == 'function' && Ctor.prototype === object) || - (typeof object != 'function' && isArrayLike(object))) { - return shimKeys(object); - } - return isObject(object) ? nativeKeys(object) : []; -}; -/** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ -function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); - } - var length = object.length; - length = (length && isLength(length) && - (isArray(object) || isArguments(object)) && length) || 0; +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually +module.exports = function (obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) +} - var Ctor = object.constructor, - index = -1, - isProto = typeof Ctor == 'function' && Ctor.prototype === object, - result = Array(length), - skipIndexes = length > 0; +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} - while (++index < length) { - result[index] = (index + ''); - } - for (var key in object) { - if (!(skipIndexes && isIndex(key, length)) && - !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) } -module.exports = keys; +},{}],58:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; -},{"lodash._getnative":58,"lodash.isarguments":61,"lodash.isarray":62}],64:[function(require,module,exports){ +},{}],59:[function(require,module,exports){ (function (process){ var path = require('path'); var fs = require('fs'); @@ -12229,18 +13753,18 @@ function mkdirP (p, opts, f, made) { else if (!opts || typeof opts !== 'object') { opts = { mode: opts }; } - + var mode = opts.mode; var xfs = opts.fs || fs; - + if (mode === undefined) { mode = _0777 & (~process.umask()); } if (!made) made = null; - + var cb = f || function () {}; p = path.resolve(p); - + xfs.mkdir(p, mode, function (er) { if (!er) { made = made || p; @@ -12273,10 +13797,10 @@ mkdirP.sync = function sync (p, opts, made) { if (!opts || typeof opts !== 'object') { opts = { mode: opts }; } - + var mode = opts.mode; var xfs = opts.fs || fs; - + if (mode === undefined) { mode = _0777 & (~process.umask()); } @@ -12315,63 +13839,486 @@ mkdirP.sync = function sync (p, opts, made) { }; }).call(this,require('_process')) -},{"_process":67,"fs":42,"path":42}],65:[function(require,module,exports){ -exports.endianness = function () { return 'LE' }; +},{"_process":69,"fs":42,"path":42}],60:[function(require,module,exports){ +/** + * Helpers. + */ -exports.hostname = function () { - if (typeof location !== 'undefined') { - return location.hostname - } - else return ''; +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var w = d * 7; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\-?\d?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'weeks': + case 'week': + case 'w': + return n * w; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return Math.round(ms / d) + 'd'; + } + if (msAbs >= h) { + return Math.round(ms / h) + 'h'; + } + if (msAbs >= m) { + return Math.round(ms / m) + 'm'; + } + if (msAbs >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return plural(ms, msAbs, d, 'day'); + } + if (msAbs >= h) { + return plural(ms, msAbs, h, 'hour'); + } + if (msAbs >= m) { + return plural(ms, msAbs, m, 'minute'); + } + if (msAbs >= s) { + return plural(ms, msAbs, s, 'second'); + } + return ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, msAbs, n, name) { + var isPlural = msAbs >= n * 1.5; + return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); +} + +},{}],61:[function(require,module,exports){ +'use strict'; + +var keysShim; +if (!Object.keys) { + // modified from https://github.com/es-shims/es5-shim + var has = Object.prototype.hasOwnProperty; + var toStr = Object.prototype.toString; + var isArgs = require('./isArguments'); // eslint-disable-line global-require + var isEnumerable = Object.prototype.propertyIsEnumerable; + var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); + var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); + var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ]; + var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; + }; + var excludedKeys = { + $applicationCache: true, + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true + }; + var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; + }()); + var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } + }; + + keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; + }; +} +module.exports = keysShim; + +},{"./isArguments":63}],62:[function(require,module,exports){ +'use strict'; + +var slice = Array.prototype.slice; +var isArgs = require('./isArguments'); + +var origKeys = Object.keys; +var keysShim = origKeys ? function keys(o) { return origKeys(o); } : require('./implementation'); + +var originalKeys = Object.keys; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + var args = Object.keys(arguments); + return args && args.length === arguments.length; + }(1, 2)); + if (!keysWorksWithArguments) { + Object.keys = function keys(object) { // eslint-disable-line func-name-matching + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } + return originalKeys(object); + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; }; -exports.loadavg = function () { return [] }; +module.exports = keysShim; -exports.uptime = function () { return 0 }; +},{"./implementation":61,"./isArguments":63}],63:[function(require,module,exports){ +'use strict'; -exports.freemem = function () { - return Number.MAX_VALUE; +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; }; -exports.totalmem = function () { - return Number.MAX_VALUE; +},{}],64:[function(require,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es6-shim +var keys = require('object-keys'); +var bind = require('function-bind'); +var canBeObject = function (obj) { + return typeof obj !== 'undefined' && obj !== null; +}; +var hasSymbols = require('has-symbols/shams')(); +var toObject = Object; +var push = bind.call(Function.call, Array.prototype.push); +var propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable); +var originalGetSymbols = hasSymbols ? Object.getOwnPropertySymbols : null; + +module.exports = function assign(target, source1) { + if (!canBeObject(target)) { throw new TypeError('target must be an object'); } + var objTarget = toObject(target); + var s, source, i, props, syms, value, key; + for (s = 1; s < arguments.length; ++s) { + source = toObject(arguments[s]); + props = keys(source); + var getSymbols = hasSymbols && (Object.getOwnPropertySymbols || originalGetSymbols); + if (getSymbols) { + syms = getSymbols(source); + for (i = 0; i < syms.length; ++i) { + key = syms[i]; + if (propIsEnumerable(source, key)) { + push(props, key); + } + } + } + for (i = 0; i < props.length; ++i) { + key = props[i]; + value = source[key]; + if (propIsEnumerable(source, key)) { + objTarget[key] = value; + } + } + } + return objTarget; }; -exports.cpus = function () { return [] }; +},{"function-bind":52,"has-symbols/shams":53,"object-keys":62}],65:[function(require,module,exports){ +'use strict'; -exports.type = function () { return 'Browser' }; +var defineProperties = require('define-properties'); -exports.release = function () { - if (typeof navigator !== 'undefined') { - return navigator.appVersion; - } - return ''; -}; +var implementation = require('./implementation'); +var getPolyfill = require('./polyfill'); +var shim = require('./shim'); + +var polyfill = getPolyfill(); + +defineProperties(polyfill, { + getPolyfill: getPolyfill, + implementation: implementation, + shim: shim +}); + +module.exports = polyfill; + +},{"./implementation":64,"./polyfill":66,"./shim":67,"define-properties":47}],66:[function(require,module,exports){ +'use strict'; -exports.networkInterfaces -= exports.getNetworkInterfaces -= function () { return {} }; +var implementation = require('./implementation'); -exports.arch = function () { return 'javascript' }; +var lacksProperEnumerationOrder = function () { + if (!Object.assign) { + return false; + } + // v8, specifically in node 4.x, has a bug with incorrect property enumeration order + // note: this does not detect the bug unless there's 20 characters + var str = 'abcdefghijklmnopqrst'; + var letters = str.split(''); + var map = {}; + for (var i = 0; i < letters.length; ++i) { + map[letters[i]] = letters[i]; + } + var obj = Object.assign({}, map); + var actual = ''; + for (var k in obj) { + actual += k; + } + return str !== actual; +}; -exports.platform = function () { return 'browser' }; +var assignHasPendingExceptions = function () { + if (!Object.assign || !Object.preventExtensions) { + return false; + } + // Firefox 37 still has "pending exception" logic in its Object.assign implementation, + // which is 72% slower than our shim, and Firefox 40's native implementation. + var thrower = Object.preventExtensions({ 1: 2 }); + try { + Object.assign(thrower, 'xy'); + } catch (e) { + return thrower[1] === 'y'; + } + return false; +}; -exports.tmpdir = exports.tmpDir = function () { - return '/tmp'; +module.exports = function getPolyfill() { + if (!Object.assign) { + return implementation; + } + if (lacksProperEnumerationOrder()) { + return implementation; + } + if (assignHasPendingExceptions()) { + return implementation; + } + return Object.assign; }; -exports.EOL = '\n'; +},{"./implementation":64}],67:[function(require,module,exports){ +'use strict'; + +var define = require('define-properties'); +var getPolyfill = require('./polyfill'); + +module.exports = function shimAssign() { + var polyfill = getPolyfill(); + define( + Object, + { assign: polyfill }, + { assign: function () { return Object.assign !== polyfill; } } + ); + return polyfill; +}; -},{}],66:[function(require,module,exports){ +},{"./polyfill":66,"define-properties":47}],68:[function(require,module,exports){ (function (process){ 'use strict'; if (!process.version || process.version.indexOf('v0.') === 0 || process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { - module.exports = nextTick; + module.exports = { nextTick: nextTick }; } else { - module.exports = process.nextTick; + module.exports = process } function nextTick(fn, arg1, arg2, arg3) { @@ -12408,8 +14355,9 @@ function nextTick(fn, arg1, arg2, arg3) { } } + }).call(this,require('_process')) -},{"_process":67}],67:[function(require,module,exports){ +},{"_process":69}],69:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -12580,6 +14528,10 @@ process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); @@ -12591,10 +14543,31 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],68:[function(require,module,exports){ -module.exports = require("./lib/_stream_duplex.js") +},{}],70:[function(require,module,exports){ +module.exports = require('./lib/_stream_duplex.js'); + +},{"./lib/_stream_duplex.js":71}],71:[function(require,module,exports){ +// 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. -},{"./lib/_stream_duplex.js":69}],69:[function(require,module,exports){ // a duplex stream is just a stream that is both readable and writable. // Since JS doesn't have multiple prototypal inheritance, this class // prototypally inherits from Readable, and then parasitically from @@ -12604,6 +14577,10 @@ module.exports = require("./lib/_stream_duplex.js") /**/ +var pna = require('process-nextick-args'); +/**/ + +/**/ var objectKeys = Object.keys || function (obj) { var keys = []; for (var key in obj) { @@ -12614,10 +14591,6 @@ var objectKeys = Object.keys || function (obj) { module.exports = Duplex; -/**/ -var processNextTick = require('process-nextick-args'); -/**/ - /**/ var util = require('core-util-is'); util.inherits = require('inherits'); @@ -12628,10 +14601,13 @@ var Writable = require('./_stream_writable'); util.inherits(Duplex, Readable); -var keys = objectKeys(Writable.prototype); -for (var v = 0; v < keys.length; v++) { - var method = keys[v]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; +{ + // avoid scope creep, the keys array can then be collected + var keys = objectKeys(Writable.prototype); + for (var v = 0; v < keys.length; v++) { + var method = keys[v]; + if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; + } } function Duplex(options) { @@ -12650,6 +14626,16 @@ function Duplex(options) { this.once('end', onend); } +Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState.highWaterMark; + } +}); + // the no-half-open enforcer function onend() { // if we allow half-open state, or if the writable side ended, @@ -12658,19 +14644,62 @@ function onend() { // no more data can be written. // But allow more writes to happen in this tick. - processNextTick(onEndNT, this); + pna.nextTick(onEndNT, this); } function onEndNT(self) { self.end(); } -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); +Object.defineProperty(Duplex.prototype, 'destroyed', { + get: function () { + if (this._readableState === undefined || this._writableState === undefined) { + return false; + } + return this._readableState.destroyed && this._writableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (this._readableState === undefined || this._writableState === undefined) { + return; + } + + // backward compatibility, the user is explicitly + // managing destroyed + this._readableState.destroyed = value; + this._writableState.destroyed = value; } -} -},{"./_stream_readable":71,"./_stream_writable":73,"core-util-is":45,"inherits":51,"process-nextick-args":66}],70:[function(require,module,exports){ +}); + +Duplex.prototype._destroy = function (err, cb) { + this.push(null); + this.end(); + + pna.nextTick(cb, err); +}; +},{"./_stream_readable":73,"./_stream_writable":75,"core-util-is":44,"inherits":56,"process-nextick-args":68}],72:[function(require,module,exports){ +// 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. + // a passthrough stream. // basically just the most minimal sort of Transform stream. // Every written chunk gets output as-is. @@ -12697,18 +14726,44 @@ function PassThrough(options) { PassThrough.prototype._transform = function (chunk, encoding, cb) { cb(null, chunk); }; -},{"./_stream_transform":72,"core-util-is":45,"inherits":51}],71:[function(require,module,exports){ -(function (process){ +},{"./_stream_transform":74,"core-util-is":44,"inherits":56}],73:[function(require,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. + 'use strict'; +/**/ + +var pna = require('process-nextick-args'); +/**/ + module.exports = Readable; /**/ -var processNextTick = require('process-nextick-args'); +var isArray = require('isarray'); /**/ /**/ -var isArray = require('isarray'); +var Duplex; /**/ Readable.ReadableState = ReadableState; @@ -12722,19 +14777,20 @@ var EElistenerCount = function (emitter, type) { /**/ /**/ -var Stream; -(function () { - try { - Stream = require('st' + 'ream'); - } catch (_) {} finally { - if (!Stream) Stream = require('events').EventEmitter; - } -})(); +var Stream = require('./internal/streams/stream'); /**/ -var Buffer = require('buffer').Buffer; /**/ -var bufferShim = require('buffer-shims'); + +var Buffer = require('safe-buffer').Buffer; +var OurUint8Array = global.Uint8Array || function () {}; +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + /**/ /**/ @@ -12753,42 +14809,53 @@ if (debugUtil && debugUtil.debuglog) { /**/ var BufferList = require('./internal/streams/BufferList'); +var destroyImpl = require('./internal/streams/destroy'); var StringDecoder; util.inherits(Readable, Stream); +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + function prependListener(emitter, event, fn) { - if (typeof emitter.prependListener === 'function') { - return emitter.prependListener(event, fn); - } else { - // This is a hack to make sure that our error handler is attached before any - // userland ones. NEVER DO THIS. This is here only because this code needs - // to continue to work with older versions of Node.js that do not include - // the prependListener() method. The goal is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; - } + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. + if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); + + // This is a hack to make sure that our error handler is attached before any + // userland ones. NEVER DO THIS. This is here only because this code needs + // to continue to work with older versions of Node.js that do not include + // the prependListener() method. The goal is to eventually remove this hack. + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; } -var Duplex; function ReadableState(options, stream) { Duplex = Duplex || require('./_stream_duplex'); options = options || {}; + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + var isDuplex = stream instanceof Duplex; + // object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away this.objectMode = !!options.objectMode; - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer // Note: 0 is a valid value, means "don't call _read preemptively ever" var hwm = options.highWaterMark; + var readableHwm = options.readableHighWaterMark; var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; + + if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm; // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; + this.highWaterMark = Math.floor(this.highWaterMark); // A linked list is used to store data chunks instead of an array because the // linked list can remove elements from the beginning faster than @@ -12802,10 +14869,10 @@ function ReadableState(options, stream) { this.endEmitted = false; this.reading = false; - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. + // a flag to be able to tell if the event 'readable'/'data' is emitted + // immediately, or on a later tick. We set this to true at first, because + // any actions that shouldn't happen until "later" should generally also + // not happen before the first read call. this.sync = true; // whenever we return null, then we set a flag to say @@ -12815,15 +14882,14 @@ function ReadableState(options, stream) { this.readableListening = false; this.resumeScheduled = false; + // has it been destroyed + this.destroyed = false; + // Crypto is kind of old and crusty. Historically, its default string // encoding is 'binary' so we have to make this configurable. // Everything else in the universe uses 'utf8', though. this.defaultEncoding = options.defaultEncoding || 'utf8'; - // when piping, we only care about 'readable' events that happen - // after read()ing all the bytes and not getting any pushback. - this.ranOut = false; - // the number of writers that are awaiting a drain event in .pipe()s this.awaitDrain = 0; @@ -12839,7 +14905,6 @@ function ReadableState(options, stream) { } } -var Duplex; function Readable(options) { Duplex = Duplex || require('./_stream_duplex'); @@ -12850,87 +14915,129 @@ function Readable(options) { // legacy this.readable = true; - if (options && typeof options.read === 'function') this._read = options.read; + if (options) { + if (typeof options.read === 'function') this._read = options.read; + + if (typeof options.destroy === 'function') this._destroy = options.destroy; + } Stream.call(this); } +Object.defineProperty(Readable.prototype, 'destroyed', { + get: function () { + if (this._readableState === undefined) { + return false; + } + return this._readableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._readableState) { + return; + } + + // backward compatibility, the user is explicitly + // managing destroyed + this._readableState.destroyed = value; + } +}); + +Readable.prototype.destroy = destroyImpl.destroy; +Readable.prototype._undestroy = destroyImpl.undestroy; +Readable.prototype._destroy = function (err, cb) { + this.push(null); + cb(err); +}; + // Manually shove something into the read() buffer. // This returns true if the highWaterMark has not been hit yet, // similar to how Writable.write() returns true if you should // write() some more. Readable.prototype.push = function (chunk, encoding) { var state = this._readableState; - - if (!state.objectMode && typeof chunk === 'string') { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = bufferShim.from(chunk, encoding); - encoding = ''; + var skipChunkCheck; + + if (!state.objectMode) { + if (typeof chunk === 'string') { + encoding = encoding || state.defaultEncoding; + if (encoding !== state.encoding) { + chunk = Buffer.from(chunk, encoding); + encoding = ''; + } + skipChunkCheck = true; } + } else { + skipChunkCheck = true; } - return readableAddChunk(this, state, chunk, encoding, false); + return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); }; // Unshift should *always* be something directly out of read() Readable.prototype.unshift = function (chunk) { - var state = this._readableState; - return readableAddChunk(this, state, chunk, '', true); -}; - -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; + return readableAddChunk(this, chunk, null, true, false); }; -function readableAddChunk(stream, state, chunk, encoding, addToFront) { - var er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (chunk === null) { +function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + var state = stream._readableState; + if (chunk === null) { state.reading = false; onEofChunk(stream, state); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (state.ended && !addToFront) { - var e = new Error('stream.push() after EOF'); - stream.emit('error', e); - } else if (state.endEmitted && addToFront) { - var _e = new Error('stream.unshift() after end event'); - stream.emit('error', _e); - } else { - var skipAdd; - if (state.decoder && !addToFront && !encoding) { - chunk = state.decoder.write(chunk); - skipAdd = !state.objectMode && chunk.length === 0; + } else { + var er; + if (!skipChunkCheck) er = chunkInvalid(state, chunk); + if (er) { + stream.emit('error', er); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { + chunk = _uint8ArrayToBuffer(chunk); } - if (!addToFront) state.reading = false; - - // Don't add to the buffer if we've decoded to an empty string chunk and - // we're not in object mode - if (!skipAdd) { - // if we want the data now, just emit it. - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); + if (addToFront) { + if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); + } else if (state.ended) { + stream.emit('error', new Error('stream.push() after EOF')); + } else { + state.reading = false; + if (state.decoder && !encoding) { + chunk = state.decoder.write(chunk); + if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - - if (state.needReadable) emitReadable(stream); + addChunk(stream, state, chunk, false); } } - - maybeReadMore(stream, state); + } else if (!addToFront) { + state.reading = false; } - } else if (!addToFront) { - state.reading = false; } return needMoreData(state); } +function addChunk(stream, state, chunk, addToFront) { + if (state.flowing && state.length === 0 && !state.sync) { + stream.emit('data', chunk); + stream.read(0); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); + + if (state.needReadable) emitReadable(stream); + } + maybeReadMore(stream, state); +} + +function chunkInvalid(state, chunk) { + var er; + if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new TypeError('Invalid non-string/buffer chunk'); + } + return er; +} + // if it's past the high water mark, we can push in some more. // Also, if we have no data yet, we can stand some // more bytes. This is to work around cases where hwm=0, @@ -12942,6 +15049,10 @@ function needMoreData(state) { return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); } +Readable.prototype.isPaused = function () { + return this._readableState.flowing === false; +}; + // backwards compatibility. Readable.prototype.setEncoding = function (enc) { if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; @@ -13090,14 +15201,6 @@ Readable.prototype.read = function (n) { return ret; }; -function chunkInvalid(state, chunk) { - var er = null; - if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== null && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; -} - function onEofChunk(stream, state) { if (state.ended) return; if (state.decoder) { @@ -13122,7 +15225,7 @@ function emitReadable(stream) { if (!state.emittedReadable) { debug('emitReadable', state.flowing); state.emittedReadable = true; - if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream); + if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream); } } @@ -13141,7 +15244,7 @@ function emitReadable_(stream) { function maybeReadMore(stream, state) { if (!state.readingMore) { state.readingMore = true; - processNextTick(maybeReadMore_, stream, state); + pna.nextTick(maybeReadMore_, stream, state); } } @@ -13162,7 +15265,7 @@ function maybeReadMore_(stream, state) { // for virtual (non-string, non-buffer) streams, "length" is somewhat // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function (n) { - this.emit('error', new Error('not implemented')); + this.emit('error', new Error('_read() is not implemented')); }; Readable.prototype.pipe = function (dest, pipeOpts) { @@ -13185,14 +15288,17 @@ Readable.prototype.pipe = function (dest, pipeOpts) { var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - var endFn = doEnd ? onend : cleanup; - if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); + var endFn = doEnd ? onend : unpipe; + if (state.endEmitted) pna.nextTick(endFn);else src.once('end', endFn); dest.on('unpipe', onunpipe); - function onunpipe(readable) { + function onunpipe(readable, unpipeInfo) { debug('onunpipe'); if (readable === src) { - cleanup(); + if (unpipeInfo && unpipeInfo.hasUnpiped === false) { + unpipeInfo.hasUnpiped = true; + cleanup(); + } } } @@ -13218,7 +15324,7 @@ Readable.prototype.pipe = function (dest, pipeOpts) { dest.removeListener('error', onerror); dest.removeListener('unpipe', onunpipe); src.removeListener('end', onend); - src.removeListener('end', cleanup); + src.removeListener('end', unpipe); src.removeListener('data', ondata); cleanedUp = true; @@ -13311,6 +15417,7 @@ function pipeOnDrain(src) { Readable.prototype.unpipe = function (dest) { var state = this._readableState; + var unpipeInfo = { hasUnpiped: false }; // if we're not piping anywhere, then do nothing. if (state.pipesCount === 0) return this; @@ -13326,7 +15433,7 @@ Readable.prototype.unpipe = function (dest) { state.pipes = null; state.pipesCount = 0; state.flowing = false; - if (dest) dest.emit('unpipe', this); + if (dest) dest.emit('unpipe', this, unpipeInfo); return this; } @@ -13340,20 +15447,20 @@ Readable.prototype.unpipe = function (dest) { state.pipesCount = 0; state.flowing = false; - for (var _i = 0; _i < len; _i++) { - dests[_i].emit('unpipe', this); + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this, unpipeInfo); }return this; } // try to find the right one. - var i = indexOf(state.pipes, dest); - if (i === -1) return this; + var index = indexOf(state.pipes, dest); + if (index === -1) return this; - state.pipes.splice(i, 1); + state.pipes.splice(index, 1); state.pipesCount -= 1; if (state.pipesCount === 1) state.pipes = state.pipes[0]; - dest.emit('unpipe', this); + dest.emit('unpipe', this, unpipeInfo); return this; }; @@ -13372,9 +15479,9 @@ Readable.prototype.on = function (ev, fn) { state.readableListening = state.needReadable = true; state.emittedReadable = false; if (!state.reading) { - processNextTick(nReadingNextTick, this); + pna.nextTick(nReadingNextTick, this); } else if (state.length) { - emitReadable(this, state); + emitReadable(this); } } } @@ -13403,7 +15510,7 @@ Readable.prototype.resume = function () { function resume(stream, state) { if (!state.resumeScheduled) { state.resumeScheduled = true; - processNextTick(resume_, stream, state); + pna.nextTick(resume_, stream, state); } } @@ -13440,18 +15547,19 @@ function flow(stream) { // This is *not* part of the readable stream interface. // It is an ugly unfortunate mess of history. Readable.prototype.wrap = function (stream) { + var _this = this; + var state = this._readableState; var paused = false; - var self = this; stream.on('end', function () { debug('wrapped end'); if (state.decoder && !state.ended) { var chunk = state.decoder.end(); - if (chunk && chunk.length) self.push(chunk); + if (chunk && chunk.length) _this.push(chunk); } - self.push(null); + _this.push(null); }); stream.on('data', function (chunk) { @@ -13461,7 +15569,7 @@ Readable.prototype.wrap = function (stream) { // don't skip over falsy values in objectMode if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; - var ret = self.push(chunk); + var ret = _this.push(chunk); if (!ret) { paused = true; stream.pause(); @@ -13481,14 +15589,13 @@ Readable.prototype.wrap = function (stream) { } // proxy certain important events. - var events = ['error', 'close', 'destroy', 'pause', 'resume']; - forEach(events, function (ev) { - stream.on(ev, self.emit.bind(self, ev)); - }); + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); + } // when we try to consume some more bytes, simply unpause the // underlying stream. - self._read = function (n) { + this._read = function (n) { debug('wrapped _read', n); if (paused) { paused = false; @@ -13496,9 +15603,19 @@ Readable.prototype.wrap = function (stream) { } }; - return self; + return this; }; +Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._readableState.highWaterMark; + } +}); + // exposed for testing purposes only. Readable._fromList = fromList; @@ -13576,7 +15693,7 @@ function copyFromBufferString(n, list) { // This function is designed to be inlinable, so please take care when making // changes to the function body. function copyFromBuffer(n, list) { - var ret = bufferShim.allocUnsafe(n); + var ret = Buffer.allocUnsafe(n); var p = list.head; var c = 1; p.data.copy(ret); @@ -13611,7 +15728,7 @@ function endReadable(stream) { if (!state.endEmitted) { state.ended = true; - processNextTick(endReadableNT, state, stream); + pna.nextTick(endReadableNT, state, stream); } } @@ -13624,20 +15741,35 @@ function endReadableNT(state, stream) { } } -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} - function indexOf(xs, x) { for (var i = 0, l = xs.length; i < l; i++) { if (xs[i] === x) return i; } return -1; } -}).call(this,require('_process')) -},{"./_stream_duplex":69,"./internal/streams/BufferList":74,"_process":67,"buffer":44,"buffer-shims":43,"core-util-is":45,"events":48,"inherits":51,"isarray":53,"process-nextick-args":66,"string_decoder/":80,"util":40}],72:[function(require,module,exports){ +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./_stream_duplex":71,"./internal/streams/BufferList":76,"./internal/streams/destroy":77,"./internal/streams/stream":78,"_process":69,"core-util-is":44,"events":50,"inherits":56,"isarray":58,"process-nextick-args":68,"safe-buffer":83,"string_decoder/":85,"util":40}],74:[function(require,module,exports){ +// 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. + // a transform stream is a readable/writable stream where you do // something with the data. Sometimes it's called a "filter", // but that's not a great name for it, since that implies a thing where @@ -13693,37 +15825,28 @@ util.inherits = require('inherits'); util.inherits(Transform, Duplex); -function TransformState(stream) { - this.afterTransform = function (er, data) { - return afterTransform(stream, er, data); - }; - - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - this.writeencoding = null; -} - -function afterTransform(stream, er, data) { - var ts = stream._transformState; +function afterTransform(er, data) { + var ts = this._transformState; ts.transforming = false; var cb = ts.writecb; - if (!cb) return stream.emit('error', new Error('no writecb in Transform class')); + if (!cb) { + return this.emit('error', new Error('write callback called multiple times')); + } ts.writechunk = null; ts.writecb = null; - if (data !== null && data !== undefined) stream.push(data); + if (data != null) // single equals check for both `null` and `undefined` + this.push(data); cb(er); - var rs = stream._readableState; + var rs = this._readableState; rs.reading = false; if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); + this._read(rs.highWaterMark); } } @@ -13732,10 +15855,14 @@ function Transform(options) { Duplex.call(this, options); - this._transformState = new TransformState(this); - - // when the writable side finishes, then flush out anything remaining. - var stream = this; + this._transformState = { + afterTransform: afterTransform.bind(this), + needTransform: false, + transforming: false, + writecb: null, + writechunk: null, + writeencoding: null + }; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; @@ -13751,11 +15878,20 @@ function Transform(options) { if (typeof options.flush === 'function') this._flush = options.flush; } - this.once('prefinish', function () { - if (typeof this._flush === 'function') this._flush(function (er) { - done(stream, er); - });else done(stream); - }); + // When the writable side finishes, then flush out anything remaining. + this.on('prefinish', prefinish); +} + +function prefinish() { + var _this = this; + + if (typeof this._flush === 'function') { + this._flush(function (er, data) { + done(_this, er, data); + }); + } else { + done(this, null, null); + } } Transform.prototype.push = function (chunk, encoding) { @@ -13774,7 +15910,7 @@ Transform.prototype.push = function (chunk, encoding) { // an error, then that'll put the hurt on the whole operation. If you // never call cb(), then you'll never get another chunk. Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('Not implemented'); + throw new Error('_transform() is not implemented'); }; Transform.prototype._write = function (chunk, encoding, cb) { @@ -13804,36 +15940,92 @@ Transform.prototype._read = function (n) { } }; -function done(stream, er) { +Transform.prototype._destroy = function (err, cb) { + var _this2 = this; + + Duplex.prototype._destroy.call(this, err, function (err2) { + cb(err2); + _this2.emit('close'); + }); +}; + +function done(stream, er, data) { if (er) return stream.emit('error', er); + if (data != null) // single equals check for both `null` and `undefined` + stream.push(data); + // if there's nothing in the write buffer, then that means // that nothing more will ever be provided - var ws = stream._writableState; - var ts = stream._transformState; + if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0'); - if (ws.length) throw new Error('Calling transform done when ws.length != 0'); - - if (ts.transforming) throw new Error('Calling transform done when still transforming'); + if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming'); return stream.push(null); } -},{"./_stream_duplex":69,"core-util-is":45,"inherits":51}],73:[function(require,module,exports){ -(function (process){ +},{"./_stream_duplex":71,"core-util-is":44,"inherits":56}],75:[function(require,module,exports){ +(function (process,global,setImmediate){ +// 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. + // A bit simpler than readable streams. // Implement an async ._write(chunk, encoding, cb), and it'll handle all // the drain event emission and buffering. 'use strict'; +/**/ + +var pna = require('process-nextick-args'); +/**/ + module.exports = Writable; +/* */ +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; + this.next = null; +} + +// It seems a linked list but it is not +// there will be only 2 of these for each stream +function CorkedRequest(state) { + var _this = this; + + this.next = null; + this.entry = null; + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +/* */ + /**/ -var processNextTick = require('process-nextick-args'); +var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick; /**/ /**/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; +var Duplex; /**/ Writable.WritableState = WritableState; @@ -13849,55 +16041,63 @@ var internalUtil = { }; /**/ -/**/ -var Stream; -(function () { - try { - Stream = require('st' + 'ream'); - } catch (_) {} finally { - if (!Stream) Stream = require('events').EventEmitter; - } -})(); +/**/ +var Stream = require('./internal/streams/stream'); /**/ -var Buffer = require('buffer').Buffer; /**/ -var bufferShim = require('buffer-shims'); + +var Buffer = require('safe-buffer').Buffer; +var OurUint8Array = global.Uint8Array || function () {}; +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + /**/ +var destroyImpl = require('./internal/streams/destroy'); + util.inherits(Writable, Stream); function nop() {} -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} - -var Duplex; function WritableState(options, stream) { Duplex = Duplex || require('./_stream_duplex'); options = options || {}; + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + var isDuplex = stream instanceof Duplex; + // object stream flag to indicate whether or not this stream // contains buffers or objects. this.objectMode = !!options.objectMode; - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false // Note: 0 is a valid value, means that we always return false if // the entire buffer is not flushed immediately on write() var hwm = options.highWaterMark; + var writableHwm = options.writableHighWaterMark; var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; + + if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm; // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; + this.highWaterMark = Math.floor(this.highWaterMark); + // if _final has been called + this.finalCalled = false; + + // drain event flag. this.needDrain = false; // at the start of calling end() this.ending = false; @@ -13906,6 +16106,9 @@ function WritableState(options, stream) { // when 'finish' is emitted this.finished = false; + // has it been destroyed + this.destroyed = false; + // should we decode strings into buffers before passing to _write? // this is here so that some node-core streams can optimize string // handling at a lower level. @@ -13972,7 +16175,7 @@ function WritableState(options, stream) { this.corkedRequestsFree = new CorkedRequest(this); } -WritableState.prototype.getBuffer = function writableStateGetBuffer() { +WritableState.prototype.getBuffer = function getBuffer() { var current = this.bufferedRequest; var out = []; while (current) { @@ -13987,18 +16190,43 @@ WritableState.prototype.getBuffer = function writableStateGetBuffer() { Object.defineProperty(WritableState.prototype, 'buffer', { get: internalUtil.deprecate(function () { return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.') + }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') }); } catch (_) {} })(); -var Duplex; +// Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. +var realHasInstance; +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function (object) { + if (realHasInstance.call(this, object)) return true; + if (this !== Writable) return false; + + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function (object) { + return object instanceof this; + }; +} + function Writable(options) { Duplex = Duplex || require('./_stream_duplex'); - // Writable ctor is applied to Duplexes, though they're not - // instanceof Writable, they're instanceof Readable. - if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options); + // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. + + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { + return new Writable(options); + } this._writableState = new WritableState(options, this); @@ -14009,6 +16237,10 @@ function Writable(options) { if (typeof options.write === 'function') this._write = options.write; if (typeof options.writev === 'function') this._writev = options.writev; + + if (typeof options.destroy === 'function') this._destroy = options.destroy; + + if (typeof options.final === 'function') this._final = options.final; } Stream.call(this); @@ -14023,28 +16255,24 @@ function writeAfterEnd(stream, cb) { var er = new Error('write after end'); // TODO: defer error events consistently everywhere, not just the cb stream.emit('error', er); - processNextTick(cb, er); + pna.nextTick(cb, er); } -// If we get something that is not a buffer, string, null, or undefined, -// and we're not in objectMode, then that's an error. -// Otherwise stream chunks are all considered to be of length=1, and the -// watermarks determine how many objects to keep in the buffer, rather than -// how many bytes or characters. +// Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. function validChunk(stream, state, chunk, cb) { var valid = true; var er = false; - // Always throw error if a null is written - // if we are not in object mode then throw - // if it is not a buffer, string, or undefined. + if (chunk === null) { er = new TypeError('May not write null values to stream'); - } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { er = new TypeError('Invalid non-string/buffer chunk'); } if (er) { stream.emit('error', er); - processNextTick(cb, er); + pna.nextTick(cb, er); valid = false; } return valid; @@ -14053,19 +16281,24 @@ function validChunk(stream, state, chunk, cb) { Writable.prototype.write = function (chunk, encoding, cb) { var state = this._writableState; var ret = false; + var isBuf = !state.objectMode && _isUint8Array(chunk); + + if (isBuf && !Buffer.isBuffer(chunk)) { + chunk = _uint8ArrayToBuffer(chunk); + } if (typeof encoding === 'function') { cb = encoding; encoding = null; } - if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; if (typeof cb !== 'function') cb = nop; - if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) { + if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); } return ret; @@ -14097,18 +16330,33 @@ Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { function decodeChunk(state, chunk, encoding) { if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = bufferShim.from(chunk, encoding); + chunk = Buffer.from(chunk, encoding); } return chunk; } +Object.defineProperty(Writable.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState.highWaterMark; + } +}); + // if we're already writing something, then just put this // in the queue, and wait our turn. Otherwise, call _write // If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, chunk, encoding, cb) { - chunk = decodeChunk(state, chunk, encoding); - - if (Buffer.isBuffer(chunk)) encoding = 'buffer'; +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + var newChunk = decodeChunk(state, chunk, encoding); + if (chunk !== newChunk) { + isBuf = true; + encoding = 'buffer'; + chunk = newChunk; + } + } var len = state.objectMode ? 1 : chunk.length; state.length += len; @@ -14119,7 +16367,13 @@ function writeOrBuffer(stream, state, chunk, encoding, cb) { if (state.writing || state.corked) { var last = state.lastBufferedRequest; - state.lastBufferedRequest = new WriteReq(chunk, encoding, cb); + state.lastBufferedRequest = { + chunk: chunk, + encoding: encoding, + isBuf: isBuf, + callback: cb, + next: null + }; if (last) { last.next = state.lastBufferedRequest; } else { @@ -14144,10 +16398,26 @@ function doWrite(stream, state, writev, len, chunk, encoding, cb) { function onwriteError(stream, state, sync, er, cb) { --state.pendingcb; - if (sync) processNextTick(cb, er);else cb(er); - stream._writableState.errorEmitted = true; - stream.emit('error', er); + if (sync) { + // defer the callback if we are being called synchronously + // to avoid piling up things on the stack + pna.nextTick(cb, er); + // this can emit finish, and it will always happen + // after error + pna.nextTick(finishMaybe, stream, state); + stream._writableState.errorEmitted = true; + stream.emit('error', er); + } else { + // the caller expect this to happen before if + // it is async + cb(er); + stream._writableState.errorEmitted = true; + stream.emit('error', er); + // this can emit finish, but finish must + // always follow error + finishMaybe(stream, state); + } } function onwriteStateUpdate(state) { @@ -14177,8 +16447,8 @@ function onwrite(stream, er) { asyncWrite(afterWrite, stream, state, finished, cb); /**/ } else { - afterWrite(stream, state, finished, cb); - } + afterWrite(stream, state, finished, cb); + } } } @@ -14212,11 +16482,14 @@ function clearBuffer(stream, state) { holder.entry = entry; var count = 0; + var allBuffers = true; while (entry) { buffer[count] = entry; + if (!entry.isBuf) allBuffers = false; entry = entry.next; count += 1; } + buffer.allBuffers = allBuffers; doWrite(stream, state, true, state.length, buffer, '', holder.finish); @@ -14230,6 +16503,7 @@ function clearBuffer(stream, state) { } else { state.corkedRequestsFree = new CorkedRequest(state); } + state.bufferedRequestCount = 0; } else { // Slow case, write chunks one-by-one while (entry) { @@ -14240,6 +16514,7 @@ function clearBuffer(stream, state) { doWrite(stream, state, false, len, chunk, encoding, cb); entry = entry.next; + state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then // it means that we need to wait until it does. // also, that means that the chunk and cb are currently @@ -14252,13 +16527,12 @@ function clearBuffer(stream, state) { if (entry === null) state.lastBufferedRequest = null; } - state.bufferedRequestCount = 0; state.bufferedRequest = entry; state.bufferProcessing = false; } Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('not implemented')); + cb(new Error('_write() is not implemented')); }; Writable.prototype._writev = null; @@ -14290,23 +16564,37 @@ Writable.prototype.end = function (chunk, encoding, cb) { function needFinish(state) { return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; } - -function prefinish(stream, state) { - if (!state.prefinished) { +function callFinal(stream, state) { + stream._final(function (err) { + state.pendingcb--; + if (err) { + stream.emit('error', err); + } state.prefinished = true; stream.emit('prefinish'); + finishMaybe(stream, state); + }); +} +function prefinish(stream, state) { + if (!state.prefinished && !state.finalCalled) { + if (typeof stream._final === 'function') { + state.pendingcb++; + state.finalCalled = true; + pna.nextTick(callFinal, stream, state); + } else { + state.prefinished = true; + stream.emit('prefinish'); + } } } function finishMaybe(stream, state) { var need = needFinish(state); if (need) { + prefinish(stream, state); if (state.pendingcb === 0) { - prefinish(stream, state); state.finished = true; stream.emit('finish'); - } else { - prefinish(stream, state); } } return need; @@ -14316,132 +16604,296 @@ function endWritable(stream, state, cb) { state.ending = true; finishMaybe(stream, state); if (cb) { - if (state.finished) processNextTick(cb);else stream.once('finish', cb); + if (state.finished) pna.nextTick(cb);else stream.once('finish', cb); } state.ended = true; stream.writable = false; } -// It seems a linked list but it is not -// there will be only 2 of these for each stream -function CorkedRequest(state) { - var _this = this; - - this.next = null; - this.entry = null; +function onCorkedFinish(corkReq, state, err) { + var entry = corkReq.entry; + corkReq.entry = null; + while (entry) { + var cb = entry.callback; + state.pendingcb--; + cb(err); + entry = entry.next; + } + if (state.corkedRequestsFree) { + state.corkedRequestsFree.next = corkReq; + } else { + state.corkedRequestsFree = corkReq; + } +} - this.finish = function (err) { - var entry = _this.entry; - _this.entry = null; - while (entry) { - var cb = entry.callback; - state.pendingcb--; - cb(err); - entry = entry.next; +Object.defineProperty(Writable.prototype, 'destroyed', { + get: function () { + if (this._writableState === undefined) { + return false; } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = _this; - } else { - state.corkedRequestsFree = _this; + return this._writableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._writableState) { + return; + } + + // backward compatibility, the user is explicitly + // managing destroyed + this._writableState.destroyed = value; + } +}); + +Writable.prototype.destroy = destroyImpl.destroy; +Writable.prototype._undestroy = destroyImpl.undestroy; +Writable.prototype._destroy = function (err, cb) { + this.end(); + cb(err); +}; +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate) +},{"./_stream_duplex":71,"./internal/streams/destroy":77,"./internal/streams/stream":78,"_process":69,"core-util-is":44,"inherits":56,"process-nextick-args":68,"safe-buffer":83,"timers":86,"util-deprecate":87}],76:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Buffer = require('safe-buffer').Buffer; +var util = require('util'); + +function copyBuffer(src, target, offset) { + src.copy(target, offset); +} + +module.exports = function () { + function BufferList() { + _classCallCheck(this, BufferList); + + this.head = null; + this.tail = null; + this.length = 0; + } + + BufferList.prototype.push = function push(v) { + var entry = { data: v, next: null }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + }; + + BufferList.prototype.unshift = function unshift(v) { + var entry = { data: v, next: this.head }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + }; + + BufferList.prototype.shift = function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + }; + + BufferList.prototype.clear = function clear() { + this.head = this.tail = null; + this.length = 0; + }; + + BufferList.prototype.join = function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + while (p = p.next) { + ret += s + p.data; + }return ret; + }; + + BufferList.prototype.concat = function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + if (this.length === 1) return this.head.data; + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; } + return ret; + }; + + return BufferList; +}(); + +if (util && util.inspect && util.inspect.custom) { + module.exports.prototype[util.inspect.custom] = function () { + var obj = util.inspect({ length: this.length }); + return this.constructor.name + ' ' + obj; }; } -}).call(this,require('_process')) -},{"./_stream_duplex":69,"_process":67,"buffer":44,"buffer-shims":43,"core-util-is":45,"events":48,"inherits":51,"process-nextick-args":66,"util-deprecate":81}],74:[function(require,module,exports){ +},{"safe-buffer":83,"util":40}],77:[function(require,module,exports){ 'use strict'; -var Buffer = require('buffer').Buffer; /**/ -var bufferShim = require('buffer-shims'); + +var pna = require('process-nextick-args'); /**/ -module.exports = BufferList; +// undocumented cb() API, needed for core, not for public API +function destroy(err, cb) { + var _this = this; -function BufferList() { - this.head = null; - this.tail = null; - this.length = 0; -} + var readableDestroyed = this._readableState && this._readableState.destroyed; + var writableDestroyed = this._writableState && this._writableState.destroyed; -BufferList.prototype.push = function (v) { - var entry = { data: v, next: null }; - if (this.length > 0) this.tail.next = entry;else this.head = entry; - this.tail = entry; - ++this.length; -}; + if (readableDestroyed || writableDestroyed) { + if (cb) { + cb(err); + } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { + pna.nextTick(emitErrorNT, this, err); + } + return this; + } -BufferList.prototype.unshift = function (v) { - var entry = { data: v, next: this.head }; - if (this.length === 0) this.tail = entry; - this.head = entry; - ++this.length; -}; + // we set destroyed to true before firing error callbacks in order + // to make it re-entrance safe in case destroy() is called within callbacks -BufferList.prototype.shift = function () { - if (this.length === 0) return; - var ret = this.head.data; - if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; - --this.length; - return ret; -}; + if (this._readableState) { + this._readableState.destroyed = true; + } -BufferList.prototype.clear = function () { - this.head = this.tail = null; - this.length = 0; -}; + // if this is a duplex stream mark the writable part as destroyed as well + if (this._writableState) { + this._writableState.destroyed = true; + } -BufferList.prototype.join = function (s) { - if (this.length === 0) return ''; - var p = this.head; - var ret = '' + p.data; - while (p = p.next) { - ret += s + p.data; - }return ret; -}; + this._destroy(err || null, function (err) { + if (!cb && err) { + pna.nextTick(emitErrorNT, _this, err); + if (_this._writableState) { + _this._writableState.errorEmitted = true; + } + } else if (cb) { + cb(err); + } + }); -BufferList.prototype.concat = function (n) { - if (this.length === 0) return bufferShim.alloc(0); - if (this.length === 1) return this.head.data; - var ret = bufferShim.allocUnsafe(n >>> 0); - var p = this.head; - var i = 0; - while (p) { - p.data.copy(ret, i); - i += p.data.length; - p = p.next; + return this; +} + +function undestroy() { + if (this._readableState) { + this._readableState.destroyed = false; + this._readableState.reading = false; + this._readableState.ended = false; + this._readableState.endEmitted = false; } - return ret; + + if (this._writableState) { + this._writableState.destroyed = false; + this._writableState.ended = false; + this._writableState.ending = false; + this._writableState.finished = false; + this._writableState.errorEmitted = false; + } +} + +function emitErrorNT(self, err) { + self.emit('error', err); +} + +module.exports = { + destroy: destroy, + undestroy: undestroy }; -},{"buffer":44,"buffer-shims":43}],75:[function(require,module,exports){ -module.exports = require("./lib/_stream_passthrough.js") +},{"process-nextick-args":68}],78:[function(require,module,exports){ +module.exports = require('events').EventEmitter; -},{"./lib/_stream_passthrough.js":70}],76:[function(require,module,exports){ -(function (process){ -var Stream = (function (){ - try { - return require('st' + 'ream'); // hack to fix a circular dependency issue when used with browserify - } catch(_){} -}()); +},{"events":50}],79:[function(require,module,exports){ +module.exports = require('./readable').PassThrough + +},{"./readable":80}],80:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); -exports.Stream = Stream || exports; +exports.Stream = exports; exports.Readable = exports; exports.Writable = require('./lib/_stream_writable.js'); exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); -if (!process.browser && process.env.READABLE_STREAM === 'disable' && Stream) { - module.exports = Stream; +},{"./lib/_stream_duplex.js":71,"./lib/_stream_passthrough.js":72,"./lib/_stream_readable.js":73,"./lib/_stream_transform.js":74,"./lib/_stream_writable.js":75}],81:[function(require,module,exports){ +module.exports = require('./readable').Transform + +},{"./readable":80}],82:[function(require,module,exports){ +module.exports = require('./lib/_stream_writable.js'); + +},{"./lib/_stream_writable.js":75}],83:[function(require,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer } -}).call(this,require('_process')) -},{"./lib/_stream_duplex.js":69,"./lib/_stream_passthrough.js":70,"./lib/_stream_readable.js":71,"./lib/_stream_transform.js":72,"./lib/_stream_writable.js":73,"_process":67}],77:[function(require,module,exports){ -module.exports = require("./lib/_stream_transform.js") +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} -},{"./lib/_stream_transform.js":72}],78:[function(require,module,exports){ -module.exports = require("./lib/_stream_writable.js") +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} -},{"./lib/_stream_writable.js":73}],79:[function(require,module,exports){ +},{"buffer":43}],84:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -14570,7 +17022,7 @@ Stream.prototype.pipe = function(dest, options) { return dest; }; -},{"events":48,"inherits":51,"readable-stream/duplex.js":68,"readable-stream/passthrough.js":75,"readable-stream/readable.js":76,"readable-stream/transform.js":77,"readable-stream/writable.js":78}],80:[function(require,module,exports){ +},{"events":50,"inherits":56,"readable-stream/duplex.js":70,"readable-stream/passthrough.js":79,"readable-stream/readable.js":80,"readable-stream/transform.js":81,"readable-stream/writable.js":82}],85:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -14592,208 +17044,361 @@ Stream.prototype.pipe = function(dest, options) { // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -var Buffer = require('buffer').Buffer; +'use strict'; + +/**/ -var isBufferEncoding = Buffer.isEncoding - || function(encoding) { - switch (encoding && encoding.toLowerCase()) { - case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; - default: return false; - } - } +var Buffer = require('safe-buffer').Buffer; +/**/ +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; + } +}; -function assertEncoding(encoding) { - if (encoding && !isBufferEncoding(encoding)) { - throw new Error('Unknown encoding: ' + encoding); +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; + } } +}; + +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; } // StringDecoder provides an interface for efficiently splitting a series of // buffers into a series of JS strings without breaking apart multi-byte -// characters. CESU-8 is handled as part of the UTF-8 encoding. -// -// @TODO Handling all encodings inside a single object makes it very difficult -// to reason about this code, so it should be split up in the future. -// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code -// points as used by CESU-8. -var StringDecoder = exports.StringDecoder = function(encoding) { - this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); - assertEncoding(encoding); +// characters. +exports.StringDecoder = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; switch (this.encoding) { - case 'utf8': - // CESU-8 represents each of Surrogate Pair by 3-bytes - this.surrogateSize = 3; - break; - case 'ucs2': case 'utf16le': - // UTF-16 represents each of Surrogate Pair by 2-bytes - this.surrogateSize = 2; - this.detectIncompleteChar = utf16DetectIncompleteChar; + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; break; case 'base64': - // Base-64 stores 3 bytes in 4 chars, and pads the remainder. - this.surrogateSize = 3; - this.detectIncompleteChar = base64DetectIncompleteChar; + this.text = base64Text; + this.end = base64End; + nb = 3; break; default: - this.write = passThroughWrite; + this.write = simpleWrite; + this.end = simpleEnd; return; } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} - // Enough space to store all bytes of a single character. UTF-8 needs 4 - // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). - this.charBuffer = new Buffer(6); - // Number of bytes received for the current incomplete multi-byte character. - this.charReceived = 0; - // Number of bytes expected for the current incomplete multi-byte character. - this.charLength = 0; +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; + } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; }; +StringDecoder.prototype.end = utf8End; -// write decodes the given buffer and returns it as JS string that is -// guaranteed to not contain any partial multi-byte characters. Any partial -// character found at the end of the buffer is buffered up, and will be -// returned when calling write again with the remaining bytes. -// -// Note: Converting a Buffer containing an orphan surrogate to a String -// currently works, but converting a String to a Buffer (via `new Buffer`, or -// Buffer#write) will replace incomplete surrogates with the unicode -// replacement character. See https://codereview.chromium.org/121173009/ . -StringDecoder.prototype.write = function(buffer) { - var charStr = ''; - // if our last write ended with an incomplete multibyte character - while (this.charLength) { - // determine how many remaining bytes this buffer has to offer for this char - var available = (buffer.length >= this.charLength - this.charReceived) ? - this.charLength - this.charReceived : - buffer.length; - - // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, available); - this.charReceived += available; - - if (this.charReceived < this.charLength) { - // still not enough chars in this buffer? wait for more ... - return ''; - } - - // remove bytes belonging to the current character from the buffer - buffer = buffer.slice(available, buffer.length); - - // get the character that was split - charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); - - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - var charCode = charStr.charCodeAt(charStr.length - 1); - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - this.charLength += this.surrogateSize; - charStr = ''; - continue; - } - this.charReceived = this.charLength = 0; +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; - // if there are no more bytes in this buffer, just emit our char - if (buffer.length === 0) { - return charStr; - } - break; +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); } + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; +}; - // determine and set charLength / charReceived - this.detectIncompleteChar(buffer); +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. If an invalid byte is detected, -2 is returned. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return byte >> 6 === 0x02 ? -1 : -2; +} + +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; + } + return nb; + } + return 0; +} - var end = buffer.length; - if (this.charLength) { - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); - end -= this.charReceived; +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'; + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'; + } + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'; + } + } } +} - charStr += buffer.toString(this.encoding, 0, end); +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} + +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character is added when ending on a partial +// character. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'; + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} - var end = charStr.length - 1; - var charCode = charStr.charCodeAt(end); - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - var size = this.surrogateSize; - this.charLength += size; - this.charReceived += size; - this.charBuffer.copy(this.charBuffer, size, 0, size); - buffer.copy(this.charBuffer, 0, 0, size); - return charStr.substring(0, end); +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); } + return r; +} - // or just emit the charStr - return charStr; -}; +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} -// detectIncompleteChar determines if there is an incomplete UTF-8 character at -// the end of the given buffer. If so, it sets this.charLength to the byte -// length that character, and sets this.charReceived to the number of bytes -// that are available for this character. -StringDecoder.prototype.detectIncompleteChar = function(buffer) { - // determine how many bytes we have to check at the end of this buffer - var i = (buffer.length >= 3) ? 3 : buffer.length; +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} - // Figure out if one of the last i bytes of our buffer announces an - // incomplete char. - for (; i > 0; i--) { - var c = buffer[buffer.length - i]; +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} - // See http://en.wikipedia.org/wiki/UTF-8#Description +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; +} +},{"safe-buffer":83}],86:[function(require,module,exports){ +(function (setImmediate,clearImmediate){ +var nextTick = require('process/browser.js').nextTick; +var apply = Function.prototype.apply; +var slice = Array.prototype.slice; +var immediateIds = {}; +var nextImmediateId = 0; - // 110XXXXX - if (i == 1 && c >> 5 == 0x06) { - this.charLength = 2; - break; - } +// DOM APIs, for completeness - // 1110XXXX - if (i <= 2 && c >> 4 == 0x0E) { - this.charLength = 3; - break; - } +exports.setTimeout = function() { + return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); +}; +exports.setInterval = function() { + return new Timeout(apply.call(setInterval, window, arguments), clearInterval); +}; +exports.clearTimeout = +exports.clearInterval = function(timeout) { timeout.close(); }; - // 11110XXX - if (i <= 3 && c >> 3 == 0x1E) { - this.charLength = 4; - break; - } - } - this.charReceived = i; +function Timeout(id, clearFn) { + this._id = id; + this._clearFn = clearFn; +} +Timeout.prototype.unref = Timeout.prototype.ref = function() {}; +Timeout.prototype.close = function() { + this._clearFn.call(window, this._id); }; -StringDecoder.prototype.end = function(buffer) { - var res = ''; - if (buffer && buffer.length) - res = this.write(buffer); +// Does not start the time, just sets up the members needed. +exports.enroll = function(item, msecs) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = msecs; +}; - if (this.charReceived) { - var cr = this.charReceived; - var buf = this.charBuffer; - var enc = this.encoding; - res += buf.slice(0, cr).toString(enc); - } +exports.unenroll = function(item) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = -1; +}; - return res; +exports._unrefActive = exports.active = function(item) { + clearTimeout(item._idleTimeoutId); + + var msecs = item._idleTimeout; + if (msecs >= 0) { + item._idleTimeoutId = setTimeout(function onTimeout() { + if (item._onTimeout) + item._onTimeout(); + }, msecs); + } }; -function passThroughWrite(buffer) { - return buffer.toString(this.encoding); -} +// That's not how node.js implements it but the exposed api is the same. +exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { + var id = nextImmediateId++; + var args = arguments.length < 2 ? false : slice.call(arguments, 1); -function utf16DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 2; - this.charLength = this.charReceived ? 2 : 0; -} + immediateIds[id] = true; -function base64DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 3; - this.charLength = this.charReceived ? 3 : 0; -} + nextTick(function onNextTick() { + if (immediateIds[id]) { + // fn.call() is faster so we optimize for the common use-case + // @see http://jsperf.com/call-apply-segu + if (args) { + fn.apply(null, args); + } else { + fn.call(null); + } + // Prevent ids from leaking + exports.clearImmediate(id); + } + }); + + return id; +}; -},{"buffer":44}],81:[function(require,module,exports){ +exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { + delete immediateIds[id]; +}; +}).call(this,require("timers").setImmediate,require("timers").clearImmediate) +},{"process/browser.js":69,"timers":86}],87:[function(require,module,exports){ (function (global){ /** @@ -14864,16 +17469,14 @@ function config (name) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],82:[function(require,module,exports){ -arguments[4][51][0].apply(exports,arguments) -},{"dup":51}],83:[function(require,module,exports){ +},{}],88:[function(require,module,exports){ module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } -},{}],84:[function(require,module,exports){ +},{}],89:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -15463,4 +18066,11 @@ function hasOwnProperty(obj, prop) { } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":83,"_process":67,"inherits":82}]},{},[1]); +},{"./support/isBuffer":88,"_process":69,"inherits":56}],90:[function(require,module,exports){ +module.exports={ + "name": "mocha", + "version": "6.1.4", + "homepage": "https://mochajs.org/", + "notifyLogo": "https://ibin.co/4QuRuGjXvl36.png" +} +},{}]},{},[1]); From 455a28c68dc1cd1046e8c458cc0f5027ed7ac03f Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 15 Jul 2019 18:15:56 +0900 Subject: [PATCH 006/207] 2.23.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f9028a..7cd552f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "blueimp-load-image", - "version": "2.22.0", + "version": "2.23.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f1266d8..39e1643 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blueimp-load-image", - "version": "2.22.0", + "version": "2.23.0", "title": "JavaScript Load Image", "description": "JavaScript Load Image is a library to load images provided as File or Blob objects or via URL. It returns an optionally scaled and/or cropped HTML img or canvas element. It also provides methods to parse image meta data to extract IPTC and Exif tags as well as embedded thumbnail images and to restore the complete image header after resizing.", "keywords": [ From c3ad3a8ed07b6d6a53c20c4358b412e18a45993f Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 27 Aug 2019 21:38:39 +0900 Subject: [PATCH 007/207] Update dev dependencies. --- package-lock.json | 299 +++++++++++++++++++++++----------------------- 1 file changed, 150 insertions(+), 149 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7cd552f..cca7c80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" @@ -25,21 +25,21 @@ } }, "@types/node": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.2.tgz", - "integrity": "sha512-gojym4tX0FWeV2gsW4Xmzo5wxGjXGm550oVUII7f7G5o4BV6c7DBdiG1RRQd+y1bvqRyYtPfMK85UM95vsapqQ==", + "version": "12.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", + "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", "dev": true }, "acorn": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", - "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", + "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", + "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", "dev": true }, "ajv": { @@ -109,9 +109,9 @@ "dev": true }, "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, "balanced-match": { @@ -278,9 +278,9 @@ "dev": true }, "comment-parser": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.5.5.tgz", - "integrity": "sha512-oB3TinFT+PV3p8UwDQt71+HkG03+zwPwikDlKU6ZDmql6QX2zFlQ+G0GGSDqyJhdZi4PSlzFBm+YJ+ebOX3Vgw==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.6.2.tgz", + "integrity": "sha512-Wdms0Q8d4vvb2Yk72OwZjwNWtMklbC5Re7lD9cjCP/AG1fhocmc0TrxGBBAXPLy8fZQPrfHGgyygwI0lA7pbzA==", "dev": true }, "concat-map": { @@ -290,20 +290,20 @@ "dev": true }, "concurrently": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.1.tgz", - "integrity": "sha512-48+FE5RJ0qc8azwKv4keVQWlni1hZeSjcWr8shBelOBtBHcKj1aJFM9lHRiSc1x7lq416pkvsqfBMhSRja+Lhw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.2.tgz", + "integrity": "sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg==", "dev": true, "requires": { - "chalk": "^2.4.1", - "date-fns": "^1.23.0", - "lodash": "^4.17.10", + "chalk": "^2.4.2", + "date-fns": "^1.30.1", + "lodash": "^4.17.15", "read-pkg": "^4.0.1", - "rxjs": "^6.3.3", + "rxjs": "^6.5.2", "spawn-command": "^0.0.2-1", "supports-color": "^4.5.0", - "tree-kill": "^1.1.0", - "yargs": "^12.0.1" + "tree-kill": "^1.2.1", + "yargs": "^12.0.5" } }, "corser": { @@ -448,9 +448,9 @@ "dev": true }, "eslint": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", - "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.2.tgz", + "integrity": "sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -459,64 +459,88 @@ "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^6.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^3.1.0", + "glob-parent": "^5.0.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", + "inquirer": "^6.4.1", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.11", + "lodash": "^4.17.14", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "progress": "^2.0.0", "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", "table": "^5.2.3", - "text-table": "^0.2.0" + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "eslint-config-blueimp": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-1.3.0.tgz", - "integrity": "sha512-6JPmtGdIamQ1AN9X9ejR9pa5kY2aS8s1EJss4ZWj4jLcEmJEGdehQAxSI9H7kT6uUpKPbEx5g5QhpQqCASxwSA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-1.4.0.tgz", + "integrity": "sha512-OWTLOSmsjDglgNvKKtb0t3iRPpyzFvXszXJkSS1w5oqkgVmFaKiNeoU6qOyZF2Q78rIog77RgIhzyA387b+7qA==", "dev": true }, "eslint-config-prettier": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz", - "integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.1.0.tgz", + "integrity": "sha512-k9fny9sPjIBQ2ftFTesJV21Rg4R/7a7t7LCtZVrYQiHEp8Nnuk3EGaDmsKSAnsPj0BYcgB2zxzHa2NTkIxcOLg==", "dev": true, "requires": { "get-stdin": "^6.0.0" } }, "eslint-plugin-jsdoc": { - "version": "15.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.5.1.tgz", - "integrity": "sha512-ZE2UyTfikhkS9XatRo+UhTFJVrW0XIpK19XQdlFkgpq/BWcewRPYZdO1nJ3r5Z/o4oITfASCPZMArW9Wjhiukg==", + "version": "15.8.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.8.3.tgz", + "integrity": "sha512-p2O6SYetuSD5gWV04HHevIfp2WfimXReYwINuB4iC33hm1jrYoP+t2XbJtCBYvjhoRjjw8w4NfnyZKixte1fug==", "dev": true, "requires": { - "comment-parser": "^0.5.5", + "comment-parser": "^0.6.2", "debug": "^4.1.1", - "flat-map-polyfill": "^0.3.8", "jsdoctypeparser": "5.0.1", - "lodash": "^4.17.14", + "lodash": "^4.17.15", + "object.entries-ponyfill": "^1.0.1", "regextras": "^0.6.1" } }, @@ -530,9 +554,9 @@ } }, "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -540,29 +564,29 @@ } }, "eslint-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", - "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", + "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", "dev": true, "requires": { "eslint-visitor-keys": "^1.0.0" } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", - "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", + "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", "dev": true, "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^7.0.0", + "acorn-jsx": "^5.0.2", + "eslint-visitor-keys": "^1.1.0" } }, "esprima": { @@ -590,15 +614,15 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "eventemitter3": { @@ -695,12 +719,6 @@ "write": "1.0.3" } }, - "flat-map-polyfill": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/flat-map-polyfill/-/flat-map-polyfill-0.3.8.tgz", - "integrity": "sha512-ZfmD5MnU7GglUEhiky9C7yEPaNq1/wh36RDohe+Xr3nJVdccwHbdTkFIYvetcdsoAckUKT51fuf44g7Ni5Doyg==", - "dev": true - }, "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", @@ -708,23 +726,12 @@ "dev": true }, "follow-redirects": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", - "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.0.tgz", + "integrity": "sha512-eYyazyi+vwXZ6LfSQicvqFwaNEF5xTvnB/rpzRLuqwK45u7WbBEnQ/dDic66KD/A8IzTXFlj2ROAcaP0f2v4lg==", "dev": true, "requires": { - "debug": "^3.2.6" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "debug": "^4.1.1" } }, "fs.realpath": { @@ -791,24 +798,12 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "is-glob": "^4.0.1" } }, "globals": { @@ -818,9 +813,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", "dev": true }, "has-flag": { @@ -836,9 +831,9 @@ "dev": true }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", "dev": true }, "http-proxy": { @@ -932,9 +927,9 @@ "dev": true }, "inquirer": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", - "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", @@ -1147,9 +1142,9 @@ } }, "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "loglevel": { @@ -1385,6 +1380,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "object.entries-ponyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz", + "integrity": "sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY=", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1485,9 +1486,9 @@ "dev": true }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1527,12 +1528,6 @@ "json-parse-better-errors": "^1.0.1" } }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -1582,9 +1577,9 @@ } }, "portfinder": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.21.tgz", - "integrity": "sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==", + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.23.tgz", + "integrity": "sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ==", "dev": true, "requires": { "async": "^1.5.2", @@ -1788,9 +1783,9 @@ "dev": true }, "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1863,9 +1858,9 @@ "dev": true }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "set-blocking": { @@ -1994,9 +1989,9 @@ "dev": true }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { @@ -2017,13 +2012,13 @@ } }, "table": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", - "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { - "ajv": "^6.9.1", - "lodash": "^4.17.11", + "ajv": "^6.10.2", + "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" }, @@ -2146,6 +2141,12 @@ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", "dev": true }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", From 1196b4ce3c56f01cacf90fc5527b324ecccdf3b0 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 27 Aug 2019 21:38:48 +0900 Subject: [PATCH 008/207] 2.24.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cca7c80..d0bd2b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "blueimp-load-image", - "version": "2.23.0", + "version": "2.24.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 39e1643..6cbe3c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blueimp-load-image", - "version": "2.23.0", + "version": "2.24.0", "title": "JavaScript Load Image", "description": "JavaScript Load Image is a library to load images provided as File or Blob objects or via URL. It returns an optionally scaled and/or cropped HTML img or canvas element. It also provides methods to parse image meta data to extract IPTC and Exif tags as well as embedded thumbnail images and to restore the complete image header after resizing.", "keywords": [ From 3a5535831e2029113f473588161013ba06a51877 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 28 Sep 2019 20:47:00 +0900 Subject: [PATCH 009/207] Add GitHub NodeJS workflow. --- .github/workflows/nodejs.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/nodejs.yml diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..b15baf3 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,26 @@ +name: Node CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x, 10.x, 12.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, build, and test + run: | + npm install + npm run build --if-present + npm test + env: + CI: true From ead9b7e314cbc1eb4bdeb275d9067901d4de6e05 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 28 Sep 2019 20:54:13 +0900 Subject: [PATCH 010/207] Remove obsolete travis config. --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 878ef22..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -dist: trusty -addons: - chrome: stable -# Using sudo as workaround for -# https://github.com/shellscape/mocha-chrome/pull/21 -sudo: required -language: node_js -node_js: - - "stable" From ebf4cfa3b57dfe01a914fa9b35d1eb5581fd7a37 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 20 Oct 2019 15:34:00 +0900 Subject: [PATCH 011/207] Run workflow on push and pull_request. Format YAML with prettier. --- .github/workflows/nodejs.yml | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index b15baf3..89973ab 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -1,10 +1,9 @@ name: Node CI -on: [push] +on: [push, pull_request] jobs: build: - runs-on: ubuntu-latest strategy: @@ -12,15 +11,15 @@ jobs: node-version: [8.x, 10.x, 12.x] steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: npm install, build, and test - run: | - npm install - npm run build --if-present - npm test - env: - CI: true + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, build, and test + run: | + npm install + npm run build --if-present + npm test + env: + CI: true From ae40880049220d8283abd880e3f95c53581548a0 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 3 Nov 2019 10:20:22 +0900 Subject: [PATCH 012/207] Add GitHub Sponsors config. --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..048b1cf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [blueimp] From 3ed1e0a30da5f63cd7670d22788628776e9e501a Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:41:09 +0900 Subject: [PATCH 013/207] Update dev dependencies. --- package-lock.json | 521 +++++++++++++++++++++++++--------------------- 1 file changed, 289 insertions(+), 232 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0bd2b9..39e7529 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,21 +25,21 @@ } }, "@types/node": { - "version": "12.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", - "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", + "version": "12.12.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.21.tgz", + "integrity": "sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==", "dev": true }, "acorn": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", - "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, "ajv": { @@ -55,10 +55,13 @@ } }, "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } }, "ansi-regex": { "version": "3.0.0", @@ -103,16 +106,13 @@ "dev": true }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } }, "balanced-match": { "version": "1.0.0", @@ -120,6 +120,12 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -190,26 +196,26 @@ "dev": true }, "chrome-launcher": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.10.7.tgz", - "integrity": "sha512-IoQLp64s2n8OQuvKZwt77CscVj3UlV2Dj7yZtd1EBMld9mSdGcsGy9fN5hd/r4vJuWZR09it78n1+A17gB+AIQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.11.2.tgz", + "integrity": "sha512-jx0kJDCXdB2ARcDMwNCtrf04oY1Up4rOmVu+fqJ5MTPOOIG8EhRcEU9NZfXZc6dMw9FU8o1r21PNp8V2M0zQ+g==", "dev": true, "requires": { "@types/node": "*", - "is-wsl": "^1.1.0", + "is-wsl": "^2.1.0", "lighthouse-logger": "^1.0.0", "mkdirp": "0.5.1", "rimraf": "^2.6.1" } }, "chrome-remote-interface": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.27.2.tgz", - "integrity": "sha512-pVLljQ29SAx8KIv5tSa9sIf8GrEsAZdPJoeWOmY3/nrIzFmE+EryNNHvDkddGod0cmAFTv+GmPG0uvzxi2NWsA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.28.1.tgz", + "integrity": "sha512-OnVjEOuZtPDImShaWSQPKPZMNnUnoZfLKhayeXUWOyqir3MT1OTqMzUDEnIVx1itPnsW7CiKgyNLLgvgdniJgQ==", "dev": true, "requires": { "commander": "2.11.x", - "ws": "^6.1.0" + "ws": "^7.2.0" } }, "chrome-unmirror": { @@ -219,12 +225,12 @@ "dev": true }, "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-width": { @@ -266,9 +272,9 @@ "dev": true }, "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "commander": { @@ -418,15 +424,15 @@ } }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -448,9 +454,9 @@ "dev": true }, "eslint": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.2.tgz", - "integrity": "sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -460,19 +466,19 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", + "eslint-utils": "^1.4.3", "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", + "espree": "^6.1.2", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", + "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -481,7 +487,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -522,32 +528,32 @@ "dev": true }, "eslint-config-prettier": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.1.0.tgz", - "integrity": "sha512-k9fny9sPjIBQ2ftFTesJV21Rg4R/7a7t7LCtZVrYQiHEp8Nnuk3EGaDmsKSAnsPj0BYcgB2zxzHa2NTkIxcOLg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz", + "integrity": "sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==", "dev": true, "requires": { "get-stdin": "^6.0.0" } }, "eslint-plugin-jsdoc": { - "version": "15.8.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.8.3.tgz", - "integrity": "sha512-p2O6SYetuSD5gWV04HHevIfp2WfimXReYwINuB4iC33hm1jrYoP+t2XbJtCBYvjhoRjjw8w4NfnyZKixte1fug==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.12.2.tgz", + "integrity": "sha512-QHzPc3VKTEbTn369/HpqDjl/czv3fCei/bZg5NA5tu9Od10MfpTH4kc1xnRDobhQoDs3AMz9wuaI4coHWRzMQw==", "dev": true, "requires": { "comment-parser": "^0.6.2", "debug": "^4.1.1", - "jsdoctypeparser": "5.0.1", + "jsdoctypeparser": "^5.1.1", "lodash": "^4.17.15", "object.entries-ponyfill": "^1.0.1", "regextras": "^0.6.1" } }, "eslint-plugin-prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz", - "integrity": "sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz", + "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -564,12 +570,12 @@ } }, "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" } }, "eslint-visitor-keys": { @@ -579,13 +585,13 @@ "dev": true }, "espree": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", - "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^7.0.0", - "acorn-jsx": "^5.0.2", + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", "eslint-visitor-keys": "^1.1.0" } }, @@ -626,9 +632,9 @@ "dev": true }, "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", "dev": true }, "execa": { @@ -670,9 +676,9 @@ "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "fast-levenshtein": { @@ -682,9 +688,9 @@ "dev": true }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -726,12 +732,23 @@ "dev": true }, "follow-redirects": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.0.tgz", - "integrity": "sha512-eYyazyi+vwXZ6LfSQicvqFwaNEF5xTvnB/rpzRLuqwK45u7WbBEnQ/dDic66KD/A8IzTXFlj2ROAcaP0f2v4lg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", "dev": true, "requires": { - "debug": "^4.1.1" + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "fs.realpath": { @@ -784,9 +801,9 @@ } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -798,24 +815,27 @@ } }, "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { "is-glob": "^4.0.1" } }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } }, "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "has-flag": { @@ -831,36 +851,38 @@ "dev": true }, "hosted-git-info": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", - "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", "dev": true, "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "http-server": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz", - "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.0.tgz", + "integrity": "sha512-imGLDSTT1BZ0QG1rBFnaZ6weK5jeisUnCxZQI1cpYTdz0luPUM5e3s+WU5zRWEkiI6DQxL2p54oeKrDlzO6bRw==", "dev": true, "requires": { - "colors": "1.0.3", - "corser": "~2.0.0", - "ecstatic": "^3.0.0", - "http-proxy": "^1.8.1", - "opener": "~1.4.0", - "optimist": "0.6.x", - "portfinder": "^1.0.13", - "union": "~0.4.3" + "basic-auth": "^1.0.3", + "colors": "^1.3.3", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.17.0", + "opener": "^1.5.1", + "optimist": "~0.6.1", + "portfinder": "^1.0.20", + "secure-compare": "3.0.1", + "union": "~0.5.0" } }, "iconv-lite": { @@ -879,9 +901,9 @@ "dev": true }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -927,32 +949,60 @@ "dev": true }, "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", + "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", + "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -960,6 +1010,14 @@ "dev": true, "requires": { "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } } } @@ -1022,9 +1080,9 @@ "dev": true }, "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", "dev": true }, "isexe": { @@ -1050,9 +1108,9 @@ } }, "jsdoctypeparser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.0.1.tgz", - "integrity": "sha512-dYwcK6TKzvq+ZKtbp4sbQSW9JMo6s+4YFfUs5D/K7bZsn3s1NhEhZ+jmIPzby0HbkbECBe+hNPEa6a+E21o94w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.1.1.tgz", + "integrity": "sha512-APGygIJrT5bbz5lsVt8vyLJC0miEbQf/z9ZBfTr4RYvdia8AhWMRlYgivvwHG5zKD/VW3d6qpChCy64hpQET3A==", "dev": true }, "json-parse-better-errors": { @@ -1148,9 +1206,9 @@ "dev": true }, "loglevel": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", - "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", + "integrity": "sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==", "dev": true }, "loud-rejection": { @@ -1276,14 +1334,14 @@ } }, "mocha-chrome": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mocha-chrome/-/mocha-chrome-2.0.0.tgz", - "integrity": "sha512-Kq6W9jdXY3C2PhNHtSrk3GnDuoAKN+DbgJKCLfXtc5cql8oHB8+rUYlq9t1c8in6vQ6/X432E/U8h0pV5QlAug==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/mocha-chrome/-/mocha-chrome-2.2.0.tgz", + "integrity": "sha512-RXP6Q2mlM2X+eO2Z8gribmiH4J9x5zu/JcTZ3deQSwiC5260BzizOc0eD1NWP3JuypGCKRwReicv4KCNIFtTZQ==", "dev": true, "requires": { "chalk": "^2.0.1", - "chrome-launcher": "^0.10.2", - "chrome-remote-interface": "^0.27.0", + "chrome-launcher": "^0.11.2", + "chrome-remote-interface": "^0.28.0", "chrome-unmirror": "^0.1.0", "debug": "^4.1.1", "deep-assign": "^3.0.0", @@ -1300,9 +1358,9 @@ "dev": true }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "nanoassert": { @@ -1396,26 +1454,18 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - } + "mimic-fn": "^2.1.0" } }, "opener": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", - "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", "dev": true }, "optimist": { @@ -1426,28 +1476,20 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "os-locale": { @@ -1577,30 +1619,24 @@ } }, "portfinder": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.23.tgz", - "integrity": "sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ==", + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", "dev": true, "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -1611,9 +1647,9 @@ "dev": true }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, "prettier-linter-helpers": { @@ -1648,9 +1684,9 @@ "dev": true }, "qs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", - "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==", "dev": true }, "quick-lru": { @@ -1783,9 +1819,9 @@ "dev": true }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", + "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1815,12 +1851,12 @@ "dev": true }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -1843,9 +1879,9 @@ } }, "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -1857,6 +1893,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -2029,6 +2071,12 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2073,9 +2121,9 @@ } }, "tree-kill": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", - "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, "trim-newlines": { @@ -2099,31 +2147,37 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", + "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", "dev": true, "requires": { - "commander": "~2.20.0", + "commander": "~2.20.3", "source-map": "~0.6.1" }, "dependencies": { "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true } } }, "union": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz", - "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", "dev": true, "requires": { - "qs": "~2.3.3" + "qs": "^6.4.0" } }, "uri-js": { @@ -2172,10 +2226,16 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { @@ -2241,13 +2301,10 @@ } }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==", + "dev": true }, "y18n": { "version": "4.0.0", From 9326d2ae5bbfd7e9c9cb7e00264030756746d389 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:42:15 +0900 Subject: [PATCH 014/207] Check if blob argument is a Blob instance. --- js/load-image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/load-image.js b/js/load-image.js index 0119c63..2e158f5 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -37,7 +37,7 @@ loadImage.fetchBlob( file, function(blob) { - if (blob) { + if (blob && loadImage.isInstanceOf('Blob', blob)) { // eslint-disable-next-line no-param-reassign file = blob url = loadImage.createObjectURL(file) From f1a1080b82247bb1bf6a255125a4832101368b8d Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:46:24 +0900 Subject: [PATCH 015/207] Add XHR2 fallback if fetch API is not available. This adds support to parse meta data for images loaded via URL for Internet Explorer 10+. --- js/load-image-fetch.js | 35 +++++++++++++++++++++++++++++++++-- test/test.js | 5 ++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/js/load-image-fetch.js b/js/load-image-fetch.js index 5dcd119..ab64665 100644 --- a/js/load-image-fetch.js +++ b/js/load-image-fetch.js @@ -28,7 +28,7 @@ if (typeof fetch !== 'undefined' && typeof Request !== 'undefined') { loadImage.fetchBlob = function(url, callback, options) { if (loadImage.hasMetaOption(options)) { - return fetch(new Request(url, options)) + fetch(new Request(url, options)) .then(function(response) { return response.blob() }) @@ -37,8 +37,39 @@ console.log(err) // eslint-disable-line no-console callback() }) + } else { + callback() + } + } + } else if ( + // Check for XHR2 support: + typeof XMLHttpRequest !== 'undefined' && + typeof ProgressEvent !== 'undefined' + ) { + loadImage.fetchBlob = function(url, callback, options) { + if (loadImage.hasMetaOption(options)) { + // eslint-disable-next-line no-param-reassign + options = options || {} + var req = new XMLHttpRequest() + req.open(options.method || 'GET', url) + if (options.headers) { + Object.keys(options.headers).forEach(function(key) { + req.setRequestHeader(key, options.headers[key]) + }) + } + req.withCredentials = options.credentials === 'include' + req.responseType = 'blob' + req.onload = function() { + callback(req.response) + } + req.onerror = req.onabort = req.ontimeout = function(e) { + console.log(e) // eslint-disable-line no-console + callback() + } + req.send(options.body) + } else { + callback() } - callback() } } }) diff --git a/test/test.js b/test/test.js index 09f4cb3..fc1d1a7 100644 --- a/test/test.js +++ b/test/test.js @@ -875,7 +875,10 @@ }) }) - if ('fetch' in window && 'Request' in window) { + if ( + ('fetch' in window && 'Request' in window) || + ('XMLHttpRequest' in window && 'ProgressEvent' in window) + ) { describe('Fetch', function() { it('Should fetch image URL as blob if meta option is true', function(done) { expect( From e9343c4a00d052cb9c0bfd2c04527ade1a800896 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:47:41 +0900 Subject: [PATCH 016/207] Add loading images via URL support to the demo. --- index.html | 8 ++++++- js/demo/demo.js | 58 +++++++++++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index 2240e6e..3610e16 100644 --- a/index.html +++ b/index.html @@ -72,7 +72,13 @@

    JavaScript Load Image Demo

  • © Sebastian Tschan
  • Select an image file

    -

    +

    + +

    +

    Or enter an image URL into the following field:

    +

    + +

    Or drag & drop an image file onto this webpage.

    Result

    Result

    diff --git a/js/demo/demo.js b/js/demo/demo.js index cd9b62d..6dc9fa3 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -29,12 +29,16 @@ $(function () { * @param {object} tags Tags object */ function displayTagData(node, tags) { - var table = node.find('table').empty() + var table = $('') var row = $('') var cell = $('') var prop for (prop in tags) { if (Object.prototype.hasOwnProperty.call(tags, prop)) { + if (typeof tags[prop] === 'object') { + displayTagData(node, tags[prop]) + continue + } table.append( row .clone() @@ -43,7 +47,7 @@ $(function () { ) } } - node.show() + node.append(table).show() } /** @@ -55,11 +59,15 @@ $(function () { */ function displayThumbnailImage(node, thumbnail, options) { if (thumbnail) { - thumbNode.empty() + var link = $('') + .attr('href', loadImage.createObjectURL(thumbnail)) + .attr('download', 'thumbnail.jpg') + .appendTo(node) loadImage( thumbnail, function (img) { - node.append(img).show() + link.append(img) + node.show() }, options ) @@ -136,9 +144,9 @@ $(function () { orientation: true, meta: true } - exifNode.hide() - iptcNode.hide() - thumbNode.hide() + exifNode.hide().find('table').remove() + iptcNode.hide().find('table').remove() + thumbNode.hide().empty() if (!loadImage(file, updateResults, options)) { result .children() diff --git a/js/load-image-exif-map.js b/js/load-image-exif-map.js index 68d90d3..9684ae8 100644 --- a/js/load-image-exif-map.js +++ b/js/load-image-exif-map.js @@ -28,15 +28,14 @@ })(function (loadImage) { 'use strict' - loadImage.ExifMap.prototype.tags = { + var ExifMapProto = loadImage.ExifMap.prototype + + ExifMapProto.tags = { // ================= // TIFF tags (IFD0): // ================= 0x0100: 'ImageWidth', 0x0101: 'ImageHeight', - 0x8769: 'ExifIFDPointer', - 0x8825: 'GPSInfoIFDPointer', - 0xa005: 'InteroperabilityIFDPointer', 0x0102: 'BitsPerSample', 0x0103: 'Compression', 0x0106: 'PhotometricInterpretation', @@ -65,116 +64,120 @@ 0x0131: 'Software', 0x013b: 'Artist', 0x8298: 'Copyright', - // ================== - // Exif Sub IFD tags: - // ================== - 0x9000: 'ExifVersion', // EXIF version - 0xa000: 'FlashpixVersion', // Flashpix format version - 0xa001: 'ColorSpace', // Color space information tag - 0xa002: 'PixelXDimension', // Valid width of meaningful image - 0xa003: 'PixelYDimension', // Valid height of meaningful image - 0xa500: 'Gamma', - 0x9101: 'ComponentsConfiguration', // Information about channels - 0x9102: 'CompressedBitsPerPixel', // Compressed bits per pixel - 0x927c: 'MakerNote', // Any desired information written by the manufacturer - 0x9286: 'UserComment', // Comments by user - 0xa004: 'RelatedSoundFile', // Name of related sound file - 0x9003: 'DateTimeOriginal', // Date and time when the original image was generated - 0x9004: 'DateTimeDigitized', // Date and time when the image was stored digitally - 0x9290: 'SubSecTime', // Fractions of seconds for DateTime - 0x9291: 'SubSecTimeOriginal', // Fractions of seconds for DateTimeOriginal - 0x9292: 'SubSecTimeDigitized', // Fractions of seconds for DateTimeDigitized - 0x829a: 'ExposureTime', // Exposure time (in seconds) - 0x829d: 'FNumber', - 0x8822: 'ExposureProgram', // Exposure program - 0x8824: 'SpectralSensitivity', // Spectral sensitivity - 0x8827: 'PhotographicSensitivity', // EXIF 2.3, ISOSpeedRatings in EXIF 2.2 - 0x8828: 'OECF', // Optoelectric conversion factor - 0x8830: 'SensitivityType', - 0x8831: 'StandardOutputSensitivity', - 0x8832: 'RecommendedExposureIndex', - 0x8833: 'ISOSpeed', - 0x8834: 'ISOSpeedLatitudeyyy', - 0x8835: 'ISOSpeedLatitudezzz', - 0x9201: 'ShutterSpeedValue', // Shutter speed - 0x9202: 'ApertureValue', // Lens aperture - 0x9203: 'BrightnessValue', // Value of brightness - 0x9204: 'ExposureBias', // Exposure bias - 0x9205: 'MaxApertureValue', // Smallest F number of lens - 0x9206: 'SubjectDistance', // Distance to subject in meters - 0x9207: 'MeteringMode', // Metering mode - 0x9208: 'LightSource', // Kind of light source - 0x9209: 'Flash', // Flash status - 0x9214: 'SubjectArea', // Location and area of main subject - 0x920a: 'FocalLength', // Focal length of the lens in mm - 0xa20b: 'FlashEnergy', // Strobe energy in BCPS - 0xa20c: 'SpatialFrequencyResponse', - 0xa20e: 'FocalPlaneXResolution', // Number of pixels in width direction per FPRUnit - 0xa20f: 'FocalPlaneYResolution', // Number of pixels in height direction per FPRUnit - 0xa210: 'FocalPlaneResolutionUnit', // Unit for measuring the focal plane resolution - 0xa214: 'SubjectLocation', // Location of subject in image - 0xa215: 'ExposureIndex', // Exposure index selected on camera - 0xa217: 'SensingMethod', // Image sensor type - 0xa300: 'FileSource', // Image source (3 == DSC) - 0xa301: 'SceneType', // Scene type (1 == directly photographed) - 0xa302: 'CFAPattern', // Color filter array geometric pattern - 0xa401: 'CustomRendered', // Special processing - 0xa402: 'ExposureMode', // Exposure mode - 0xa403: 'WhiteBalance', // 1 = auto white balance, 2 = manual - 0xa404: 'DigitalZoomRatio', // Digital zoom ratio - 0xa405: 'FocalLengthIn35mmFilm', - 0xa406: 'SceneCaptureType', // Type of scene - 0xa407: 'GainControl', // Degree of overall image gain adjustment - 0xa408: 'Contrast', // Direction of contrast processing applied by camera - 0xa409: 'Saturation', // Direction of saturation processing applied by camera - 0xa40a: 'Sharpness', // Direction of sharpness processing applied by camera - 0xa40b: 'DeviceSettingDescription', - 0xa40c: 'SubjectDistanceRange', // Distance to subject - 0xa420: 'ImageUniqueID', // Identifier assigned uniquely to each image - 0xa430: 'CameraOwnerName', - 0xa431: 'BodySerialNumber', - 0xa432: 'LensSpecification', - 0xa433: 'LensMake', - 0xa434: 'LensModel', - 0xa435: 'LensSerialNumber', - // ============== - // GPS Info tags: - // ============== - 0x0000: 'GPSVersionID', - 0x0001: 'GPSLatitudeRef', - 0x0002: 'GPSLatitude', - 0x0003: 'GPSLongitudeRef', - 0x0004: 'GPSLongitude', - 0x0005: 'GPSAltitudeRef', - 0x0006: 'GPSAltitude', - 0x0007: 'GPSTimeStamp', - 0x0008: 'GPSSatellites', - 0x0009: 'GPSStatus', - 0x000a: 'GPSMeasureMode', - 0x000b: 'GPSDOP', - 0x000c: 'GPSSpeedRef', - 0x000d: 'GPSSpeed', - 0x000e: 'GPSTrackRef', - 0x000f: 'GPSTrack', - 0x0010: 'GPSImgDirectionRef', - 0x0011: 'GPSImgDirection', - 0x0012: 'GPSMapDatum', - 0x0013: 'GPSDestLatitudeRef', - 0x0014: 'GPSDestLatitude', - 0x0015: 'GPSDestLongitudeRef', - 0x0016: 'GPSDestLongitude', - 0x0017: 'GPSDestBearingRef', - 0x0018: 'GPSDestBearing', - 0x0019: 'GPSDestDistanceRef', - 0x001a: 'GPSDestDistance', - 0x001b: 'GPSProcessingMethod', - 0x001c: 'GPSAreaInformation', - 0x001d: 'GPSDateStamp', - 0x001e: 'GPSDifferential', - 0x001f: 'GPSHPositioningError' + 0x8769: { + // ExifIFDPointer + 0x9000: 'ExifVersion', // EXIF version + 0xa000: 'FlashpixVersion', // Flashpix format version + 0xa001: 'ColorSpace', // Color space information tag + 0xa002: 'PixelXDimension', // Valid width of meaningful image + 0xa003: 'PixelYDimension', // Valid height of meaningful image + 0xa500: 'Gamma', + 0x9101: 'ComponentsConfiguration', // Information about channels + 0x9102: 'CompressedBitsPerPixel', // Compressed bits per pixel + 0x927c: 'MakerNote', // Any desired information written by the manufacturer + 0x9286: 'UserComment', // Comments by user + 0xa004: 'RelatedSoundFile', // Name of related sound file + 0x9003: 'DateTimeOriginal', // Date and time when the original image was generated + 0x9004: 'DateTimeDigitized', // Date and time when the image was stored digitally + 0x9290: 'SubSecTime', // Fractions of seconds for DateTime + 0x9291: 'SubSecTimeOriginal', // Fractions of seconds for DateTimeOriginal + 0x9292: 'SubSecTimeDigitized', // Fractions of seconds for DateTimeDigitized + 0x829a: 'ExposureTime', // Exposure time (in seconds) + 0x829d: 'FNumber', + 0x8822: 'ExposureProgram', // Exposure program + 0x8824: 'SpectralSensitivity', // Spectral sensitivity + 0x8827: 'PhotographicSensitivity', // EXIF 2.3, ISOSpeedRatings in EXIF 2.2 + 0x8828: 'OECF', // Optoelectric conversion factor + 0x8830: 'SensitivityType', + 0x8831: 'StandardOutputSensitivity', + 0x8832: 'RecommendedExposureIndex', + 0x8833: 'ISOSpeed', + 0x8834: 'ISOSpeedLatitudeyyy', + 0x8835: 'ISOSpeedLatitudezzz', + 0x9201: 'ShutterSpeedValue', // Shutter speed + 0x9202: 'ApertureValue', // Lens aperture + 0x9203: 'BrightnessValue', // Value of brightness + 0x9204: 'ExposureBias', // Exposure bias + 0x9205: 'MaxApertureValue', // Smallest F number of lens + 0x9206: 'SubjectDistance', // Distance to subject in meters + 0x9207: 'MeteringMode', // Metering mode + 0x9208: 'LightSource', // Kind of light source + 0x9209: 'Flash', // Flash status + 0x9214: 'SubjectArea', // Location and area of main subject + 0x920a: 'FocalLength', // Focal length of the lens in mm + 0xa20b: 'FlashEnergy', // Strobe energy in BCPS + 0xa20c: 'SpatialFrequencyResponse', + 0xa20e: 'FocalPlaneXResolution', // Number of pixels in width direction per FPRUnit + 0xa20f: 'FocalPlaneYResolution', // Number of pixels in height direction per FPRUnit + 0xa210: 'FocalPlaneResolutionUnit', // Unit for measuring the focal plane resolution + 0xa214: 'SubjectLocation', // Location of subject in image + 0xa215: 'ExposureIndex', // Exposure index selected on camera + 0xa217: 'SensingMethod', // Image sensor type + 0xa300: 'FileSource', // Image source (3 == DSC) + 0xa301: 'SceneType', // Scene type (1 == directly photographed) + 0xa302: 'CFAPattern', // Color filter array geometric pattern + 0xa401: 'CustomRendered', // Special processing + 0xa402: 'ExposureMode', // Exposure mode + 0xa403: 'WhiteBalance', // 1 = auto white balance, 2 = manual + 0xa404: 'DigitalZoomRatio', // Digital zoom ratio + 0xa405: 'FocalLengthIn35mmFilm', + 0xa406: 'SceneCaptureType', // Type of scene + 0xa407: 'GainControl', // Degree of overall image gain adjustment + 0xa408: 'Contrast', // Direction of contrast processing applied by camera + 0xa409: 'Saturation', // Direction of saturation processing applied by camera + 0xa40a: 'Sharpness', // Direction of sharpness processing applied by camera + 0xa40b: 'DeviceSettingDescription', + 0xa40c: 'SubjectDistanceRange', // Distance to subject + 0xa420: 'ImageUniqueID', // Identifier assigned uniquely to each image + 0xa430: 'CameraOwnerName', + 0xa431: 'BodySerialNumber', + 0xa432: 'LensSpecification', + 0xa433: 'LensMake', + 0xa434: 'LensModel', + 0xa435: 'LensSerialNumber' + }, + 0x8825: { + // GPSInfoIFDPointer + 0x0000: 'GPSVersionID', + 0x0001: 'GPSLatitudeRef', + 0x0002: 'GPSLatitude', + 0x0003: 'GPSLongitudeRef', + 0x0004: 'GPSLongitude', + 0x0005: 'GPSAltitudeRef', + 0x0006: 'GPSAltitude', + 0x0007: 'GPSTimeStamp', + 0x0008: 'GPSSatellites', + 0x0009: 'GPSStatus', + 0x000a: 'GPSMeasureMode', + 0x000b: 'GPSDOP', + 0x000c: 'GPSSpeedRef', + 0x000d: 'GPSSpeed', + 0x000e: 'GPSTrackRef', + 0x000f: 'GPSTrack', + 0x0010: 'GPSImgDirectionRef', + 0x0011: 'GPSImgDirection', + 0x0012: 'GPSMapDatum', + 0x0013: 'GPSDestLatitudeRef', + 0x0014: 'GPSDestLatitude', + 0x0015: 'GPSDestLongitudeRef', + 0x0016: 'GPSDestLongitude', + 0x0017: 'GPSDestBearingRef', + 0x0018: 'GPSDestBearing', + 0x0019: 'GPSDestDistanceRef', + 0x001a: 'GPSDestDistance', + 0x001b: 'GPSProcessingMethod', + 0x001c: 'GPSAreaInformation', + 0x001d: 'GPSDateStamp', + 0x001e: 'GPSDifferential', + 0x001f: 'GPSHPositioningError' + }, + 0xa005: { + // InteroperabilityIFDPointer + 0x0001: 'InteroperabilityIndex' + } } - loadImage.ExifMap.prototype.stringValues = { + ExifMapProto.stringValues = { ExposureProgram: { 0: 'Undefined', 1: 'Manual', @@ -321,9 +324,9 @@ } } - loadImage.ExifMap.prototype.getText = function (id) { - var value = this.get(id) - switch (id) { + ExifMapProto.getText = function (name) { + var value = this.get(name) + switch (name) { case 'LightSource': case 'Flash': case 'MeteringMode': @@ -340,7 +343,7 @@ case 'SubjectDistanceRange': case 'FileSource': case 'Orientation': - return this.stringValues[id][value] + return this.stringValues[name][value] case 'ExifVersion': case 'FlashpixVersion': if (!value) return @@ -348,10 +351,10 @@ case 'ComponentsConfiguration': if (!value) return return ( - this.stringValues[id][value[0]] + - this.stringValues[id][value[1]] + - this.stringValues[id][value[2]] + - this.stringValues[id][value[3]] + this.stringValues[name][value[0]] + + this.stringValues[name][value[1]] + + this.stringValues[name][value[2]] + + this.stringValues[name][value[3]] ) case 'GPSVersionID': if (!value) return @@ -359,30 +362,53 @@ } return String(value) } - ;(function (exifMapPrototype) { - var tags = exifMapPrototype.tags - var map = exifMapPrototype.map - var prop - // Map the tag names to tags: - for (prop in tags) { - if (Object.prototype.hasOwnProperty.call(tags, prop)) { - map[tags[prop]] = prop - } - } - })(loadImage.ExifMap.prototype) - loadImage.ExifMap.prototype.getAll = function () { + ExifMapProto.getAll = function () { var map = {} var prop - var id + var obj + var name for (prop in this) { if (Object.prototype.hasOwnProperty.call(this, prop)) { - id = this.tags[prop] - if (id) { - map[id] = this.getText(id) + obj = this[prop] + if (obj && obj.getAll) { + map[this.privateIFDs[prop].name] = obj.getAll() + } else { + name = this.tags[prop] + if (name) map[name] = this.getText(name) } } } return map } + + ExifMapProto.getName = function (tagCode) { + var name = this.tags[tagCode] + if (typeof name === 'object') return this.privateIFDs[tagCode].name + return name + } + + // Extend the map of tag names to tag codes: + ;(function () { + var tags = ExifMapProto.tags + var prop + var privateIFD + var subTags + // Map the tag names to tags: + for (prop in tags) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { + privateIFD = ExifMapProto.privateIFDs[prop] + if (privateIFD) { + subTags = tags[prop] + for (prop in subTags) { + if (Object.prototype.hasOwnProperty.call(subTags, prop)) { + privateIFD.map[subTags[prop]] = Number(prop) + } + } + } else { + ExifMapProto.map[tags[prop]] = Number(prop) + } + } + } + })() }) diff --git a/js/load-image-exif.js b/js/load-image-exif.js index 74c2632..7dff053 100644 --- a/js/load-image-exif.js +++ b/js/load-image-exif.js @@ -27,28 +27,67 @@ })(function (loadImage) { 'use strict' - loadImage.ExifMap = function () { - return this + /** + * Exif tag map + * + * @name ExifMap + * @class + * @param {number} tagCode Private IFD tag code + */ + function ExifMap(tagCode) { + if (tagCode) { + Object.defineProperty(this, 'map', { + value: this.privateIFDs[tagCode].map + }) + Object.defineProperty(this, 'tags', { + value: (this.tags && this.tags[tagCode]) || {} + }) + } } - loadImage.ExifMap.prototype.map = { + ExifMap.prototype.map = { Orientation: 0x0112, - Thumbnail: 0x0201 + Thumbnail: 0x0201, + Exif: 0x8769, + GPSInfo: 0x8825, + Interoperability: 0xa005 + } + + ExifMap.prototype.privateIFDs = { + 0x8769: { name: 'Exif', map: {} }, + 0x8825: { name: 'GPSInfo', map: {} }, + 0xa005: { name: 'Interoperability', map: {} } } - loadImage.ExifMap.prototype.get = function (id) { + /** + * Retrieves exif tag value + * + * @param {number|string} id Exif tag code or name + * @returns {object} Exif tag value + */ + ExifMap.prototype.get = function (id) { return this[id] || this[this.map[id]] } - loadImage.getExifThumbnail = function (dataView, offset, length) { + /** + * Returns the Exif Thumbnail data as Blob. + * + * @param {DataView} dataView Data view interface + * @param {number} offset Thumbnail data offset + * @param {number} length Thumbnail data length + * @returns {undefined|Blob} Returns the Thumbnail Blob or undefined + */ + function getExifThumbnail(dataView, offset, length) { if (!length || offset + length > dataView.byteLength) { console.log('Invalid Exif data: Invalid thumbnail data.') return } - return new Blob([dataView.buffer.slice(offset, offset + length)]) + return new Blob([dataView.buffer.slice(offset, offset + length)], { + type: 'image/jpeg' + }) } - loadImage.exifTagTypes = { + var ExifTagTypes = { // byte, 8-bit unsigned int: 1: { getValue: function (dataView, dataOffset) { @@ -107,9 +146,20 @@ } } // undefined, 8-bit byte, value depending on field: - loadImage.exifTagTypes[7] = loadImage.exifTagTypes[1] + ExifTagTypes[7] = ExifTagTypes[1] - loadImage.getExifValue = function ( + /** + * Returns Exif tag value. + * + * @param {DataView} dataView Data view interface + * @param {number} tiffOffset TIFF offset + * @param {number} offset Tag offset + * @param {number} type Tag type + * @param {number} length Tag length + * @param {boolean} littleEndian Little endian encoding + * @returns {object} Tag value + */ + function getExifValue( dataView, tiffOffset, offset, @@ -117,7 +167,7 @@ length, littleEndian ) { - var tagType = loadImage.exifTagTypes[type] + var tagType = ExifTagTypes[type] var tagSize var dataOffset var values @@ -166,33 +216,30 @@ return values } - loadImage.parseExifTag = function ( - dataView, - tiffOffset, - offset, - littleEndian - ) { - return { - number: dataView.getUint16(offset, littleEndian), - value: loadImage.getExifValue( - dataView, - tiffOffset, - offset, - dataView.getUint16(offset + 2, littleEndian), // tag type - dataView.getUint32(offset + 4, littleEndian), // tag length - littleEndian - ) - } - } - - loadImage.parseExifTags = function ( + /** + * Parses Exif tags. + * + * @param {DataView} dataView Data view interface + * @param {number} tiffOffset TIFF offset + * @param {number} dirOffset Directory offset + * @param {boolean} littleEndian Little endian encoding + * @param {ExifMap} tags Map to store parsed exif tags + * @param {ExifMap} tagOffsets Map to store parsed exif tag offsets + * @param {object} includeTags Map of tags to include + * @param {object} excludeTags Map of tags to exclude + * @returns {number} Next directory offset + */ + function parseExifTags( dataView, tiffOffset, dirOffset, littleEndian, - data + tags, + tagOffsets, + includeTags, + excludeTags ) { - var tagsNumber, dirEndOffset, i, tagOffset, tag + var tagsNumber, dirEndOffset, i, tagOffset, tagNumber, tagValue if (dirOffset + 6 > dataView.byteLength) { console.log('Invalid Exif data: Invalid directory offset.') return @@ -205,29 +252,80 @@ } for (i = 0; i < tagsNumber; i += 1) { tagOffset = dirOffset + 2 + 12 * i - tag = this.parseExifTag( + tagNumber = dataView.getUint16(tagOffset, littleEndian) + if (includeTags && !includeTags[tagNumber]) continue + if (excludeTags && excludeTags[tagNumber] === true) continue + tagValue = getExifValue( dataView, tiffOffset, tagOffset, - littleEndian, - data + dataView.getUint16(tagOffset + 2, littleEndian), // tag type + dataView.getUint32(tagOffset + 4, littleEndian), // tag length + littleEndian ) - data.exif[tag.number] = tag.value - if (data.exifOffsets) { - data.exifOffsets[tag.number] = tagOffset + tags[tagNumber] = tagValue + if (tagOffsets) { + tagOffsets[tagNumber] = tagOffset } } // Return the offset to the next directory: return dataView.getUint32(dirEndOffset, littleEndian) } + /** + * Parses Private IFD tags. + * + * @param {object} data Data object to store exif tags and offsets + * @param {number} tagCode Private IFD tag code + * @param {DataView} dataView Data view interface + * @param {number} tiffOffset TIFF offset + * @param {boolean} littleEndian Little endian encoding + * @param {object} includeTags Map of tags to include + * @param {object} excludeTags Map of tags to exclude + */ + function parseExifPrivateIFD( + data, + tagCode, + dataView, + tiffOffset, + littleEndian, + includeTags, + excludeTags + ) { + var dirOffset = data.exif[tagCode] + if (dirOffset) { + data.exif[tagCode] = new ExifMap(tagCode) + if (data.exifOffsets) { + data.exifOffsets[tagCode] = new ExifMap(tagCode) + } + parseExifTags( + dataView, + tiffOffset, + tiffOffset + dirOffset, + littleEndian, + data.exif[tagCode], + data.exifOffsets && data.exifOffsets[tagCode], + includeTags && includeTags[tagCode], + excludeTags && excludeTags[tagCode] + ) + } + } + loadImage.parseExifData = function (dataView, offset, length, data, options) { if (options.disableExif) { return } + var includeTags = options.includeExifTags + var excludeTags = options.excludeExifTags || { + 0x8769: { + // ExifIFDPointer + 0x927c: true // MakerNote + } + } var tiffOffset = offset + 10 var littleEndian var dirOffset + var privateIFDs // Check for the ASCII code for "Exif" (0x45786966): if (dataView.getUint32(offset + 4) !== 0x45786966) { // No Exif data, might be XMP data instead @@ -262,58 +360,56 @@ // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal: dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian) // Create the exif object to store the tags: - data.exif = new loadImage.ExifMap() + data.exif = new ExifMap() if (!options.disableExifOffsets) { - data.exifOffsets = new loadImage.ExifMap() + data.exifOffsets = new ExifMap() data.exifTiffOffset = tiffOffset data.exifLittleEndian = littleEndian } // Parse the tags of the main image directory and retrieve the // offset to the next directory, usually the thumbnail directory: - dirOffset = loadImage.parseExifTags( + dirOffset = parseExifTags( dataView, tiffOffset, tiffOffset + dirOffset, littleEndian, - data + data.exif, + data.exifOffsets, + includeTags, + excludeTags ) if (dirOffset && !options.disableExifThumbnail) { - dirOffset = loadImage.parseExifTags( + dirOffset = parseExifTags( dataView, tiffOffset, tiffOffset + dirOffset, littleEndian, - data + data.exif, + data.exifOffsets, + includeTags, + excludeTags ) // Check for JPEG Thumbnail offset: - if (data.exif[0x0201]) { - data.exif[0x0201] = loadImage.getExifThumbnail( + if (data.exif[0x0201] && data.exif[0x0202]) { + data.exif[0x0201] = getExifThumbnail( dataView, tiffOffset + data.exif[0x0201], data.exif[0x0202] // Thumbnail data length ) } } - // Check for Exif Sub IFD Pointer: - if (data.exif[0x8769] && !options.disableExifSub) { - loadImage.parseExifTags( - dataView, - tiffOffset, - tiffOffset + data.exif[0x8769], // directory offset - littleEndian, - data - ) - } - // Check for GPS Info IFD Pointer: - if (data.exif[0x8825] && !options.disableExifGps) { - loadImage.parseExifTags( + privateIFDs = Object.keys(data.exif.privateIFDs) + privateIFDs.forEach(function (tagCode) { + parseExifPrivateIFD( + data, + tagCode, dataView, tiffOffset, - tiffOffset + data.exif[0x8825], // directory offset littleEndian, - data + includeTags, + excludeTags ) - } + }) } // Registers the Exif parser for the APP1 JPEG meta data segment: @@ -332,16 +428,18 @@ loadImage.exifWriters[data.exif.map[id]](buffer, data, value) } + loadImage.ExifMap = ExifMap + // Adds the following properties to the parseMetaData callback data: - // * exif: The parsed Exif tags - // * exifOffsets: The parsed Exif tag offsets - // * exifTiffOffset: TIFF header offset (used for offset pointers) - // * exifLittleEndian: little endian order if true, big endian if false + // - exif: The parsed Exif tags + // - exifOffsets: The parsed Exif tag offsets + // - exifTiffOffset: TIFF header offset (used for offset pointers) + // - exifLittleEndian: little endian order if true, big endian if false // Adds the following options to the parseMetaData method: - // * disableExif: Disables Exif parsing. - // * disableExifThumbnail: Disables parsing of the Exif Thumbnail. - // * disableExifSub: Disables parsing of the Exif Sub IFD. - // * disableExifGps: Disables parsing of the Exif GPS Info IFD. - // * disableExifOffsets: Disables storing Exif tag offsets + // - disableExif: Disables Exif parsing when true. + // - disableExifThumbnail: Disables parsing of Thumbnail data when true. + // - disableExifOffsets: Disables storing Exif tag offsets when true. + // - includeExifTags: A map of Exif tags to include for parsing. + // - excludeExifTags: A map of Exif tags to exclude from parsing. }) diff --git a/js/load-image-iptc-map.js b/js/load-image-iptc-map.js index adffa21..165d17d 100644 --- a/js/load-image-iptc-map.js +++ b/js/load-image-iptc-map.js @@ -6,9 +6,8 @@ * Copyright 2018, Dave Bevan * * IPTC tags mapping based on - * https://github.com/jseidelin/exif-js * https://iptc.org/standards/photo-metadata - * http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf + * https://exiftool.org/TagNames/IPTC.html * * Licensed under the MIT license: * https://opensource.org/licenses/MIT @@ -30,100 +29,141 @@ })(function (loadImage) { 'use strict' - loadImage.IptcMap.prototype.tags = { - // ========== - // IPTC tags: - // ========== - 0x03: 'ObjectType', - 0x04: 'ObjectAttribute', - 0x05: 'ObjectName', - 0x07: 'EditStatus', - 0x08: 'EditorialUpdate', - 0x0a: 'Urgency', - 0x0c: 'SubjectRef', - 0x0f: 'Category', - 0x14: 'SupplCategory', - 0x16: 'FixtureID', - 0x19: 'Keywords', - 0x1a: 'ContentLocCode', - 0x1b: 'ContentLocName', - 0x1e: 'ReleaseDate', - 0x23: 'ReleaseTime', - 0x25: 'ExpirationDate', - 0x26: 'ExpirationTime', - 0x28: 'SpecialInstructions', - 0x2a: 'ActionAdvised', - 0x2d: 'RefService', - 0x2f: 'RefDate', - 0x32: 'RefNumber', - 0x37: 'DateCreated', - 0x3c: 'TimeCreated', - 0x3e: 'DigitalCreationDate', - 0x3f: 'DigitalCreationTime', - 0x41: 'OriginatingProgram', - 0x46: 'ProgramVersion', - 0x4b: 'ObjectCycle', - 0x50: 'Byline', - 0x55: 'BylineTitle', - 0x5a: 'City', - 0x5c: 'Sublocation', - 0x5f: 'State', - 0x64: 'CountryCode', - 0x65: 'CountryName', - 0x67: 'OrigTransRef', - 0x69: 'Headline', - 0x6e: 'Credit', - 0x73: 'Source', - 0x74: 'CopyrightNotice', - 0x76: 'Contact', - 0x78: 'Caption', - 0x7a: 'WriterEditor', - 0x82: 'ImageType', - 0x83: 'ImageOrientation', - 0x87: 'LanguageID' + var IptcMapProto = loadImage.IptcMap.prototype - // We don't record these tags: - // - // 0x00: 'RecordVersion', - // 0x7d: 'RasterizedCaption', - // 0x96: 'AudioType', - // 0x97: 'AudioSamplingRate', - // 0x98: 'AudioSamplingRes', - // 0x99: 'AudioDuration', - // 0x9a: 'AudioOutcue', - // 0xc8: 'PreviewFileFormat', - // 0xc9: 'PreviewFileFormatVer', - // 0xca: 'PreviewData' + IptcMapProto.tags = { + 0: 'ApplicationRecordVersion', + 3: 'ObjectTypeReference', + 4: 'ObjectAttributeReference', + 5: 'ObjectName', + 7: 'EditStatus', + 8: 'EditorialUpdate', + 10: 'Urgency', + 12: 'SubjectReference', + 15: 'Category', + 20: 'SupplementalCategories', + 22: 'FixtureIdentifier', + 25: 'Keywords', + 26: 'ContentLocationCode', + 27: 'ContentLocationName', + 30: 'ReleaseDate', + 35: 'ReleaseTime', + 37: 'ExpirationDate', + 38: 'ExpirationTime', + 40: 'SpecialInstructions', + 42: 'ActionAdvised', + 45: 'ReferenceService', + 47: 'ReferenceDate', + 50: 'ReferenceNumber', + 55: 'DateCreated', + 60: 'TimeCreated', + 62: 'DigitalCreationDate', + 63: 'DigitalCreationTime', + 65: 'OriginatingProgram', + 70: 'ProgramVersion', + 75: 'ObjectCycle', + 80: 'Byline', + 85: 'BylineTitle', + 90: 'City', + 92: 'Sublocation', + 95: 'State', + 100: 'CountryCode', + 101: 'Country', + 103: 'OriginalTransmissionReference', + 105: 'Headline', + 110: 'Credit', + 115: 'Source', + 116: 'CopyrightNotice', + 118: 'Contact', + 120: 'Caption', + 121: 'LocalCaption', + 122: 'Writer', + 125: 'RasterizedCaption', + 130: 'ImageType', + 131: 'ImageOrientation', + 135: 'LanguageIdentifier', + 150: 'AudioType', + 151: 'AudioSamplingRate', + 152: 'AudioSamplingResolution', + 153: 'AudioDuration', + 154: 'AudioOutcue', + 184: 'JobID', + 185: 'MasterDocumentID', + 186: 'ShortDocumentID', + 187: 'UniqueDocumentID', + 188: 'OwnerID', + 200: 'ObjectPreviewFileFormat', + 201: 'ObjectPreviewFileVersion', + 202: 'ObjectPreviewData', + 221: 'Prefs', + 225: 'ClassifyState', + 228: 'SimilarityIndex', + 230: 'DocumentNotes', + 231: 'DocumentHistory', + 232: 'ExifCameraInfo', + 255: 'CatalogSets' } - loadImage.IptcMap.prototype.getText = function (id) { + IptcMapProto.stringValues = { + 10: { + 0: '0 (reserved)', + 1: '1 (most urgent)', + 2: '2', + 3: '3', + 4: '4', + 5: '5 (normal urgency)', + 6: '6', + 7: '7', + 8: '8 (least urgent)', + 9: '9 (user-defined priority)' + }, + 75: { + a: 'Morning', + b: 'Both Morning and Evening', + p: 'Evening' + }, + 131: { + L: 'Landscape', + P: 'Portrait', + S: 'Square' + } + } + + IptcMapProto.getText = function (id) { var value = this.get(id) + var tagCode = this.map[id] + var stringValue = this.stringValues[tagCode] + if (stringValue) return stringValue[value] return String(value) } - ;(function (iptcMapPrototype) { - var tags = iptcMapPrototype.tags - var map = iptcMapPrototype.map || {} - var prop - // Map the tag names to tags: - for (prop in tags) { - if (Object.prototype.hasOwnProperty.call(tags, prop)) { - map[tags[prop]] = prop - } - } - })(loadImage.IptcMap.prototype) - loadImage.IptcMap.prototype.getAll = function () { + IptcMapProto.getAll = function () { var map = {} var prop - var id + var name for (prop in this) { if (Object.prototype.hasOwnProperty.call(this, prop)) { - id = this.tags[prop] - if (id) { - map[id] = this.getText(id) - } + name = this.tags[prop] + if (name) map[name] = this.getText(name) } } return map } + + IptcMapProto.getName = function (tagCode) { + return this.tags[tagCode] + } + + // Extend the map of tag names to tag codes: + ;(function () { + var tags = IptcMapProto.tags + var map = IptcMapProto.map || {} + var prop + // Map the tag names to tags: + for (prop in tags) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { + map[tags[prop]] = Number(prop) + } + } + })() }) diff --git a/js/load-image-iptc.js b/js/load-image-iptc.js index c7ce7c1..9f6a900 100644 --- a/js/load-image-iptc.js +++ b/js/load-image-iptc.js @@ -10,7 +10,7 @@ * https://opensource.org/licenses/MIT */ -/* global define, module, require, Buffer */ +/* global define, module, require, DataView */ ;(function (factory) { 'use strict' @@ -26,128 +26,214 @@ })(function (loadImage) { 'use strict' - loadImage.IptcMap = function () { - return this + /** + * IPTC tag map + * + * @name IptcMap + * @class + */ + function IptcMap() {} + + IptcMap.prototype.map = { + ObjectName: 5 } - loadImage.IptcMap.prototype.map = { - ObjectName: 0x5 + IptcMap.prototype.types = { + 0: 'Uint16', // ApplicationRecordVersion + 200: 'Uint16', // ObjectPreviewFileFormat + 201: 'Uint16', // ObjectPreviewFileVersion + 202: 'binary' // ObjectPreviewData } - loadImage.IptcMap.prototype.get = function (id) { + /** + * Retrieves IPTC tag value + * + * @param {number|string} id IPTC tag code or name + * @returns {object} IPTC tag value + */ + IptcMap.prototype.get = function (id) { return this[id] || this[this.map[id]] } - loadImage.parseIptcTags = function ( + /** + * Retrieves string for the given DataView and range + * + * @param {DataView} dataView Data view interface + * @param {number} offset Offset start + * @param {number} length Offset length + * @returns {string} String value + */ + function getStringValue(dataView, offset, length) { + var outstr = '' + var end = offset + length + for (var n = offset; n < end; n += 1) { + outstr += String.fromCharCode(dataView.getUint8(n)) + } + return outstr + } + + /** + * Retrieves tag value for the given DataView and range + * + * @param {number} tagCode Private IFD tag code + * @param {IptcMap} map IPTC tag map + * @param {DataView} dataView Data view interface + * @param {number} offset Range start + * @param {number} length Range length + * @returns {object} Tag value + */ + function getTagValue(tagCode, map, dataView, offset, length) { + if (map.types[tagCode] === 'binary') { + return new Blob([dataView.buffer.slice(offset, offset + length)]) + } + if (map.types[tagCode] === 'Uint16') { + return dataView.getUint16(offset) + } + return getStringValue(dataView, offset, length) + } + + /** + * Combines IPTC value with existing ones. + * + * @param {object} value Existing IPTC field value + * @param {object} newValue New IPTC field value + * @returns {object} Resulting IPTC field value + */ + function combineTagValues(value, newValue) { + if (value === undefined) return newValue + if (value instanceof Array) { + value.push(newValue) + return value + } + return [value, newValue] + } + + /** + * Parses IPTC tags. + * + * @param {DataView} dataView Data view interface + * @param {number} segmentOffset Segment offset + * @param {number} segmentLength Segment length + * @param {object} data Data export object + * @param {object} includeTags Map of tags to include + * @param {object} excludeTags Map of tags to exclude + */ + function parseIptcTags( dataView, - startOffset, - sectionLength, - data + segmentOffset, + segmentLength, + data, + includeTags, + excludeTags ) { - /** - * Retrieves string for the given Buffer and range - * - * @param {Buffer} buffer IPTC buffer - * @param {number} start Range start - * @param {number} length Range length - * @returns {string} String value - */ - function getStringFromDB(buffer, start, length) { - var outstr = '' - for (var n = start; n < start + length; n++) { - outstr += String.fromCharCode(buffer.getUint8(n)) - } - return outstr - } - var fieldValue, dataSize, segmentType - var segmentStartPos = startOffset - while (segmentStartPos < startOffset + sectionLength) { - // we currently handle the 2: class of iptc tag + var value, tagSize, tagCode + var segmentEnd = segmentOffset + segmentLength + var offset = segmentOffset + while (offset < segmentEnd) { if ( - dataView.getUint8(segmentStartPos) === 0x1c && - dataView.getUint8(segmentStartPos + 1) === 0x02 + dataView.getUint8(offset) === 0x1c && // tag marker + dataView.getUint8(offset + 1) === 0x02 // record number, only handles v2 ) { - segmentType = dataView.getUint8(segmentStartPos + 2) - // only store data for known tags - if (segmentType in data.iptc.tags) { - dataSize = dataView.getInt16(segmentStartPos + 3) - fieldValue = getStringFromDB(dataView, segmentStartPos + 5, dataSize) - // Check if we already stored a value with this name - if (Object.prototype.hasOwnProperty.call(data.iptc, segmentType)) { - // Value already stored with this name, create multivalue field - if (data.iptc[segmentType] instanceof Array) { - data.iptc[segmentType].push(fieldValue) - } else { - data.iptc[segmentType] = [data.iptc[segmentType], fieldValue] - } - } else { - data.iptc[segmentType] = fieldValue + tagCode = dataView.getUint8(offset + 2) + if ( + (!includeTags || includeTags[tagCode]) && + (!excludeTags || !excludeTags[tagCode]) + ) { + tagSize = dataView.getInt16(offset + 3) + value = getTagValue(tagCode, data.iptc, dataView, offset + 5, tagSize) + data.iptc[tagCode] = combineTagValues(data.iptc[tagCode], value) + if (data.iptcOffsets) { + data.iptcOffsets[tagCode] = offset } } } - segmentStartPos++ + offset += 1 } } + /** + * Tests if field segment starts at offset. + * + * @param {DataView} dataView Data view interface + * @param {number} offset Segment offset + * @returns {boolean} True if '8BIM' exists at offset + */ + function isSegmentStart(dataView, offset) { + return ( + dataView.getUint32(offset) === 0x3842494d && // Photoshop segment start + dataView.getUint16(offset + 4) === 0x0404 // IPTC segment start + ) + } + + /** + * Returns header length. + * + * @param {DataView} dataView Data view interface + * @param {number} offset Segment offset + * @returns {number} Header length + */ + function getHeaderLength(dataView, offset) { + var length = dataView.getUint8(offset + 7) + if (length % 2 !== 0) length += 1 + // Check for pre photoshop 6 format + if (length === 0) { + // Always 4 + length = 4 + } + return length + } + loadImage.parseIptcData = function (dataView, offset, length, data, options) { if (options.disableIptc) { return } var markerLength = offset + length - // Found '8BIM' ? - var isFieldSegmentStart = function (dataView, offset) { - return ( - dataView.getUint32(offset) === 0x3842494d && - dataView.getUint16(offset + 4) === 0x0404 - ) - } - // Hunt forward, looking for the correct IPTC block signature: - // Reference: https://metacpan.org/pod/distribution/Image-MetaData-JPEG/lib/Image/MetaData/JPEG/Structures.pod#Structure-of-a-Photoshop-style-APP13-segment - // From https://github.com/exif-js/exif-js/blob/master/exif.js ~ line 474 on while (offset + 8 < markerLength) { - if (isFieldSegmentStart(dataView, offset)) { - var nameHeaderLength = dataView.getUint8(offset + 7) - if (nameHeaderLength % 2 !== 0) nameHeaderLength += 1 - // Check for pre photoshop 6 format - if (nameHeaderLength === 0) { - // Always 4 - nameHeaderLength = 4 - } - var startOffset = offset + 8 + nameHeaderLength - if (startOffset > markerLength) { + if (isSegmentStart(dataView, offset)) { + var headerLength = getHeaderLength(dataView, offset) + var segmentOffset = offset + 8 + headerLength + if (segmentOffset > markerLength) { // eslint-disable-next-line no-console console.log('Invalid IPTC data: Invalid segment offset.') break } - var sectionLength = dataView.getUint16(offset + 6 + nameHeaderLength) - if (offset + sectionLength > markerLength) { + var segmentLength = dataView.getUint16(offset + 6 + headerLength) + if (offset + segmentLength > markerLength) { // eslint-disable-next-line no-console console.log('Invalid IPTC data: Invalid segment size.') break } // Create the iptc object to store the tags: - data.iptc = new loadImage.IptcMap() - // Parse the tags - return loadImage.parseIptcTags( + data.iptc = new IptcMap() + if (!options.disableIptcOffsets) { + data.iptcOffsets = new IptcMap() + } + parseIptcTags( dataView, - startOffset, - sectionLength, - data + segmentOffset, + segmentLength, + data, + options.includeIptcTags, + options.excludeIptcTags || { 202: true } // ObjectPreviewData ) + return } // eslint-disable-next-line no-param-reassign - offset++ + offset += 1 } - // eslint-disable-next-line no-console - console.log('No IPTC data at this offset - could be XMP') } // Registers this IPTC parser for the APP13 JPEG meta data segment: loadImage.metaDataParsers.jpeg[0xffed].push(loadImage.parseIptcData) + loadImage.IptcMap = IptcMap + // Adds the following properties to the parseMetaData callback data: - // * iptc: The iptc tags, parsed by the parseIptcData method + // - iptc: The iptc tags, parsed by the parseIptcData method // Adds the following options to the parseMetaData method: - // * disableIptc: Disables IPTC parsing. + // - disableIptc: Disables IPTC parsing when true. + // - disableIptcOffsets: Disables storing IPTC tag offsets when true. + // - includeIptcTags: A map of IPTC tags to include for parsing. + // - excludeIptcTags: A map of IPTC tags to exclude from parsing. }) diff --git a/test/test.js b/test/test.js index e33843c..6f2b039 100644 --- a/test/test.js +++ b/test/test.js @@ -989,6 +989,17 @@ }) }) + it('Should not parse Exif tags if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.undefined + done() + }, + { disableExif: true } + ) + }) + it('Should parse Exif tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exifOffsets).to.be.ok @@ -999,6 +1010,57 @@ }) }) + it('Should not parse Exif tag offsets if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exifOffsets).to.be.undefined + done() + }, + { disableExifOffsets: true } + ) + }) + + it('Should only parse included Exif tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.equal(6) + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.be.undefined + done() + }, + { includeExifTags: { 0x0132: true } } // DateTime + ) + }, + { includeExifTags: { 0x0112: true } } // Orientation + ) + }) + + it('Should not parse excluded Exif tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.equal(6) + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.be.undefined + done() + }, + { excludeExifTags: { 0x0112: true } } // Orientation + ) + }, + { excludeExifTags: { 0x0132: true } } // DateTime + ) + }) + it('Should parse IPTC tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.iptc).to.be.ok @@ -1007,6 +1069,80 @@ }) }) + it('Should not parse IPTC tags if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.undefined + done() + }, + { disableIptc: true } + ) + }) + + it('Should parse IPTC tag offsets', function (done) { + loadImage.parseMetaData(blobJPEG, function (data) { + expect(data.iptcOffsets).to.be.ok + expect(data.iptcOffsets.get('ObjectName')).to.equal(0x44) + done() + }) + }) + + it('Should not parse IPTC tag offsets if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptcOffsets).to.be.undefined + done() + }, + { disableIptcOffsets: true } + ) + }) + + it('Should only parse included IPTC tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.be.undefined + expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.equal(4) + expect(data.iptc.get('ObjectName')).to.be.undefined + done() + }, + { includeIptcTags: { 0: true } } // ApplicationRecordVersion + ) + }, + { includeIptcTags: { 5: true } } // ObjectName + ) + }) + + it('Should not parse excluded IPTC tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.equal(4) + expect(data.iptc.get('ObjectName')).to.be.undefined + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.be.undefined + expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') + done() + }, + { excludeIptcTags: { 0: true } } // Orientation + ) + }, + { excludeIptcTags: { 5: true } } // DateTime + ) + }) + it('Should parse the complete image head', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.imageHead).to.be.ok @@ -1021,6 +1157,17 @@ }) }) + it('Should not parse the complete image head if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.imageHead).to.be.undefined + done() + }, + { disableImageHead: true } + ) + }) + it('Should parse meta data automatically', function (done) { expect( loadImage( From 79fdc82d6fe5fdd4ce037d184202708dac87349c Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 11 Apr 2020 23:54:11 +0900 Subject: [PATCH 045/207] Fix ObjectURL revoke tests for Edge Legacy and IE. --- test/test.js | 72 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/test/test.js b/test/test.js index 6f2b039..35f9eab 100644 --- a/test/test.js +++ b/test/test.js @@ -68,6 +68,25 @@ } } + /** + * Request helper function. + * + * @param {string} url URL to request + * @param {Function} callback Request callback + */ + function request(url, callback) { + var xhr = new XMLHttpRequest() + xhr.onload = callback + xhr.onerror = callback + try { + xhr.open('GET', url, true) + } catch (e) { + callback.call(xhr, e) + return + } + xhr.send() + } + describe('Loading', function () { it('Return an object with onload and onerror methods', function () { var img = loadImage(blobGIF, function () {}) @@ -116,32 +135,37 @@ ).to.be.ok }) - it('Keep object URL if noRevoke is true', function (done) { - expect( - loadImage( - blobGIF, - function (img) { - loadImage(img.src, function (img2) { - expect(img.width).to.equal(img2.width) - expect(img.height).to.equal(img2.height) + describe('ObjectURL revoke', function () { + // Using XMLHttpRequest via the request helper function to test Object + // URLs to work around Edge Legacy and IE caching image URLs. + if (!window.XMLHttpRequest) return + + it('Keep object URL if noRevoke is set to true', function (done) { + expect( + loadImage( + blobGIF, + function (img) { + request(img.src, function (event) { + expect(event.type).to.equal('load') + done() + }) + }, + { noRevoke: true } + ) + ).to.be.ok + }) + + it('Discard object URL if noRevoke is not set', function (done) { + expect( + loadImage(blobGIF, function (img) { + request(img.src, function (event) { + // IE throws an error that has no type property: + expect(event.type).to.be.oneOf(['error', undefined]) done() }) - }, - { noRevoke: true } - ) - ).to.be.ok - }) - - it('Discard object URL if noRevoke is undefined/false', function (done) { - expect( - loadImage(blobGIF, function (img) { - loadImage(img.src, function (img2) { - expect(img2).to.be.an.instanceOf(window.Event) - expect(img2.type).to.equal('error') - done() }) - }) - ).to.be.ok + ).to.be.ok + }) }) }) @@ -1232,7 +1256,7 @@ it('Should fetch image URL as blob if meta option is true', function (done) { expect( loadImage( - // IE11 does not allow XMLHttpRequest access to data URLs, + // IE does not allow XMLHttpRequest access to data URLs, // so we use an ObjectURL instead of imageUrlJPEG directly: loadImage.createObjectURL(blobJPEG), function (img, data) { From 95b46948e57a6c719d119db3ac1454320c0f2d02 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 11 Apr 2020 23:57:56 +0900 Subject: [PATCH 046/207] Add url to load/error event handler params. --- js/load-image.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/js/load-image.js b/js/load-image.js index a93ea13..ea633e4 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -28,10 +28,10 @@ var img = document.createElement('img') var url img.onerror = function (event) { - return loadImage.onerror(img, event, file, callback, options) + return loadImage.onerror(img, event, file, url, callback, options) } img.onload = function (event) { - return loadImage.onload(img, event, file, callback, options) + return loadImage.onload(img, event, file, url, callback, options) } if (typeof file === 'string') { loadImage.fetchBlob( @@ -58,7 +58,7 @@ // (Firefox 3.6) support the File API but not Blobs: loadImage.isInstanceOf('File', file) ) { - url = img._objectURL = loadImage.createObjectURL(file) + url = loadImage.createObjectURL(file) if (url) { img.src = url return img @@ -83,13 +83,12 @@ /** * Helper function to revoke an object URL * - * @param {HTMLImageElement} img Image element + * @param {string} url Blob Object URL * @param {object} [options] Options object */ - function revokeHelper(img, options) { - if (img._objectURL && !(options && options.noRevoke)) { - loadImage.revokeObjectURL(img._objectURL) - delete img._objectURL + function revokeHelper(url, options) { + if (url && url.slice(0, 5) === 'blob:' && !(options && options.noRevoke)) { + loadImage.revokeObjectURL(url) } } @@ -109,15 +108,15 @@ callback(img, data) } - loadImage.onerror = function (img, event, file, callback, options) { - revokeHelper(img, options) + loadImage.onerror = function (img, event, file, url, callback, options) { + revokeHelper(url, options) if (callback) { callback.call(img, event) } } - loadImage.onload = function (img, event, file, callback, options) { - revokeHelper(img, options) + loadImage.onload = function (img, event, file, url, callback, options) { + revokeHelper(url, options) if (callback) { loadImage.transform(img, options, callback, file, { originalWidth: img.naturalWidth || img.width, From 6b38e52d6525415f08785ee571529f63b72cbc51 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 12 Apr 2020 00:00:47 +0900 Subject: [PATCH 047/207] Remove the meta dependency from the fetch plugin. --- js/load-image-fetch.js | 64 ++++++++++++++++++------------------------ js/load-image-meta.js | 5 ---- js/load-image.js | 48 ++++++++++++++++++++----------- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/js/load-image-fetch.js b/js/load-image-fetch.js index 83fbfd5..7aabda1 100644 --- a/js/load-image-fetch.js +++ b/js/load-image-fetch.js @@ -15,9 +15,9 @@ 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: - define(['./load-image', './load-image-meta'], factory) + define(['./load-image'], factory) } else if (typeof module === 'object' && module.exports) { - factory(require('./load-image'), require('./load-image-meta')) + factory(require('./load-image')) } else { // Browser globals: factory(window.loadImage) @@ -27,19 +27,14 @@ if (typeof fetch !== 'undefined' && typeof Request !== 'undefined') { loadImage.fetchBlob = function (url, callback, options) { - if (loadImage.hasMetaOption(options)) { - fetch(new Request(url, options)) - .then(function (response) { - return response.blob() - }) - .then(callback) - .catch(function (err) { - console.log(err) // eslint-disable-line no-console - callback() - }) - } else { - callback() - } + fetch(new Request(url, options)) + .then(function (response) { + return response.blob() + }) + .then(callback) + .catch(function (err) { + callback(null, err) + }) } } else if ( // Check for XHR2 support: @@ -47,29 +42,24 @@ typeof ProgressEvent !== 'undefined' ) { loadImage.fetchBlob = function (url, callback, options) { - if (loadImage.hasMetaOption(options)) { - // eslint-disable-next-line no-param-reassign - options = options || {} - var req = new XMLHttpRequest() - req.open(options.method || 'GET', url) - if (options.headers) { - Object.keys(options.headers).forEach(function (key) { - req.setRequestHeader(key, options.headers[key]) - }) - } - req.withCredentials = options.credentials === 'include' - req.responseType = 'blob' - req.onload = function () { - callback(req.response) - } - req.onerror = req.onabort = req.ontimeout = function (e) { - console.log(e) // eslint-disable-line no-console - callback() - } - req.send(options.body) - } else { - callback() + // eslint-disable-next-line no-param-reassign + options = options || {} + var req = new XMLHttpRequest() + req.open(options.method || 'GET', url) + if (options.headers) { + Object.keys(options.headers).forEach(function (key) { + req.setRequestHeader(key, options.headers[key]) + }) + } + req.withCredentials = options.credentials === 'include' + req.responseType = 'blob' + req.onload = function () { + callback(req.response) + } + req.onerror = req.onabort = req.ontimeout = function (err) { + callback(null, err) } + req.send(options.body) } } }) diff --git a/js/load-image-meta.js b/js/load-image-meta.js index 2bcb8e6..ecdb077 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -179,11 +179,6 @@ ) } - // Determines if meta data should be loaded automatically: - loadImage.hasMetaOption = function (options) { - return options && options.meta - } - var originalTransform = loadImage.transform loadImage.transform = function (img, options, callback, file, data) { if (loadImage.hasMetaOption(options)) { diff --git a/js/load-image.js b/js/load-image.js index ea633e4..50a36cd 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -27,6 +27,26 @@ function loadImage(file, callback, options) { var img = document.createElement('img') var url + /** + * Callback for the fetchBlob call. + * + * @param {Blob} blob Blob object + * @param {Error} err Error object + */ + function fetchBlobCallback(blob, err) { + if (err) console.log(err) // eslint-disable-line no-console + if (blob && loadImage.isInstanceOf('Blob', blob)) { + // eslint-disable-next-line no-param-reassign + file = blob + url = loadImage.createObjectURL(file) + } else { + url = file + if (options && options.crossOrigin) { + img.crossOrigin = options.crossOrigin + } + } + img.src = url + } img.onerror = function (event) { return loadImage.onerror(img, event, file, url, callback, options) } @@ -34,23 +54,11 @@ return loadImage.onload(img, event, file, url, callback, options) } if (typeof file === 'string') { - loadImage.fetchBlob( - file, - function (blob) { - if (blob && loadImage.isInstanceOf('Blob', blob)) { - // eslint-disable-next-line no-param-reassign - file = blob - url = loadImage.createObjectURL(file) - } else { - url = file - if (options && options.crossOrigin) { - img.crossOrigin = options.crossOrigin - } - } - img.src = url - }, - options - ) + if (loadImage.hasMetaOption(options)) { + loadImage.fetchBlob(file, fetchBlobCallback, options) + } else { + fetchBlobCallback() + } return img } else if ( loadImage.isInstanceOf('Blob', file) || @@ -92,6 +100,12 @@ } } + // Determines if meta data should be loaded automatically. + // Requires the load image meta extension to load meta data. + loadImage.hasMetaOption = function (options) { + return options && options.meta + } + // If the callback given to this function returns a blob, it is used as image // source instead of the original url and overrides the file argument used in // the onload and onerror event callbacks: From ff22e11daa25d0cff328124abf1cca22ffaa4be5 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 12 Apr 2020 00:09:31 +0900 Subject: [PATCH 048/207] 3.0.0 --- js/load-image.all.min.js | 2 +- js/load-image.all.min.js.map | 2 +- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/load-image.all.min.js b/js/load-image.all.min.js index f09182f..a1522ed 100644 --- a/js/load-image.all.min.js +++ b/js/load-image.all.min.js @@ -1,2 +1,2 @@ -!function(o){"use strict";function r(t,i,a){var o,n=document.createElement("img");return n.onerror=function(e){return r.onerror(n,e,t,i,a)},n.onload=function(e){return r.onload(n,e,t,i,a)},"string"==typeof t?(r.fetchBlob(t,function(e){e&&r.isInstanceOf("Blob",e)?o=r.createObjectURL(t=e):(o=t,a&&a.crossOrigin&&(n.crossOrigin=a.crossOrigin)),n.src=o},a),n):r.isInstanceOf("Blob",t)||r.isInstanceOf("File",t)?(o=n._objectURL=r.createObjectURL(t))?(n.src=o,n):r.readFile(t,function(e){var t=e.target;t&&t.result?n.src=t.result:i&&i(e)}):void 0}var t=o.createObjectURL&&o||o.URL&&URL.revokeObjectURL&&URL||o.webkitURL&&webkitURL;function n(e,t){!e._objectURL||t&&t.noRevoke||(r.revokeObjectURL(e._objectURL),delete e._objectURL)}r.fetchBlob=function(e,t){t()},r.isInstanceOf=function(e,t){return Object.prototype.toString.call(t)==="[object "+e+"]"},r.transform=function(e,t,i,a,o){i(e,o)},r.onerror=function(e,t,i,a,o){n(e,o),a&&a.call(e,t)},r.onload=function(e,t,i,a,o){n(e,o),a&&r.transform(e,o,a,i,{originalWidth:e.naturalWidth||e.width,originalHeight:e.naturalHeight||e.height})},r.createObjectURL=function(e){return!!t&&t.createObjectURL(e)},r.revokeObjectURL=function(e){return!!t&&t.revokeObjectURL(e)},r.readFile=function(e,t,i){if(o.FileReader){var a=new FileReader;if(a.onload=a.onerror=t,a[i=i||"readAsDataURL"])return a[i](e),a}return!1},"function"==typeof define&&define.amd?define(function(){return r}):"object"==typeof module&&module.exports?module.exports=r:o.loadImage=r}("undefined"!=typeof window&&window||this),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):"object"==typeof module&&module.exports?e(require("./load-image")):e(window.loadImage)}(function(x){"use strict";var n=x.transform;x.transform=function(e,t,i,a,o){n.call(x,x.scale(e,t,o),t,i,a,o)},x.transformCoordinates=function(){},x.getTransformedOptions=function(e,t){var i,a,o,n,r=t.aspectRatio;if(!r)return t;for(a in i={},t)Object.prototype.hasOwnProperty.call(t,a)&&(i[a]=t[a]);return i.crop=!0,r<(o=e.naturalWidth||e.width)/(n=e.naturalHeight||e.height)?(i.maxWidth=n*r,i.maxHeight=n):(i.maxWidth=o,i.maxHeight=o/r),i},x.renderImageToCanvas=function(e,t,i,a,o,n,r,s,l,c,d){var u=e.getContext("2d");return!1===d.imageSmoothingEnabled?u.imageSmoothingEnabled=!1:d.imageSmoothingQuality&&(u.imageSmoothingQuality=d.imageSmoothingQuality),u.drawImage(t,i,a,o,n,r,s,l,c),e},x.hasCanvasOption=function(e){return e.canvas||e.crop||!!e.aspectRatio},x.scale=function(e,t,i){t=t||{};var a,o,n,r,s,l,c,d,u,f,g,p=document.createElement("canvas"),m=e.getContext||x.hasCanvasOption(t)&&p.getContext,h=e.naturalWidth||e.width,A=e.naturalHeight||e.height,b=h,y=A;function S(){var e=Math.max((n||b)/b,(r||y)/y);1r.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if((a=p.metaDataParsers.jpeg[t])&&!u.disableMetaDataParsers)for(o=0;oe.byteLength))return g.createObjectURL(new Blob([e.buffer.slice(t,t+i)]));console.log("Invalid Exif data: Invalid thumbnail data.")},g.exifTagTypes={1:{getValue:function(e,t){return e.getUint8(t)},size:1},2:{getValue:function(e,t){return String.fromCharCode(e.getUint8(t))},size:1,ascii:!0},3:{getValue:function(e,t,i){return e.getUint16(t,i)},size:2},4:{getValue:function(e,t,i){return e.getUint32(t,i)},size:4},5:{getValue:function(e,t,i){return e.getUint32(t,i)/e.getUint32(t+4,i)},size:8},9:{getValue:function(e,t,i){return e.getInt32(t,i)},size:4},10:{getValue:function(e,t,i){return e.getInt32(t,i)/e.getInt32(t+4,i)},size:8}},g.exifTagTypes[7]=g.exifTagTypes[1],g.getExifValue=function(e,t,i,a,o,n){var r,s,l,c,d,u,f=g.exifTagTypes[a];if(f){if(!((s=4<(r=f.size*o)?t+e.getUint32(i+8,n):i+8)+r>e.byteLength)){if(1===o)return f.getValue(e,s,n);for(l=[],c=0;ce.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(!((r=i+2+12*(n=e.getUint16(i,a)))+4>e.byteLength)){for(s=0;se.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===e.getUint16(t+8)){switch(e.getUint16(l)){case 18761:n=!0;break;case 19789:n=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===e.getUint16(l+2,n)?(r=e.getUint32(l+4,n),a.exif=new g.ExifMap,o.disableExifOffsets||(a.exifOffsets=new g.ExifMap,a.exifTiffOffset=l,a.exifLittleEndian=n),(r=g.parseExifTags(e,l,l+r,n,a))&&!o.disableExifThumbnail&&(s={exif:{}},r=g.parseExifTags(e,l,l+r,n,s),s.exif[513]&&(a.exif.Thumbnail=g.getExifThumbnail(e,l+s.exif[513],s.exif[514]))),a.exif[34665]&&!o.disableExifSub&&g.parseExifTags(e,l,l+a.exif[34665],n,a),a.exif[34853]&&!o.disableExifGps&&g.parseExifTags(e,l,l+a.exif[34853],n,a)):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},g.metaDataParsers.jpeg[65505].push(g.parseExifData),g.exifWriters={274:function(e,t,i){return new DataView(e,t.exifOffsets[274]+8,2).setUint16(0,i,t.exifLittleEndian),e}},g.writeExifData=function(e,t,i,a){g.exifWriters[t.exif.map[i]](e,t,a)}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";e.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},e.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},e.ExifMap.prototype.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},function(e){var t,i=e.tags,a=e.map;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(a[i[t]]=t)}(e.ExifMap.prototype),e.ExifMap.prototype.getAll=function(){var e,t,i={};for(e in this)Object.prototype.hasOwnProperty.call(this,e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(u){"use strict";u.IptcMap=function(){return this},u.IptcMap.prototype.map={ObjectName:5},u.IptcMap.prototype.get=function(e){return this[e]||this[this.map[e]]},u.parseIptcTags=function(e,t,i,a){function o(e,t,i){for(var a="",o=t;or.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if((n=m.metaDataParsers.jpeg[t])&&!u.disableMetaDataParsers)for(a=0;ae.byteLength)){if(1===a)return f.getValue(e,s,o);for(l=[],c=0;ce.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(!((c=i+2+12*(l=e.getUint16(i,n)))+4>e.byteLength)){for(d=0;dc.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===c.getUint16(e+8)){switch(c.getUint16(m)){case 18761:u=!0;break;case 19789:u=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===c.getUint16(m+2,u)?(n=c.getUint32(m+4,u),d.exif=new h,i.disableExifOffsets||(d.exifOffsets=new h,d.exifTiffOffset=m,d.exifLittleEndian=u),(n=p(c,m,m+n,u,d.exif,d.exifOffsets,f,g))&&!i.disableExifThumbnail&&(n=p(c,m,m+n,u,d.exif,d.exifOffsets,f,g),d.exif[513]&&d.exif[514]&&(d.exif[513]=function(e,t,i){if(i&&!(t+i>e.byteLength))return new Blob([e.buffer.slice(t,t+i)],{type:"image/jpeg"});console.log("Invalid Exif data: Invalid thumbnail data.")}(c,m+d.exif[513],d.exif[514]))),Object.keys(d.exif.privateIFDs).forEach(function(e){var t,i,n,a,o,r,s,l;i=e,n=c,a=m,o=u,r=f,s=g,(l=(t=d).exif[i])&&(t.exif[i]=new h(i),t.exifOffsets&&(t.exifOffsets[i]=new h(i)),p(n,a,a+l,o,t.exif[i],t.exifOffsets&&t.exifOffsets[i],r&&r[i],s&&s[i]))})):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},a.metaDataParsers.jpeg[65505].push(a.parseExifData),a.exifWriters={274:function(e,t,i){return new DataView(e,t.exifOffsets[274]+8,2).setUint16(0,i,t.exifLittleEndian),e}},a.writeExifData=function(e,t,i,n){a.exifWriters[t.exif.map[i]](e,t,n)},a.ExifMap=h}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";var a=e.ExifMap.prototype;a.tags={256:"ImageWidth",257:"ImageHeight",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",34665:{36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber"},34853:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},40965:{1:"InteroperabilityIndex"}},a.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},a.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},a.getAll=function(){var e,t,i,n={};for(e in this)Object.prototype.hasOwnProperty.call(this,e)&&((t=this[e])&&t.getAll?n[this.privateIFDs[e].name]=t.getAll():(i=this.tags[e])&&(n[i]=this.getText(i)));return n},a.getName=function(e){var t=this.tags[e];return"object"==typeof t?this.privateIFDs[e].name:t},function(){var e,t,i,n=a.tags;for(e in n)if(Object.prototype.hasOwnProperty.call(n,e))if(t=a.privateIFDs[e])for(e in i=n[e])Object.prototype.hasOwnProperty.call(i,e)&&(t.map[i[e]]=Number(e));else a.map[n[e]]=Number(e)}()}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";function g(){}function m(e,t,i,n,a){return"binary"===t.types[e]?new Blob([i.buffer.slice(n,n+a)]):"Uint16"===t.types[e]?i.getUint16(n):function(e,t,i){for(var n="",a=t+i,o=t;o Date: Mon, 20 Apr 2020 12:36:13 +0600 Subject: [PATCH 049/207] Compatibility with jQuery 3.5.0 --- js/demo/demo.js | 6 +++--- js/vendor/jquery.Jcrop.js | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/demo/demo.js b/js/demo/demo.js index 6dc9fa3..b42cdcd 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -29,7 +29,7 @@ $(function () { * @param {object} tags Tags object */ function displayTagData(node, tags) { - var table = $('
    ') + var table = $('
    ') var row = $('') var cell = $('') var prop @@ -59,7 +59,7 @@ $(function () { */ function displayThumbnailImage(node, thumbnail, options) { if (thumbnail) { - var link = $('') + var link = $('') .attr('href', loadImage.createObjectURL(thumbnail)) .attr('download', 'thumbnail.jpg') .appendTo(node) @@ -105,7 +105,7 @@ $(function () { result.children().replaceWith($('Loading image file failed')) return } - var content = $('').append(img) + var content = $('').append(img) result.children().replaceWith(content) if (data) { if (img.getContext) { diff --git a/js/vendor/jquery.Jcrop.js b/js/vendor/jquery.Jcrop.js index 41f80e6..a879391 100755 --- a/js/vendor/jquery.Jcrop.js +++ b/js/vendor/jquery.Jcrop.js @@ -329,7 +329,7 @@ boundy = $img.height(), - $div = $('
    ').width(boundx).height(boundy).addClass(cssClass('holder')).css({ + $div = $('
    ').width(boundx).height(boundy).addClass(cssClass('holder')).css({ position: 'relative', backgroundColor: options.bgColor }).insertAfter($origimg).append($img); @@ -338,19 +338,19 @@ $div.addClass(options.addClass); } - var $img2 = $('
    '), + var $img2 = $('
    '), - $img_holder = $('
    ') + $img_holder = $('
    ') .width('100%').height('100%').css({ zIndex: 310, position: 'absolute', overflow: 'hidden' }), - $hdl_holder = $('
    ') + $hdl_holder = $('
    ') .width('100%').height('100%').css('zIndex', 320), - $sel = $('
    ') + $sel = $('
    ') .css({ position: 'absolute', zIndex: 600 @@ -737,7 +737,7 @@ // Shade Module {{{ var Shade = (function() { var enabled = false, - holder = $('
    ').css({ + holder = $('
    ').css({ position: 'absolute', zIndex: 240, opacity: 0 @@ -779,7 +779,7 @@ }); } function createShade() { - return $('
    ').css({ + return $('
    ').css({ position: 'absolute', backgroundColor: options.shadeColor||options.bgColor }).appendTo(holder); @@ -863,7 +863,7 @@ // Private Methods function insertBorder(type) //{{{ { - var jq = $('
    ').css({ + var jq = $('
    ').css({ position: 'absolute', opacity: options.borderOpacity }).addClass(cssClass(type)); @@ -873,7 +873,7 @@ //}}} function dragDiv(ord, zi) //{{{ { - var jq = $('
    ').mousedown(createDragger(ord)).css({ + var jq = $('
    ').mousedown(createDragger(ord)).css({ cursor: ord + '-resize', position: 'absolute', zIndex: zi @@ -1226,7 +1226,7 @@ width: '12px' }).addClass('jcrop-keymgr'), - $keywrap = $('
    ').css({ + $keywrap = $('
    ').css({ position: 'absolute', overflow: 'hidden' }).append($keymgr); From 804fd90a10177d7a9ccdbdfde2a663046cb02a8e Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:31:56 +0900 Subject: [PATCH 050/207] Remove unnecessary whitespace. --- README.md | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index cc067d4..3c7a154 100644 --- a/README.md +++ b/README.md @@ -240,100 +240,103 @@ Defines the minimum height of the img/canvas element. The width of the sub-rectangle of the source image to draw into the destination canvas. - Defaults to the source image width and requires `canvas: true`. +Defaults to the source image width and requires `canvas: true`. ### sourceHeight The height of the sub-rectangle of the source image to draw into the destination canvas. - Defaults to the source image height and requires `canvas: true`. +Defaults to the source image height and requires `canvas: true`. ### top The top margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### right The right margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### bottom The bottom margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### left The left margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### contain Scales the image up/down to contain it in the max dimensions if set to `true`. - This emulates the CSS feature [background-image: contain](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#contain). +This emulates the CSS feature +[background-image: contain](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#contain). ### cover Scales the image up/down to cover the max dimensions with the image dimensions if set to `true`. - This emulates the CSS feature [background-image: cover](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#cover). +This emulates the CSS feature +[background-image: cover](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#cover). ### aspectRatio Crops the image to the given aspect ratio (e.g. `16/9`). - Setting the `aspectRatio` also enables the `crop` option. +Setting the `aspectRatio` also enables the `crop` option. ### pixelRatio Defines the ratio of the canvas pixels to the physical image pixels on the screen. - Should be set to `window.devicePixelRatio` unless the scaled image is not rendered -on screen. - Defaults to `1` and requires `canvas: true`. +Should be set to `window.devicePixelRatio` unless the scaled image is not +rendered on screen. +Defaults to `1` and requires `canvas: true`. ### downsamplingRatio Defines the ratio in which the image is downsampled. - By default, images are downsampled in one step. With a ratio of `0.5`, each step +By default, images are downsampled in one step. With a ratio of `0.5`, each step scales the image to half the size, before reaching the target dimensions. - Requires `canvas: true`. +Requires `canvas: true`. ### imageSmoothingEnabled If set to `false`, [disables image smoothing](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled). - Defaults to `true` and requires `canvas: true`. +Defaults to `true` and requires `canvas: true`. ### imageSmoothingQuality Sets the [quality of image smoothing](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality). - Possible values: `'low'`, `'medium'`, `'high'` - Defaults to `'low'` and requires `canvas: true`. +Possible values: `'low'`, `'medium'`, `'high'` +Defaults to `'low'` and requires `canvas: true`. ### crop Crops the image to the maxWidth/maxHeight constraints if set to `true`. - Enabling the `crop` option also enables the `canvas` option. +Enabling the `crop` option also enables the `canvas` option. ### orientation Transform the canvas according to the specified Exif orientation, which can be an `integer` in the range of `1` to `8` or the boolean value `true`. - When set to `true`, it will set the orientation value based on the EXIF data of +When set to `true`, it will set the orientation value based on the EXIF data of the image, which will be parsed automatically if the exif library is available. Setting `orientation` to an integer in the range of `2` to `8` enables the `canvas` option. - Setting `orientation` to `true` enables the `canvas` and `meta` options, unless -the browser supports automatic image orientation (see [browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). +Setting `orientation` to `true` enables the `canvas` and `meta` options, unless +the browser supports automatic image orientation (see +[browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). ### meta Automatically parses the image meta data if set to `true`. - The meta data is passed to the callback as part of the second argument. - If the file is given as URL and the browser supports the +The meta data is passed to the callback as part of the second argument. +If the file is given as URL and the browser supports the [fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API), fetches the file as Blob to be able to parse the meta data. From 3f7b50eab933a339b1dac49b284581957b245c85 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:43:51 +0900 Subject: [PATCH 051/207] Clarify meta option. --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3c7a154..8a1e09a 100644 --- a/README.md +++ b/README.md @@ -335,10 +335,13 @@ the browser supports automatic image orientation (see ### meta Automatically parses the image meta data if set to `true`. -The meta data is passed to the callback as part of the second argument. +If meta data has been found, the data object passed as second argument to the +callback function has additional properties (see +[meta data parsing](#meta-data-parsing)). If the file is given as URL and the browser supports the -[fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API), fetches -the file as Blob to be able to parse the meta data. +[fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) or the XHR +[responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType) +`blob`, fetches the file as Blob to be able to parse the meta data. ### canvas From addca35c4769526606d303f44a5064557a1f420b Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:51:22 +0900 Subject: [PATCH 052/207] Flash tag is not in the base exif map anymore. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a1e09a..0e334be 100644 --- a/README.md +++ b/README.md @@ -473,7 +473,7 @@ become available, as well as three additional methods: - `exif.getAll()` ```js -var flashText = data.exif.getText('Flash') // e.g.: 'Flash fired, auto mode', +var flashText = data.exif.getText('Orientation') // e.g. right-top for value 6 var name = data.exif.getName(0x0112) // Orientation From 2715acb296be9dbbd122fbf4131bb2958becb635 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:56:47 +0900 Subject: [PATCH 053/207] Add headlines for the Exif/IPTC parser options. --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0e334be..48c2d33 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,10 @@ - [Meta data parsing](#meta-data-parsing) - [Image head](#image-head) - [Exif parser](#exif-parser) + - [Exif parser options](#exif-parser-options) - [Exif writer](#exif-writer) - [IPTC parser](#iptc-parser) + - [IPTC parser options](#iptc-parser-options) - [License](#license) - [Credits](#credits) @@ -481,8 +483,9 @@ var name = data.exif.getName(0x0112) // Orientation var allTags = data.exif.getAll() ``` -The Exif parser also adds additional options for the parseMetaData method, to -disable certain aspects of the parser: +#### Exif parser options + +The Exif parser adds additional options: - `disableExif`: Disables Exif parsing when `true`. - `disableExifThumbnail`: Disables parsing of Thumbnail data when `true`. @@ -599,8 +602,9 @@ var name = data.iptc.getName(5) // ObjectName var allTags = data.iptc.getAll() ``` -The IPTC parser also adds additional options for the parseMetaData method, to -disable certain aspects of the parser: +#### IPTC parser options + +The IPTC parser adds additional options: - `disableIptc`: Disables IPTC parsing when true. - `disableIptcOffsets`: Disables storing IPTC tag offsets when `true`. From b96a82149f6fb13befc1764caec141647b1324e7 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 23:35:53 +0900 Subject: [PATCH 054/207] Add examples for parsing Exif Thumbnail and IFDs. --- README.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 48c2d33..865156c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ - [Meta data parsing](#meta-data-parsing) - [Image head](#image-head) - [Exif parser](#exif-parser) + - [Exif Thumbnail](#exif-thumbnail) + - [Exif IFD](#exif-ifd) + - [GPSInfo IFD](#gpsinfo-ifd) + - [Interoperability IFD](#interoperability-ifd) - [Exif parser options](#exif-parser-options) - [Exif writer](#exif-writer) - [IPTC parser](#iptc-parser) @@ -463,9 +467,9 @@ By default, only the following names are mapped: - `Orientation` - `Thumbnail` -- `Exif` -- `GPSInfo` -- `Interoperability` +- `Exif` (see [Exif IFD](#exif-ifd)) +- `GPSInfo` (see [GPSInfo IFD](#gpsinfo-ifd)) +- `Interoperability` (see [Interoperability IFD](#interoperability-ifd)) If you also include the Load Image Exif Map library, additional tag mappings become available, as well as three additional methods: @@ -483,6 +487,86 @@ var name = data.exif.getName(0x0112) // Orientation var allTags = data.exif.getAll() ``` +#### Exif Thumbnail + +Example code displaying a thumbnail image embedded into the Exif meta data: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var thumbBlob = data.exif && data.exif.get('Thumbnail') + if (thumbBlob) { + loadImage(thumbBlob, function (thumbImage) { + document.body.appendChild(thumbImage) + }) + } + }, + { meta: true } +) +``` + +#### Exif IFD + +Example code displaying data from the Exif IFD (Image File Directory) that +contains Exif specified TIFF tags: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var exifIFD = data.exif && data.exif.get('Exif') + if (exifIFD) { + // Map of all Exif IFD tags with their mapped names/text as keys/values: + console.log(exifIFD.getAll()) + // A specific Exif IFD tag value: + console.log(exifIFD.get('UserComment')) + } + }, + { meta: true } +) +``` + +#### GPSInfo IFD + +Example code displaying data from the Exif IFD (Image File Directory) that +contains [GPS](https://en.wikipedia.org/wiki/Global_Positioning_System) info: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var gpsInfo = data.exif && data.exif.get('GPSInfo') + if (gpsInfo) { + // Map of all GPSInfo tags with their mapped names/text as keys/values: + console.log(gpsInfo.getAll()) + // A specific GPSInfo tag value: + console.log(gpsInfo.get('GPSLatitude')) + } + }, + { meta: true } +) +``` + +#### Interoperability IFD + +Example code displaying data from the Exif IFD (Image File Directory) that +contains Interoperability data: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var interoperabilityData = data.exif && data.exif.get('Interoperability') + if (interoperabilityData) { + // The InteroperabilityIndex tag value: + console.log(interoperabilityData.get('InteroperabilityIndex')) + } + }, + { meta: true } +) +``` + #### Exif parser options The Exif parser adds additional options: From 6869b3b537e0e88f7e9cad04932aaca922708e05 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 17:34:37 +0900 Subject: [PATCH 055/207] Remove unnecessary "Should" as test prefix. --- test/test.js | 66 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/test/test.js b/test/test.js index 35f9eab..cb1cd8d 100644 --- a/test/test.js +++ b/test/test.js @@ -682,7 +682,7 @@ }) describe('Orientation', function () { - it('Should keep the orientation', function (done) { + it('Keep the orientation', function (done) { expect( loadImage( blobGIF, @@ -696,7 +696,7 @@ ).to.be.ok }) - it('Should rotate left', function (done) { + it('Rotate left', function (done) { expect( loadImage( blobGIF, @@ -710,7 +710,7 @@ ).to.be.ok }) - it('Should rotate right', function (done) { + it('Rotate right', function (done) { expect( loadImage( blobGIF, @@ -724,7 +724,7 @@ ).to.be.ok }) - it('Should adjust constraints to new coordinates', function (done) { + it('Adjust constraints to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -738,7 +738,7 @@ ).to.be.ok }) - it('Should adjust left and top to new coordinates', function (done) { + it('Adjust left and top to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -752,7 +752,7 @@ ).to.be.ok }) - it('Should adjust right and bottom to new coordinates', function (done) { + it('Adjust right and bottom to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -766,7 +766,7 @@ ).to.be.ok }) - it('Should adjust left and bottom to new coordinates', function (done) { + it('Adjust left and bottom to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -780,7 +780,7 @@ ).to.be.ok }) - it('Should adjust right and top to new coordinates', function (done) { + it('Adjust right and top to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -794,7 +794,7 @@ ).to.be.ok }) - it('Should rotate left with the given pixelRatio', function (done) { + it('Rotate left with the given pixelRatio', function (done) { expect( loadImage( blobGIF, @@ -810,7 +810,7 @@ ).to.be.ok }) - it('Should rotate right with the given pixelRatio', function (done) { + it('Rotate right with the given pixelRatio', function (done) { expect( loadImage( blobGIF, @@ -826,7 +826,7 @@ ).to.be.ok }) - it('Should ignore too small orientation value', function (done) { + it('Ignore too small orientation value', function (done) { expect( loadImage( blobGIF, @@ -840,7 +840,7 @@ ).to.be.ok }) - it('Should ignore too large orientation value', function (done) { + it('Ignore too large orientation value', function (done) { expect( loadImage( blobGIF, @@ -854,7 +854,7 @@ ).to.be.ok }) - it('Should rotate right based on the exif orientation value', function (done) { + it('Rotate right based on the exif orientation value', function (done) { expect( loadImage( blobJPEG, @@ -906,7 +906,7 @@ ).to.be.ok }) - it('Should scale image after exif based orientation', function (done) { + it('Scale image after exif based orientation', function (done) { expect( loadImage( blobJPEG, @@ -923,7 +923,7 @@ describe('from-image', function () { if (!loadImage.orientation) return - it('Should use automatic browser image orientation', function (done) { + it('Use automatic browser image orientation', function (done) { expect( loadImage( blobJPEG, @@ -1005,7 +1005,7 @@ }) describe('Metadata', function () { - it('Should parse Exif tags', function (done) { + it('Parse Exif tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) @@ -1013,7 +1013,7 @@ }) }) - it('Should not parse Exif tags if disabled', function (done) { + it('Do not parse Exif tags if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1024,7 +1024,7 @@ ) }) - it('Should parse Exif tag offsets', function (done) { + it('Parse Exif tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exifOffsets).to.be.ok expect(data.exifOffsets.get('Orientation')).to.equal(0x16) @@ -1034,7 +1034,7 @@ }) }) - it('Should not parse Exif tag offsets if disabled', function (done) { + it('Do not parse Exif tag offsets if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1045,7 +1045,7 @@ ) }) - it('Should only parse included Exif tags', function (done) { + it('Only parse included Exif tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1065,7 +1065,7 @@ ) }) - it('Should not parse excluded Exif tags', function (done) { + it('Do not parse excluded Exif tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1085,7 +1085,7 @@ ) }) - it('Should parse IPTC tags', function (done) { + it('Parse IPTC tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.iptc).to.be.ok expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') @@ -1093,7 +1093,7 @@ }) }) - it('Should not parse IPTC tags if disabled', function (done) { + it('Do not parse IPTC tags if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1104,7 +1104,7 @@ ) }) - it('Should parse IPTC tag offsets', function (done) { + it('Parse IPTC tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.iptcOffsets).to.be.ok expect(data.iptcOffsets.get('ObjectName')).to.equal(0x44) @@ -1112,7 +1112,7 @@ }) }) - it('Should not parse IPTC tag offsets if disabled', function (done) { + it('Do not parse IPTC tag offsets if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1123,7 +1123,7 @@ ) }) - it('Should only parse included IPTC tags', function (done) { + it('Only parse included IPTC tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1145,7 +1145,7 @@ ) }) - it('Should not parse excluded IPTC tags', function (done) { + it('Do not parse excluded IPTC tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1167,7 +1167,7 @@ ) }) - it('Should parse the complete image head', function (done) { + it('Parse the complete image head', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.imageHead).to.be.ok loadImage.parseMetaData( @@ -1181,7 +1181,7 @@ }) }) - it('Should not parse the complete image head if disabled', function (done) { + it('Do not parse the complete image head if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1192,7 +1192,7 @@ ) }) - it('Should parse meta data automatically', function (done) { + it('Parse meta data automatically', function (done) { expect( loadImage( blobJPEG, @@ -1210,7 +1210,7 @@ ).to.be.ok }) - it('Should write Exif Orientation tag and replace image head', function (done) { + it('Write Exif Orientation tag and replace image head', function (done) { loadImage( blobJPEG, function (img, data) { @@ -1253,7 +1253,7 @@ return } - it('Should fetch image URL as blob if meta option is true', function (done) { + it('Fetch image URL as blob if meta option is true', function (done) { expect( loadImage( // IE does not allow XMLHttpRequest access to data URLs, @@ -1273,7 +1273,7 @@ ).to.be.ok }) - it('Should load image URL as img if meta option is false', function (done) { + it('Load image URL as img if meta option is false', function (done) { expect( loadImage(imageUrlJPEG, function (img, data) { expect(data.imageHead).to.be.undefined From 4931b411b0d1df37850e0c480ee521a10e2e20a6 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:16:45 +0900 Subject: [PATCH 056/207] Always pass a data arg to getTransformedOptions. --- js/load-image-scale.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 57ac273..dbebf50 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -45,7 +45,7 @@ // Returns transformed options, allows to override e.g. // maxWidth, maxHeight and crop options based on the aspectRatio. - // gets img, options passed as arguments: + // gets img, options, data passed as arguments: loadImage.getTransformedOptions = function (img, options) { var aspectRatio = options.aspectRatio var newOptions @@ -168,7 +168,7 @@ } if (useCanvas) { // eslint-disable-next-line no-param-reassign - options = loadImage.getTransformedOptions(img, options, data) + options = loadImage.getTransformedOptions(img, options, data || {}) sourceX = options.left || 0 sourceY = options.top || 0 if (options.sourceWidth) { From 379922b53b38a601738dfa8e79d3a396d494e82d Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:23:47 +0900 Subject: [PATCH 057/207] Ensure pixelRatio scaling is idempotent. --- js/load-image-scale.js | 16 +++++++++++----- test/test.js | 12 ++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index dbebf50..a662dde 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -225,11 +225,17 @@ if (useCanvas) { pixelRatio = options.pixelRatio if (pixelRatio > 1) { - canvas.style.width = destWidth + 'px' - canvas.style.height = destHeight + 'px' - destWidth *= pixelRatio - destHeight *= pixelRatio - canvas.getContext('2d').scale(pixelRatio, pixelRatio) + if (parseInt(img.style.width, 10) === width / pixelRatio) { + // Source image is already scaled according to device pixel ratio + canvas.style.width = destWidth / pixelRatio + 'px' + canvas.style.height = destHeight / pixelRatio + 'px' + } else { + canvas.style.width = destWidth + 'px' + canvas.style.height = destHeight + 'px' + destWidth *= pixelRatio + destHeight *= pixelRatio + canvas.getContext('2d').scale(pixelRatio, pixelRatio) + } } downsamplingRatio = options.downsamplingRatio if ( diff --git a/test/test.js b/test/test.js index cb1cd8d..1e688ae 100644 --- a/test/test.js +++ b/test/test.js @@ -300,6 +300,12 @@ expect(img.height).to.equal(160) expect(img.style.width).to.equal('120px') expect(img.style.height).to.equal('80px') + // Check if pixelRatio scaling is idempotent: + var img2 = loadImage.scale(img, { minWidth: 120, pixelRatio: 2 }) + expect(img2.width).to.equal(240) + expect(img2.height).to.equal(160) + expect(img2.style.width).to.equal('120px') + expect(img2.style.height).to.equal('80px') done() }, { minWidth: 120, canvas: true, pixelRatio: 2 } @@ -316,6 +322,12 @@ expect(img.height).to.equal(40) expect(img.style.width).to.equal('30px') expect(img.style.height).to.equal('20px') + // Check if pixelRatio scaling is idempotent: + var img2 = loadImage.scale(img, { minWidth: 30, pixelRatio: 2 }) + expect(img2.width).to.equal(60) + expect(img2.height).to.equal(40) + expect(img2.style.width).to.equal('30px') + expect(img2.style.height).to.equal('20px') done() }, { maxWidth: 30, canvas: true, pixelRatio: 2 } From 029ac424c3a9bb4c40951a1e12c73424c0808f00 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:39:31 +0900 Subject: [PATCH 058/207] Document orientation values visually in source. --- js/load-image-orientation.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 74a5be1..7527527 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -9,6 +9,20 @@ * https://opensource.org/licenses/MIT */ +/* + +Exif orientation values to correctly display the letter F: + + 1 2 3 4 5 6 7 8 + +██████ ██████ ██ ██ ██████████ ██ ██ ██████████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +████ ████ ████ ████ ██ ██████████ ██████████ ██ +██ ██ ██ ██ +██ ██ ██████ ██████ + +*/ + /* global define, module, require */ ;(function (factory) { From cda87fc468211987d808be08dc7ab06c059fa3e7 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:41:32 +0900 Subject: [PATCH 059/207] Add missing degree character in source comments. --- js/load-image-orientation.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 7527527..e48ebcd 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -119,7 +119,7 @@ Exif orientation values to correctly display the letter F: ctx.scale(1, -1) break case 5: - // vertical flip + 90 rotate right + // vertical flip + 90° rotate right ctx.rotate(0.5 * Math.PI) ctx.scale(1, -1) break @@ -129,7 +129,7 @@ Exif orientation values to correctly display the letter F: ctx.translate(0, -height) break case 7: - // horizontal flip + 90 rotate right + // horizontal flip + 90° rotate right ctx.rotate(0.5 * Math.PI) ctx.translate(width, -height) ctx.scale(-1, 1) @@ -185,7 +185,7 @@ Exif orientation values to correctly display the letter F: newOptions.bottom = options.top break case 5: - // vertical flip + 90 rotate right + // vertical flip + 90° rotate right newOptions.left = options.top newOptions.top = options.left newOptions.right = options.bottom @@ -199,7 +199,7 @@ Exif orientation values to correctly display the letter F: newOptions.bottom = options.left break case 7: - // horizontal flip + 90 rotate right + // horizontal flip + 90° rotate right newOptions.left = options.bottom newOptions.top = options.right newOptions.right = options.top From 61761388e0b9fff19acef3c4d5c1413c11b8c843 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:45:39 +0900 Subject: [PATCH 060/207] Normalize original width+height dimensions. Switch reported original dimensions for browsers with automatic image orientation. --- js/load-image-orientation.js | 28 ++++++++++++++++++++++++++++ test/test.js | 14 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index e48ebcd..41ac1ee 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -43,6 +43,7 @@ Exif orientation values to correctly display the letter F: })(function (loadImage) { 'use strict' + var originalTransform = loadImage.transform var originalHasCanvasOption = loadImage.hasCanvasOption var originalHasMetaOption = loadImage.hasMetaOption var originalTransformCoordinates = loadImage.transformCoordinates @@ -66,6 +67,33 @@ Exif orientation values to correctly display the letter F: img.src = testImageURL })() + loadImage.transform = function (img, options, callback, file, data) { + originalTransform.call( + loadImage, + img, + options, + function (img, data) { + if (data) { + var exifOrientation = data.exif && data.exif.get('Orientation') + if ( + loadImage.orientation && + exifOrientation > 4 && + exifOrientation < 9 + ) { + // Automatic image orientation switched image dimensions + var originalWidth = data.originalWidth + var originalHeight = data.originalHeight + data.originalWidth = originalHeight + data.originalHeight = originalWidth + } + } + callback(img, data) + }, + file, + data + ) + } + // Determines if the target image should be a canvas element: loadImage.hasCanvasOption = function (options) { return ( diff --git a/test/test.js b/test/test.js index 1e688ae..84b4a4b 100644 --- a/test/test.js +++ b/test/test.js @@ -932,6 +932,20 @@ ).to.be.ok }) + it('Provide original image width+height from before orientation', function (done) { + expect( + loadImage( + blobJPEG, + function (img, data) { + expect(data.originalWidth).to.equal(3) + expect(data.originalHeight).to.equal(2) + done() + }, + { meta: true, minWidth: 20, minHeight: 30 } + ) + ).to.be.ok + }) + describe('from-image', function () { if (!loadImage.orientation) return From 2e72d13f9f4de50623d9b7e057d969e2121aa0ea Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:46:48 +0900 Subject: [PATCH 061/207] Return early for invalid orientation values. --- js/load-image-orientation.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 41ac1ee..71faf2f 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -111,19 +111,18 @@ Exif orientation values to correctly display the letter F: ) } - // Transform image orientation based on - // the given EXIF orientation option: + // Transform image orientation based on the given EXIF orientation option: loadImage.transformCoordinates = function (canvas, options) { originalTransformCoordinates.call(loadImage, canvas, options) + var orientation = options.orientation + if (!(orientation > 1 && orientation < 9)) { + return + } var ctx = canvas.getContext('2d') var width = canvas.width var height = canvas.height var styleWidth = canvas.style.width var styleHeight = canvas.style.height - var orientation = options.orientation - if (!(orientation > 1 && orientation < 9)) { - return - } if (orientation > 4) { canvas.width = height canvas.height = width From ae7013d4084a1b82a283be23c0543e92bd8ff2c2 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:49:37 +0900 Subject: [PATCH 062/207] Move transformCoordinates declaration to the end. --- js/load-image-orientation.js | 116 +++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 71faf2f..2f28171 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -111,64 +111,6 @@ Exif orientation values to correctly display the letter F: ) } - // Transform image orientation based on the given EXIF orientation option: - loadImage.transformCoordinates = function (canvas, options) { - originalTransformCoordinates.call(loadImage, canvas, options) - var orientation = options.orientation - if (!(orientation > 1 && orientation < 9)) { - return - } - var ctx = canvas.getContext('2d') - var width = canvas.width - var height = canvas.height - var styleWidth = canvas.style.width - var styleHeight = canvas.style.height - if (orientation > 4) { - canvas.width = height - canvas.height = width - canvas.style.width = styleHeight - canvas.style.height = styleWidth - } - switch (orientation) { - case 2: - // horizontal flip - ctx.translate(width, 0) - ctx.scale(-1, 1) - break - case 3: - // 180° rotate left - ctx.translate(width, height) - ctx.rotate(Math.PI) - break - case 4: - // vertical flip - ctx.translate(0, height) - ctx.scale(1, -1) - break - case 5: - // vertical flip + 90° rotate right - ctx.rotate(0.5 * Math.PI) - ctx.scale(1, -1) - break - case 6: - // 90° rotate right - ctx.rotate(0.5 * Math.PI) - ctx.translate(0, -height) - break - case 7: - // horizontal flip + 90° rotate right - ctx.rotate(0.5 * Math.PI) - ctx.translate(width, -height) - ctx.scale(-1, 1) - break - case 8: - // 90° rotate left - ctx.rotate(-0.5 * Math.PI) - ctx.translate(-width, 0) - break - } - } - // Transforms coordinate and dimension options // based on the given orientation option: loadImage.getTransformedOptions = function (img, opts, data) { @@ -250,4 +192,62 @@ Exif orientation values to correctly display the letter F: } return newOptions } + + // Transform image orientation based on the given EXIF orientation option: + loadImage.transformCoordinates = function (canvas, options) { + originalTransformCoordinates.call(loadImage, canvas, options) + var orientation = options.orientation + if (!(orientation > 1 && orientation < 9)) { + return + } + var ctx = canvas.getContext('2d') + var width = canvas.width + var height = canvas.height + var styleWidth = canvas.style.width + var styleHeight = canvas.style.height + if (orientation > 4) { + canvas.width = height + canvas.height = width + canvas.style.width = styleHeight + canvas.style.height = styleWidth + } + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(width, 0) + ctx.scale(-1, 1) + break + case 3: + // 180° rotate left + ctx.translate(width, height) + ctx.rotate(Math.PI) + break + case 4: + // vertical flip + ctx.translate(0, height) + ctx.scale(1, -1) + break + case 5: + // vertical flip + 90° rotate right + ctx.rotate(0.5 * Math.PI) + ctx.scale(1, -1) + break + case 6: + // 90° rotate right + ctx.rotate(0.5 * Math.PI) + ctx.translate(0, -height) + break + case 7: + // horizontal flip + 90° rotate right + ctx.rotate(0.5 * Math.PI) + ctx.translate(width, -height) + ctx.scale(-1, 1) + break + case 8: + // 90° rotate left + ctx.rotate(-0.5 * Math.PI) + ctx.translate(-width, 0) + break + } + } }) From 83ace3efe41ffbf8221431f546365918311656aa Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 00:07:26 +0900 Subject: [PATCH 063/207] Remove unnecessary double negation. --- js/load-image-orientation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 2f28171..312f6ac 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -97,7 +97,7 @@ Exif orientation values to correctly display the letter F: // Determines if the target image should be a canvas element: loadImage.hasCanvasOption = function (options) { return ( - (!!options.orientation === true && !loadImage.orientation) || + (options.orientation === true && !loadImage.orientation) || (options.orientation > 1 && options.orientation < 9) || originalHasCanvasOption.call(loadImage, options) ) From 2abe1704e69886711b4b3b8bafe946822a57f7cc Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 18:31:51 +0900 Subject: [PATCH 064/207] Pass data object to transformCoordinates function. --- js/load-image-scale.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index a662dde..2f1fcc7 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -40,7 +40,7 @@ // Transform image coordinates, allows to override e.g. // the canvas orientation based on the orientation option, - // gets canvas, options passed as arguments: + // gets canvas, options and data passed as arguments: loadImage.transformCoordinates = function () {} // Returns transformed options, allows to override e.g. @@ -121,6 +121,8 @@ loadImage.scale = function (img, options, data) { // eslint-disable-next-line no-param-reassign options = options || {} + // eslint-disable-next-line no-param-reassign + data = data || {} var canvas = document.createElement('canvas') var useCanvas = img.getContext || @@ -168,7 +170,7 @@ } if (useCanvas) { // eslint-disable-next-line no-param-reassign - options = loadImage.getTransformedOptions(img, options, data || {}) + options = loadImage.getTransformedOptions(img, options, data) sourceX = options.left || 0 sourceY = options.top || 0 if (options.sourceWidth) { @@ -285,7 +287,7 @@ } canvas.width = destWidth canvas.height = destHeight - loadImage.transformCoordinates(canvas, options) + loadImage.transformCoordinates(canvas, options, data) return loadImage.renderImageToCanvas( canvas, img, From e52c67b9f77c18a9a7a6f0f22b04ea0a80ce63ae Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 21:22:09 +0900 Subject: [PATCH 065/207] Rename functions for canvas and meta requirements. --- js/load-image-meta.js | 2 +- js/load-image-orientation.js | 12 ++++++------ js/load-image-scale.js | 10 +++------- js/load-image.js | 4 ++-- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/js/load-image-meta.js b/js/load-image-meta.js index ecdb077..63177d3 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -181,7 +181,7 @@ var originalTransform = loadImage.transform loadImage.transform = function (img, options, callback, file, data) { - if (loadImage.hasMetaOption(options)) { + if (loadImage.requiresMetaData(options)) { loadImage.parseMetaData( file, function (data) { diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 312f6ac..ce0557f 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -44,8 +44,8 @@ Exif orientation values to correctly display the letter F: 'use strict' var originalTransform = loadImage.transform - var originalHasCanvasOption = loadImage.hasCanvasOption - var originalHasMetaOption = loadImage.hasMetaOption + var originalRequiresCanvas = loadImage.requiresCanvas + var originalRequiresMetaData = loadImage.requiresMetaData var originalTransformCoordinates = loadImage.transformCoordinates var originalGetTransformedOptions = loadImage.getTransformedOptions @@ -95,19 +95,19 @@ Exif orientation values to correctly display the letter F: } // Determines if the target image should be a canvas element: - loadImage.hasCanvasOption = function (options) { + loadImage.requiresCanvas = function (options) { return ( (options.orientation === true && !loadImage.orientation) || (options.orientation > 1 && options.orientation < 9) || - originalHasCanvasOption.call(loadImage, options) + originalRequiresCanvas.call(loadImage, options) ) } // Determines if meta data should be loaded automatically: - loadImage.hasMetaOption = function (options) { + loadImage.requiresMetaData = function (options) { return ( (options && options.orientation === true && !loadImage.orientation) || - originalHasMetaOption.call(loadImage, options) + originalRequiresMetaData.call(loadImage, options) ) } diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 2f1fcc7..53fe5e6 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -109,15 +109,12 @@ } // Determines if the target image should be a canvas element: - loadImage.hasCanvasOption = function (options) { + loadImage.requiresCanvas = function (options) { return options.canvas || options.crop || !!options.aspectRatio } // Scales and/or crops the given image (img or canvas HTML element) - // using the given options. - // Returns a canvas object if the browser supports canvas - // and the hasCanvasOption method returns true or a canvas - // object is passed as image, else the scaled image: + // using the given options: loadImage.scale = function (img, options, data) { // eslint-disable-next-line no-param-reassign options = options || {} @@ -125,8 +122,7 @@ data = data || {} var canvas = document.createElement('canvas') var useCanvas = - img.getContext || - (loadImage.hasCanvasOption(options) && canvas.getContext) + img.getContext || (loadImage.requiresCanvas(options) && canvas.getContext) var width = img.naturalWidth || img.width var height = img.naturalHeight || img.height var destWidth = width diff --git a/js/load-image.js b/js/load-image.js index 50a36cd..865586d 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -54,7 +54,7 @@ return loadImage.onload(img, event, file, url, callback, options) } if (typeof file === 'string') { - if (loadImage.hasMetaOption(options)) { + if (loadImage.requiresMetaData(options)) { loadImage.fetchBlob(file, fetchBlobCallback, options) } else { fetchBlobCallback() @@ -102,7 +102,7 @@ // Determines if meta data should be loaded automatically. // Requires the load image meta extension to load meta data. - loadImage.hasMetaOption = function (options) { + loadImage.requiresMetaData = function (options) { return options && options.meta } From 0a0dc98c0103463de2e8911306c8726321c842e8 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 21:43:28 +0900 Subject: [PATCH 066/207] Refactor canvas+meta requirement checks for reuse. --- js/load-image-orientation.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index ce0557f..6920d73 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -94,11 +94,31 @@ Exif orientation values to correctly display the letter F: ) } + /** + * Determines if the image requires orientation. + * + * @param {object} [options] Options object + * @param {boolean} [withMetaData] Is meta data required for orientation + * @returns {boolean} Returns true if the image requires orientation + */ + function requiresOrientation(options, withMetaData) { + var orientation = options && options.orientation + return ( + // Exif orientation for browsers without automatic image orientation: + (orientation === true && !loadImage.orientation) || + // Orientation reset for browsers with automatic image orientation: + (orientation === 1 && loadImage.orientation) || + // Orientation to defined value, requires meta data for orientation reset: + ((!withMetaData || loadImage.orientation) && + orientation > 1 && + orientation < 9) + ) + } + // Determines if the target image should be a canvas element: loadImage.requiresCanvas = function (options) { return ( - (options.orientation === true && !loadImage.orientation) || - (options.orientation > 1 && options.orientation < 9) || + requiresOrientation(options) || originalRequiresCanvas.call(loadImage, options) ) } @@ -106,7 +126,7 @@ Exif orientation values to correctly display the letter F: // Determines if meta data should be loaded automatically: loadImage.requiresMetaData = function (options) { return ( - (options && options.orientation === true && !loadImage.orientation) || + requiresOrientation(options, true) || originalRequiresMetaData.call(loadImage, options) ) } From a3eb4cda44a6b7d3327af93fe970151dea697f0c Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 21:45:16 +0900 Subject: [PATCH 067/207] Move transform function below requirements checks. --- js/load-image-orientation.js | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 6920d73..edddb7c 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -67,33 +67,6 @@ Exif orientation values to correctly display the letter F: img.src = testImageURL })() - loadImage.transform = function (img, options, callback, file, data) { - originalTransform.call( - loadImage, - img, - options, - function (img, data) { - if (data) { - var exifOrientation = data.exif && data.exif.get('Orientation') - if ( - loadImage.orientation && - exifOrientation > 4 && - exifOrientation < 9 - ) { - // Automatic image orientation switched image dimensions - var originalWidth = data.originalWidth - var originalHeight = data.originalHeight - data.originalWidth = originalHeight - data.originalHeight = originalWidth - } - } - callback(img, data) - }, - file, - data - ) - } - /** * Determines if the image requires orientation. * @@ -131,6 +104,33 @@ Exif orientation values to correctly display the letter F: ) } + loadImage.transform = function (img, options, callback, file, data) { + originalTransform.call( + loadImage, + img, + options, + function (img, data) { + if (data) { + var exifOrientation = data.exif && data.exif.get('Orientation') + if ( + loadImage.orientation && + exifOrientation > 4 && + exifOrientation < 9 + ) { + // Automatic image orientation switched image dimensions + var originalWidth = data.originalWidth + var originalHeight = data.originalHeight + data.originalWidth = originalHeight + data.originalHeight = originalWidth + } + } + callback(img, data) + }, + file, + data + ) + } + // Transforms coordinate and dimension options // based on the given orientation option: loadImage.getTransformedOptions = function (img, opts, data) { From 212a3a3dcc138da248163795e2fa9221b3d4c614 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 23:35:29 +0900 Subject: [PATCH 068/207] Arrange Exif orientation visualization vertically. --- js/load-image-orientation.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index edddb7c..f700df1 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -10,16 +10,31 @@ */ /* - Exif orientation values to correctly display the letter F: - 1 2 3 4 5 6 7 8 + 1 2 + ██████ ██████ + ██ ██ + ████ ████ + ██ ██ + ██ ██ + + 3 4 + ██ ██ + ██ ██ + ████ ████ + ██ ██ + ██████ ██████ + + 5 6 +██████████ ██ +██ ██ ██ ██ +██ ██████████ -██████ ██████ ██ ██ ██████████ ██ ██ ██████████ -██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -████ ████ ████ ████ ██ ██████████ ██████████ ██ -██ ██ ██ ██ -██ ██ ██████ ██████ + 7 8 + ██ ██████████ + ██ ██ ██ ██ +██████████ ██ */ From 7e5f90b8c623bcdb2088715af89686f2ccb877b2 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 23:36:38 +0900 Subject: [PATCH 069/207] Update orientation requirements for canvas/meta. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 865156c..75d87c7 100644 --- a/README.md +++ b/README.md @@ -332,11 +332,15 @@ an `integer` in the range of `1` to `8` or the boolean value `true`. When set to `true`, it will set the orientation value based on the EXIF data of the image, which will be parsed automatically if the exif library is available. -Setting `orientation` to an integer in the range of `2` to `8` enables the -`canvas` option. Setting `orientation` to `true` enables the `canvas` and `meta` options, unless the browser supports automatic image orientation (see -[browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). +[browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). +Setting `orientation` to `1` enables the `canvas` and `meta` options if the +browser does support automatic image orientation (to allow reset of the +orientation). +Setting `orientation` to an integer in the range of `2` to `8` always enables +the `canvas` option and also enables the `meta` option if the browser supports +automatic image orientation (again to allow reset). ### meta From 0f65d7d1241dc0f0463a531e612a5b56c9e856da Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 23:38:06 +0900 Subject: [PATCH 070/207] Add Exif orientation visualization to the README. --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 75d87c7..a13ac05 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,34 @@ an `integer` in the range of `1` to `8` or the boolean value `true`. When set to `true`, it will set the orientation value based on the EXIF data of the image, which will be parsed automatically if the exif library is available. +Exif orientation values to correctly display the letter F: + +``` + 1 2 + ██████ ██████ + ██ ██ + ████ ████ + ██ ██ + ██ ██ + + 3 4 + ██ ██ + ██ ██ + ████ ████ + ██ ██ + ██████ ██████ + + 5 6 +██████████ ██ +██ ██ ██ ██ +██ ██████████ + + 7 8 + ██ ██████████ + ██ ██ ██ ██ +██████████ ██ +``` + Setting `orientation` to `true` enables the `canvas` and `meta` options, unless the browser supports automatic image orientation (see [browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). From 14b599e924979e43f8f5d75e3afde4752aea5ac9 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Thu, 23 Apr 2020 00:32:05 +0900 Subject: [PATCH 071/207] Simplify original dimensions normalization. --- js/load-image-orientation.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index f700df1..30833de 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -126,12 +126,9 @@ Exif orientation values to correctly display the letter F: options, function (img, data) { if (data) { - var exifOrientation = data.exif && data.exif.get('Orientation') - if ( - loadImage.orientation && - exifOrientation > 4 && - exifOrientation < 9 - ) { + var autoOrientation = + loadImage.orientation && data.exif && data.exif.get('Orientation') + if (autoOrientation > 4 && autoOrientation < 9) { // Automatic image orientation switched image dimensions var originalWidth = data.originalWidth var originalHeight = data.originalHeight From f088760e7b29c88f75e622e97b2a937491a2fc60 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:13:32 +0900 Subject: [PATCH 072/207] Normalize EXIF test names spelling. --- test/test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test.js b/test/test.js index 84b4a4b..33ed5f8 100644 --- a/test/test.js +++ b/test/test.js @@ -1031,7 +1031,7 @@ }) describe('Metadata', function () { - it('Parse Exif tags', function (done) { + it('Parse EXIF tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) @@ -1039,7 +1039,7 @@ }) }) - it('Do not parse Exif tags if disabled', function (done) { + it('Do not parse EXIF tags if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1050,7 +1050,7 @@ ) }) - it('Parse Exif tag offsets', function (done) { + it('Parse EXIF tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exifOffsets).to.be.ok expect(data.exifOffsets.get('Orientation')).to.equal(0x16) @@ -1060,7 +1060,7 @@ }) }) - it('Do not parse Exif tag offsets if disabled', function (done) { + it('Do not parse EXIF tag offsets if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1071,7 +1071,7 @@ ) }) - it('Only parse included Exif tags', function (done) { + it('Only parse included EXIF tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1091,7 +1091,7 @@ ) }) - it('Do not parse excluded Exif tags', function (done) { + it('Do not parse excluded EXIF tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1236,7 +1236,7 @@ ).to.be.ok }) - it('Write Exif Orientation tag and replace image head', function (done) { + it('Write EXIF Orientation tag and replace image head', function (done) { loadImage( blobJPEG, function (img, data) { @@ -1245,7 +1245,7 @@ expect(data.exif.get('Orientation')).to.equal(6) expect(data.iptc).to.be.ok expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') - // Reset Exif Orientation data: + // Reset EXIF Orientation data: loadImage.writeExifData(data.imageHead, data, 'Orientation', 1) img.toBlob(function (blob) { loadImage.replaceHead(blob, data.imageHead, function (newBlob) { From 001fe7fcf345d1fb7e5a8faa9545a7eb09da5c94 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:15:07 +0900 Subject: [PATCH 073/207] Test functions via instanceOf method. --- test/test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test.js b/test/test.js index 33ed5f8..64899a2 100644 --- a/test/test.js +++ b/test/test.js @@ -91,8 +91,8 @@ it('Return an object with onload and onerror methods', function () { var img = loadImage(blobGIF, function () {}) expect(img).to.be.an.instanceOf(Object) - expect(img.onload).to.be.a('function') - expect(img.onerror).to.be.a('function') + expect(img.onload).to.be.an.instanceOf(Function) + expect(img.onerror).to.be.an.instanceOf(Function) }) it('Load image url', function (done) { @@ -984,7 +984,7 @@ loadImage( blobGIF, function (img) { - expect(img.getContext).to.be.ok + expect(img.getContext).to.be.an.instanceOf(Function) expect(img.nodeName.toLowerCase()).to.equal('canvas') done() }, @@ -998,7 +998,7 @@ loadImage( blobGIF, function (img) { - expect(img.getContext).to.be.ok + expect(img.getContext).to.be.an.instanceOf(Function) expect(img.nodeName.toLowerCase()).to.equal('canvas') expect(img.width).to.equal(30) expect(img.height).to.equal(20) @@ -1018,7 +1018,7 @@ img = loadImage.scale(img, { maxWidth: 30 }) - expect(img.getContext).to.be.ok + expect(img.getContext).to.be.an.instanceOf(Function) expect(img.nodeName.toLowerCase()).to.equal('canvas') expect(img.width).to.equal(30) expect(img.height).to.equal(20) From 996dbb1bcfc60238961619be7a1889d8d409e383 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:18:04 +0900 Subject: [PATCH 074/207] Remove unnecessary destX/destY arguments. --- js/load-image-scale.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 53fe5e6..4f6ab50 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -82,8 +82,6 @@ sourceY, sourceWidth, sourceHeight, - destX, - destY, destWidth, destHeight, options @@ -100,8 +98,8 @@ sourceY, sourceWidth, sourceHeight, - destX, - destY, + 0, + 0, destWidth, destHeight ) @@ -252,8 +250,6 @@ sourceY, sourceWidth, sourceHeight, - 0, - 0, canvas.width, canvas.height, options @@ -273,8 +269,6 @@ 0, sourceWidth, sourceHeight, - 0, - 0, sourceWidth, sourceHeight, options @@ -291,8 +285,6 @@ sourceY, sourceWidth, sourceHeight, - 0, - 0, destWidth, destHeight, options From 8776ebe52bbe9509ba4407a0ce873bda51639680 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:22:33 +0900 Subject: [PATCH 075/207] Limit pixel ratio handling to scaling library. --- js/load-image-orientation.js | 4 ---- js/load-image-scale.js | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 30833de..d5e215e 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -235,13 +235,9 @@ Exif orientation values to correctly display the letter F: var ctx = canvas.getContext('2d') var width = canvas.width var height = canvas.height - var styleWidth = canvas.style.width - var styleHeight = canvas.style.height if (orientation > 4) { canvas.width = height canvas.height = width - canvas.style.width = styleHeight - canvas.style.height = styleWidth } switch (orientation) { case 2: diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 4f6ab50..e398b13 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -220,18 +220,14 @@ } if (useCanvas) { pixelRatio = options.pixelRatio - if (pixelRatio > 1) { - if (parseInt(img.style.width, 10) === width / pixelRatio) { - // Source image is already scaled according to device pixel ratio - canvas.style.width = destWidth / pixelRatio + 'px' - canvas.style.height = destHeight / pixelRatio + 'px' - } else { - canvas.style.width = destWidth + 'px' - canvas.style.height = destHeight + 'px' - destWidth *= pixelRatio - destHeight *= pixelRatio - canvas.getContext('2d').scale(pixelRatio, pixelRatio) - } + if ( + pixelRatio > 1 && + // Check if image has not yet device pixel ratio applied: + parseInt(img.style.width, 10) !== width / pixelRatio + ) { + destWidth *= pixelRatio + destHeight *= pixelRatio + canvas.getContext('2d').scale(pixelRatio, pixelRatio) } downsamplingRatio = options.downsamplingRatio if ( @@ -278,6 +274,10 @@ canvas.width = destWidth canvas.height = destHeight loadImage.transformCoordinates(canvas, options, data) + if (pixelRatio > 1) { + canvas.style.width = canvas.width / pixelRatio + 'px' + canvas.style.height = canvas.height / pixelRatio + 'px' + } return loadImage.renderImageToCanvas( canvas, img, From 4c79652b5357fdf7fd5ce0b3f45c386e4e732719 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 22:24:44 +0900 Subject: [PATCH 076/207] Fix IE10 ArrayBuffer.slice workaround. To use imageHead as DataView argument (e.g. for writing EXIF data), it needs to be a buffer. --- js/load-image-meta.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/load-image-meta.js b/js/load-image-meta.js index 63177d3..21c9961 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -96,6 +96,8 @@ var markerLength var parsers var i + var arr1 + var arr2 // Check for the JPEG marker (0xffd8): if (dataView.getUint16(0) === 0xffd8) { while (offset < maxOffset) { @@ -144,9 +146,12 @@ if (buffer.slice) { data.imageHead = buffer.slice(0, headLength) } else { - // Workaround for IE10, which does not yet - // support ArrayBuffer.slice: - data.imageHead = new Uint8Array(buffer).subarray(0, headLength) + // Workaround for IE10, which does not support + // ArrayBuffer.slice: + arr1 = new Uint8Array(buffer, 0, headLength) + arr2 = new Uint8Array(headLength) + arr2.set(arr1) + data.imageHead = arr2.buffer } } } else { From 681143cfb196bfeade745252fcc67fa04bb87d80 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 28 Apr 2020 19:40:14 +0900 Subject: [PATCH 077/207] Demo: take pixelRatio into account when cropping. Use contain:true instead of specifying both minWidth and maxWidth. Remove unnecessary downsamplingRatio option for cropping. --- js/demo/demo.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/demo/demo.js b/js/demo/demo.js index b42cdcd..fe1984c 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -250,10 +250,9 @@ $(function () { top: coordinates.y * pixelRatio, sourceWidth: coordinates.w * pixelRatio, sourceHeight: coordinates.h * pixelRatio, - minWidth: result.width(), - maxWidth: result.width(), + maxWidth: result.width() * pixelRatio, + contain: true, pixelRatio: pixelRatio, - downsamplingRatio: 0.5 }) ) coordinates = null From b86c22f62000513963980180454bb62901fba592 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 28 Apr 2020 19:41:03 +0900 Subject: [PATCH 078/207] Demo: add orientation selector. --- index.html | 18 ++++++++++++++++++ js/demo/demo.js | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index bc619ec..7192a00 100644 --- a/index.html +++ b/index.html @@ -80,6 +80,24 @@

    Select an image file

    Or drag & drop an image file onto this webpage.

    +

    + + +

    Result

    Select an image file

    +

    + + +

    Result

    Result

    API.

    -