diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34dca74..61ea93f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,49 +1,79 @@ name: CI on: - push: - branches: [main] - pull_request: - branches: [main] + push: + branches: [main] + pull_request: + branches: [main] jobs: - verify_files: - name: Verify Files - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Setup Node - uses: actions/setup-node@v2 - with: - node-version: '18.x' - cache: 'npm' - - name: Install Packages - run: npm ci - - name: Lint Files - run: npm run lint - - name: Typecheck - run: npm run typecheck - - name: Typecheck (React 18) - run: | - npm i --no-save @types/react@18 @types/react-dom@18 - npm run typecheck - tests: - name: Tests - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Setup Node - uses: actions/setup-node@v2 - with: - node-version: '18.x' - cache: 'npm' - - name: Install Packages - run: npm ci - - name: Unit Tests - run: npm run test + verify_files: + name: Verify Files + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '18.x' + cache: 'npm' + - name: Install Packages + run: npm ci + - name: Lint Files + run: npm run lint + - name: Typecheck + run: npm run typecheck + - name: Typecheck (React 18) + run: | + npm i --no-save @types/react@18 @types/react-dom@18 + npm run typecheck + + tests_units: + name: Unit testing + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '18.x' + cache: 'npm' + - name: Install Packages + run: npm ci + - name: Unit Tests + run: npm run test:units + + test_screenshots: + name: Screenshot testing + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '18.x' + cache: 'npm' + + - name: Install Packages + run: npm ci + - name: Build + run: npm run build + - name: Run tests + run: npm run test:screenshots -- --updateSnapshot + + - name: Commit + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "robot@gravity-ui.com" + git add . + git commit -m "Update screenshots test" + git push origin test/screenshots diff --git a/jest.config.screenshots.ts b/jest.config.screenshots.ts new file mode 100644 index 0000000..8716b9b --- /dev/null +++ b/jest.config.screenshots.ts @@ -0,0 +1,9 @@ +import type {Config} from '@jest/types'; + +const cfg: Config.InitialOptions = { + preset: 'ts-jest', + roots: ['/tests/screenshots'], + globalTeardown: '/tests/screenshots/teardown.ts', +}; + +export default cfg; diff --git a/jest.config.ts b/jest.config.units.ts similarity index 90% rename from jest.config.ts rename to jest.config.units.ts index 663e974..b160eb2 100644 --- a/jest.config.ts +++ b/jest.config.units.ts @@ -8,6 +8,7 @@ const cfg: Config.InitialOptions = { coverageReporters: ['json', 'html'], coverageDirectory: './coverage', setupFiles: ['/tests/setup.js'], + roots: ['/tests/units'], }; export default cfg; diff --git a/package-lock.json b/package-lock.json index 8c24430..183b37e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@babel/preset-react": "^7.22.5", "@doc-tools/docs": "^1.13.1", "@types/jest": "^26.0.24", + "@types/jest-image-snapshot": "^6.1.0", "@types/node": "^10.11.0", "@types/react": "^17.0.2", "@typescript-eslint/eslint-plugin": "^4.5.0", @@ -30,10 +31,12 @@ "husky": "^1.0.1", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", + "jest-image-snapshot": "^6.2.0", "lint-staged": "^8.0.0", "monaco-editor": "^0.23.0", "node-sass": "^7.0.1", "prettier": "^2.3.0", + "puppeteer": "^20.9.0", "react": "^17.0.1", "react-dom": "^17.0.1", "rimraf": "^2.6.2", @@ -2316,6 +2319,125 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "dev": true }, + "node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@puppeteer/browsers/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@puppeteer/browsers/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@puppeteer/browsers/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@puppeteer/browsers/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@puppeteer/browsers/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@ramda/composep": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/@ramda/composep/-/composep-0.26.1.tgz", @@ -2375,6 +2497,12 @@ "node": ">= 6" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -2493,6 +2621,17 @@ "pretty-format": "^26.0.0" } }, + "node_modules/@types/jest-image-snapshot": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/jest-image-snapshot/-/jest-image-snapshot-6.1.0.tgz", + "integrity": "sha512-wYayjKQGdI0ZbmsAq7OPt+5wMMi1CDXXkF3LfoGj4eRC0dOqlYJdXqLwfC89Qf2apQdlL9StgCkw0iTDb8lpUw==", + "dev": true, + "dependencies": { + "@types/jest": "*", + "@types/pixelmatch": "*", + "ssim.js": "^3.1.1" + } + }, "node_modules/@types/jsdom": { "version": "20.0.1", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", @@ -2570,6 +2709,15 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, + "node_modules/@types/pixelmatch": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@types/pixelmatch/-/pixelmatch-5.2.4.tgz", + "integrity": "sha512-HDaSHIAv9kwpMN7zlmwfTv6gax0PiporJOipcrGsVNF3Ba+kryOZc0Pio5pn6NhisgWr7TaajlPEKTbTAypIBQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", @@ -2644,6 +2792,16 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "4.33.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", @@ -3250,6 +3408,24 @@ "node": ">=0.10.0" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3348,6 +3524,12 @@ "follow-redirects": "^1.14.4" } }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "node_modules/babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -3525,6 +3707,15 @@ } ] }, + "node_modules/basic-ftp": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", + "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -3671,6 +3862,15 @@ "isarray": "^1.0.0" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3974,6 +4174,18 @@ "node": ">=10" } }, + "node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -4485,6 +4697,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4569,6 +4790,15 @@ "node": ">=0.10" } }, + "node_modules/data-uri-to-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", + "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -4714,6 +4944,20 @@ "node": ">=0.10.0" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/del": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", @@ -4827,6 +5071,12 @@ "node": ">=8" } }, + "node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -5261,15 +5511,14 @@ } }, "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" + "esutils": "^2.0.2" }, "bin": { "escodegen": "bin/escodegen.js", @@ -5282,57 +5531,6 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint": { "version": "7.32.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", @@ -6064,6 +6262,41 @@ "node": ">=0.10.0" } }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -6079,6 +6312,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", + "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -6147,6 +6386,15 @@ "bser": "2.1.1" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", @@ -6350,6 +6598,20 @@ "node": ">=0.10.0" } }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -6590,6 +6852,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-uri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", + "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", + "dev": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^5.0.1", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -6756,6 +7033,12 @@ "node": "*" } }, + "node_modules/glur": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glur/-/glur-1.1.2.tgz", + "integrity": "sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA==", + "dev": true + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -8662,6 +8945,42 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jest-image-snapshot": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jest-image-snapshot/-/jest-image-snapshot-6.2.0.tgz", + "integrity": "sha512-9mTHBKiiSIZ26csbLmjKyN+SrVypM93S5y+jULCvn6YItgepvcrJIKGNeSyt9d2EZiutOroLs/UjtrWiBzpHbA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "get-stdin": "^5.0.1", + "glur": "^1.1.2", + "lodash": "^4.17.4", + "pixelmatch": "^5.1.0", + "pngjs": "^3.4.0", + "rimraf": "^2.6.2", + "ssim.js": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": ">=20 <=29" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "node_modules/jest-image-snapshot/node_modules/get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/jest-leak-detector": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", @@ -10907,6 +11226,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", + "dev": true + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -10932,6 +11257,12 @@ "node": ">=10" } }, + "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==", + "dev": true + }, "node_modules/monaco-editor": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.23.0.tgz", @@ -11005,6 +11336,15 @@ "node": ">= 0.6" } }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/nice-grpc": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-1.2.2.tgz", @@ -11077,9 +11417,9 @@ "dev": true }, "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -11838,6 +12178,97 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz", + "integrity": "sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA==", + "dev": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", + "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "dev": true, + "dependencies": { + "degenerator": "^5.0.0", + "ip": "^1.1.8", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver/node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11932,6 +12363,12 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11995,6 +12432,27 @@ "node": ">= 6" } }, + "node_modules/pixelmatch": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", + "dev": true, + "dependencies": { + "pngjs": "^6.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true, + "engines": { + "node": ">=12.13.0" + } + }, "node_modules/pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -12016,6 +12474,15 @@ "semver-compare": "^1.0.0" } }, + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -12221,6 +12688,92 @@ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", "dev": true }, + "node_modules/proxy-agent": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -12246,6 +12799,82 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.9.0.tgz", + "integrity": "sha512-kAglT4VZ9fWEGg3oLc4/de+JcONuEJhlh3J6f5R1TLkrY/EHHIHxWXDOzXvaxQCtedmyVXBwg8M+P8YCO/wZjw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "cosmiconfig": "8.2.0", + "puppeteer-core": "20.9.0" + }, + "engines": { + "node": ">=16.3.0" + } + }, + "node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "dev": true, + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + } + }, + "node_modules/puppeteer/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pure-rand": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", @@ -12307,6 +12936,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -13888,6 +14523,12 @@ "node": ">=0.10.0" } }, + "node_modules/ssim.js": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ssim.js/-/ssim.js-3.5.0.tgz", + "integrity": "sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==", + "dev": true + }, "node_modules/ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", @@ -14079,18 +14720,14 @@ "node": ">=8.0" } }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/streamx": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", + "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" } }, "node_modules/string_decoder": { @@ -14427,6 +15064,28 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -14525,6 +15184,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -14966,6 +15631,40 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/unbzip2-stream/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "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/underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -15701,6 +16400,16 @@ "node": ">=6" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -17542,6 +18251,89 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "dev": true }, + "@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "dependencies": { + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, "@ramda/composep": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/@ramda/composep/-/composep-0.26.1.tgz", @@ -17587,6 +18379,12 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -17705,6 +18503,17 @@ "pretty-format": "^26.0.0" } }, + "@types/jest-image-snapshot": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/jest-image-snapshot/-/jest-image-snapshot-6.1.0.tgz", + "integrity": "sha512-wYayjKQGdI0ZbmsAq7OPt+5wMMi1CDXXkF3LfoGj4eRC0dOqlYJdXqLwfC89Qf2apQdlL9StgCkw0iTDb8lpUw==", + "dev": true, + "requires": { + "@types/jest": "*", + "@types/pixelmatch": "*", + "ssim.js": "^3.1.1" + } + }, "@types/jsdom": { "version": "20.0.1", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", @@ -17775,6 +18584,15 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, + "@types/pixelmatch": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@types/pixelmatch/-/pixelmatch-5.2.4.tgz", + "integrity": "sha512-HDaSHIAv9kwpMN7zlmwfTv6gax0PiporJOipcrGsVNF3Ba+kryOZc0Pio5pn6NhisgWr7TaajlPEKTbTAypIBQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", @@ -17849,6 +18667,16 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@typescript-eslint/eslint-plugin": { "version": "4.33.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", @@ -18270,6 +19098,23 @@ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true + } + } + }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -18344,6 +19189,12 @@ "follow-redirects": "^1.14.4" } }, + "b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -18474,6 +19325,12 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "basic-ftp": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", + "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", + "dev": true + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -18588,6 +19445,12 @@ "isarray": "^1.0.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -18807,6 +19670,15 @@ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "requires": { + "mitt": "3.0.0" + } + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -19226,6 +20098,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -19294,6 +20175,12 @@ "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", + "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", + "dev": true + }, "data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -19400,6 +20287,17 @@ "isobject": "^3.0.1" } }, + "degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "requires": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + } + }, "del": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", @@ -19490,6 +20388,12 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -19830,57 +20734,15 @@ "dev": true }, "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, "requires": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", "source-map": "~0.6.1" - }, - "dependencies": { - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "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.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } } }, "eslint": { @@ -20442,6 +21304,29 @@ } } }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -20454,6 +21339,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-fifo": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", + "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==", + "dev": true + }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -20506,6 +21397,15 @@ "bser": "2.1.1" } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", @@ -20654,6 +21554,17 @@ "map-cache": "^0.2.2" } }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -20840,6 +21751,18 @@ "get-intrinsic": "^1.1.1" } }, + "get-uri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", + "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", + "dev": true, + "requires": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^5.0.1", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -20968,6 +21891,12 @@ } } }, + "glur": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glur/-/glur-1.1.2.tgz", + "integrity": "sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA==", + "dev": true + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -22375,6 +23304,30 @@ } } }, + "jest-image-snapshot": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jest-image-snapshot/-/jest-image-snapshot-6.2.0.tgz", + "integrity": "sha512-9mTHBKiiSIZ26csbLmjKyN+SrVypM93S5y+jULCvn6YItgepvcrJIKGNeSyt9d2EZiutOroLs/UjtrWiBzpHbA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "get-stdin": "^5.0.1", + "glur": "^1.1.2", + "lodash": "^4.17.4", + "pixelmatch": "^5.1.0", + "pngjs": "^3.4.0", + "rimraf": "^2.6.2", + "ssim.js": "^3.1.1" + }, + "dependencies": { + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==", + "dev": true + } + } + }, "jest-leak-detector": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", @@ -24179,6 +25132,12 @@ } } }, + "mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", + "dev": true + }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -24195,6 +25154,12 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, + "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==", + "dev": true + }, "monaco-editor": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.23.0.tgz", @@ -24250,6 +25215,12 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true + }, "nice-grpc": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-1.2.2.tgz", @@ -24328,9 +25299,9 @@ "dev": true }, "node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dev": true, "requires": { "whatwg-url": "^5.0.0" @@ -24913,6 +25884,83 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "pac-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz", + "integrity": "sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA==", + "dev": true, + "requires": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.1" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "socks-proxy-agent": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "dev": true, + "requires": { + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + } + } + } + }, + "pac-resolver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", + "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "dev": true, + "requires": { + "degenerator": "^5.0.0", + "ip": "^1.1.8", + "netmask": "^2.0.2" + }, + "dependencies": { + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "dev": true + } + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -24986,6 +26034,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -25031,6 +26085,23 @@ "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, + "pixelmatch": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", + "dev": true, + "requires": { + "pngjs": "^6.0.0" + }, + "dependencies": { + "pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true + } + } + }, "pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -25049,6 +26120,12 @@ "semver-compare": "^1.0.0" } }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -25212,6 +26289,76 @@ } } }, + "proxy-agent": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "socks-proxy-agent": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "dev": true, + "requires": { + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + } + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -25234,6 +26381,57 @@ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, + "puppeteer": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.9.0.tgz", + "integrity": "sha512-kAglT4VZ9fWEGg3oLc4/de+JcONuEJhlh3J6f5R1TLkrY/EHHIHxWXDOzXvaxQCtedmyVXBwg8M+P8YCO/wZjw==", + "dev": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "cosmiconfig": "8.2.0", + "puppeteer-core": "20.9.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "dev": true, + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + } + } + }, + "puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "requires": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + } + }, "pure-rand": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", @@ -25264,6 +26462,12 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -26483,6 +27687,12 @@ "tweetnacl": "~0.14.0" } }, + "ssim.js": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ssim.js/-/ssim.js-3.5.0.tgz", + "integrity": "sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==", + "dev": true + }, "ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", @@ -26643,19 +27853,16 @@ "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } + } + }, + "streamx": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", + "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", + "dev": true, + "requires": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" } }, "string_decoder": { @@ -26926,6 +28133,28 @@ } } }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -26989,6 +28218,12 @@ "loader-utils": "^1.1.0" } }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -27317,6 +28552,28 @@ "which-boxed-primitive": "^1.0.2" } }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, "underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -27901,6 +29158,16 @@ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 2801bd7..16d09f0 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "node": ">=16.0.0" }, "scripts": { - "test": "TZ=UTC jest --coverage", + "test": "npm run test:units && npm run test:screenshots", + "test:units": "TZ=UTC jest --coverage -c jest.config.units.ts", + "test:screenshots": "TZ=UTC jest -c jest.config.screenshots.ts", "lint": "eslint src tests --ext .js,.jsx,.ts,.tsx", "typecheck": "tsc -p tsconfig.json", "prebuild": "rimraf dist", @@ -44,7 +46,7 @@ "husky": { "hooks": { "pre-commit": "lint-staged", - "pre-push": "npm run test" + "pre-push": "npm run test:units" } }, "lint-staged": { @@ -56,6 +58,7 @@ "@babel/preset-react": "^7.22.5", "@doc-tools/docs": "^1.13.1", "@types/jest": "^26.0.24", + "@types/jest-image-snapshot": "^6.1.0", "@types/node": "^10.11.0", "@types/react": "^17.0.2", "@typescript-eslint/eslint-plugin": "^4.5.0", @@ -71,10 +74,12 @@ "husky": "^1.0.1", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", + "jest-image-snapshot": "^6.2.0", "lint-staged": "^8.0.0", "monaco-editor": "^0.23.0", "node-sass": "^7.0.1", "prettier": "^2.3.0", + "puppeteer": "^20.9.0", "react": "^17.0.1", "react-dom": "^17.0.1", "rimraf": "^2.6.2", diff --git a/src/YagrCore/plugins/markers/index.ts b/src/YagrCore/plugins/markers/index.ts index 50dccb4..2ba7f00 100644 --- a/src/YagrCore/plugins/markers/index.ts +++ b/src/YagrCore/plugins/markers/index.ts @@ -2,7 +2,7 @@ import type Yagr from '../../index'; import UPlot, {Plugin, Series} from 'uplot'; import {DEFAULT_X_SCALE, DEFAULT_Y_SCALE, DEFAULT_POINT_SIZE} from '../../defaults'; -import {DotsSeriesOptions, YagrConfig} from '../../types'; +import {YagrConfig} from '../../types'; export const renderCircle = ( u: UPlot, @@ -84,16 +84,13 @@ export function drawMarkersIfRequired(u: UPlot, i: number, i0: number, i1: numbe export default function YagrMarkersPlugin(yagr: Yagr, config: YagrConfig): Plugin { const {size = DEFAULT_POINT_SIZE, strokeWidth = 2, strokeColor = '#ffffff', show} = config.markers; - const chartSeriesOptions = config.chart?.series as DotsSeriesOptions; - const defaultDotsSize = chartSeriesOptions?.pointsSize || DEFAULT_POINT_SIZE; - function drawCircles(u: UPlot, i: number, i0: number, i1: number) { - const {scale, _focus, color, getFocusedColor, type} = u.series[i]; + const {scale, _focus, color, getFocusedColor, type, pointsSize = size} = u.series[i]; let j = i0; // eslint-disable-next-line no-nested-ternary - const pointSize = type === 'dots' ? (show ? size : defaultDotsSize) : size; + const pointSize = type === 'dots' ? (show ? size : pointsSize) : size; while (j <= i1) { const val = u.data[i][j]; diff --git a/src/YagrCore/plugins/tooltip/render.ts b/src/YagrCore/plugins/tooltip/render.ts index f065ca5..29a32db 100644 --- a/src/YagrCore/plugins/tooltip/render.ts +++ b/src/YagrCore/plugins/tooltip/render.ts @@ -2,7 +2,7 @@ import {TooltipRenderOptions, TooltipRow} from './types'; import {getOptionValue, escapeHTML} from './utils'; -function renderItems(rows: TooltipRow[], opts: TooltipRenderOptions['options']) { +function renderItems(rows: TooltipRow[], opts: TooltipRenderOptions['options'], scale: string) { return rows .map(({value, name = 'unnamed', color, active, transformed, seriesIdx}, i) => { const val = ` @@ -13,7 +13,7 @@ function renderItems(rows: TooltipRow[], opts: TooltipRenderOptions['options'])
${opts.showIndicies ? `${rows.length - i}` : ''} ${escapeHTML(name)}  ${val} -
`; +${getOptionValue(opts.percent, scale) ? '%' : ''}`; }) .join(''); } @@ -37,7 +37,7 @@ export function renderTooltip(data: TooltipRenderOptions) {
${sectionTitle && sectionTitleBody ? `
${sectionTitleBody}
` : ''} ${scaleBody ? `
${scaleBody}
` : ''} -
${renderItems(x.rows, data.options)}
+
${renderItems(x.rows, data.options, x.scale)}
${ getOptionValue(data.options.sum, x.scale) ? ` diff --git a/src/YagrCore/plugins/tooltip/tooltip.ts b/src/YagrCore/plugins/tooltip/tooltip.ts index 893247a..119cda7 100644 --- a/src/YagrCore/plugins/tooltip/tooltip.ts +++ b/src/YagrCore/plugins/tooltip/tooltip.ts @@ -337,7 +337,7 @@ class YagrTooltip { const section = sections[scale]; const cursorValue = Number(u.posToVal(top, scale).toFixed(2)); - const valueRender = getOptionValue(opts.value, scale); + const valueRender = getOptionValue(opts.value, scale) ?? this.defaultTooltipValueFormatter; for (const seriesIdx of serieIndicies) { const seriesData = u.data[seriesIdx] as DataSeries; diff --git a/src/YagrCore/types.ts b/src/YagrCore/types.ts index 96587fa..9ba13ba 100644 --- a/src/YagrCore/types.ts +++ b/src/YagrCore/types.ts @@ -11,6 +11,7 @@ type AllSeriesOptions = ExtendedSeriesOptions & Omit & Omit & Omit; + declare module 'uplot' { interface Series extends Omit { id: string; diff --git a/tests/screenshots/index.html b/tests/screenshots/index.html new file mode 100644 index 0000000..ae409d5 --- /dev/null +++ b/tests/screenshots/index.html @@ -0,0 +1,28 @@ + + + + + + + Test + + +
+ + \ No newline at end of file diff --git a/tests/screenshots/teardown.ts b/tests/screenshots/teardown.ts new file mode 100644 index 0000000..c5adfc0 --- /dev/null +++ b/tests/screenshots/teardown.ts @@ -0,0 +1,3 @@ +export default () => { + process.exit(0); +}; diff --git a/tests/screenshots/tests/interpolation.test.ts b/tests/screenshots/tests/interpolation.test.ts new file mode 100644 index 0000000..250f58f --- /dev/null +++ b/tests/screenshots/tests/interpolation.test.ts @@ -0,0 +1,195 @@ +import {getScreenshot} from '../utils'; + +describe('interpolation', () => { + it.each([ + { + type: 'closest', + snapToValues: 'closest', + } as const, + { + type: 'closest', + snapToValues: 'left', + } as const, + { + type: 'closest', + snapToValues: 'right', + } as const, + { + type: 'closest', + snapToValues: false, + } as const, + { + type: 'next', + snapToValues: 'closest', + } as const, + { + type: 'next', + snapToValues: 'left', + } as const, + { + type: 'next', + snapToValues: 'right', + } as const, + { + type: 'next', + snapToValues: false, + } as const, + { + type: 'previous', + snapToValues: 'closest', + } as const, + { + type: 'previous', + snapToValues: 'left', + } as const, + { + type: 'previous', + snapToValues: 'right', + } as const, + { + type: 'previous', + snapToValues: false, + } as const, + { + type: 'linear', + snapToValues: 'closest', + } as const, + { + type: 'linear', + snapToValues: 'left', + } as const, + { + type: 'linear', + snapToValues: 'right', + } as const, + { + type: 'linear', + snapToValues: false, + } as const, + { + type: 'right', + snapToValues: 'closest', + } as const, + { + type: 'right', + snapToValues: 'left', + } as const, + { + type: 'right', + snapToValues: 'right', + } as const, + { + type: 'right', + snapToValues: false, + } as const, + { + type: 'left', + snapToValues: 'closest', + } as const, + { + type: 'left', + snapToValues: 'left', + } as const, + { + type: 'left', + snapToValues: 'right', + } as const, + { + type: 'left', + snapToValues: false, + } as const, + ])('should render type=$type snap=$snapToValues', async (conf) => { + const image = await getScreenshot(async (conf) => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3, 4, 5], + chart: { + series: { + type: 'area', + }, + }, + scales: { + y: { + stacking: true, + }, + }, + series: [ + { + data: [1, 'x', 2, 'x', 2], + color: 'red', + }, + { + data: [1, 3, 2, 5, 2], + color: 'green', + }, + { + data: ['x', 'x', 2, 4, 'x'], + color: 'blue', + }, + { + data: ['x', 3, 3, 4, 'x'], + color: 'orange', + }, + ], + processing: { + interpolation: { + value: 'x', + type: 'linear', + ...conf, + }, + }, + }); + + y.uplot.setCursor({left: 150, top: 50}); + }, conf); + expect(image).toMatchImageSnapshot(); + + const after = await getScreenshot(async (conf) => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3, 4, 5], + chart: { + series: { + type: 'area', + }, + }, + scales: { + y: { + stacking: true, + }, + }, + series: [ + { + data: [1, 'x', 2, 'x', 2], + color: 'red', + }, + { + data: [1, 3, 2, 5, 2], + color: 'green', + }, + { + data: ['x', 'x', 2, 4, 'x'], + color: 'blue', + }, + { + data: ['x', 3, 3, 4, 'x'], + color: 'orange', + }, + ], + processing: { + interpolation: { + value: 'x', + type: 'linear', + ...conf, + }, + }, + }); + + y.uplot.setCursor({left: 700, top: 50}); + }, conf); + + expect(after).toMatchImageSnapshot({ + customSnapshotIdentifier: ({defaultIdentifier}) => { + return `${defaultIdentifier}-end`; + }, + }); + }); +}); diff --git a/tests/screenshots/tests/markers.test.ts b/tests/screenshots/tests/markers.test.ts new file mode 100644 index 0000000..30d2eef --- /dev/null +++ b/tests/screenshots/tests/markers.test.ts @@ -0,0 +1,55 @@ +import {getImage} from '../utils'; + +describe('markers plugin', () => { + it('should render markers', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + markers: { + show: true, + }, + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should set marker size', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + markers: { + show: true, + size: 15, + }, + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should set marker strokeWidth and color', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'black', + }, + ], + markers: { + show: true, + size: 10, + strokeWidth: 20, + strokeColor: 'orange', + }, + }); + expect(image).toMatchImageSnapshot(); + }); +}); diff --git a/tests/screenshots/tests/plotlines.test.ts b/tests/screenshots/tests/plotlines.test.ts new file mode 100644 index 0000000..1bfb3b1 --- /dev/null +++ b/tests/screenshots/tests/plotlines.test.ts @@ -0,0 +1,97 @@ +import {getImage} from '../utils'; + +describe('plotlines plugin', () => { + it('should render x plot line width', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + axes: { + x: { + plotLines: [ + { + value: 2, + width: 2, + color: 'rgba(255, 0, 0, 0.5)', + }, + ], + }, + }, + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should render x plot line from to', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + axes: { + x: { + plotLines: [ + { + value: [2, 4], + color: 'rgba(255, 0, 0, 0.5)', + }, + ], + }, + }, + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should render y plot line width', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + axes: { + y: { + plotLines: [ + { + value: 2, + width: 2, + color: 'rgba(255, 0, 0, 0.5)', + }, + ], + }, + }, + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should render y plot line from to', async () => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + axes: { + y: { + plotLines: [ + { + value: [2, 4], + color: 'rgba(255, 0, 0, 0.5)', + }, + ], + }, + }, + }); + expect(image).toMatchImageSnapshot(); + }); +}); diff --git a/tests/screenshots/tests/tooltip.test.ts b/tests/screenshots/tests/tooltip.test.ts new file mode 100644 index 0000000..afa40f8 --- /dev/null +++ b/tests/screenshots/tests/tooltip.test.ts @@ -0,0 +1,251 @@ +import {getScreenshot} from '../utils'; + +describe('tooltip plugin', () => { + describe('options', () => { + it('should render tooltip', async () => { + const image = await getScreenshot(async () => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + }); + + y.uplot.setCursor({left: 20, top: 100}); + }); + expect(image).toMatchImageSnapshot(); + }); + + it('shouldnt render tooltip if disable', async () => { + const image = await getScreenshot(async () => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + tooltip: { + show: false, + }, + }); + + y.uplot.setCursor({left: 20, top: 100}); + }); + expect(image).toMatchImageSnapshot(); + }); + + it.each([ + { + key: 'sum', + value: { + sum: true, + }, + }, + { + key: 'sum [per scale]', + value: { + sum: { + y: true, + r: false, + }, + }, + }, + { + key: 'percent', + value: { + percent: true, + }, + }, + { + key: 'percent [per scale]', + value: { + percent: { + y: true, + r: false, + }, + }, + }, + { + key: 'title', + value: { + title: 'Title', + }, + }, + { + key: 'title [per scale]', + value: { + title: { + y: 'Y Title', + r: 'R Title', + }, + }, + }, + { + key: 'precision', + value: { + precision: 3, + }, + }, + { + key: 'precision [per scale]', + value: { + precision: { + y: 3, + r: 2, + }, + }, + }, + { + key: 'value', + value: { + value: (x: string | number | null) => x + ' [MOD]', + }, + }, + ])('should render tooltip with $key = $value', async ({value}) => { + const image = await getScreenshot(async (patch) => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3, 4, 5], + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + scale: 'y', + }, + { + data: [5, 3, 2, 5, 1], + color: 'blue', + scale: 'r', + }, + ], + tooltip: { + ...patch, + }, + }); + + y.uplot.setCursor({left: 20, top: 100}); + }, value); + expect(image).toMatchImageSnapshot(); + }); + + it('should track correct line, sticky', async () => { + const image = await getScreenshot(async () => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3], + series: [ + { + data: [1, 1, 1], + color: 'red', + }, + { + data: [5, 5, 5], + color: 'blue', + }, + ], + tooltip: { + tracking: 'sticky', + }, + }); + + y.uplot.setCursor({left: 20, top: 100}); + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should track correct line, area', async () => { + const image = await getScreenshot(async () => { + const y = await window.AsyncYagr(window.test, { + chart: { + series: { + type: 'area', + }, + }, + scales: { + y: { + stacking: true, + }, + }, + timeline: [1, 2, 3], + series: [ + { + data: [1, 1, 1], + color: 'red', + }, + { + data: [5, 5, 5], + color: 'blue', + }, + ], + tooltip: { + tracking: 'sticky', + }, + }); + + y.uplot.setCursor({left: 20, top: 100}); + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should track correct line, sticky, bottom', async () => { + const image = await getScreenshot(async () => { + const y = await window.AsyncYagr(window.test, { + timeline: [1, 2, 3], + series: [ + { + data: [1, 1, 1], + color: 'red', + }, + { + data: [5, 5, 5], + color: 'blue', + }, + ], + tooltip: { + tracking: 'sticky', + }, + }); + + y.uplot.setCursor({left: 20, top: 300}); + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should track correct line, area, bottom', async () => { + const image = await getScreenshot(async () => { + const y = await window.AsyncYagr(window.test, { + chart: { + series: { + type: 'area', + }, + }, + scales: { + y: { + stacking: true, + }, + }, + timeline: [1, 2, 3], + series: [ + { + data: [1, 1, 1], + color: 'red', + }, + { + data: [5, 5, 5], + color: 'blue', + }, + ], + tooltip: { + tracking: 'sticky', + }, + }); + + y.uplot.setCursor({left: 20, top: 300}); + }); + expect(image).toMatchImageSnapshot(); + }); + }); +}); diff --git a/tests/screenshots/tests/visualization.test.ts b/tests/screenshots/tests/visualization.test.ts new file mode 100644 index 0000000..de88018 --- /dev/null +++ b/tests/screenshots/tests/visualization.test.ts @@ -0,0 +1,252 @@ +import {ChartType, InterpolationType} from '../../../src'; +import {getImage} from '../utils'; + +describe('visualization types', () => { + it.each(['line', 'area', 'column', 'dots'])('should render chart.series.type = %s', async (type) => { + const image = await getImage({ + chart: { + series: { + type: type as ChartType, + }, + }, + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + }, + { + data: [3, 2, 1], + color: 'green', + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); + + it.each(['line', 'area', 'column', 'dots'])('should render series.type = %s', async (type) => { + const image = await getImage({ + chart: { + series: { + type: type === 'line' ? 'area' : 'line', + }, + }, + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + }, + { + data: [3, 2, 1], + color: 'green', + type: type as ChartType, + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); +}); + +describe('common properties', () => { + it.each([ + { + key: 'show = false', + value: { + show: false, + }, + }, + { + key: 'color = orange', + value: { + color: 'orange', + }, + }, + { + key: 'spanGaps = true', + value: { + spanGaps: true, + data: [1, null, 2], + }, + }, + ])('should render with specific option: $key', async ({value}) => { + const image = await getImage({ + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + }, + { + data: [3, 2, 1], + ...value, + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); +}); + +describe('line properties', () => { + it.each([ + { + key: 'width = 10', + value: { + width: 10, + }, + }, + ])('should render with specific option: $key', async ({value}) => { + const image = await getImage({ + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + }, + { + data: [3, 2, 1], + ...value, + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); + + it('should render with transform = x2', async () => { + const image = await getImage(async () => { + await new Promise((resolve) => { + // eslint-disable-next-line no-new + new window.Yagr(window.test, { + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + transform: (v: any) => v * 2, + }, + ], + hooks: { + load: [resolve], + }, + }); + }); + }); + + expect(image).toMatchImageSnapshot(); + }); + + it('should render with postProcess = [1,1,1]', async () => { + const image = await getImage(async () => { + await new Promise((resolve) => { + // eslint-disable-next-line no-new + new window.Yagr(window.test, { + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + postProcess: () => [1, 1, 1], + }, + ], + hooks: { + load: [resolve], + }, + }); + }); + }); + + expect(image).toMatchImageSnapshot(); + }); +}); + +describe('area properties', () => { + it.each([ + { + key: 'lineWidth = 5', + value: { + lineWidth: 10, + }, + }, + { + key: 'lineColor = orange', + value: { + lineColor: 'orange', + }, + }, + ])('should render with specific option: $key', async ({value}) => { + const image = await getImage({ + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + }, + { + data: [3, 2, 1], + color: 'green', + type: 'area', + ...value, + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); +}); + +describe('dots properties', () => { + it.each([ + { + key: 'pointSize = 20', + value: { + pointsSize: 20, + }, + }, + ])('should render with specific option: $key', async ({value}) => { + const image = await getImage({ + timeline: [1, 2, 3], + series: [ + { + data: [1, 2, 3], + color: 'red', + }, + { + data: [3, 2, 1], + color: 'blue', + type: 'dots', + ...value, + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); +}); + +describe('interpolation properties', () => { + it.each([ + ['line', 'left'], + ['line', 'right'], + ['line', 'linear'], + ['line', 'smooth'], + ['area', 'left'], + ['area', 'right'], + ['area', 'linear'], + ['area', 'smooth'], + ])('should interpolate type = %s, interpolation = %s', async (cType, iType) => { + const image = await getImage({ + timeline: [1, 2, 3, 4, 5], + chart: { + series: { + type: cType as ChartType, + interpolation: iType as InterpolationType, + }, + }, + series: [ + { + data: [1, 3, 2, 6, 2], + color: 'red', + }, + ], + }); + expect(image).toMatchImageSnapshot(); + }); +}); diff --git a/tests/screenshots/utils.ts b/tests/screenshots/utils.ts new file mode 100644 index 0000000..d3df51e --- /dev/null +++ b/tests/screenshots/utils.ts @@ -0,0 +1,89 @@ +import {resolve} from 'path'; +import {toMatchImageSnapshot} from 'jest-image-snapshot'; +import type {EvaluateFunc} from 'puppeteer'; +import Yagr, {MinimalValidConfig} from '../../src'; +import puppeteer, {Browser} from 'puppeteer'; + +if (typeof expect !== 'undefined') { + expect.extend({toMatchImageSnapshot}); +} + +const path = resolve(__dirname, './index.html'); + +declare global { + interface Window { + Yagr: typeof Yagr; + AsyncYagr: (...args: ConstructorParameters) => Promise; + test: HTMLElement; + } +} + +let browser: Browser; + +export async function start() { + browser = await puppeteer.launch({ + headless: process.env.HEADLESS !== 'false', + }); + + const page = await browser.newPage(); + await page.setViewport({width: 1100, height: 500}); + await page.goto(`file://${path}`); + await page.waitForSelector('#test'); + + return page; +} + +async function getPage() { + if (!browser) { + return start(); + } + + const page = await browser.newPage(); + await page.setViewport({width: 1100, height: 500}); + await page.goto(`file://${path}`); + await page.waitForSelector('#test'); + return page; +} + +export async function getImage(configOrFunction: MinimalValidConfig | (() => void)) { + const page = await getPage(); + + if (typeof configOrFunction === 'function') { + await page.evaluate(configOrFunction); + } else { + await page.evaluate(async (config) => { + await new Promise((resolve) => { + config.axes = config.axes || {}; + config.axes.x = config.axes.x || {}; + config.axes.x.font = '11px sans-serif'; + config.axes.y = config.axes.y || {}; + config.axes.y.font = '11px sans-serif'; + config.hooks = config.hooks || {}; + config.hooks.load = config.hooks.load || []; + config.hooks.load.push(resolve); + new window.Yagr(window.test, config); // eslint-disable-line no-new + }); + }, configOrFunction); + } + + const imageURL = await page.$eval('#test', (el) => { + return el.querySelector('canvas')?.toDataURL(); + }); + + // convert the data URL to a buffer + const image = Buffer.from((imageURL || '').split(',')[1], 'base64'); + + await page.close(); + return image; +} + +export async function getScreenshot(evaluation: EvaluateFunc<[T | undefined]>, data?: T) { + const page = await getPage(); + + await page.evaluate(evaluation, data); + + const image = await page.screenshot(); + + await page.close(); + return image; +} diff --git a/tests/core/hooks.test.ts b/tests/units/core/hooks.test.ts similarity index 93% rename from tests/core/hooks.test.ts rename to tests/units/core/hooks.test.ts index d765c0d..f235422 100644 --- a/tests/core/hooks.test.ts +++ b/tests/units/core/hooks.test.ts @@ -1,5 +1,5 @@ -import {MinimalValidConfig} from '../../src'; -import Yagr from '../../src/YagrCore'; +import {MinimalValidConfig} from '../../../src'; +import Yagr from '../../../src/YagrCore'; describe('yagr hooks', () => { it('should call ready hook', async () => { diff --git a/tests/core/i18n.test.ts b/tests/units/core/i18n.test.ts similarity index 94% rename from tests/core/i18n.test.ts rename to tests/units/core/i18n.test.ts index 54dea2f..1e1a25b 100644 --- a/tests/core/i18n.test.ts +++ b/tests/units/core/i18n.test.ts @@ -1,4 +1,4 @@ -import Yagr from '../../src/YagrCore'; +import Yagr from '../../../src/YagrCore'; const DEFAULT_CONFIG = { timeline: [1, 2], diff --git a/tests/core/methods.test.ts b/tests/units/core/methods.test.ts similarity index 99% rename from tests/core/methods.test.ts rename to tests/units/core/methods.test.ts index dc41a21..e51695f 100644 --- a/tests/core/methods.test.ts +++ b/tests/units/core/methods.test.ts @@ -1,6 +1,6 @@ import {Axis} from 'uplot'; -import {MinimalValidConfig} from '../../src'; -import Yagr from '../../src/YagrCore'; +import {MinimalValidConfig} from '../../../src'; +import Yagr from '../../../src/YagrCore'; const exec = (fn: any, ...args: any[]) => { return typeof fn === 'function' ? (fn as any)(...args) : fn; diff --git a/tests/core/options.test.ts b/tests/units/core/options.test.ts similarity index 94% rename from tests/core/options.test.ts rename to tests/units/core/options.test.ts index e10788a..3f409b8 100644 --- a/tests/core/options.test.ts +++ b/tests/units/core/options.test.ts @@ -1,5 +1,5 @@ -import {DEFAULT_X_SCALE, DEFAULT_X_SERIE_NAME} from '../../src/YagrCore/defaults'; -import Yagr from '../../src/YagrCore'; +import {DEFAULT_X_SCALE, DEFAULT_X_SERIE_NAME} from '../../../src/YagrCore/defaults'; +import Yagr from '../../../src/YagrCore'; const DEFAULT_CONFIG = { timeline: [1, 2], diff --git a/tests/core/plugins.test.ts b/tests/units/core/plugins.test.ts similarity index 87% rename from tests/core/plugins.test.ts rename to tests/units/core/plugins.test.ts index edaeda4..ac3cfb2 100644 --- a/tests/core/plugins.test.ts +++ b/tests/units/core/plugins.test.ts @@ -1,6 +1,6 @@ -import {MinimalValidConfig} from '../../src'; -import Yagr from '../../src/YagrCore'; -import DataRefs from '../../src/plugins/dataRefs/dataRefs'; +import {MinimalValidConfig} from '../../../src'; +import Yagr from '../../../src/YagrCore'; +import DataRefs from '../../../src/plugins/dataRefs/dataRefs'; describe('yagr plugins', () => { it('should be able to use dataRefs plugin', async () => { diff --git a/tests/core/theme.test.ts b/tests/units/core/theme.test.ts similarity index 95% rename from tests/core/theme.test.ts rename to tests/units/core/theme.test.ts index 9c295db..449aac0 100644 --- a/tests/core/theme.test.ts +++ b/tests/units/core/theme.test.ts @@ -1,4 +1,4 @@ -import Yagr from '../../src/YagrCore'; +import Yagr from '../../../src/YagrCore'; const DEFAULT_CONFIG = { timeline: [1, 2], diff --git a/tests/plugins/cursor.test.ts b/tests/units/plugins/cursor.test.ts similarity index 94% rename from tests/plugins/cursor.test.ts rename to tests/units/plugins/cursor.test.ts index 2f93f24..6a38801 100644 --- a/tests/plugins/cursor.test.ts +++ b/tests/units/plugins/cursor.test.ts @@ -1,5 +1,5 @@ -import Yagr from '../../src/YagrCore'; -import {cursorPoint} from '../../src/YagrCore/plugins/cursor/cursor'; +import Yagr from '../../../src/YagrCore'; +import {cursorPoint} from '../../../src/YagrCore/plugins/cursor/cursor'; describe('cursor plugin', () => { describe('rendering', () => { diff --git a/tests/plugins/dataRefs.test.ts b/tests/units/plugins/dataRefs.test.ts similarity index 98% rename from tests/plugins/dataRefs.test.ts rename to tests/units/plugins/dataRefs.test.ts index 819d25a..cbe573f 100644 --- a/tests/plugins/dataRefs.test.ts +++ b/tests/units/plugins/dataRefs.test.ts @@ -1,5 +1,5 @@ -import Yagr from '../../src/YagrCore'; -import DataRefs from '../../src/plugins/dataRefs/dataRefs'; +import Yagr from '../../../src/YagrCore'; +import DataRefs from '../../../src/plugins/dataRefs/dataRefs'; describe('DataRefs plugin', () => { describe('plain data', () => { diff --git a/tests/plugins/legend.test.ts b/tests/units/plugins/legend.test.ts similarity index 95% rename from tests/plugins/legend.test.ts rename to tests/units/plugins/legend.test.ts index 3b574f7..6e25324 100644 --- a/tests/plugins/legend.test.ts +++ b/tests/units/plugins/legend.test.ts @@ -1,7 +1,7 @@ import {Series} from 'uplot'; -import {MinimalValidConfig} from '../../src'; -import Yagr from '../../src/YagrCore'; -import {hasOneVisibleLine} from '../../src/YagrCore/plugins/legend/legend'; +import {MinimalValidConfig} from '../../../src'; +import Yagr from '../../../src/YagrCore'; +import {hasOneVisibleLine} from '../../../src/YagrCore/plugins/legend/legend'; const getUSeries = (series: Series[]) => { const [, ...s] = series; diff --git a/tests/plugins/plotlines.test.ts b/tests/units/plugins/plotlines.test.ts similarity index 97% rename from tests/plugins/plotlines.test.ts rename to tests/units/plugins/plotlines.test.ts index a99c6d1..c8a9809 100644 --- a/tests/plugins/plotlines.test.ts +++ b/tests/units/plugins/plotlines.test.ts @@ -1,5 +1,5 @@ -import {PlotLineConfig} from '../../src'; -import Yagr from '../../src/YagrCore'; +import {PlotLineConfig} from '../../../src'; +import Yagr from '../../../src/YagrCore'; const DEFAULT_CONFIG = { timeline: [1, 2, 3], diff --git a/tests/plugins/tooltip.test.ts b/tests/units/plugins/tooltip.test.ts similarity index 98% rename from tests/plugins/tooltip.test.ts rename to tests/units/plugins/tooltip.test.ts index 501eeeb..b84c3ee 100644 --- a/tests/plugins/tooltip.test.ts +++ b/tests/units/plugins/tooltip.test.ts @@ -1,5 +1,5 @@ -import {MinimalValidConfig, TooltipHandler} from '../../src'; -import Yagr from '../../src/YagrCore'; +import {MinimalValidConfig, TooltipHandler} from '../../../src'; +import Yagr from '../../../src/YagrCore'; const gen = (cfg: MinimalValidConfig) => { const el = window.document.createElement('div'); diff --git a/tests/utils/axes.test.ts b/tests/units/utils/axes.test.ts similarity index 93% rename from tests/utils/axes.test.ts rename to tests/units/utils/axes.test.ts index 502b8fa..c555447 100644 --- a/tests/utils/axes.test.ts +++ b/tests/units/utils/axes.test.ts @@ -1,5 +1,5 @@ -import {YagrConfig} from '../../src/YagrCore/types'; -import {getTimeFormatter} from '../../src/YagrCore/utils/axes'; +import {YagrConfig} from '../../../src/YagrCore/types'; +import {getTimeFormatter} from '../../../src/YagrCore/utils/axes'; describe('axes:getTimeFormatter', () => { const formatter = getTimeFormatter({ diff --git a/tests/utils/chart.test.ts b/tests/units/utils/chart.test.ts similarity index 81% rename from tests/utils/chart.test.ts rename to tests/units/utils/chart.test.ts index 0a411ae..b0c4f8f 100644 --- a/tests/utils/chart.test.ts +++ b/tests/units/utils/chart.test.ts @@ -1,6 +1,6 @@ import {Options} from 'uplot'; -import {PADDING_BOTH, PADDING_LEFT, PADDING_RIGHT} from '../../src/YagrCore/defaults'; -import {getPaddingByAxes} from '../../src/YagrCore/utils/chart'; +import {PADDING_BOTH, PADDING_LEFT, PADDING_RIGHT} from '../../../src/YagrCore/defaults'; +import {getPaddingByAxes} from '../../../src/YagrCore/utils/chart'; describe('utils:charts', () => { it('empty is left', () => { diff --git a/tests/utils/cursor.test.ts b/tests/units/utils/cursor.test.ts similarity index 99% rename from tests/utils/cursor.test.ts rename to tests/units/utils/cursor.test.ts index 6d99482..775a788 100644 --- a/tests/utils/cursor.test.ts +++ b/tests/units/utils/cursor.test.ts @@ -1,4 +1,4 @@ -import {findDataIdx} from '../../src/YagrCore/utils/common'; +import {findDataIdx} from '../../../src/YagrCore/utils/common'; describe('utils:findDataIdx', () => { describe('closest', () => { diff --git a/tests/utils/normalization.test.ts b/tests/units/utils/normalization.test.ts similarity index 96% rename from tests/utils/normalization.test.ts rename to tests/units/utils/normalization.test.ts index e03f4e7..6f43b59 100644 --- a/tests/utils/normalization.test.ts +++ b/tests/units/utils/normalization.test.ts @@ -1,4 +1,4 @@ -import Yagr from '../../src/YagrCore'; +import Yagr from '../../../src/YagrCore'; describe('processing:normalization', () => { it('should normalize with simple dataset', () => { diff --git a/tests/utils/preprocess.test.ts b/tests/units/utils/preprocess.test.ts similarity index 99% rename from tests/utils/preprocess.test.ts rename to tests/units/utils/preprocess.test.ts index c8caf3a..ec27970 100644 --- a/tests/utils/preprocess.test.ts +++ b/tests/units/utils/preprocess.test.ts @@ -1,4 +1,4 @@ -import {preprocess} from '../../src/YagrCore/utils/common'; +import {preprocess} from '../../../src/YagrCore/utils/common'; describe('utils:preprocess', () => { describe('nullValues', () => { diff --git a/tests/utils/scales.test.ts b/tests/units/utils/scales.test.ts similarity index 95% rename from tests/utils/scales.test.ts rename to tests/units/utils/scales.test.ts index 9d5aeb7..8cd1593 100644 --- a/tests/utils/scales.test.ts +++ b/tests/units/utils/scales.test.ts @@ -1,5 +1,5 @@ -import {Scale} from '../../src/YagrCore/types'; -import {offsetScale} from '../../src/YagrCore/utils/scales'; +import {Scale} from '../../../src/YagrCore/types'; +import {offsetScale} from '../../../src/YagrCore/utils/scales'; type TArgs = [number, number, Scale]; type TResult = {min: number; max: number}; diff --git a/tests/utils/series.test.ts b/tests/units/utils/series.test.ts similarity index 97% rename from tests/utils/series.test.ts rename to tests/units/utils/series.test.ts index a5b8b92..788d1b4 100644 --- a/tests/utils/series.test.ts +++ b/tests/units/utils/series.test.ts @@ -1,5 +1,5 @@ -import Yagr from '../../src/YagrCore'; -import {configureSeries} from '../../src/YagrCore/utils/series'; +import Yagr from '../../../src/YagrCore'; +import {configureSeries} from '../../../src/YagrCore/utils/series'; import { DEFAULT_Y_SCALE, SERIE_AREA_BORDER_COLOR, @@ -7,8 +7,8 @@ import { SERIE_LINE_WIDTH, DEFAULT_POINT_SIZE, LIGHT_DEFAULT_LINE_COLOR, -} from '../../src/YagrCore/defaults'; -import {AreaSeriesOptions, DotsSeriesOptions, LineSeriesOptions, RawSerieData} from '../../src'; +} from '../../../src/YagrCore/defaults'; +import {AreaSeriesOptions, DotsSeriesOptions, LineSeriesOptions, RawSerieData} from '../../../src'; const COLOR = '#000000'; diff --git a/tests/utils/stacking.test.ts b/tests/units/utils/stacking.test.ts similarity index 98% rename from tests/utils/stacking.test.ts rename to tests/units/utils/stacking.test.ts index d3fa710..92286d1 100644 --- a/tests/utils/stacking.test.ts +++ b/tests/units/utils/stacking.test.ts @@ -1,4 +1,4 @@ -import Yagr from '../../src/YagrCore'; +import Yagr from '../../../src/YagrCore'; describe('scales: stacking', () => { describe('without processing', () => { diff --git a/tests/utils/tracking.test.ts b/tests/units/utils/tracking.test.ts similarity index 95% rename from tests/utils/tracking.test.ts rename to tests/units/utils/tracking.test.ts index 1d0f199..c225788 100644 --- a/tests/utils/tracking.test.ts +++ b/tests/units/utils/tracking.test.ts @@ -1,5 +1,5 @@ -import {TooltipRow, TooltipSection} from '../../src/YagrCore/plugins/tooltip/types'; -import {findInRange, findSticky} from '../../src/YagrCore/utils/common'; +import {TooltipRow, TooltipSection} from '../../../src/YagrCore/plugins/tooltip/types'; +import {findInRange, findSticky} from '../../../src/YagrCore/utils/common'; const fromArr = (n: (number | null)[]): TooltipSection => { return { diff --git a/tests/utils/utils.test.ts b/tests/units/utils/utils.test.ts similarity index 95% rename from tests/utils/utils.test.ts rename to tests/units/utils/utils.test.ts index 252ade9..1563f60 100644 --- a/tests/utils/utils.test.ts +++ b/tests/units/utils/utils.test.ts @@ -1,5 +1,5 @@ import {Series} from 'uplot'; -import {getSumByIdx} from '../../src/YagrCore/utils/common'; +import {getSumByIdx} from '../../../src/YagrCore/utils/common'; describe('utils:getSumByIdx', () => { it('should sum all series by idx', () => {