diff --git a/bzl/deps.bzl b/bzl/deps.bzl
index 95d9ec4091..18bde9daaa 100644
--- a/bzl/deps.bzl
+++ b/bzl/deps.bzl
@@ -4,8 +4,7 @@
# Install the nodejs "bootstrap" package
# This provides the basic tools for running and packaging nodejs programs in Bazel
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
def fetch_dependencies():
http_archive(
@@ -110,6 +109,14 @@ def fetch_dependencies():
],
)
+ http_file(
+ name = "inkscape_linux",
+ sha256 = "b7a99b6c0ee2817706e77803643f4a6caf9e35bdec928e963c1d2ae86e5e4beb",
+ urls = ["https://inkscape.org/es/gallery/item/31669/Inkscape-0a00cf5-x86_64.AppImage"],
+ executable = True,
+ downloaded_file_path = "bin",
+ )
+
http_archive(
name = "pulumi_cli",
sha256 = "c0e4b0ef05dcc96f2ccd7065afc8e3d6b3b63054fd9978f271a88862664d1547",
diff --git a/cc/inkscape/BUILD b/cc/inkscape/BUILD
new file mode 100644
index 0000000000..d55ab0d3cf
--- /dev/null
+++ b/cc/inkscape/BUILD
@@ -0,0 +1,17 @@
+alias(
+ name = "app_image",
+ actual = "@inkscape_linux//file:bin",
+ visibility = ["//:__subpackages__"],
+)
+
+# Required to bypass FUSE restrictions on bazel.
+sh_binary(
+ name = "bin",
+ srcs = ["run.sh"],
+ data = [":app_image"],
+ env = {"APP_IMAGE": "$(location :app_image)"},
+ visibility = [
+ "//ts/cmd/svgshot:__subpackages__",
+ ],
+ deps = ["@bazel_tools//tools/bash/runfiles"],
+)
diff --git a/cc/inkscape/run.sh b/cc/inkscape/run.sh
new file mode 100755
index 0000000000..1192229db6
--- /dev/null
+++ b/cc/inkscape/run.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+# --- begin runfiles.bash initialization v2 ---
+# Copy-pasted from the Bazel Bash runfiles library v2.
+set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
+source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
+source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
+source "$0.runfiles/$f" 2>/dev/null || \
+source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
+# --- end runfiles.bash initialization v2 ---
+
+# bypasses FUSE issues on bazel https://github.com/AppImage/AppImageKit/pull/842
+$(rlocation inkscape_linux/file/bin) --appimage-extract-and-run $@
diff --git a/js/jest/rules.bzl b/js/jest/rules.bzl
index 1761f64638..4d906fde80 100644
--- a/js/jest/rules.bzl
+++ b/js/jest/rules.bzl
@@ -2,19 +2,21 @@
load("@npm//jest-cli:index.bzl", "jest", _jest_test = "jest_test")
-def jest_test(name, srcs, deps = [], jest_config = "//:jest.ts.config.js", link_workspace_root = True, **kwargs):
+def jest_test(name, srcs, data = [], deps = [], jest_config = "//:jest.ts.config.js", link_workspace_root = True, **kwargs):
"A macro around the autogenerated jest_test rule"
templated_args = [
"--no-cache",
"--no-watchman",
"--ci",
"--colors",
+ "--forceExit",
]
templated_args.extend(["--config", "$(rootpath %s)" % jest_config])
for src in srcs:
templated_args.extend(["--runTestsByPath", "$(rootpath %s)" % src])
- data = [jest_config] + srcs + deps + ["//js/jest:jest_reporter_js"]
+ data = [jest_config] + data + srcs + deps + ["//js/jest:jest_reporter_js"]
+
_jest_test(
name = name,
data = data,
diff --git a/package.json b/package.json
index 573cf1aaae..c286b14823 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"@bazel/buildozer": "^5.1.0",
"@bazel/esbuild": "^4.5.0",
"@bazel/ibazel": "latest",
+ "@bazel/runfiles": "^5.4.2",
"@bazel/typescript": "^4.5.0",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
@@ -26,6 +27,9 @@
"@types/node": "^17.0.35",
"@types/react": "17.0.37",
"@types/react-dom": "^17.0.11",
+ "@types/svgo": "^2.6.3",
+ "@types/tmp": "^0.2.3",
+ "commander": "^9.2.0",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^5.26.0",
@@ -40,6 +44,7 @@
"eslint-config-next": "12.1.6",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
+ "grunt-cli": "^1.4.3",
"http-server": "^14.1.0",
"jest-cli": "^27.4.5",
"jsdom": "^19.0.0",
diff --git a/ts/cmd/svgshot/BUILD b/ts/cmd/svgshot/BUILD
new file mode 100644
index 0000000000..f3d3666ecd
--- /dev/null
+++ b/ts/cmd/svgshot/BUILD
@@ -0,0 +1,43 @@
+load("//:rules.bzl", "jest_test", "nodejs_binary", "ts_project")
+
+ts_project(
+ name = "project",
+ srcs = [
+ "index.ts",
+ "lib.ts",
+ "svgshot_test.ts",
+ ],
+ deps = [
+ "@npm//@bazel/runfiles",
+ "@npm//@types/jest",
+ "@npm//@types/node",
+ "@npm//@types/svgo",
+ "@npm//@types/tmp",
+ "@npm//commander",
+ "@npm//puppeteer",
+ "@npm//svgo",
+ "@npm//tmp",
+ ],
+)
+
+nodejs_binary(
+ name = "svgshot",
+ args = [
+ "--inkscapeBin",
+ "$(location //cc/inkscape:bin)",
+ ],
+ data = [
+ ":project_ts",
+ "//cc/inkscape:bin",
+ ],
+ entry_point = "index.ts",
+)
+
+jest_test(
+ name = "tests",
+ srcs = ["svgshot_test.js"],
+ data = [
+ "//cc/inkscape:bin",
+ ],
+ project_deps = [":project"],
+)
diff --git a/ts/cmd/svgshot/README.md b/ts/cmd/svgshot/README.md
new file mode 100644
index 0000000000..1424ca9d0f
--- /dev/null
+++ b/ts/cmd/svgshot/README.md
@@ -0,0 +1,87 @@
+svgshot
+=============================================================================
+[svgshot]: #svgshot
+
+Svgshot takes 'screenshots' of webpages as minmised SVGs. This makes them
+great for rendering in videos or webpages.
+
+
+Example
+-----------------------------------------------------------------------------
+[Example]: #example
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bash
+svgshot https://en.wikipedia.org
+# loading https://en.wikipedia.org
+# writing Wikipedia__the_free_encyclopedia.svg
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[Wikipedia SVG]: ./Wikipedia__the_free_encyclopedia.svg
+![Wikipedia SVG]
+
+With `--block` for removing text¹:
+
+[Twitch SVG]: ./Twitch.svg
+![Twitch SVG]
+
+[Examples directory]: ./examples
+For more examples, take a look at the [Examples directory].
+
+[BLOKK font]: http://www.blokkfont.com/
+
+¹ Orginally this was intended to block out text like the [BLOKK font], but
+I couldn't do this without creating truly huge SVGs. If you have any ideas
+as to how this could be achieved, let me know!
+
+Installation
+-----------------------------------------------------------------------------
+[Installation]: #Installation
+
+With node and `inkscape` installed:
+```bash
+npm install -g svgshot
+```
+
+If you don't have `inkscape` installed on windows, try `scoop`:
+```powershell
+scoop install inkscape
+```
+
+For temporary usage you might want to use `npx`:
+```bash
+npx svgshot https://en.wikipedia.org
+```
+
+TODO
+-----------------------------------------------------------------------------
+Replace SVG dimensions with viewBox so they dont get weirdly warped when
+rendered at the wrong size:
+https://gist.github.com/fyrebase/4604f540bc4a329ff3bfde225775d39e
+
+License
+-----------------------------------------------------------------------------
+[License]: #license
+
+
+MIT License
+
+Copyright (c) 2019 Zemnmez
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/ts/cmd/svgshot/Twitch.svg b/ts/cmd/svgshot/Twitch.svg
new file mode 100644
index 0000000000..778a5ef7dc
--- /dev/null
+++ b/ts/cmd/svgshot/Twitch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/Wikipedia__the_free_encyclopedia.svg b/ts/cmd/svgshot/Wikipedia__the_free_encyclopedia.svg
new file mode 100644
index 0000000000..2909eb40d0
--- /dev/null
+++ b/ts/cmd/svgshot/Wikipedia__the_free_encyclopedia.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/dist/index.js b/ts/cmd/svgshot/dist/index.js
new file mode 100644
index 0000000000..d53bdc2336
--- /dev/null
+++ b/ts/cmd/svgshot/dist/index.js
@@ -0,0 +1,147 @@
+#!/usr/bin/env node
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+ result["default"] = mod;
+ return result;
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const puppeteer_1 = __importDefault(require("puppeteer"));
+const tmp = __importStar(require("tmp"));
+const child_process_1 = require("child_process");
+const svgo_1 = __importDefault(require("svgo"));
+const fs_1 = require("fs");
+const util_1 = require("util");
+const svgoPlugins = [{ cleanupAttrs: true, }, { removeDoctype: true, }, { removeXMLProcInst: true, }, { removeComments: true, }, { removeMetadata: true, }, { removeTitle: true, }, { removeDesc: true, }, { removeUselessDefs: true, }, { removeEditorsNSData: true, }, { removeEmptyAttrs: true, }, { removeHiddenElems: true, }, { removeEmptyText: true, }, { removeEmptyContainers: true, }, { removeViewBox: false, }, { cleanupEnableBackground: true, }, { convertColors: true, }, { convertPathData: true, }, { convertTransform: true, }, { removeUnknownsAndDefaults: true, }, { removeNonInheritableGroupAttrs: true, }, { removeUselessStrokeAndFill: true, }, { removeUnusedNS: true, }, { cleanupIDs: true, }, { cleanupNumericValues: true, }, { moveElemsAttrsToGroup: true, }, { moveGroupAttrsToElems: true, }, { collapseGroups: true, }, { removeRasterImages: false, }, { mergePaths: true, }, { convertShapeToPath: true, }, { sortAttrs: true, }];
+const program = require('commander');
+program
+ .name("svgshot")
+ .usage("")
+ .description('take svg screenshots of webpages. requires the inkscape cli tool')
+ .option('-s, --scale ', 'scale of the render. must be between 1 and 2', 1)
+ .option('--no-background', 'do not render backgounds')
+ .option('--width ', 'Width; using px, mm or in (as though printed)', '1000px')
+ .option('--height ', 'Height; using px, mm or in (as though printed)', '1000px')
+ .option('--media ', 'CSS @page media', 'screen')
+ .option('--timeout ', 'Maximum time to wait for page to become idle before taking screenshot', 10000)
+ .option('--throttle ', 'Maximum number of pages to load at once. set to `1` for sequential operation', 10)
+ .option('--block', "make text invisible for presentation (it's still in the file though)", false)
+ .option('--headful', "run in a visible chromium instance (useful for debugging). also implicitly retains the chromium instance", false);
+program.parse(process.argv);
+const { background, width, height, media, scale, timeout, throttle: throttleN, block, headful } = program;
+const args = program.args;
+const isValidMedia = (s) => s == "screen" || s == "print";
+if (!isValidMedia(media))
+ throw new Error(`invalid media type ${media}; must be "screen" or "print"`);
+const map = async function* (f, iter) {
+ let n = 0;
+ for await (let value of iter)
+ yield (await f)(value, n++);
+};
+const chunk = (size) => (iter) => (async function* () {
+ let bucket = [];
+ for await (let value of iter) {
+ bucket.push(value);
+ if (bucket.length == await size) {
+ yield bucket;
+ bucket = [];
+ }
+ }
+})();
+const EventuallyIterable = async function* (I) {
+ for await (let value of I)
+ yield await value;
+};
+/** perform a promise iterator lazily in chunks */
+const chunkedPromise = (N) => (I) => map(v => Promise.all(v), chunk(N)(I));
+;
+const flat = async function* (I) {
+ for await (let chunk of I)
+ for await (let member of chunk)
+ yield member;
+};
+/** lazily completes the given async iterable in chunks of given size */
+const throttle = N => I => flat(EventuallyIterable(chunkedPromise(N)(I)));
+const main = async () => {
+ const browser = await puppeteer_1.default.launch({
+ headless: !headful,
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu'] // unfortunate, but needed to work with wsl...
+ });
+ const captures = map(async (url, i) => {
+ console.warn("loading", url);
+ const loading = setInterval(() => {
+ console.warn("still loading", url);
+ }, timeout / 2);
+ const page = await browser.newPage();
+ try {
+ await page.goto(url, {
+ waitUntil: 'networkidle2',
+ timeout
+ });
+ }
+ catch (e) {
+ // if the network doesn't go idle, we still take the screenshot
+ }
+ clearInterval(loading);
+ if (block) {
+ const loading = setInterval(() => {
+ console.warn("waiting for injected style...", url);
+ }, timeout / 2);
+ await page.evaluate(() => {
+ const s = document.createElement("style");
+ s.innerHTML = `* { color: transparent !important }`;
+ document.head.appendChild(s);
+ /*
+ const d = window.document;
+ const y = d.createTreeWalker(d.body, 4);
+ for(;y.nextNode();y.currentNode.textContent=y.currentNode!.textContent!.replace(/\S/g, '…'));
+ */
+ });
+ clearInterval(loading);
+ }
+ await page.emulateMediaType(media);
+ const pdf = await page.pdf({
+ scale: scale,
+ printBackground: background,
+ width: width,
+ height: height,
+ margin: { top: 0, right: 0, left: 0, bottom: 0 }
+ });
+ const [pdfFile, svgFile] = await Promise.all(['.pdf', '.svg'].map(async (extension) => {
+ return new Promise((ok, err) => {
+ tmp.file({ postfix: extension }, (error, path) => {
+ if (error)
+ return err(error);
+ return ok(path);
+ });
+ });
+ }));
+ await util_1.promisify(fs_1.writeFile)(pdfFile, pdf);
+ const line = `inkscape --without-gui ${pdfFile} --export-plain-svg ${svgFile}`;
+ try {
+ await util_1.promisify(child_process_1.exec)(line);
+ }
+ catch (e) {
+ throw new Error(`failed to run ${line} with ${e} -- make sure you have inkscape installed and in your PATH`);
+ }
+ const svgo = new svgo_1.default({
+ plugins: svgoPlugins
+ });
+ const title = ((await page.title()).trim() || page.url()).replace(/[^A-z_-]/g, "_");
+ const fileName = title + ".svg";
+ const svgContents = await util_1.promisify(fs_1.readFile)(svgFile, 'utf8');
+ const optimSvg = await svgo.optimize(svgContents.toString(), { path: svgFile });
+ console.warn(`writing ${i + 1}/${args.length} ${fileName} (${width} x ${height})`);
+ await util_1.promisify(fs_1.writeFile)(fileName, optimSvg.data);
+ }, args);
+ for await (let _ of throttle(throttleN)(captures))
+ ;
+ if (!headful)
+ await browser.close();
+};
+main().catch(e => { console.error(e); process.exit(1); }).then(() => process.exit(0));
diff --git a/ts/cmd/svgshot/examples/Apple.svg b/ts/cmd/svgshot/examples/Apple.svg
new file mode 100644
index 0000000000..952ff29e27
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Apple.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Hacker_News.svg b/ts/cmd/svgshot/examples/Hacker_News.svg
new file mode 100644
index 0000000000..0535ac5138
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Hacker_News.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Home_-_BBC_News.svg b/ts/cmd/svgshot/examples/Home_-_BBC_News.svg
new file mode 100644
index 0000000000..a12d0077aa
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Home_-_BBC_News.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Music_for_everyone_-_Spotify.svg b/ts/cmd/svgshot/examples/Music_for_everyone_-_Spotify.svg
new file mode 100644
index 0000000000..da2f303857
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Music_for_everyone_-_Spotify.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Serebii_net_-_Where_Legends_Come_To_Life.svg b/ts/cmd/svgshot/examples/Serebii_net_-_Where_Legends_Come_To_Life.svg
new file mode 100644
index 0000000000..1a923954a9
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Serebii_net_-_Where_Legends_Come_To_Life.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Stack_Overflow_-_Where_Developers_Learn__Share____Build_Careers.svg b/ts/cmd/svgshot/examples/Stack_Overflow_-_Where_Developers_Learn__Share____Build_Careers.svg
new file mode 100644
index 0000000000..8cc0acae87
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Stack_Overflow_-_Where_Developers_Learn__Share____Build_Careers.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Twitch.svg b/ts/cmd/svgshot/examples/Twitch.svg
new file mode 100644
index 0000000000..d3cef14caa
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Twitch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Where_work_happens___Slack.svg b/ts/cmd/svgshot/examples/Where_work_happens___Slack.svg
new file mode 100644
index 0000000000..5c6cc5bc45
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Where_work_happens___Slack.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/Wikipedia__the_free_encyclopedia.svg b/ts/cmd/svgshot/examples/Wikipedia__the_free_encyclopedia.svg
new file mode 100644
index 0000000000..0b487df7d0
--- /dev/null
+++ b/ts/cmd/svgshot/examples/Wikipedia__the_free_encyclopedia.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/YouTube.svg b/ts/cmd/svgshot/examples/YouTube.svg
new file mode 100644
index 0000000000..fa66fd9405
--- /dev/null
+++ b/ts/cmd/svgshot/examples/YouTube.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/examples/______zemnmez__on_Twitter.svg b/ts/cmd/svgshot/examples/______zemnmez__on_Twitter.svg
new file mode 100644
index 0000000000..8caa8fade5
--- /dev/null
+++ b/ts/cmd/svgshot/examples/______zemnmez__on_Twitter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ts/cmd/svgshot/index.ts b/ts/cmd/svgshot/index.ts
new file mode 100644
index 0000000000..b159bff44d
--- /dev/null
+++ b/ts/cmd/svgshot/index.ts
@@ -0,0 +1,10 @@
+#!/usr/bin/env node
+
+import main from './lib';
+
+main()
+ .catch(e => {
+ console.error(e);
+ process.exit(1);
+ })
+ .then(() => process.exit(0));
diff --git a/ts/cmd/svgshot/lib.ts b/ts/cmd/svgshot/lib.ts
new file mode 100644
index 0000000000..22d61f4078
--- /dev/null
+++ b/ts/cmd/svgshot/lib.ts
@@ -0,0 +1,243 @@
+import puppeteer from 'puppeteer';
+import * as tmp from 'tmp';
+import { exec } from 'child_process';
+import * as svgo from 'svgo';
+import { writeFile, readFile } from 'fs/promises';
+import { promisify } from 'util';
+import { Command } from 'commander';
+
+const program = new Command()
+ .name('svgshot')
+ .usage('')
+ .description(
+ 'take svg screenshots of webpages. requires the inkscape cli tool'
+ )
+ .option(
+ '-s, --scale ',
+ 'scale of the render. must be between 1 and 2',
+ '1'
+ )
+ .option('--no-background', 'do not render backgounds')
+ .option(
+ '--width ',
+ 'Width; using px, mm or in (as though printed)',
+ '1000px'
+ )
+ .option(
+ '--height ',
+ 'Height; using px, mm or in (as though printed)',
+ '1000px'
+ )
+ .option('--media ', 'CSS @page media', 'screen')
+ .option(
+ '--timeout ',
+ 'Maximum time to wait for page to become idle before taking screenshot',
+ '10000'
+ )
+ .option(
+ '--block',
+ "make text invisible for presentation (it's still in the file though)",
+ false
+ )
+ .option(
+ '--headful',
+ 'run in a visible chromium instance (useful for debugging). also implicitly retains the chromium instance',
+ false
+ )
+ .option(
+ '--out ',
+ 'manually specify an output file name -- this fails if multiple URLs are to be recorded',
+ undefined
+ )
+ .option(
+ '--inkscapeBin ',
+ 'specify the location of the inkscape binary',
+ 'inkscape'
+ );
+
+const isValidMedia = (s: string): s is 'screen' | 'print' =>
+ s == 'screen' || s == 'print';
+
+type Eventually = T | Promise;
+
+type EventuallyIterable = Iterable | AsyncIterable;
+
+const map: (
+ v: EventuallyIterable,
+ f: Eventually<(v: T, i: number) => Eventually>
+) => EventuallyIterable = async function* (iter, f) {
+ let n = 0;
+ for await (const value of iter) yield (await f)(value, n++);
+};
+
+const main = async (argv: string[] = process.argv) => {
+ let {
+ background,
+ width,
+ height,
+ media,
+ scale,
+ timeout,
+ block,
+ headful,
+ inkscapeBin,
+ out,
+ } = program.parse(argv).opts();
+
+ scale = +scale;
+
+ const args = program.args;
+
+ if (!isValidMedia(media))
+ throw new Error(
+ `invalid media type ${media}; must be "screen" or "print"`
+ );
+
+ const browser = await puppeteer.launch({
+ headless: !headful,
+ args: [
+ '--no-sandbox',
+ '--disable-setuid-sandbox',
+ '--disable-dev-shm-usage',
+ '--disable-gpu',
+ ], // unfortunate, but needed to work with wsl...
+ });
+
+ if (out !== undefined && args.length > 1) {
+ throw new Error(
+ `Out file specified and more than one URL (${args}) to load.`
+ );
+ }
+
+ const captures = map(args, async (url, i) => {
+ console.warn('loading', url);
+
+ const loading = setInterval(() => {
+ console.warn('still loading', url);
+ }, timeout / 2);
+
+ const page = await browser.newPage();
+
+ try {
+ await page.goto(url, {
+ waitUntil: 'networkidle2',
+ timeout,
+ });
+ } catch (e) {
+ // if the network doesn't go idle, we still take the screenshot
+ }
+
+ clearInterval(loading);
+
+ if (block) {
+ const loading = setInterval(() => {
+ console.warn('waiting for injected style...', url);
+ }, timeout / 2);
+
+ await page.evaluate(() => {
+ const s = document.createElement('style');
+ s.innerHTML = `* { color: transparent !important }`;
+ document.head.appendChild(s);
+ });
+
+ clearInterval(loading);
+ }
+
+ await page.emulateMediaType(media);
+
+ const pdf = await page.pdf({
+ scale: scale,
+ printBackground: background,
+ width: width,
+ height: height,
+ margin: { top: 0, right: 0, left: 0, bottom: 0 },
+ });
+
+ const [[pdfFile, cleanup1], [svgFile, cleanup2]] = await Promise.all(
+ ['.pdf', '.svg'].map(
+ async (extension): Promise<[string, () => void]> => {
+ return new Promise((ok, err) => {
+ tmp.file(
+ {
+ tmpdir: process.env['TEST_TMPDIR'] || undefined,
+ postfix: extension,
+ },
+ (error, path, _, cleanup) => {
+ if (error) return err(error);
+ return ok([path, cleanup]);
+ }
+ );
+ });
+ }
+ )
+ );
+
+ const cleanup = () => {
+ cleanup1();
+ cleanup2();
+ };
+
+ if (pdf.length === 0) {
+ throw new Error('Failed to generate PDF.');
+ }
+
+ await writeFile(pdfFile, pdf);
+
+ const line =
+ `${inkscapeBin} --without-gui ${pdfFile} ` +
+ `--export-type=svg --export-plain-svg --export-filename=${svgFile}`;
+ console.warn('running', line);
+ try {
+ const result = await promisify(exec)(line);
+ if (result.stderr.length > 0) console.warn(result.stderr);
+ console.info(result.stdout);
+ } catch (e) {
+ throw new Error(
+ `failed to run ${line} with ${e} -- make sure you have inkscape installed and in your PATH`
+ );
+ }
+
+ const fileName =
+ out === undefined
+ ? ((await page.title()).trim() || page.url()).replace(
+ /[^A-z_-]/g,
+ '_'
+ ) + '.svg'
+ : out;
+
+ const svgContents = (await readFile(svgFile, 'utf8')).toString();
+
+ if (svgContents.length === 0) {
+ throw new Error('Failed to generate SVG.');
+ }
+
+ const optimSvg = await svgo.optimize(svgContents, {
+ multipass: true,
+ path: svgFile,
+ });
+
+ if (optimSvg.error !== undefined) throw optimSvg.error;
+
+ if (!optimSvg.data) {
+ throw new Error('Failed to optimize SVG.');
+ }
+
+ console.warn(
+ `writing ${i + 1}/${args.length} ${fileName} (${width} x ${height})`
+ );
+
+ await writeFile(fileName, optimSvg.data);
+
+ cleanup();
+
+ return fileName;
+ });
+
+ for await (const filepath of captures) {
+ console.info('Wrote', filepath);
+ }
+
+ if (!headful) await browser.close();
+};
+
+export default main;
diff --git a/ts/cmd/svgshot/svgshot_test.ts b/ts/cmd/svgshot/svgshot_test.ts
new file mode 100644
index 0000000000..4230f08a16
--- /dev/null
+++ b/ts/cmd/svgshot/svgshot_test.ts
@@ -0,0 +1,50 @@
+import main from './lib';
+import tmp from 'tmp';
+import fs from 'fs/promises';
+import { runfiles } from '@bazel/runfiles';
+
+describe('svgshot', () => {
+ it('should render a test URL', async () => {
+ const [target, cleanup] = await new Promise<[string, () => void]>(
+ (ok, err) =>
+ tmp.file(
+ {
+ // https://docs.bazel.build/versions/main/test-encyclopedia.html#test-interaction-with-the-filesystem
+ tmpdir: process.env['TEST_TMPDIR'] || undefined,
+ postfix: '.svg',
+ },
+ (error, path, _, cleanup) => {
+ if (error) return err(error);
+ return ok([path, cleanup]);
+ }
+ )
+ );
+
+ const inkscape =
+ runfiles.resolveWorkspaceRelative('cc/inkscape/run.sh');
+
+ await expect(
+ main([
+ 'fake123',
+ 'fake1234',
+ '--inkscapeBin',
+ inkscape,
+ 'data:text/plain,Hello, world!',
+ '--out',
+ target,
+ ])
+ ).resolves.toBeUndefined();
+
+ const result = (await fs.readFile(target)).toString();
+
+ cleanup();
+
+ expect(result).not.toEqual('');
+ expect(result).not.toBeUndefined();
+ expect(result).not.toBeNull();
+
+ expect(result).toEqual(
+ ``
+ );
+ });
+});
diff --git a/ts/jest/jest.setup.ts b/ts/jest/jest.setup.ts
index 7b0828bfa8..331666cea8 100644
--- a/ts/jest/jest.setup.ts
+++ b/ts/jest/jest.setup.ts
@@ -1 +1 @@
-import '@testing-library/jest-dom';
+import '@testing-library/jest-dom';
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index c947ec4835..ae58096ce9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -514,6 +514,11 @@
resolved "https://registry.yarnpkg.com/@bazel/labs/-/labs-4.6.1.tgz#c638b6b54e831abdca57ac8700af8c478c21e085"
integrity sha512-7CRtjP9W3ywX6AvTAzV5is0LrXt3zxUSW5SzUGa+LhdsrDc3+VDyW7MOJlwMai2xmBb4J1tqaZKo8KSlr2H2tg==
+"@bazel/runfiles@^5.4.2":
+ version "5.4.2"
+ resolved "https://registry.yarnpkg.com/@bazel/runfiles/-/runfiles-5.4.2.tgz#85d6ee8ab99c8a1ebe7b320b2bc452135c2ff30f"
+ integrity sha512-FfX+GeoeBcFP7JfsZN0T3cfFOpi80Nf9W9/g2U5pjcYay2Q06fmj3Fi3SVg+iyzjo+cbW9Sw/F3otCsvvZYPiw==
+
"@bazel/typescript@^4.5.0":
version "4.5.0"
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-4.5.0.tgz#8167a5f29bd9e89dabecb0ad62f38c065c48d9f4"
@@ -1467,6 +1472,18 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
+"@types/svgo@^2.6.3":
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/@types/svgo/-/svgo-2.6.3.tgz#0786d8329b67cd48d84e57cb92b79832b85e6c8e"
+ integrity sha512-5sP0Xgo0dXppY0tbYF6TevB/1+tzFLuu71XXxC/zGvQAn9PW7y+DwtDO81g0ZUPye00K6tPwtsLDOpARa0mFcA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/tmp@^0.2.3":
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.3.tgz#908bfb113419fd6a42273674c00994d40902c165"
+ integrity sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==
+
"@types/uuid@^8.3.4":
version "8.3.4"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
@@ -1576,6 +1593,11 @@ abab@^2.0.3, abab@^2.0.5:
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
acorn-globals@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
@@ -1705,6 +1727,11 @@ aria-query@^5.0.0:
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c"
integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==
+array-each@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
+ integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8=
+
array-includes@^3.1.3, array-includes@^3.1.4, array-includes@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb"
@@ -1716,6 +1743,11 @@ array-includes@^3.1.3, array-includes@^3.1.4, array-includes@^3.1.5:
get-intrinsic "^1.1.1"
is-string "^1.0.7"
+array-slice@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
+ integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
+
array-union@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
@@ -1909,7 +1941,7 @@ bl@^4.0.3:
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
- integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+ integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
brace-expansion@^1.1.7:
version "1.1.11"
@@ -1952,7 +1984,7 @@ bser@2.1.1:
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
- integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
+ integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer-from@^1.0.0, buffer-from@^1.1.0:
version "1.1.2"
@@ -2139,6 +2171,11 @@ commander@^7.2.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+commander@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9"
+ integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==
+
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -2435,6 +2472,11 @@ deprecation@^2.0.0, deprecation@^2.3.1:
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
+detect-file@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+ integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
@@ -3072,6 +3114,13 @@ exit@^0.1.2:
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+ integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
expect@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74"
@@ -3082,6 +3131,11 @@ expect@^27.5.1:
jest-matcher-utils "^27.5.1"
jest-message-util "^27.5.1"
+extend@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
extract-zip@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
@@ -3179,6 +3233,32 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
+findup-sync@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0"
+ integrity sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==
+ dependencies:
+ detect-file "^1.0.0"
+ is-glob "^4.0.0"
+ micromatch "^4.0.2"
+ resolve-dir "^1.0.1"
+
+fined@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b"
+ integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==
+ dependencies:
+ expand-tilde "^2.0.2"
+ is-plain-object "^2.0.3"
+ object.defaults "^1.1.0"
+ object.pick "^1.2.0"
+ parse-filepath "^1.0.1"
+
+flagged-respawn@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41"
+ integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==
+
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@@ -3197,6 +3277,18 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4"
integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==
+for-in@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+ integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
+ integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
+ dependencies:
+ for-in "^1.0.1"
+
form-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
@@ -3358,6 +3450,15 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0:
once "^1.3.0"
path-is-absolute "^1.0.0"
+global-modules@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+ integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+ dependencies:
+ global-prefix "^1.0.1"
+ is-windows "^1.0.1"
+ resolve-dir "^1.0.0"
+
global-modules@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@@ -3365,6 +3466,17 @@ global-modules@^2.0.0:
dependencies:
global-prefix "^3.0.0"
+global-prefix@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+ integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+ dependencies:
+ expand-tilde "^2.0.2"
+ homedir-polyfill "^1.0.1"
+ ini "^1.3.4"
+ is-windows "^1.0.1"
+ which "^1.2.14"
+
global-prefix@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
@@ -3413,6 +3525,22 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4,
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+grunt-cli@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/grunt-cli/-/grunt-cli-1.4.3.tgz#22c9f1a3d2780bf9b0d206e832e40f8f499175ff"
+ integrity sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==
+ dependencies:
+ grunt-known-options "~2.0.0"
+ interpret "~1.1.0"
+ liftup "~3.0.1"
+ nopt "~4.0.1"
+ v8flags "~3.2.0"
+
+grunt-known-options@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/grunt-known-options/-/grunt-known-options-2.0.0.tgz#cac641e897f9a0a680b8c9839803d35f3325103c"
+ integrity sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==
+
hard-rejection@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
@@ -3471,6 +3599,13 @@ history@^5.2.0:
dependencies:
"@babel/runtime" "^7.7.6"
+homedir-polyfill@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+ integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+ dependencies:
+ parse-passwd "^1.0.0"
+
hosted-git-info@^2.1.4:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
@@ -3654,7 +3789,7 @@ inherits@2, inherits@^2.0.3, inherits@^2.0.4:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-ini@^1.3.5:
+ini@^1.3.4, ini@^1.3.5:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
@@ -3678,6 +3813,19 @@ internal-slot@^1.0.3:
resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==
+interpret@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
+ integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=
+
+is-absolute@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
+ integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
+ dependencies:
+ is-relative "^1.0.0"
+ is-windows "^1.0.1"
+
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -3761,6 +3909,13 @@ is-plain-obj@^1.1.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+ dependencies:
+ isobject "^3.0.1"
+
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
@@ -3784,6 +3939,13 @@ is-regexp@^2.0.0:
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d"
integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==
+is-relative@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
+ integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
+ dependencies:
+ is-unc-path "^1.0.0"
+
is-shared-array-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
@@ -3815,6 +3977,13 @@ is-typedarray@^1.0.0:
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+is-unc-path@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
+ integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
+ dependencies:
+ unc-path-regex "^0.1.2"
+
is-weakref@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
@@ -3822,6 +3991,11 @@ is-weakref@^1.0.2:
dependencies:
call-bind "^1.0.2"
+is-windows@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
isarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -3832,6 +4006,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3"
@@ -4473,6 +4652,20 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
+liftup@~3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/liftup/-/liftup-3.0.1.tgz#1cb81aff0f368464ed3a5f1a7286372d6b1a60ce"
+ integrity sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==
+ dependencies:
+ extend "^3.0.2"
+ findup-sync "^4.0.0"
+ fined "^1.2.0"
+ flagged-respawn "^1.0.1"
+ is-plain-object "^2.0.4"
+ object.map "^1.0.1"
+ rechoir "^0.7.0"
+ resolve "^1.19.0"
+
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -4554,6 +4747,13 @@ make-error@^1.1.1:
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
+make-iterator@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6"
+ integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==
+ dependencies:
+ kind-of "^6.0.2"
+
makeerror@1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
@@ -4561,6 +4761,11 @@ makeerror@1.0.12:
dependencies:
tmpl "1.0.5"
+map-cache@^0.2.0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+ integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
map-obj@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
@@ -4609,7 +4814,7 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-micromatch@^4.0.4, micromatch@^4.0.5:
+micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
@@ -4734,6 +4939,14 @@ node-releases@^2.0.3:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
+nopt@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
+ integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
normalize-package-data@^2.0.0, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@@ -4772,9 +4985,9 @@ npm-run-path@^4.0.1:
path-key "^3.0.0"
nth-check@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
- integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2"
+ integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==
dependencies:
boolbase "^1.0.0"
@@ -4808,6 +5021,16 @@ object.assign@^4.1.2:
has-symbols "^1.0.1"
object-keys "^1.1.1"
+object.defaults@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
+ integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=
+ dependencies:
+ array-each "^1.0.1"
+ array-slice "^1.0.0"
+ for-own "^1.0.0"
+ isobject "^3.0.0"
+
object.entries@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861"
@@ -4844,6 +5067,21 @@ object.hasown@^1.1.1:
define-properties "^1.1.4"
es-abstract "^1.19.5"
+object.map@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37"
+ integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=
+ dependencies:
+ for-own "^1.0.0"
+ make-iterator "^1.0.0"
+
+object.pick@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+ dependencies:
+ isobject "^3.0.1"
+
object.values@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac"
@@ -4896,6 +5134,24 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+ integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-tmpdir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
p-limit@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@@ -4941,6 +5197,15 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+parse-filepath@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
+ integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=
+ dependencies:
+ is-absolute "^1.0.0"
+ map-cache "^0.2.0"
+ path-root "^0.1.1"
+
parse-json@^5.0.0, parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
@@ -4951,6 +5216,11 @@ parse-json@^5.0.0, parse-json@^5.2.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
+parse-passwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+ integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
parse5@6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
@@ -4981,6 +5251,18 @@ path-parse@^1.0.6, path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+path-root-regex@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+ integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=
+
+path-root@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+ integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=
+ dependencies:
+ path-root-regex "^0.1.0"
+
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
@@ -5371,6 +5653,13 @@ readdir-scoped-modules@^1.0.0:
graceful-fs "^4.1.2"
once "^1.3.0"
+rechoir@^0.7.0:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686"
+ integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==
+ dependencies:
+ resolve "^1.9.0"
+
redent@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
@@ -5420,6 +5709,14 @@ resolve-cwd@^3.0.0:
dependencies:
resolve-from "^5.0.0"
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+ integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+ dependencies:
+ expand-tilde "^2.0.0"
+ global-modules "^1.0.0"
+
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -5435,7 +5732,7 @@ resolve.exports@^1.1.0:
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9"
integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==
-resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.7.1:
+resolve@^1.10.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.7.1, resolve@^1.9.0:
version "1.22.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
@@ -6201,6 +6498,11 @@ unbzip2-stream@1.4.3:
buffer "^5.2.1"
through "^2.3.8"
+unc-path-regex@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+ integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
+
underscore@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
@@ -6294,6 +6596,13 @@ v8-to-istanbul@^8.1.0:
convert-source-map "^1.6.0"
source-map "^0.7.3"
+v8flags@~3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656"
+ integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
@@ -6410,7 +6719,7 @@ which-boxed-primitive@^1.0.2:
is-string "^1.0.5"
is-symbol "^1.0.3"
-which@^1.3.1:
+which@^1.2.14, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==