From d32441a31cfa1d7f5ab0cf21663c01e8bad4e87f Mon Sep 17 00:00:00 2001 From: Roman Kuznetsov Date: Wed, 16 Nov 2022 01:08:06 +0300 Subject: [PATCH] feat: add different files format support --- README.md | 19 +- index.js | 55 +- lib/antialiasing-comparator.js | 6 +- lib/ignore-caret-comparator/index.js | 2 +- lib/ignore-caret-comparator/states/init.js | 6 +- lib/{png-base.js => image-base.js} | 2 +- .../bounded-png.js => image/bounded-image.js} | 14 +- lib/image/image.js | 41 + lib/image/index.js | 27 + lib/image/original-image.js | 17 + .../bounded-buffer.js | 4 +- lib/{png-buffer => img-buffer}/buffer.js | 4 +- lib/{png-buffer => img-buffer}/index.js | 2 +- lib/img-buffer/original-buffer.js | 20 + lib/png-buffer/original-buffer.js | 20 - lib/png-image/index.js | 42 - lib/png-image/original-png.js | 17 - lib/png-image/png.js | 51 - lib/utils.js | 34 +- package-lock.json | 909 ++++++++++++++++-- package.json | 3 +- test/ignore-caret-comparator.js | 6 +- test/png/index.js | 40 +- test/test.js | 2 +- 24 files changed, 1058 insertions(+), 285 deletions(-) rename lib/{png-base.js => image-base.js} (89%) rename lib/{png-image/bounded-png.js => image/bounded-image.js} (63%) create mode 100644 lib/image/image.js create mode 100644 lib/image/index.js create mode 100644 lib/image/original-image.js rename lib/{png-buffer => img-buffer}/bounded-buffer.js (83%) rename lib/{png-buffer => img-buffer}/buffer.js (61%) rename lib/{png-buffer => img-buffer}/index.js (89%) create mode 100644 lib/img-buffer/original-buffer.js delete mode 100644 lib/png-buffer/original-buffer.js delete mode 100644 lib/png-image/index.js delete mode 100644 lib/png-image/original-png.js delete mode 100644 lib/png-image/png.js diff --git a/README.md b/README.md index 6a4b5e9..922314e 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,17 @@ [![Build Status](https://travis-ci.org/gemini-testing/looks-same.svg?branch=master)](https://travis-ci.org/gemini-testing/looks-same) -Node.js library for comparing PNG-images, taking into account human color +Node.js library for comparing images, taking into account human color perception. It is created specially for the needs of visual regression testing for [`hermione`](http://github.com/gemini-testing/hermione) utility, but can be used for other purposes. +## Supported image formats + +JPEG, PNG, WebP, GIF, AVIF, TIFF and SVG images are supported. + +*Note: If you want to compare jpeg files, you may encounter random differences due to the jpeg structure if they are not lossless jpeg files.* + ## Comparing images ```javascript @@ -16,7 +22,7 @@ const looksSame = require('looks-same'); const {equal} = await looksSame('image1.png', 'image2.png'); ``` -Parameters can be paths to files or buffer with compressed `png` image. +Parameters can be paths to files or buffer with compressed image. By default, it will detect only noticeable differences. If you wish to detect any difference, use `strict` options: @@ -109,12 +115,15 @@ await looksSame.createDiff({ ## Building diff image as a Buffer If you don't want the diff image to be written on disk, then simply **don't** -pass any `diff: path` to the `createDiff` method. The callback will then -receive a `Buffer` containing the diff as the 2nd argument. +pass any `diff: path` to the `createDiff` method. The method will then +resolve a `Buffer` containing the diff. You can also specify buffer format +with `extension` key. Default extension is `png`. List of supported formats: +*`heic`, `heif`, `avif`, `jpeg`, `jpg`, `png`, `raw`, `tiff`, `tif`, `webp`, `gif`, `jp2`, `jpx`, `j2k`, `j2c`* ```javascript const buffer = await looksSame.createDiff({ - // exactly same options as above, but without diff + // exactly same options as above, but with optional extension and without diff + extension: 'png' }); ``` diff --git a/index.js b/index.js index 9f33d97..0566ab6 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ const _ = require('lodash'); const parseColor = require('parse-color'); const colorDiff = require('color-diff'); -const png = require('./lib/png-image'); +const img = require('./lib/image'); const areColorsSame = require('./lib/same-colors'); const AntialiasingComparator = require('./lib/antialiasing-comparator'); const IgnoreCaretComparator = require('./lib/ignore-caret-comparator'); @@ -11,8 +11,8 @@ const DiffArea = require('./lib/diff-area'); const utils = require('./lib/utils'); const {JND} = require('./lib/constants'); -const makeAntialiasingComparator = (comparator, png1, png2, opts) => { - const antialiasingComparator = new AntialiasingComparator(comparator, png1, png2, opts); +const makeAntialiasingComparator = (comparator, img1, img2, opts) => { + const antialiasingComparator = new AntialiasingComparator(comparator, img1, img2, opts); return (data) => antialiasingComparator.compare(data); }; @@ -34,11 +34,11 @@ function makeCIEDE2000Comparator(tolerance) { }; } -const createComparator = (png1, png2, opts) => { +const createComparator = (img1, img2, opts) => { let comparator = opts.strict ? areColorsSame : makeCIEDE2000Comparator(opts.tolerance); if (opts.ignoreAntialiasing) { - comparator = makeAntialiasingComparator(comparator, png1, png2, opts); + comparator = makeAntialiasingComparator(comparator, img1, img2, opts); } if (opts.ignoreCaret) { @@ -70,31 +70,39 @@ const iterateRect = async (width, height, callback) => { }); }; -const buildDiffImage = async (png1, png2, options) => { - const width = Math.max(png1.width, png2.width); - const height = Math.max(png1.height, png2.height); - const minWidth = Math.min(png1.width, png2.width); - const minHeight = Math.min(png1.height, png2.height); +const buildDiffImage = async (img1, img2, options) => { + const width = Math.max(img1.width, img2.width); + const height = Math.max(img1.height, img2.height); + const minWidth = Math.min(img1.width, img2.width); + const minHeight = Math.min(img1.height, img2.height); + const highlightColor = options.highlightColor; - const result = png.empty(width, height); + const resultBuffer = Buffer.alloc(width * height * 3); + + const setPixel = (buf, x, y, {R, G, B}) => { + const pixelInd = (y * width + x) * 3; + buf[pixelInd] = R; + buf[pixelInd + 1] = G; + buf[pixelInd + 2] = B; + }; await iterateRect(width, height, (x, y) => { if (x >= minWidth || y >= minHeight) { - result.setPixel(x, y, highlightColor); + setPixel(resultBuffer, x, y, highlightColor); return; } - const color1 = png1.getPixel(x, y); - const color2 = png2.getPixel(x, y); + const color1 = img1.getPixel(x, y); + const color2 = img2.getPixel(x, y); - if (!options.comparator({color1, color2, png1, png2, x, y, width, height})) { - result.setPixel(x, y, highlightColor); + if (!options.comparator({color1, color2, img1, img2, x, y, width, height})) { + setPixel(resultBuffer, x, y, highlightColor); } else { - result.setPixel(x, y, color1); + setPixel(resultBuffer, x, y, color1); } }); - return result; + return img.fromBuffer(resultBuffer, {raw: {width, height, channels: 3}}); }; const parseColorString = (str) => { @@ -163,16 +171,16 @@ module.exports = exports = async function looksSame(image1, image2, opts = {}) { return {equal: false, metaInfo, diffBounds, diffClusters: [diffBounds]}; } - const {first: png1, second: png2} = await utils.readPair( + const {first: img1, second: img2} = await utils.readPair( {...image1, source: first.buffer}, {...image2, source: second.buffer}, - utils.readPngCb + utils.readImgCb ); - const comparator = createComparator(png1, png2, opts); + const comparator = createComparator(img1, img2, opts); const {stopOnFirstFail, shouldCluster, clustersSize} = opts; - const {diffArea, diffClusters} = await utils.getDiffPixelsCoords(png1, png2, comparator, {stopOnFirstFail, shouldCluster, clustersSize}); + const {diffArea, diffClusters} = await utils.getDiffPixelsCoords(img1, img2, comparator, {stopOnFirstFail, shouldCluster, clustersSize}); const diffBounds = diffArea.area; const equal = diffArea.isEmpty(); @@ -202,6 +210,7 @@ exports.getDiffArea = async function(image1, image2, opts = {}) { exports.createDiff = async function saveDiff(opts) { opts = prepareOpts(opts); + opts.extension = opts.extension || 'png'; const [image1, image2] = utils.formatImages(opts.reference, opts.current); const {first, second} = await utils.readPair(image1, image2); @@ -211,7 +220,7 @@ exports.createDiff = async function saveDiff(opts) { }); return opts.diff === undefined - ? diffImage.createBuffer() + ? diffImage.createBuffer(opts.extension) : diffImage.save(opts.diff); }; diff --git a/lib/antialiasing-comparator.js b/lib/antialiasing-comparator.js index 3b9f9c7..cb354c9 100644 --- a/lib/antialiasing-comparator.js +++ b/lib/antialiasing-comparator.js @@ -8,10 +8,10 @@ const DEFAULT_BRIGHTNESS_TOLERANCE = 0; module.exports = class AntialiasingComparator { - constructor(baseComparator, png1, png2, {antialiasingTolerance = 0}) { + constructor(baseComparator, img1, img2, {antialiasingTolerance = 0}) { this._baseComparator = baseComparator; - this._img1 = png1; - this._img2 = png2; + this._img1 = img1; + this._img2 = img2; this._brightnessTolerance = antialiasingTolerance; // used only when comparing the darkest and the brightest pixels } diff --git a/lib/ignore-caret-comparator/index.js b/lib/ignore-caret-comparator/index.js index 3db834f..c78cc5a 100644 --- a/lib/ignore-caret-comparator/index.js +++ b/lib/ignore-caret-comparator/index.js @@ -31,7 +31,7 @@ module.exports = class IgnoreCaretComparator { } _checkIsCaret(data) { - return this._state.validate(_.pick(data, ['x', 'y']), _.pick(data, ['png1', 'png2'])); + return this._state.validate(_.pick(data, ['x', 'y']), _.pick(data, ['img1', 'img2'])); } switchState(stateName) { diff --git a/lib/ignore-caret-comparator/states/init.js b/lib/ignore-caret-comparator/states/init.js index 2f4805e..7045f1a 100644 --- a/lib/ignore-caret-comparator/states/init.js +++ b/lib/ignore-caret-comparator/states/init.js @@ -35,12 +35,12 @@ module.exports = class InitState extends State { } _isPointOutsideImages(point, imgs) { - return _.some(imgs, (png) => point.x >= png.width || point.y >= png.height); + return _.some(imgs, (img) => point.x >= img.width || point.y >= img.height); } _areColorsSame(point, imgs) { - const color1 = imgs.png1.getPixel(point.x, point.y); - const color2 = imgs.png2.getPixel(point.x, point.y); + const color1 = imgs.img1.getPixel(point.x, point.y); + const color2 = imgs.img2.getPixel(point.x, point.y); return areColorsSame({color1, color2}); } diff --git a/lib/png-base.js b/lib/image-base.js similarity index 89% rename from lib/png-base.js rename to lib/image-base.js index 1197aee..382dea4 100644 --- a/lib/png-base.js +++ b/lib/image-base.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports = class PNGBase { +module.exports = class ImageBase { static create(...args) { return new this(...args); } diff --git a/lib/png-image/bounded-png.js b/lib/image/bounded-image.js similarity index 63% rename from lib/png-image/bounded-png.js rename to lib/image/bounded-image.js index 9b49e85..93e02e2 100644 --- a/lib/png-image/bounded-png.js +++ b/lib/image/bounded-image.js @@ -1,10 +1,10 @@ 'use strict'; -const PNGImage = require('./png'); +const Image = require('./image'); -module.exports = class BoundedPNGImage extends PNGImage { - constructor(png, boundingBox) { - super(png); +module.exports = class BoundedImage extends Image { + constructor(img, boundingBox) { + super(img); this._boundingBox = boundingBox; } @@ -15,12 +15,6 @@ module.exports = class BoundedPNGImage extends PNGImage { return super.getPixel(actX, actY); } - setPixel(x, y, color) { - const {x: actX, y: actY} = this.getActualCoord(x, y); - - super.setPixel(actX, actY, color); - } - getActualCoord(x, y) { return {x: x + this._boundingBox.left, y: y + this._boundingBox.top}; } diff --git a/lib/image/image.js b/lib/image/image.js new file mode 100644 index 0000000..0f01d4e --- /dev/null +++ b/lib/image/image.js @@ -0,0 +1,41 @@ +'use strict'; + +const ImageBase = require('../image-base'); + +module.exports = class Image extends ImageBase { + constructor(img) { + super(); + + this._img = img; + } + + async init() { + const {data, info} = await this._img.raw().toBuffer({resolveWithObject: true}); + + this._buffer = data; + this._width = info.width; + this._height = info.height; + this._channels = info.channels; + } + + getPixel(x, y) { + const idx = this._getIdx(x, y); + return { + R: this._buffer[idx], + G: this._buffer[idx + 1], + B: this._buffer[idx + 2] + }; + } + + _getIdx(x, y) { + return (this._width * y + x) * this._channels; + } + + async save(path) { + return this._img.toFile(path); + } + + async createBuffer(extension) { + return this._img.toFormat(extension).toBuffer(); + } +}; diff --git a/lib/image/index.js b/lib/image/index.js new file mode 100644 index 0000000..f65b1dc --- /dev/null +++ b/lib/image/index.js @@ -0,0 +1,27 @@ +'use strict'; + +const fs = require('fs-extra'); +const NestedError = require('nested-error-stacks'); +const sharp = require('sharp'); +const OriginalIMG = require('./original-image'); +const BoundedIMG = require('./bounded-image'); + +const createimage = async (img, {boundingBox} = {}) => { + return boundingBox + ? BoundedIMG.create(img, boundingBox) + : OriginalIMG.create(img); +}; + +exports.fromBuffer = async (buffer, opts) => { + const img = sharp(buffer, opts); + return createimage(img, opts); +}; + +exports.fromFile = async (filePath, opts = {}) => { + try { + const buffer = await fs.readFile(filePath); + return exports.fromBuffer(buffer, opts); + } catch (err) { + throw new NestedError(`Can't load img file ${filePath}`, err); + } +}; diff --git a/lib/image/original-image.js b/lib/image/original-image.js new file mode 100644 index 0000000..e5157a8 --- /dev/null +++ b/lib/image/original-image.js @@ -0,0 +1,17 @@ +'use strict'; + +const Image = require('./image'); + +module.exports = class OriginalImage extends Image { + getActualCoord(x, y) { + return {x, y}; + } + + get width() { + return this._width; + } + + get height() { + return this._height; + } +}; diff --git a/lib/png-buffer/bounded-buffer.js b/lib/img-buffer/bounded-buffer.js similarity index 83% rename from lib/png-buffer/bounded-buffer.js rename to lib/img-buffer/bounded-buffer.js index da821f9..466dc7d 100644 --- a/lib/png-buffer/bounded-buffer.js +++ b/lib/img-buffer/bounded-buffer.js @@ -1,8 +1,8 @@ 'use strict'; -const PNGBuffer = require('./buffer'); +const IMGBuffer = require('./buffer'); -module.exports = class BoundedPNGBuffer extends PNGBuffer { +module.exports = class BoundedIMGBuffer extends IMGBuffer { constructor(buffer, boundingBox) { super(buffer); diff --git a/lib/png-buffer/buffer.js b/lib/img-buffer/buffer.js similarity index 61% rename from lib/png-buffer/buffer.js rename to lib/img-buffer/buffer.js index 3dc720d..6bd0f66 100644 --- a/lib/png-buffer/buffer.js +++ b/lib/img-buffer/buffer.js @@ -1,8 +1,8 @@ 'use strict'; -const PNGBase = require('../png-base'); +const ImageBase = require('../image-base'); -module.exports = class PNGBuffer extends PNGBase { +module.exports = class IMGBuffer extends ImageBase { constructor(buffer) { super(); diff --git a/lib/png-buffer/index.js b/lib/img-buffer/index.js similarity index 89% rename from lib/png-buffer/index.js rename to lib/img-buffer/index.js index 68bfb68..8ff50c4 100644 --- a/lib/png-buffer/index.js +++ b/lib/img-buffer/index.js @@ -16,6 +16,6 @@ exports.fromFile = async (filePath, opts = {}) => { const buffer = await fs.readFile(filePath); return exports.create(buffer, opts); } catch (err) { - throw new NestedError(`Can't load png file ${filePath}`, err); + throw new NestedError(`Can't load img file ${filePath}`, err); } }; diff --git a/lib/img-buffer/original-buffer.js b/lib/img-buffer/original-buffer.js new file mode 100644 index 0000000..77d24d7 --- /dev/null +++ b/lib/img-buffer/original-buffer.js @@ -0,0 +1,20 @@ +'use strict'; + +const IMGBuffer = require('./buffer'); + +const IMG_WIDTH_OFFSET = 16; +const IMG_HEIGHT_OFFSET = 20; + +module.exports = class OriginalIMGBuffer extends IMGBuffer { + getActualCoord(x, y) { + return {x, y}; + } + + get width() { + return this._buffer.readUInt32BE(IMG_WIDTH_OFFSET); + } + + get height() { + return this._buffer.readUInt32BE(IMG_HEIGHT_OFFSET); + } +}; diff --git a/lib/png-buffer/original-buffer.js b/lib/png-buffer/original-buffer.js deleted file mode 100644 index 240e59e..0000000 --- a/lib/png-buffer/original-buffer.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -const PNGBuffer = require('./buffer'); - -const PNG_WIDTH_OFFSET = 16; -const PNG_HEIGHT_OFFSET = 20; - -module.exports = class OriginalPNGBuffer extends PNGBuffer { - getActualCoord(x, y) { - return {x, y}; - } - - get width() { - return this._buffer.readUInt32BE(PNG_WIDTH_OFFSET); - } - - get height() { - return this._buffer.readUInt32BE(PNG_HEIGHT_OFFSET); - } -}; diff --git a/lib/png-image/index.js b/lib/png-image/index.js deleted file mode 100644 index 2142983..0000000 --- a/lib/png-image/index.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const fs = require('fs-extra'); -const NestedError = require('nested-error-stacks'); -const {PNG} = require('pngjs'); -const OriginalPNG = require('./original-png'); -const BoundedPNG = require('./bounded-png'); - -function parseBuffer(buffer) { - return new Promise((resolve, reject) => { - const png = new PNG(); - png.parse(buffer, (err) => { - if (err) { - reject(err); - } else { - resolve(png); - } - }); - }); -} - -exports.create = (png, {boundingBox} = {}) => { - return boundingBox - ? BoundedPNG.create(png, boundingBox) - : OriginalPNG.create(png); -}; - -exports.fromFile = async (filePath, opts = {}) => { - try { - const buffer = await fs.readFile(filePath); - return await exports.fromBuffer(buffer, opts); - } catch (err) { - throw new NestedError(`Can't load png file ${filePath}`, err); - } -}; - -exports.fromBuffer = async (buffer, opts = {}) => { - const png = await parseBuffer(buffer); - return exports.create(png, opts); -}; - -exports.empty = (width, height) => exports.create(new PNG({width, height})); diff --git a/lib/png-image/original-png.js b/lib/png-image/original-png.js deleted file mode 100644 index 47c8408..0000000 --- a/lib/png-image/original-png.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -const PNGImage = require('./png'); - -module.exports = class OriginalPNGImage extends PNGImage { - getActualCoord(x, y) { - return {x, y}; - } - - get width() { - return this._png.width; - } - - get height() { - return this._png.height; - } -}; diff --git a/lib/png-image/png.js b/lib/png-image/png.js deleted file mode 100644 index a6c4e73..0000000 --- a/lib/png-image/png.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const concat = require('concat-stream'); -const PNGBase = require('../png-base'); - -module.exports = class PNGImage extends PNGBase { - constructor(png) { - super(); - - this._png = png; - } - - getPixel(x, y) { - const idx = this._getIdx(x, y); - return { - R: this._png.data[idx], - G: this._png.data[idx + 1], - B: this._png.data[idx + 2] - }; - } - - setPixel(x, y, color) { - const idx = this._getIdx(x, y); - this._png.data[idx] = color.R; - this._png.data[idx + 1] = color.G; - this._png.data[idx + 2] = color.B; - this._png.data[idx + 3] = 255; - } - - _getIdx(x, y) { - return (this._png.width * y + x) * 4; - } - - async save(path) { - const writeStream = fs.createWriteStream(path); - this._png.pack().pipe(writeStream); - - return new Promise((resolve, reject) => { - writeStream.on('error', (error) => reject(error)); - writeStream.on('finish', () => resolve(null)); - }); - } - - async createBuffer() { - return new Promise((resolve, reject) => { - this._png.pack().pipe(concat(resolve)); - this._png.on('error', reject); - }); - } -}; diff --git a/lib/utils.js b/lib/utils.js index e5ba735..b7d52e1 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,15 +1,19 @@ 'use strict'; const _ = require('lodash'); -const png = require('./png-image'); -const buffer = require('./png-buffer'); +const img = require('./image'); +const buffer = require('./img-buffer'); const DiffArea = require('./diff-area'); const DiffClusters = require('./diff-clusters'); const validators = require('./validators'); -exports.readPngCb = ({source, ...opts}) => { - const readFunc = Buffer.isBuffer(source) ? png.fromBuffer : png.fromFile; - return readFunc(source, opts); +exports.readImgCb = async ({source, ...opts}) => { + const readFunc = Buffer.isBuffer(source) ? img.fromBuffer : img.fromFile; + const image = await readFunc(source, opts); + + await image.init(); + + return image; }; exports.readBufferCb = ({source, ...opts}) => { @@ -17,21 +21,21 @@ exports.readBufferCb = ({source, ...opts}) => { return readFunc(source, opts); }; -exports.readPair = async (first, second, readCb = exports.readPngCb) => { - const [firstPng, secondPng] = await Promise.all([first, second].map(readCb)); +exports.readPair = async (first, second, readCb = exports.readImgCb) => { + const [firstImg, secondImg] = await Promise.all([first, second].map(readCb)); - return {first: firstPng, second: secondPng}; + return {first: firstImg, second: secondImg}; }; const getDiffClusters = (diffClusters, diffArea, {shouldCluster}) => { return shouldCluster ? diffClusters.clusters : [diffArea.area]; }; -exports.getDiffPixelsCoords = async (png1, png2, predicate, opts = {}) => { +exports.getDiffPixelsCoords = async (img1, img2, predicate, opts = {}) => { const stopOnFirstFail = opts.hasOwnProperty('stopOnFirstFail') ? opts.stopOnFirstFail : false; - const width = Math.min(png1.width, png2.width); - const height = Math.min(png1.height, png2.height); + const width = Math.min(img1.width, img2.width); + const height = Math.min(img1.height, img2.height); const diffArea = new DiffArea(); const diffClusters = new DiffClusters(opts.clustersSize); @@ -40,18 +44,18 @@ exports.getDiffPixelsCoords = async (png1, png2, predicate, opts = {}) => { const processRow = (y) => { setImmediate(() => { for (let x = 0; x < width; x++) { - const color1 = png1.getPixel(x, y); - const color2 = png2.getPixel(x, y); + const color1 = img1.getPixel(x, y); + const color2 = img2.getPixel(x, y); const result = predicate({ color1, color2, - png1, png2, + img1, img2, x, y, width, height }); if (!result) { - const {x: actX, y: actY} = png1.getActualCoord(x, y); + const {x: actX, y: actY} = img1.getActualCoord(x, y); diffArea.update(actX, actY); if (opts.shouldCluster) { diffClusters.update(actX, actY); diff --git a/package-lock.json b/package-lock.json index 51c7e39..de00140 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,17 +6,16 @@ "packages": { "": { "name": "looks-same", - "version": "7.3.0", + "version": "8.0.1", "license": "MIT", "dependencies": { "color-diff": "^1.1.0", - "concat-stream": "^1.6.2", "fs-extra": "^8.1.0", "js-graph-algorithms": "1.0.18", "lodash": "^4.17.3", "nested-error-stacks": "^2.1.0", "parse-color": "^1.0.0", - "pngjs": "^6.0.0" + "sharp": "~0.30.7" }, "devDependencies": { "@types/node": "^10.12.3", @@ -33,7 +32,7 @@ "temp": "^0.8.3" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 12.0.0" } }, "node_modules/@sinonjs/commons": { @@ -255,6 +254,48 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -271,10 +312,34 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true }, "node_modules/caller-path": { "version": "0.1.0", @@ -411,6 +476,11 @@ "node": "*" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "node_modules/circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", @@ -482,6 +552,18 @@ "node": ">=6" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", @@ -495,8 +577,32 @@ "node_modules/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", - "dev": true + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { "version": "2.15.1", @@ -520,20 +626,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "node_modules/conventional-changelog": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.9.tgz", @@ -853,7 +945,8 @@ "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "node_modules/cross-spawn": { "version": "6.0.5", @@ -944,6 +1037,20 @@ "node": ">=0.10.0" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -956,6 +1063,14 @@ "node": ">=0.12" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -1002,6 +1117,14 @@ "node": ">=8" } }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.0.0.tgz", @@ -1121,6 +1244,14 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, + "node_modules/end-of-stream": { + "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==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1327,6 +1458,14 @@ "node": ">=0.10.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/external-editor": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", @@ -1497,6 +1636,11 @@ "node": ">=0.10.0" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -1875,6 +2019,11 @@ "ini": "^1.3.2" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -2050,6 +2199,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -2088,16 +2256,15 @@ } }, "node_modules/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==" }, "node_modules/ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", - "dev": true, "engines": { "node": "*" } @@ -2282,7 +2449,8 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "node_modules/isexe": { "version": "2.0.0", @@ -2551,6 +2719,17 @@ "node": ">=4" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -2595,6 +2774,11 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/mocha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", @@ -2660,6 +2844,11 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2696,6 +2885,52 @@ "text-encoding": "^0.6.4" } }, + "node_modules/node-abi": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.28.0.tgz", + "integrity": "sha512-fRlDb4I0eLcQeUvGq7IY3xHrSb0c9ummdvDSYWfT9+LKP+3jCKw/tKoqaM7r1BAoiAC6GtwyjaGnOz6B3OtF+A==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -2757,7 +2992,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "dependencies": { "wrappy": "1" } @@ -3002,12 +3236,37 @@ "node": ">=4" } }, - "node_modules/pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, "engines": { - "node": ">=12.13.0" + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/prelude-ls": { @@ -3022,7 +3281,8 @@ "node_modules/process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true }, "node_modules/progress": { "version": "2.0.0", @@ -3050,6 +3310,15 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -3078,6 +3347,28 @@ "node": ">=4" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -3121,6 +3412,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3302,6 +3594,58 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "node_modules/sharp": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", + "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.7", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=12.13.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -3329,6 +3673,62 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/sinon": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.5.tgz", @@ -3644,7 +4044,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3684,6 +4083,45 @@ "node": ">=4.0.0" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", @@ -3773,6 +4211,17 @@ "node": ">=0.10.0" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -3797,7 +4246,8 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, "node_modules/uglify-js": { "version": "3.6.4", @@ -3958,8 +4408,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/write": { "version": "0.2.1", @@ -4309,6 +4758,33 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4325,10 +4801,20 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true }, "caller-path": { "version": "0.1.0", @@ -4437,6 +4923,11 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", @@ -4497,6 +4988,30 @@ } } }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "dependencies": { + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, "color-convert": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", @@ -4510,8 +5025,16 @@ "color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", - "dev": true + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } }, "commander": { "version": "2.15.1", @@ -4535,17 +5058,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "conventional-changelog": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.9.tgz", @@ -4796,7 +5308,8 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "cross-spawn": { "version": "6.0.5", @@ -4868,6 +5381,14 @@ } } }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -4877,6 +5398,11 @@ "type-detect": "^4.0.0" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -4914,6 +5440,11 @@ "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", "dev": true }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, "detect-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.0.0.tgz", @@ -5005,6 +5536,14 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, + "end-of-stream": { + "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==", + "requires": { + "once": "^1.4.0" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -5165,6 +5704,11 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "external-editor": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", @@ -5301,6 +5845,11 @@ "null-check": "^1.0.0" } }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -5603,6 +6152,11 @@ "ini": "^1.3.2" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -5736,6 +6290,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -5765,15 +6324,14 @@ } }, "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==" }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { "version": "5.2.0", @@ -5916,7 +6474,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isexe": { "version": "2.0.0", @@ -6150,6 +6709,11 @@ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -6184,6 +6748,11 @@ "minimist": "0.0.8" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "mocha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", @@ -6238,6 +6807,11 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6274,6 +6848,42 @@ "text-encoding": "^0.6.4" } }, + "node-abi": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.28.0.tgz", + "integrity": "sha512-fRlDb4I0eLcQeUvGq7IY3xHrSb0c9ummdvDSYWfT9+LKP+3jCKw/tKoqaM7r1BAoiAC6GtwyjaGnOz6B3OtF+A==", + "requires": { + "semver": "^7.3.5" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -6325,7 +6935,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -6522,10 +7131,31 @@ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, - "pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==" + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + } + } }, "prelude-ls": { "version": "1.1.2", @@ -6536,7 +7166,8 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true }, "progress": { "version": "2.0.0", @@ -6561,6 +7192,15 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -6579,6 +7219,24 @@ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", "dev": true }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + } + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -6615,6 +7273,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6759,6 +7418,44 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "sharp": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", + "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "requires": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.7", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -6780,6 +7477,36 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "sinon": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.5.tgz", @@ -7050,8 +7777,7 @@ "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=", - "dev": true + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { "version": "2.0.0", @@ -7079,6 +7805,41 @@ "string-width": "^2.1.1" } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", @@ -7151,6 +7912,14 @@ "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", "dev": true }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -7169,7 +7938,8 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, "uglify-js": { "version": "3.6.4", @@ -7307,8 +8077,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", diff --git a/package.json b/package.json index d942c70..5afc6fb 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,12 @@ }, "dependencies": { "color-diff": "^1.1.0", - "concat-stream": "^1.6.2", "fs-extra": "^8.1.0", "js-graph-algorithms": "1.0.18", "lodash": "^4.17.3", "nested-error-stacks": "^2.1.0", "parse-color": "^1.0.0", - "pngjs": "^6.0.0" + "sharp": "~0.30.7" }, "devDependencies": { "@types/node": "^10.12.3", diff --git a/test/ignore-caret-comparator.js b/test/ignore-caret-comparator.js index 7c16e39..ee8eec6 100644 --- a/test/ignore-caret-comparator.js +++ b/test/ignore-caret-comparator.js @@ -16,14 +16,14 @@ describe('IgnoreCaretComparator', () => { const width = pixels[0].length; const height = pixels.length; - const png1 = {data: pixels, getPixel: (x, y) => pixels[y][x], width, height}; - const png2 = {data: emptyPixels, getPixel: (x, y) => emptyPixels[y][x], width, height}; + const img1 = {data: pixels, getPixel: (x, y) => pixels[y][x], width, height}; + const img2 = {data: emptyPixels, getPixel: (x, y) => emptyPixels[y][x], width, height}; let res = true; for (let y = 0; y < pixels.length; ++y) { for (let x = 0; x < pixels[y].length; ++x) { - res = comparator({color1: png1.data[y][x], color2: png2.data[y][x], x, y, png1, png2}); + res = comparator({color1: img1.data[y][x], color2: img2.data[y][x], x, y, img1, img2}); if (!res) { break; } diff --git a/test/png/index.js b/test/png/index.js index 3a8c81c..264ea05 100644 --- a/test/png/index.js +++ b/test/png/index.js @@ -1,42 +1,56 @@ 'use strict'; const sinon = require('sinon'); +const proxyquire = require('proxyquire'); const fs = require('fs-extra'); -const {PNG} = require('pngjs'); -const {fromFile} = require('../../lib/png-image'); const stubBuffer = Buffer.from([123]); -describe('lib/png-image/index.js', () => { +describe('lib/image/index.js', () => { const sandbox = sinon.createSandbox(); let parseError; - + let image; + let mkSharpImage_; beforeEach(() => { parseError = null; + mkSharpImage_ = sandbox.stub(); + image = proxyquire('../../lib/image', {'sharp': mkSharpImage_}); sandbox.stub(fs, 'readFile').resolves(stubBuffer); - sandbox.stub(PNG.prototype, 'parse').callsFake((buffer, cb) => { - cb(parseError); - }); }); afterEach(() => sandbox.restore()); describe('fromFile', () => { - it('should parse and return PNG', async () => { - const png = await fromFile('/filePath'); + it('should parse and return sharp instance', async () => { + await image.fromFile('/filePath'); - assert.instanceOf(png._png, PNG); - assert.calledOnceWith(PNG.prototype.parse, stubBuffer); + assert.calledOnceWith(mkSharpImage_, stubBuffer); }); it('should throw error with file path and original error message at stack', async () => { parseError = new Error('test error'); + fs.readFile.withArgs('/filePath').rejects(parseError); - const error = await assert.isRejected(fromFile('/filePath')); + const error = await assert.isRejected(image.fromFile('/filePath')); - assert.match(error.message, 'Can\'t load png file /filePath'); + assert.match(error.message, 'Can\'t load img file /filePath'); assert.match(error.stack, 'Error: test error'); }); }); + + it('should create image from raw buffer', async () => { + const rawBuffer = 'foo'; + const rawOpts = { + raw: { + width: 100500, + height: 500100, + channels: 42 + } + }; + + await image.fromBuffer(rawBuffer, rawOpts); + + assert.calledOnceWith(mkSharpImage_, rawBuffer, rawOpts); + }); }); diff --git a/test/test.js b/test/test.js index 9313191..b3da29b 100644 --- a/test/test.js +++ b/test/test.js @@ -71,7 +71,7 @@ describe('looksSame', () => { assert.notCalled(utils.getDiffPixelsCoords); }); - it('should return false for different images (compare by png pixels)', async () => { + it('should return false for different images (compare by img pixels)', async () => { sandbox.spy(utils, 'getDiffPixelsCoords'); const {equal} = await looksSame(getImage('ref.png'), getImage('different.png'));