From f506f07385c676d454ce59f9938a3b1a7111f539 Mon Sep 17 00:00:00 2001 From: Mario Ranftl Date: Mon, 20 Feb 2023 22:49:20 +0100 Subject: [PATCH] ts: activate linting --- .devcontainer.json | 12 +- .eslintrc.cjs | 10 + .prettierrc | 5 + Dockerfile | 4 +- Gruntfile.js | 2 +- docker-compose.yml | 7 +- package.json | 7 + server/api/fonts.controller.ts | 63 ++- server/api/fonts.spec.ts | 239 +++++----- server/api/healthy.controller.ts | 16 +- server/api/healthy.spec.ts | 9 +- server/app.spec.ts | 22 +- server/app.ts | 49 ++- server/config.ts | 57 +-- server/logic/core.ts | 30 +- server/logic/fetchCSS.ts | 65 ++- server/logic/fetchFontFiles.ts | 51 ++- server/logic/fetchFontURLs.ts | 28 +- server/logic/fetchGoogleFonts.ts | 45 +- server/logic/store.ts | 57 ++- server/routes.ts | 27 +- server/utils/asyncRetry.spec.ts | 71 +-- server/utils/asyncRetry.ts | 11 +- server/utils/synchronized.ts | 12 +- yarn.lock | 730 ++++++++++++++++++++++++++++++- 25 files changed, 1180 insertions(+), 449 deletions(-) create mode 100644 .eslintrc.cjs create mode 100644 .prettierrc diff --git a/.devcontainer.json b/.devcontainer.json index ffb9969..61bbac3 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -20,10 +20,18 @@ "customizations": { "vscode": { "settings": { - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.formatOnType": false, + "editor.formatOnPaste": false + } }, "extensions": [ - "eamodio.gitlens" + "eamodio.gitlens", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" ] } } diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..4b75b88 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,10 @@ +module.exports = { + ignorePatterns: [".eslintrc.cjs", "Gruntfile.js", "dist/**/*.js", "client/**/*.js"], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + root: true, + parserOptions: { + project: "./tsconfig.json" + } +}; \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..fd55683 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": true, + "singleQuote": false, + "printWidth": 140 +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 522c4aa..ea99e02 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,9 +27,7 @@ RUN apt-get update && apt-get install -y -q --no-install-recommends \ # global npm installs RUN npm install -g grunt-cli@1.2.0 \ - && npm cache clean --force - -# git config --global --add safe.directory /app + && npm cache clean --force WORKDIR /app diff --git a/Gruntfile.js b/Gruntfile.js index 324f50e..030ba71 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -57,7 +57,7 @@ module.exports = function (grunt) { tasks: ['injector:css'] }, mochaTest: { - files: ['server/**/*.ts', 'server/**/*.js'], + files: ['server/**/*.spec.ts', 'server/**/*.spec.js'], tasks: ['env:test', 'mochaTest'] }, injectLess: { diff --git a/docker-compose.yml b/docker-compose.yml index 3cdbe75..c5700e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,4 +24,9 @@ services: GOOGLE_FONTS_API_KEY: ${GOOGLE_FONTS_API_KEY} # Overrides default command so things don't shut down after the process ends. - command: /bin/sh -c "while sleep 1000; do :; done" + command: + - /bin/sh + - -c + - | + git config --global --add safe.directory /app + while sleep 1000; do :; done diff --git a/package.json b/package.json index 70e1691..84b93b6 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,12 @@ "@types/node": "18", "@types/speakingurl": "^13.0.3", "@types/supertest": "^2.0.12", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@typescript-eslint/parser": "^5.52.0", "bower": "^1.3.8", "connect-livereload": "~0.4.0", "errorhandler": "~1.0.0", + "eslint": "^8.34.0", "grunt": "~0.4.4", "grunt-angular-templates": "^0.5.4", "grunt-asset-injector": "^0.1.0", @@ -75,6 +78,9 @@ "grunt-wiredep": "~1.8.0", "jit-grunt": "^0.5.0", "mocha": "^10.2.0", + "prettier": "^2.8.4", + "prettier-eslint": "^15.0.1", + "prettier-plugin-organize-imports": "^3.2.2", "punycode": "^1.4.1", "should": "13.2.3", "supertest": "6.3.3", @@ -84,6 +90,7 @@ }, "scripts": { "start": "ts-node server/app.ts", + "lint": "eslint --ext .ts .", "build": "grunt build", "test": "grunt test", "dev": "grunt serve", diff --git a/server/api/fonts.controller.ts b/server/api/fonts.controller.ts index 29e2065..856bcc3 100644 --- a/server/api/fonts.controller.ts +++ b/server/api/fonts.controller.ts @@ -1,11 +1,11 @@ +import { NextFunction, Request, Response } from "express"; +import * as fs from "fs"; +import * as JSZip from "jszip"; import * as _ from "lodash"; +import * as path from "path"; import * as stream from "stream"; -import { Request, Response, NextFunction } from "express"; -import { loadFontBundle, loadFontItems, loadSubsetMap, loadVariantItems, loadFontFilePaths } from "../logic/core"; import { IUserAgents } from "../config"; -import * as JSZip from "jszip"; -import * as path from "path"; -import * as fs from "fs"; +import { loadFontBundle, loadFontFilePaths, loadFontItems, loadSubsetMap, loadVariantItems } from "../logic/core"; // Get list of fonts // /api/fonts @@ -23,7 +23,6 @@ interface IAPIListFont { } export async function getApiFonts(req: Request, res: Response, next: NextFunction) { try { - const fonts = loadFontItems(); const apiListFonts: IAPIListFont[] = _.map(fonts, (font) => { @@ -37,7 +36,7 @@ export async function getApiFonts(req: Request, res: Response, n lastModified: font.lastModified, popularity: font.popularity, defSubset: font.defSubset, - defVariant: font.defVariant + defVariant: font.defVariant, }; }); @@ -61,7 +60,7 @@ interface IAPIFont { defVariant: string; subsetMap: { [subset: string]: boolean; - } + }; storeID: string; variants: { id: string; @@ -76,29 +75,27 @@ interface IAPIFont { }[]; } export async function getApiFontsById(req: Request, res: Response, next: NextFunction) { - try { - // get the subset string if it was supplied... + // get the subset string if it was supplied... // e.g. "subset=latin,latin-ext," will be transformed into ["latin","latin-ext"] (non whitespace arrays) - const subsets = _.isString(req.query.subsets) ? _.without(req.query.subsets.split(/[,]+/), '') : null; + const subsets = _.isString(req.query.subsets) ? _.without(req.query.subsets.split(/[,]+/), "") : null; const fontBundle = await loadFontBundle(req.params.id, subsets); if (_.isNil(fontBundle)) { - return res.status(404).send('Not found'); + return res.status(404).send("Not found"); } const subsetMap = loadSubsetMap(fontBundle); const variantItems = await loadVariantItems(fontBundle); if (_.isNil(variantItems)) { - return res.status(404).send('Not found'); + return res.status(404).send("Not found"); } // default case: json serialize... if (req.query.download !== "zip") { - - const { font, storeID } = fontBundle; + const { font } = fontBundle; const apiFont: IAPIFont = { id: font.id, @@ -119,51 +116,52 @@ export async function getApiFontsById(req: Request, res: Response { - sum[vurl.format] = vurl.url; - return sum; - }, {} as IUserAgents)) + ..._.reduce( + variant.urls, + (sum, vurl) => { + sum[vurl.format] = vurl.url; + return sum; + }, + {} as IUserAgents + ), }; - }) + }), }; return res.json(apiFont); } // otherwise: download as zip - const variants = _.isString(req.query.variants) ? _.without(req.query.variants.split(/[,]+/), '') : null; - const formats = _.isString(req.query.formats) ? _.without(req.query.formats.split(/[,]+/), '') : null; - - const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`; + const variants = _.isString(req.query.variants) ? _.without(req.query.variants.split(/[,]+/), "") : null; + const formats = _.isString(req.query.formats) ? _.without(req.query.formats.split(/[,]+/), "") : null; const fontFilePaths = await loadFontFilePaths(fontBundle, variantItems); const filteredFiles = _.filter(fontFilePaths, (file) => { - return (_.isNil(variants) || _.includes(variants, file.variant)) - && (_.isNil(formats) || _.includes(formats, file.format)); + return (_.isNil(variants) || _.includes(variants, file.variant)) && (_.isNil(formats) || _.includes(formats, file.format)); }); if (filteredFiles.length === 0) { - return res.status(404).send('Not found'); + return res.status(404).send("Not found"); } const archive = new JSZip(); _.each(filteredFiles, function (file) { - archive.file(path.basename(file.path), fs.createReadStream(file.path)) + archive.file(path.basename(file.path), fs.createReadStream(file.path)); }); - const zipFilename = fontBundle.font.id + "-" + fontBundle.font.version + "-" + fontBundle.storeID + '.zip'; + const zipFilename = `${fontBundle.font.id}-${fontBundle.font.version}-${fontBundle.subsets.join("_")}.zip` // Tell the browser that this is a zip file. res.writeHead(200, { - 'Content-Type': 'application/zip', - 'Content-disposition': 'attachment; filename=' + zipFilename + "Content-Type": "application/zip", + "Content-disposition": `attachment; filename=${zipFilename}`, }); const zipStream = archive.generateNodeStream({ streamFiles: true, - compression: 'DEFLATE' + compression: "DEFLATE", }); return stream.pipeline(zipStream, res, function (err) { @@ -171,7 +169,6 @@ export async function getApiFontsById(req: Request, res: Response { - - it('should respond with JSON array with all fonts', async () => { +describe("GET /api/fonts", () => { + afterEach(() => { + return reinitStore(); + }); - const res = await request(app) - .get('/api/fonts') - .timeout(10000) - .expect(200) - .expect('Content-Type', /json/); + it("should respond with JSON array with all fonts", async () => { + const res = await request(app).get("/api/fonts").timeout(10000).expect(200).expect("Content-Type", /json/); should(res.body).be.instanceof(Array); - }); - }); -describe('GET /api/fonts/:id', () => { - - it('should respond with font files for arvo', async function () { +describe("GET /api/fonts/:id", () => { + afterEach(() => { + return reinitStore(); + }); - const res = await request(app) - .get('/api/fonts/arvo') - .timeout(10000) - .expect(200) - .expect('Content-Type', /json/); + it("should respond with font files for arvo", async function () { + const res = await request(app).get("/api/fonts/arvo").timeout(10000).expect(200).expect("Content-Type", /json/); should(res.body).be.instanceof(Object); should(res.body).have.property("id", "arvo"); @@ -78,23 +73,24 @@ describe('GET /api/fonts/:id', () => { should(_.get(variant, "svg", {}).length).greaterThan(1); should(_.get(variant, "eot", {}).length).greaterThan(1); should(_.get(variant, "ttf", {}).length).greaterThan(1); - }) + }); } + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(0); }); - it('should respond with font files for istok-web multi charsets filtered', async () => { - + it("should respond with font files for istok-web multi charsets filtered", async () => { const res = await request(app) - .get('/api/fonts/istok-web?subsets=cyrillic,cyrillic-ext,latin') + .get("/api/fonts/istok-web?subsets=cyrillic,cyrillic-ext,latin") .timeout(10000) .expect(200) - .expect('Content-Type', /json/); + .expect("Content-Type", /json/); should(res.body).be.instanceof(Object); should(res.body).have.property("id", "istok-web"); should(res.body).have.property("family", "Istok Web"); - should(res.body).have.property("subsets", ['cyrillic', 'cyrillic-ext', 'latin', 'latin-ext']); + should(res.body).have.property("subsets", ["cyrillic", "cyrillic-ext", "latin", "latin-ext"]); should(res.body).have.property("category", "sans-serif"); should(res.body).have.property("version", "v20"); should(res.body).have.property("lastModified", "2022-09-22"); @@ -103,9 +99,9 @@ describe('GET /api/fonts/:id', () => { should(res.body).have.property("defVariant", "regular"); should(res.body).have.property("subsetMap", { cyrillic: true, - 'cyrillic-ext': true, + "cyrillic-ext": true, latin: true, - 'latin-ext': false + "latin-ext": false, }); should(res.body).have.property("storeID", "cyrillic_cyrillic-ext_latin"); @@ -145,251 +141,252 @@ describe('GET /api/fonts/:id', () => { should(_.get(variant, "svg", {}).length).greaterThan(1); should(_.get(variant, "eot", {}).length).greaterThan(1); should(_.get(variant, "ttf", {}).length).greaterThan(1); - }) + }); } + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(0); }); - it('should respond with 200 for known font istok-web empty subsets', async () => { - - const res = await request(app) - .get('/api/fonts/istok-web?subsets=') - .timeout(10000) - .expect(200) - .expect('Content-Type', /json/); + it("should respond with 200 for known font istok-web empty subsets", async () => { + const res = await request(app).get("/api/fonts/istok-web?subsets=").timeout(10000).expect(200).expect("Content-Type", /json/); should(res.body).be.instanceof(Object); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(0); }); - it('should respond with 404 for unknown font', async () => { - + it("should respond with 404 for unknown font", async () => { await request(app) - .get('/api/fonts/unknown-font') + .get("/api/fonts/unknown-font") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); + .expect("Content-Type", /text\/html/); + should(getStats().urlMap).eql(0); + should(getStats().fileMap).eql(0); }); - it('should respond with 404 for unknown font and subset', async () => { - + it("should respond with 404 for unknown font and subset", async () => { await request(app) - .get('/api/fonts/unknown-font?subsets=latin') + .get("/api/fonts/unknown-font?subsets=latin") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); + .expect("Content-Type", /text\/html/); + should(getStats().urlMap).eql(0); + should(getStats().fileMap).eql(0); }); - it('should respond with 404 for known font istok-web and unknown subset', async () => { - + it("should respond with 404 for known font istok-web and unknown subset", async () => { await request(app) - .get('/api/fonts/istok-web?subsets=unknownsubset') + .get("/api/fonts/istok-web?subsets=unknownsubset") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); - + .expect("Content-Type", /text\/html/); }); - }); -describe('GET /api/fonts/:id?download=zip', () => { - - it('should (concurrently) download istok-web', async function () { +describe("GET /api/fonts/:id?download=zip", () => { + afterEach(() => { + return reinitStore(); + }); + it("should (concurrently) download istok-web", async function () { this.timeout(10000); let triggered = 0; await Promise.all([ request(app) - .get('/api/fonts/istok-web?download=zip&subsets=latin&formats=woff,woff2') + .get("/api/fonts/istok-web?download=zip&subsets=latin&formats=woff,woff2") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip") + .expect("Content-Type", "application/zip") .then(() => { triggered += 1; }), request(app) - .get('/api/fonts/istok-web?download=zip&subsets=latin&formats=woff,woff2') + .get("/api/fonts/istok-web?download=zip&subsets=latin&formats=woff,woff2") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip") + .expect("Content-Type", "application/zip") .then(() => { triggered += 1; - }) + }), ]); should(triggered).eql(2); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should (concurrently) download istok-web (subsets and formats mix)', async function () { - + it("should (concurrently) download istok-web (subsets and formats mix)", async function () { this.timeout(10000); let triggered = 0; await Promise.all([ request(app) - .get('/api/fonts/istok-web?download=zip&subsets=cyrillic-ext,latin,latin-ext&formats=woff,woff2') + .get("/api/fonts/istok-web?download=zip&subsets=cyrillic-ext,latin,latin-ext&formats=woff,woff2") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip") + .expect("Content-Type", "application/zip") .then(() => { triggered += 1; }), request(app) - .get('/api/fonts/istok-web?download=zip&subsets=latin-ext,latin,cyrillic-ext&formats=woff,woff2,eot,ttf,svg') + .get("/api/fonts/istok-web?download=zip&subsets=latin-ext,latin,cyrillic-ext&formats=woff,woff2,eot,ttf,svg") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip") + .expect("Content-Type", "application/zip") .then(() => { triggered += 1; - }) + }), ]); should(triggered).eql(2); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); // "GET /api/fonts/playfair-display?subsets=devanagari,vietnamese,cyrillic-ext,latin,greek-ext,greek,cyrillic,latin-ext,hebrew,korean,oriya" // "GET /api/fonts/playfair-display?download=zip&subsets=cyrillic,latin,latin-ext,vietnamese" - it('should (concurrently) download playfair-display (different subsets)', async function () { - + it("should (concurrently) download playfair-display (different but unknown subsets resolve to the same key)", async function () { let triggered = 0; this.timeout(10000); await Promise.all([ request(app) - .get('/api/fonts/playfair-display?subsets=devanagari,vietnamese,cyrillic-ext,latin,greek-ext,greek,cyrillic,latin-ext,hebrew,korean,oriya') + .get( + "/api/fonts/playfair-display?subsets=devanagari,vietnamese,cyrillic-ext,latin,greek-ext,greek,cyrillic,latin-ext,hebrew,korean,oriya" + ) .timeout(10000) .expect(200) - .expect('Content-Type', /json/) + .expect("Content-Type", /json/) .then(() => { triggered += 1; }), request(app) - .get('/api/fonts/playfair-display?download=zip&subsets=cyrillic,latin,latin-ext,vietnamese') + .get("/api/fonts/playfair-display?download=zip&subsets=cyrillic,latin,latin-ext,vietnamese") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip") + .expect("Content-Type", "application/zip") .then(() => { triggered += 1; - }) + }), ]); should(triggered).eql(2); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 200 for download attempt of known font istok-web with unspecified subset', async () => { - + it("should respond with 200 for download attempt of known font istok-web with unspecified subset", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=woff,woff2') + .get("/api/fonts/istok-web?download=zip&formats=woff,woff2") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip"); + .expect("Content-Type", "application/zip"); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 200 for download attempt of known font istok-web with unspecified formats', async () => { - + it("should respond with 200 for download attempt of known font istok-web with unspecified formats", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&subsets=latin') + .get("/api/fonts/istok-web?download=zip&subsets=latin") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip"); + .expect("Content-Type", "application/zip"); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 200 for download attempt of known font istok-web and empty subsets', async () => { - + it("should respond with 200 for download attempt of known font istok-web and empty subsets", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&subsets=') + .get("/api/fonts/istok-web?download=zip&subsets=") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip"); + .expect("Content-Type", "application/zip"); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 200 for download attempt of known font istok-web and a single unknown format sneaked in', async () => { - + it("should respond with 200 for download attempt of known font istok-web and a single unknown format sneaked in", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=woff,woff2,rolf') + .get("/api/fonts/istok-web?download=zip&formats=woff,woff2,rolf") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip"); + .expect("Content-Type", "application/zip"); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 200 for download attempt of known font istok-web with variants', async () => { - + it("should respond with 200 for download attempt of known font istok-web with variants", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=woff,woff2&variants=regular') + .get("/api/fonts/istok-web?download=zip&formats=woff,woff2&variants=regular") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip"); + .expect("Content-Type", "application/zip"); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 200 for download attempt of known font istok-web with one known, one unknown variant', async () => { - + it("should respond with 200 for download attempt of known font istok-web with one known, one unknown variant", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=woff,woff2&variants=regular,unknownvar') + .get("/api/fonts/istok-web?download=zip&formats=woff,woff2&variants=regular,unknownvar") .timeout(10000) .expect(200) - .expect('Content-Type', "application/zip"); + .expect("Content-Type", "application/zip"); + should(getStats().urlMap).eql(1); + should(getStats().fileMap).eql(1); }); - it('should respond with 404 for download attempt of known font istok-web with empty variants', async () => { - + it("should respond with 404 for download attempt of known font istok-web with empty variants", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=woff,woff2&variants=') + .get("/api/fonts/istok-web?download=zip&formats=woff,woff2&variants=") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); - + .expect("Content-Type", /text\/html/); }); // https://gwfh.mranftl.com/api/fonts/siemreap?download=zip&subsets=latin,latin-ext&formats=eot,woff,woff2,svg,ttf - it('should respond with 404 for download attempt of unknown font and unknown subset', async () => { - + it("should respond with 404 for download attempt of unknown font and unknown subset", async () => { await request(app) - .get('/api/fonts/unknown-font?download=zip&subsets=latin&formats=woff,woff2') + .get("/api/fonts/unknown-font?download=zip&subsets=latin&formats=woff,woff2") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); - + .expect("Content-Type", /text\/html/); }); - it('should respond with 404 for download attempt of known font istok-web and unknown subset', async () => { - + it("should respond with 404 for download attempt of known font istok-web and unknown subset", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&subsets=unknown&formats=woff,woff2') + .get("/api/fonts/istok-web?download=zip&subsets=unknown&formats=woff,woff2") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); - + .expect("Content-Type", /text\/html/); }); - it('should respond with 404 for download attempt of known font istok-web and unknown format', async () => { - + it("should respond with 404 for download attempt of known font istok-web and unknown format", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=rolf') + .get("/api/fonts/istok-web?download=zip&formats=rolf") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); - + .expect("Content-Type", /text\/html/); }); - it('should respond with 404 for download attempt of known font istok-web and empty formats', async () => { - + it("should respond with 404 for download attempt of known font istok-web and empty formats", async () => { await request(app) - .get('/api/fonts/istok-web?download=zip&formats=') + .get("/api/fonts/istok-web?download=zip&formats=") .timeout(10000) .expect(404) - .expect('Content-Type', /text\/html/); - + .expect("Content-Type", /text\/html/); }); - }); diff --git a/server/api/healthy.controller.ts b/server/api/healthy.controller.ts index eef8c75..2084741 100644 --- a/server/api/healthy.controller.ts +++ b/server/api/healthy.controller.ts @@ -1,14 +1,16 @@ -import * as _ from "lodash"; -import { Request, Response, NextFunction } from "express"; -import { getStoredFilePathsLength, getStoredFilePathsFilesLength, getStoredFontItems } from "../logic/store"; +import { NextFunction, Request, Response } from "express"; +import { getStats } from "../logic/store"; // /-/healthy export async function getHealthy(req: Request, res: Response, next: NextFunction) { try { - res.type('text/plain'); - return res.send(`${getStoredFontItems().length} fonts. -Cached ${getStoredFilePathsLength()} variants, ${getStoredFilePathsFilesLength()} files.`); + const { fontMap, urlMap, fileMap, files, urls } = getStats(); + + res.type("text/plain"); + + return res.send(`${fontMap} fonts available. +${urlMap} unique subsets loaded (${urls} URLs), ${fileMap} subsets fetched (${files} files).`); } catch (e) { next(e); } -} \ No newline at end of file +} diff --git a/server/api/healthy.spec.ts b/server/api/healthy.spec.ts index 3017e0f..adb45e8 100644 --- a/server/api/healthy.spec.ts +++ b/server/api/healthy.spec.ts @@ -1,13 +1,12 @@ import * as request from "supertest"; import { app } from "../app"; -describe('GET /-/healthy', () => { - - it('should respond with 200', async () => { +describe("GET /-/healthy", () => { + it("should respond with 200", async () => { await request(app) - .get('/-/healthy') + .get("/-/healthy") .timeout(2000) .expect(200) - .expect('Content-Type', /text\/plain/); + .expect("Content-Type", /text\/plain/); }); }); diff --git a/server/app.spec.ts b/server/app.spec.ts index 7d4056a..44efdc7 100644 --- a/server/app.spec.ts +++ b/server/app.spec.ts @@ -1,26 +1,22 @@ import * as request from "supertest"; import { app } from "./app"; -describe('GET /api/not_defined', () => { - - it('should respond with 404', async () => { +describe("GET /api/not_defined", () => { + it("should respond with 404", async () => { await request(app) - .get('/api/not_defined') + .get("/api/not_defined") .timeout(2000) .expect(404) - .expect('Content-Type', /text\/html/); + .expect("Content-Type", /text\/html/); }); - }); -describe('GET /', () => { - - it('should respond with 200', async () => { +describe("GET /", () => { + it("should respond with 200", async () => { await request(app) - .get('/') + .get("/") .timeout(2000) .expect(200) - .expect('Content-Type', /text\/html/); + .expect("Content-Type", /text\/html/); }); - -}); \ No newline at end of file +}); diff --git a/server/app.ts b/server/app.ts index 18cf0b1..ffb5d41 100644 --- a/server/app.ts +++ b/server/app.ts @@ -1,12 +1,12 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ require("source-map-support").install(); import * as express from "express"; -import * as http from "http" +import * as http from "http"; import * as path from "path"; -import * as _ from "lodash"; -import { setupRoutes } from "./routes"; import { config } from "./config"; import { initStore } from "./logic/store"; +import { setupRoutes } from "./routes"; export const app = express(); @@ -14,28 +14,28 @@ export const app = express(); const server = http.createServer(app); server.timeout = config.TIMEOUT_MS; - const env = app.get('env'); + const env = app.get("env"); // http://expressjs.com/en/api.html app.set("x-powered-by", false); if (config.ENABLE_MIDDLEWARE_COMPRESSION) { - app.use(require('compression')()); + app.use(require("compression")()); } - if (env === 'production') { - app.use(express.static(path.join(config.ROOT, 'public'))); - app.set('appPath', config.ROOT + '/public'); + if (env === "production") { + app.use(express.static(path.join(config.ROOT, "public"))); + app.set("appPath", config.ROOT + "/public"); if (config.ENABLE_MIDDLEWARE_ACCESS_LOG) { - app.use(require('morgan')(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]')); + app.use(require("morgan")(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]')); } } else { - app.use(require('connect-livereload')()); - app.use(express.static(path.join(config.ROOT, '.tmp'))); - app.use(express.static(path.join(config.ROOT, 'client'))); - app.set('appPath', config.ROOT + '/client'); - app.use(require('morgan')('dev')); - app.use(require('errorhandler')()); // Error handler - has to be last + app.use(require("connect-livereload")()); + app.use(express.static(path.join(config.ROOT, ".tmp"))); + app.use(express.static(path.join(config.ROOT, "client"))); + app.set("appPath", config.ROOT + "/client"); + app.use(require("morgan")("dev")); + app.use(require("errorhandler")()); // Error handler - has to be last } setupRoutes(app); @@ -44,18 +44,23 @@ export const app = express(); // Start server server.listen(config.PORT, config.IP, function () { - console.log('Express server listening on %d, in %s mode (timeout=%dms, compress=%s, accesslog=%s)', - config.PORT, app.get('env'), server.timeout, config.ENABLE_MIDDLEWARE_COMPRESSION, config.ENABLE_MIDDLEWARE_ACCESS_LOG); + console.log( + "Express server listening on %d, in %s mode (timeout=%dms, compress=%s, accesslog=%s)", + config.PORT, + app.get("env"), + server.timeout, + config.ENABLE_MIDDLEWARE_COMPRESSION, + config.ENABLE_MIDDLEWARE_ACCESS_LOG + ); }); - process.once('SIGINT', function () { - console.log('SIGINT received, closing server...'); + process.once("SIGINT", function () { + console.log("SIGINT received, closing server..."); server.close(); }); - process.once('SIGTERM', function () { - console.log('SIGTERM received, closing server...'); + process.once("SIGTERM", function () { + console.log("SIGTERM received, closing server..."); server.close(); }); - })(); diff --git a/server/config.ts b/server/config.ts index 7d1709e..f2d86b2 100644 --- a/server/config.ts +++ b/server/config.ts @@ -1,13 +1,13 @@ -import * as path from "path" import * as _ from "lodash"; +import * as path from "path"; -const env = process.env.NODE_ENV || 'development'; +const env = process.env.NODE_ENV || "development"; const GOOGLE_FONTS_API_KEY = process.env.GOOGLE_FONTS_API_KEY; if (!_.isString(GOOGLE_FONTS_API_KEY) || _.isEmpty(GOOGLE_FONTS_API_KEY)) { console.error('Error: ENV var "GOOGLE_FONTS_API_KEY" must be set!'); - console.error('See https://developers.google.com/fonts/docs/developer_api') + console.error("See https://developers.google.com/fonts/docs/developer_api"); process.exit(1); } @@ -23,60 +23,41 @@ export const config = { ENV: env, // Root path of server - ROOT: path.normalize(__dirname + '/..'), + ROOT: path.normalize(__dirname + "/.."), // Server port - PORT: process.env.PORT - ? _.parseInt(process.env.PORT) - : (env === "production" - ? 8080 - : 9000), + PORT: process.env.PORT ? _.parseInt(process.env.PORT) : env === "production" ? 8080 : 9000, - IP: process.env.IP - || undefined, + IP: process.env.IP || undefined, // Server port - TIMEOUT_MS: process.env.TIMEOUT_MS - ? _.parseInt(process.env.TIMEOUT_MS) - : 60 * 1000, // 60 seconds + TIMEOUT_MS: process.env.TIMEOUT_MS ? _.parseInt(process.env.TIMEOUT_MS) : 60 * 1000, // 60 seconds // Middlewares - ENABLE_MIDDLEWARE_ACCESS_LOG: process.env.ENABLE_MIDDLEWARE_ACCESS_LOG === 'true' - ? true - : false, // default false + ENABLE_MIDDLEWARE_ACCESS_LOG: process.env.ENABLE_MIDDLEWARE_ACCESS_LOG === "true" ? true : false, // default false - ENABLE_MIDDLEWARE_COMPRESSION: process.env.ENABLE_MIDDLEWARE_COMPRESSION === 'false' - ? false - : true, // default true + ENABLE_MIDDLEWARE_COMPRESSION: process.env.ENABLE_MIDDLEWARE_COMPRESSION === "false" ? false : true, // default true GOOGLE_FONTS_API_KEY, - GOOGLE_FONTS_USE_TEST_JSON: process.env.GOOGLE_FONTS_USE_TEST_JSON === 'true' - ? true - : (env === "test" - ? true - : false), // enabled in test, else default false + GOOGLE_FONTS_USE_TEST_JSON: process.env.GOOGLE_FONTS_USE_TEST_JSON === "true" ? true : env === "test" ? true : false, // enabled in test, else default false - CACHE_DIR: process.env.CACHE_DIR - || `${path.normalize(__dirname + '/logic')}/cachedFonts/`, + CACHE_DIR: process.env.CACHE_DIR || `${path.normalize(__dirname + "/logic")}/cachedFonts`, USER_AGENTS: { // see http://www.dvdprojekt.de/category.php?name=Safari for a list of sample user handlers // test generation through running grunt mochaTest:src - eot: process.env.USER_AGENT_EOT - || 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)', - woff: process.env.USER_AGENT_WOFF - || 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0', + eot: process.env.USER_AGENT_EOT || "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)", + woff: process.env.USER_AGENT_WOFF || "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0", // must serve complete woff2 file for one variant (no unicode range support yet!) // see http://www.useragentstring.com/pages/Firefox/ // see http://caniuse.com/#search=woff2 // see http://caniuse.com/#feat=font-unicode-range // see https://developers.googleblog.com/2015/02/smaller-fonts-with-woff-20-and-unicode.html - woff2: process.env.USER_AGENT_WOFF2 - || 'Mozilla/5.0 (Windows NT 6.3; rv:39.0) Gecko/20100101 Firefox/39.0', - svg: process.env.USER_AGENT_SVG - || 'Mozilla/4.0 (iPad; CPU OS 4_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/4.1 Mobile/9A405 Safari/7534.48.3', - ttf: process.env.USER_AGENT_TTF - || 'Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) Safari/538.1 Daum/4.1' + woff2: process.env.USER_AGENT_WOFF2 || "Mozilla/5.0 (Windows NT 6.3; rv:39.0) Gecko/20100101 Firefox/39.0", + svg: + process.env.USER_AGENT_SVG || + "Mozilla/4.0 (iPad; CPU OS 4_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/4.1 Mobile/9A405 Safari/7534.48.3", + ttf: process.env.USER_AGENT_TTF || "Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) Safari/538.1 Daum/4.1", }, -}; \ No newline at end of file +}; diff --git a/server/logic/core.ts b/server/logic/core.ts index a9eae84..a496edd 100644 --- a/server/logic/core.ts +++ b/server/logic/core.ts @@ -1,9 +1,17 @@ import * as _ from "lodash"; +import { synchronizedBy } from "../utils/synchronized"; import { fetchFontFiles, IFontFilePath } from "./fetchFontFiles"; import { fetchFontURLs, IVariantItem } from "./fetchFontURLs"; -import { synchronizedBy } from "../utils/synchronized"; import { IFontItem } from "./fetchGoogleFonts"; -import { getFontBundle, getStoredFontFilePaths, getStoredFontItems, getStoredVariantItems, IFontBundle, storeFontFilePaths, storeVariantItems } from "./store"; +import { + getFontBundle, + getStoredFontFilePaths, + getStoredFontItems, + getStoredVariantItems, + IFontBundle, + storeFontFilePaths, + storeVariantItems, +} from "./store"; export function loadFontItems(): IFontItem[] { return getStoredFontItems(); @@ -17,7 +25,6 @@ export async function loadVariantItems(fontBundle: IFontBundle): Promise { - const storedVariantItems = getStoredVariantItems(fontBundle); if (!_.isNil(storedVariantItems)) { @@ -28,7 +35,7 @@ const _loadVariantItems = synchronizedBy(async function (fontBundle: IFontBundle const variantItems = await fetchFontURLs(font.family, font.variants, subsets); if (variantItems === null) { - console.error('urlStoreObject resolved null for ' + storeID); + console.error(`loadVariantItems resolved null for storeID=${storeID}`); return null; } @@ -51,7 +58,7 @@ const _loadFontFilePaths = synchronizedBy(async function (fontBundle: IFontBundl const fontFilePaths = await fetchFontFiles(fontBundle.font.id, fontBundle.font.version, variants); if (fontFilePaths.length === 0) { - throw new Error(`No local paths received for ${fontBundle.font.id}, ${fontBundle.storeID}`); + throw new Error(`No local paths received for ${fontBundle.storeID}`); } // SIDE-EFFECT! @@ -64,9 +71,12 @@ export interface ISubsetMap { } export function loadSubsetMap(fontBundle: IFontBundle): ISubsetMap { - return _.reduce(fontBundle.font.subsets, (sum, subset) => { - sum[subset] = _.includes(fontBundle.subsets, subset); - return sum; - }, {} as ISubsetMap); + return _.reduce( + fontBundle.font.subsets, + (sum, subset) => { + sum[subset] = _.includes(fontBundle.subsets, subset); + return sum; + }, + {} as ISubsetMap + ); } - diff --git a/server/logic/fetchCSS.ts b/server/logic/fetchCSS.ts index 986391b..4023882 100644 --- a/server/logic/fetchCSS.ts +++ b/server/logic/fetchCSS.ts @@ -13,35 +13,34 @@ interface IResource { url: string; } -export async function fetchCSS(family: string, cssSubsetString: string, type: keyof IUserAgents, userAgent: string, retry = 0): Promise { - - const reqPath = '/css?family=' + encodeURIComponent(family) + '&subset=' + cssSubsetString; +export async function fetchCSS(family: string, cssSubsetString: string, type: keyof IUserAgents, userAgent: string): Promise { + const reqPath = `/css?family=${encodeURIComponent(family)}&subset=${cssSubsetString}`; const hostname = "fonts.googleapis.com"; const url = `http://${hostname}${reqPath}`; - const txt = await asyncRetry(async () => { - - const res = await fetch(url, { - headers: { - 'accept': 'text/css,*/*;q=0.1', - 'User-Agent': userAgent + const txt = await asyncRetry( + async () => { + const res = await fetch(url, { + headers: { + accept: "text/css,*/*;q=0.1", + "User-Agent": userAgent, + }, + }); + + if (res.status !== 200) { + throw new Error(`${url} fetchCSS request failed. status code: ${res.status} ${res.statusText}`); } - }); - - if (res.status !== 200) { - throw new Error(`${url} fetchCSS request failed. status code: ${res.status} ${res.statusText}`); - } - const contentType = res.headers.get('content-type'); + const contentType = res.headers.get("content-type"); - if (_.isNil(contentType) - || _.isEmpty(contentType) - || contentType.indexOf("css") === -1) { - throw new Error(`${url} fetchCSS request failed. expected "css" to be in content-type header: ${contentType}`); - } + if (_.isNil(contentType) || _.isEmpty(contentType) || contentType.indexOf("css") === -1) { + throw new Error(`${url} fetchCSS request failed. expected "css" to be in content-type header: ${contentType}`); + } - return res.text(); - }, { retries: RETRIES }); + return res.text(); + }, + { retries: RETRIES } + ); return parseRemoteCSS(txt, type); } @@ -55,14 +54,12 @@ function parseRemoteCSS(remoteCSS: string, type: string): IResource[] { const resources: IResource[] = []; _.each(parsedCSS.stylesheet.rules, (rule) => { - // only font-face rules are relevant... if (rule.type !== "font-face") { return; } try { - const src = getCSSRuleDeclarationPropertyValue(rule, "src"); if (_.isNil(src)) { @@ -70,9 +67,7 @@ function parseRemoteCSS(remoteCSS: string, type: string): IResource[] { return; } - const matched = type === "svg" - ? src.match("http:\\/\\/[^\\)]+") - : src.match("http:\\/\\/[^\\)]+\\." + type); + const matched = type === "svg" ? src.match("http:\\/\\/[^\\)]+") : src.match("http:\\/\\/[^\\)]+\\." + type); if (_.isNil(matched) || matched.length === 0) { console.warn(`parseRemoteCSS: no matched url in parsed css for ${type}: ${remoteCSS}`); @@ -85,25 +80,25 @@ function parseRemoteCSS(remoteCSS: string, type: string): IResource[] { fontStyle: getCSSRuleDeclarationPropertyValue(rule, "font-style"), fontWeight: getCSSRuleDeclarationPropertyValue(rule, "font-weight"), // extract the url - url: matched[0] + url: matched[0], }; // push the current rule (= resource) to the resources array resources.push(resource); - } catch (e) { console.error("cannot load resource of type", type, remoteCSS, e); } - }); return resources; } function getCSSRuleDeclarationPropertyValue(rule: css.Rule, property: string): string | null { - return _.get(_.find((rule).declarations, (declaration) => { - return _.has(declaration, "property") - && (declaration).property === property; - }), "value", null); + return _.get( + _.find(rule.declarations, (declaration) => { + return _.has(declaration, "property") && (declaration).property === property; + }), + "value", + null + ); } - diff --git a/server/logic/fetchFontFiles.ts b/server/logic/fetchFontFiles.ts index 4ad3217..e371124 100644 --- a/server/logic/fetchFontFiles.ts +++ b/server/logic/fetchFontFiles.ts @@ -1,9 +1,10 @@ +import * as Bluebird from "bluebird"; +import * as fs from "fs"; import * as _ from "lodash"; +import * as path from "path"; import { Readable } from "stream"; import { finished } from "stream/promises"; -import * as fs from "fs"; import { config } from "../config"; -import * as Bluebird from "bluebird"; import { asyncRetry } from "../utils/asyncRetry"; import { IVariantItem } from "./fetchFontURLs"; @@ -16,19 +17,20 @@ export interface IFontFilePath { } export async function fetchFontFiles(fontID: string, fontVersion: string, variants: IVariantItem[]): Promise { - const filePaths: IFontFilePath[] = []; await Bluebird.map(variants, async (variant) => { await Bluebird.map(variant.urls, async (variantUrl) => { - const filename = config.CACHE_DIR + fontID + "-" + fontVersion + "-" + variant.subsets.join("_") + "-" + variant.id + "." + variantUrl.format; + const filename = path.join( + config.CACHE_DIR, + `/${fontID}-${fontVersion}-${variant.subsets.join("_")}-${variant.id}.${variantUrl.format}` + ); // download the file for type (filename now known) try { await downloadFile(variantUrl.url, filename, variantUrl.format); } catch (e) { // if a specific format does not work, silently discard it. - console.error("fetchFontFiles discarding", fontID, variant.subsets.join("_"), variantUrl.url, variantUrl.format, filename, e); return; } @@ -36,36 +38,33 @@ export async function fetchFontFiles(fontID: string, fontVersion: string, varian filePaths.push({ variant: variant.id, // variants and format are used to filter them out later! format: variantUrl.format, - path: filename + path: filename, }); - }); }); return filePaths; - } async function downloadFile(url: string, dest: string, format: string) { - await asyncRetry(async () => { - - const response = await fetch(url); - const contentType = response.headers.get('content-type'); - - if (response.status !== 200) { - throw new Error(`${url} downloadFile request failed. status code: ${response.status} ${response.statusText}`); - } + await asyncRetry( + async () => { + const response = await fetch(url); + const contentType = response.headers.get("content-type"); - if (_.isNil(contentType) - || _.isEmpty(contentType) - || contentType.indexOf(format) === -1) { - throw new Error(`${url} downloadFile request failed. expected ${format} to be in content-type header: ${contentType}`); - } - - const stream = fs.createWriteStream(dest); - // TODO typing mismatch ReadableStream vs ReadableStream - await finished(Readable.fromWeb((response.body)).pipe(stream)); + if (response.status !== 200) { + throw new Error(`${url} downloadFile request failed. status code: ${response.status} ${response.statusText}`); + } - }, { retries: RETRIES }); + if (_.isNil(contentType) || _.isEmpty(contentType) || contentType.indexOf(format) === -1) { + throw new Error(`${url} downloadFile request failed. expected ${format} to be in content-type header: ${contentType}`); + } + const stream = fs.createWriteStream(dest); + // TODO typing mismatch ReadableStream vs ReadableStream + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await finished(Readable.fromWeb(response.body).pipe(stream)); + }, + { retries: RETRIES } + ); } diff --git a/server/logic/fetchFontURLs.ts b/server/logic/fetchFontURLs.ts index d16b84e..86e626e 100644 --- a/server/logic/fetchFontURLs.ts +++ b/server/logic/fetchFontURLs.ts @@ -1,7 +1,7 @@ +import * as Bluebird from "bluebird"; import * as _ from "lodash"; import { config, IUserAgents } from "../config"; import { fetchCSS } from "./fetchCSS"; -import * as Bluebird from "bluebird"; export interface IVariantURL { format: keyof IUserAgents; @@ -14,24 +14,22 @@ export interface IVariantItem { fontFamily: null | string; fontStyle: null | string; fontWeight: null | string; - urls: IVariantURL[] + urls: IVariantURL[]; } const TARGETS = _.map(_.keys(config.USER_AGENTS), (key) => { return { format: key, - userAgent: config.USER_AGENTS[key] + userAgent: config.USER_AGENTS[key], }; }); export async function fetchFontURLs(fontFamily: string, fontVariants: string[], fontSubsets: string[]): Promise { - let variants: IVariantItem[] = []; const cssSubsetString = fontSubsets.join(","); // make the variant string google API compatible... await Bluebird.map(fontVariants, async (variant) => { - - const cssFontFamily = fontFamily + ":" + variant; + const cssFontFamily = `${fontFamily}:${variant}`; const variantItem: IVariantItem = { id: variant, @@ -39,19 +37,25 @@ export async function fetchFontURLs(fontFamily: string, fontVariants: string[], fontFamily: null, fontStyle: null, fontWeight: null, - urls: [] + urls: [], }; await Bluebird.map(TARGETS, async (target) => { const resources = await fetchCSS(cssFontFamily, cssSubsetString, target.format, target.userAgent); if (resources.length === 0) { - console.warn(`fetchFontURLs: no css ressources encountered for fontFamily='${cssFontFamily}' subset='${cssSubsetString}' format=${target.format}`, resources); + console.warn( + `fetchFontURLs: no css ressources encountered for fontFamily='${cssFontFamily}' subset='${cssSubsetString}' format=${target.format}`, + resources + ); return; } if (resources.length > 1) { - console.warn(`fetchFontURLs: multiple css ressources encountered for fontFamily='${cssFontFamily}' subset='${cssSubsetString}' format=${target.format}`, resources); + console.warn( + `fetchFontURLs: multiple css ressources encountered for fontFamily='${cssFontFamily}' subset='${cssSubsetString}' format=${target.format}`, + resources + ); } _.each(resources, (resource) => { @@ -59,7 +63,7 @@ export async function fetchFontURLs(fontFamily: string, fontVariants: string[], variantItem.urls.push({ format: target.format, // rewrite url to use https instead on http! - url: resource.url.split("http://").join("https://") // resource.url.replace(/^http:\/\//i, 'https://'); + url: resource.url.split("http://").join("https://"), // resource.url.replace(/^http:\/\//i, 'https://'); }); // if not defined, also save procedded font-family, fontstyle, font-weight, unicode-range @@ -75,16 +79,14 @@ export async function fetchFontURLs(fontFamily: string, fontVariants: string[], variantItem.fontWeight = resource.fontWeight; } }); - }); variants.push(variantItem); - }); variants = _.sortBy(variants, function ({ fontWeight, fontStyle }) { const styleOrder = fontStyle === "normal" ? 0 : 1; - return `${fontWeight}-${styleOrder}` + return `${fontWeight}-${styleOrder}`; }); return variants; diff --git a/server/logic/fetchGoogleFonts.ts b/server/logic/fetchGoogleFonts.ts index 8bddc16..8c833c0 100644 --- a/server/logic/fetchGoogleFonts.ts +++ b/server/logic/fetchGoogleFonts.ts @@ -1,8 +1,8 @@ +import * as fs from "fs/promises"; import * as _ from "lodash"; +import * as path from "path"; import * as speakingurl from "speakingurl"; import { config } from "../config"; -import * as fs from "fs/promises"; -import * as path from "path"; import { asyncRetry } from "../utils/asyncRetry"; const RETRIES = 5; @@ -40,32 +40,37 @@ interface IGoogleFontsResItem { // build up fonts cache via google API... export async function fetchGoogleFonts(): Promise { - if (config.GOOGLE_FONTS_USE_TEST_JSON) { const localPath = path.join(config.ROOT, "test/googlefonts.json"); - console.warn(`fetchGoogleFonts is using local "${localPath}"`) + + if (config.ENV !== "test") { + console.warn(`fetchGoogleFonts is using local "${localPath}"`); + } + const testJson = await fs.readFile(localPath); return transform(JSON.parse(testJson.toString())); } - return asyncRetry(async () => { - const res = await fetch(`https://www.googleapis.com/webfonts/v1/webfonts?sort=popularity&key=${config.GOOGLE_FONTS_API_KEY}`, { - headers: { - 'accept': 'application/json', - } - }); - - if (res.status !== 200) { - throw new Error(`fetchGoogleFonts request failed. status code: ${res.status} ${res.statusText}`); - } + return asyncRetry( + async () => { + const res = await fetch(`https://www.googleapis.com/webfonts/v1/webfonts?sort=popularity&key=${config.GOOGLE_FONTS_API_KEY}`, { + headers: { + accept: "application/json", + }, + }); - const resData: IGoogleFontsRes = await res.json(); + if (res.status !== 200) { + throw new Error(`fetchGoogleFonts request failed. status code: ${res.status} ${res.statusText}`); + } - // console.log(JSON.stringify(resData)); + const resData: IGoogleFontsRes = await res.json(); - return transform(resData); - }, { retries: RETRIES }); + // console.log(JSON.stringify(resData)); + return transform(resData); + }, + { retries: RETRIES } + ); } function transform(resData: IGoogleFontsRes): IFontItem[] { @@ -80,8 +85,8 @@ function transform(resData: IGoogleFontsRes): IFontItem[] { lastModified: item.lastModified, popularity: index + 1, // property order by popularity -> index // use latin per default, else first found font - defSubset: _.includes(item.subsets, 'latin') ? 'latin' : item.subsets[0], - defVariant: _.includes(item.variants, 'regular') ? 'regular' : item.variants[0] + defSubset: _.includes(item.subsets, "latin") ? "latin" : item.subsets[0], + defVariant: _.includes(item.variants, "regular") ? "regular" : item.variants[0], }; }); } diff --git a/server/logic/store.ts b/server/logic/store.ts index ebd87eb..c6d3f82 100644 --- a/server/logic/store.ts +++ b/server/logic/store.ts @@ -1,9 +1,9 @@ import * as _ from "lodash"; import * as mkdirp from "mkdirp"; -import { fetchGoogleFonts, IFontItem } from "./fetchGoogleFonts"; import { config } from "../config"; -import { IVariantItem } from "./fetchFontURLs"; import { IFontFilePath } from "./fetchFontFiles"; +import { IVariantItem } from "./fetchFontURLs"; +import { fetchGoogleFonts, IFontItem } from "./fetchGoogleFonts"; // FontBundle holds: // * the found stored font from google, @@ -14,11 +14,11 @@ export interface IFontBundle { storeID: string; subsets: string[]; font: IFontItem; -}; +} -const fontMap = new Map; -const urlMap = new Map; -const fileMap = new Map; +const fontMap = new Map(); +const urlMap = new Map(); +const fileMap = new Map(); export async function initStore() { await mkdirp(config.CACHE_DIR); @@ -26,7 +26,19 @@ export async function initStore() { _.each(await fetchGoogleFonts(), (font: IFontItem) => { fontMap.set(font.id, font); }); -}; +} + +export async function reinitStore() { + if (config.ENV !== "test") { + console.warn("reinitStore was called, building fresh stores..."); + } + + fontMap.clear(); + urlMap.clear(); + fileMap.clear(); + + return initStore(); +} export function getStoredFontItems(): IFontItem[] { return Array.from(fontMap.values()); @@ -39,9 +51,10 @@ export function getFontBundle(fontID: string, wantedSubsets: string[] | null): I return null; } - const match = (!_.isArray(wantedSubsets) || wantedSubsets.length === 0) - ? [font.defSubset] // supply filter with the default subset as defined in googleFontsAPI fetcher (latin or if no found other) - : _.intersection(font.subsets, wantedSubsets); + const match = + !_.isArray(wantedSubsets) || wantedSubsets.length === 0 + ? [font.defSubset] // supply filter with the default subset as defined in googleFontsAPI fetcher (latin or if no found other) + : _.intersection(font.subsets, wantedSubsets); const subsets = _.sortBy(_.uniq(match)); @@ -53,14 +66,14 @@ export function getFontBundle(fontID: string, wantedSubsets: string[] | null): I // not this must be a stable key fully identifying the font, its version and wantedSubsets storeID: `${font.id}@${font.version}__${subsets.join("_")}`, subsets, - font + font, }; } export function getStoredVariantItems({ storeID }: IFontBundle): IVariantItem[] | null { const variants = urlMap.get(storeID); if (_.isNil(variants)) { - return null + return null; } return variants; } @@ -91,7 +104,7 @@ export function storeFontFilePaths({ storeID }: IFontBundle, fontFilePaths: IFon const existings = fileMap.get(storeID); if (!_.isNil(existings)) { - console.warn("storeFontFilePaths: duplicate save of storeID: ", storeID, "existings:", existings, "discarded:", fontFilePaths); + console.warn("storeFontFilePaths: duplicate save of storeID: ", storeID); if (config.ENV === "test") { throw new Error("storeFontFilePaths duplicate write"); } @@ -101,10 +114,16 @@ export function storeFontFilePaths({ storeID }: IFontBundle, fontFilePaths: IFon fileMap.set(storeID, fontFilePaths); } -export function getStoredFilePathsLength() { - return fileMap.size; -} - -export function getStoredFilePathsFilesLength() { - return _.sumBy(Array.from(fileMap.values()), function (f) { return (f) ? f.length : 0; }); +export function getStats() { + return { + fontMap: fontMap.size, + urlMap: urlMap.size, + fileMap: fileMap.size, + urls: _.sumBy(Array.from(urlMap.values()), function (f) { + return f ? f.length : 0; + }), + files: _.sumBy(Array.from(fileMap.values()), function (f) { + return f ? f.length : 0; + }), + }; } diff --git a/server/routes.ts b/server/routes.ts index 7b99fa3..b169da2 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -3,26 +3,19 @@ import { getApiFonts, getApiFontsById } from "./api/fonts.controller"; import { getHealthy } from "./api/healthy.controller"; export function setupRoutes(app: express.Express) { + app.route("/api/fonts").get(getApiFonts); - app.route('/api/fonts') - .get(getApiFonts); + app.route("/api/fonts/:id").get(getApiFontsById); - app.route('/api/fonts/:id') - .get(getApiFontsById); - - app.route('/-/healthy') - .get(getHealthy); + app.route("/-/healthy").get(getHealthy); // All undefined asset or api routes should return a 404 - app.route('/:url(-|api|auth|components|app|bower_components|assets)/*') - .get(function (req, res) { - res.status(404) - .send('Not found'); - }); + app.route("/:url(-|api|auth|components|app|bower_components|assets)/*").get(function (req, res) { + res.status(404).send("Not found"); + }); // All other routes should redirect to the index.html - app.route('/*') - .get(function (req, res) { - res.sendFile(app.get('appPath') + '/index.html'); - }); -}; + app.route("/*").get(function (req, res) { + res.sendFile(app.get("appPath") + "/index.html"); + }); +} diff --git a/server/utils/asyncRetry.spec.ts b/server/utils/asyncRetry.spec.ts index 96cd0f4..a9aec04 100644 --- a/server/utils/asyncRetry.spec.ts +++ b/server/utils/asyncRetry.spec.ts @@ -1,41 +1,43 @@ -import * as should from 'should'; -import * as _ from "lodash"; -import { asyncRetry } from './asyncRetry'; import * as Bluebird from "bluebird"; +import * as should from "should"; +import { asyncRetry } from "./asyncRetry"; -describe('utils/asyncRetry', function () { - - it('retry works as expected when last succeeds', async () => { +describe("utils/asyncRetry", function () { + it("retry works as expected when last succeeds", async () => { const RETRIES = 2; let cnt = 0; - await asyncRetry(async () => { - await Bluebird.delay(1); - - cnt += 1; - if (cnt <= RETRIES) { - throw new Error("not yet") - } + await asyncRetry( + async () => { + await Bluebird.delay(1); - }, { retries: RETRIES }); + cnt += 1; + if (cnt <= RETRIES) { + throw new Error("not yet"); + } + }, + { retries: RETRIES } + ); should(cnt).eql(RETRIES + 1); - }); - it('retry works as expected when all fail with same error', async () => { + it("retry works as expected when all fail with same error", async () => { const RETRIES = 2; let cnt = 0; let err: AggregateError | null = null; try { - await asyncRetry(async () => { - await Bluebird.delay(1); - - cnt += 1; - throw new Error("step err"); - - }, { retries: RETRIES }); + await asyncRetry( + async () => { + await Bluebird.delay(1); + + cnt += 1; + throw new Error("step err"); + }, + { retries: RETRIES } + ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e: any) { err = e; } @@ -44,22 +46,24 @@ describe('utils/asyncRetry', function () { should(cnt).eql(RETRIES + 1); should(err).instanceOf(AggregateError); should(err?.errors.length).eql(1); // unique errors returned by msg - }); - it('retry works as expected when all fail with different errors', async () => { + it("retry works as expected when all fail with different errors", async () => { const RETRIES = 2; let cnt = 0; let err: AggregateError | null = null; try { - await asyncRetry(async () => { - await Bluebird.delay(1); - - cnt += 1; - throw new Error("step" + cnt); - - }, { retries: RETRIES }); + await asyncRetry( + async () => { + await Bluebird.delay(1); + + cnt += 1; + throw new Error("step" + cnt); + }, + { retries: RETRIES } + ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e: any) { err = e; } @@ -68,6 +72,5 @@ describe('utils/asyncRetry', function () { should(cnt).eql(RETRIES + 1); should(err).instanceOf(AggregateError); should(err?.errors.length).eql(RETRIES + 1); - }); -}); \ No newline at end of file +}); diff --git a/server/utils/asyncRetry.ts b/server/utils/asyncRetry.ts index 213a11c..0603637 100644 --- a/server/utils/asyncRetry.ts +++ b/server/utils/asyncRetry.ts @@ -8,20 +8,23 @@ import * as _ from "lodash"; // 2 ** 4 * 100 = 1600ms => 3100ms // 2 ** 5 * 100 = 3200ms => 6300ms // 2 ** 6 * 100 = 6400ms => 12700ms +// eslint-disable-next-line @typescript-eslint/no-explicit-any export async function asyncRetry(fn: () => Promise, options: { retries: number }, errors: any[] = []): Promise { let t: T; try { t = await fn(); } catch (e) { - if (errors.length >= options.retries) { - throw new AggregateError(_.unionBy([...errors, e], "message"), `asyncRetry: maximal retries exceeded. retries=${options.retries} errors=${errors.length}`); + throw new AggregateError( + _.unionBy([...errors, e], "message"), + `asyncRetry: maximal retries exceeded. retries=${options.retries} errors=${errors.length}` + ); } await Bluebird.delay(2 ** options.retries * 100); - return asyncRetry(fn, options, [...errors, e]) + return asyncRetry(fn, options, [...errors, e]); } return t; -} \ No newline at end of file +} diff --git a/server/utils/synchronized.ts b/server/utils/synchronized.ts index f7cd521..05646dc 100644 --- a/server/utils/synchronized.ts +++ b/server/utils/synchronized.ts @@ -2,19 +2,16 @@ export function synchronizedBy(target: () => Promise): (cacheKey: string) => Promise; export function synchronizedBy(target: (arg1: A1) => Promise): (cacheKey: string, arg1: A1) => Promise; export function synchronizedBy(target: (arg1: A1, arg2: A2) => Promise): (cacheKey: string, arg1: A1, arg2: A2) => Promise; -export function synchronizedBy(target: (arg1: A1, arg2: A2, arg3: A3) => Promise): (cacheKey: string, arg1: A1, arg2: A2, arg3: A3) => Promise; -export function synchronizedBy(target: (arg1: A1, arg2: A2, arg3: A3, arg4: A4) => Promise): (cacheKey: string, arg1: A1, arg2: A2, arg3: A3, arg4: A4) => Promise; -export function synchronizedBy(target: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5) => Promise): (cacheKey: string, arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5) => Promise; export function synchronizedBy(target: (...args: A[]) => Promise): (cacheKey: string, ...args: A[]) => Promise { - const mutexCache: { [cacheKey: string]: Promise } = {}; return async function (cacheKey: string, ...params: A[]) { - let resolveMutexPromise: Function = () => { }; - let rejectMutexPromise: Function = () => { }; + // eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-empty-function + let resolveMutexPromise: Function = () => {}; + // eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-empty-function + let rejectMutexPromise: Function = () => {}; if (!mutexCache[cacheKey]) { - mutexCache[cacheKey] = new Promise(function (this: Promise, resolve, reject) { resolveMutexPromise = resolve.bind(this); rejectMutexPromise = reject.bind(this); @@ -27,7 +24,6 @@ export function synchronizedBy(target: (...args: A[]) => Promise): (cac } catch (err) { rejectMutexPromise(err); } - } try { diff --git a/yarn.lock b/yarn.lock index 2c4ebbc..b18ccbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,6 +9,40 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@eslint/eslintrc@^1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" + integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.4.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" @@ -27,6 +61,27 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -82,6 +137,19 @@ resolved "https://registry.yarnpkg.com/@types/css/-/css-0.0.33.tgz#d0b49c4090c09c8e5dc01364560627e5ebb770f2" integrity sha512-qjeDgh86R0LIeEM588q65yatc8Yyo/VvSIYFqq8JOIHDolhGNX0rz7k/OuxqDpnpqlefoHj8X4Ai/6hT9IWtKQ== +"@types/eslint@^8.4.2": + version "8.21.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.21.1.tgz#110b441a210d53ab47795124dbc3e9bb993d1e7c" + integrity sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + "@types/express-serve-static-core@^4.17.33": version "4.17.33" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" @@ -101,6 +169,11 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/json-schema@*", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + "@types/lodash@^4.14.191": version "4.14.191" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" @@ -121,6 +194,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== +"@types/prettier@^2.6.0": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== + "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -131,6 +209,11 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@types/serve-static@*": version "1.15.0" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" @@ -159,6 +242,90 @@ dependencies: "@types/superagent" "*" +"@typescript-eslint/eslint-plugin@^5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz#5fb0d43574c2411f16ea80f5fc335b8eaa7b28a8" + integrity sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg== + dependencies: + "@typescript-eslint/scope-manager" "5.52.0" + "@typescript-eslint/type-utils" "5.52.0" + "@typescript-eslint/utils" "5.52.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.10.0", "@typescript-eslint/parser@^5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.52.0.tgz#73c136df6c0133f1d7870de7131ccf356f5be5a4" + integrity sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA== + dependencies: + "@typescript-eslint/scope-manager" "5.52.0" + "@typescript-eslint/types" "5.52.0" + "@typescript-eslint/typescript-estree" "5.52.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz#a993d89a0556ea16811db48eabd7c5b72dcb83d1" + integrity sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw== + dependencies: + "@typescript-eslint/types" "5.52.0" + "@typescript-eslint/visitor-keys" "5.52.0" + +"@typescript-eslint/type-utils@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz#9fd28cd02e6f21f5109e35496df41893f33167aa" + integrity sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw== + dependencies: + "@typescript-eslint/typescript-estree" "5.52.0" + "@typescript-eslint/utils" "5.52.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.52.0.tgz#19e9abc6afb5bd37a1a9bea877a1a836c0b3241b" + integrity sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ== + +"@typescript-eslint/typescript-estree@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz#6408cb3c2ccc01c03c278cb201cf07e73347dfca" + integrity sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ== + dependencies: + "@typescript-eslint/types" "5.52.0" + "@typescript-eslint/visitor-keys" "5.52.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.52.0.tgz#b260bb5a8f6b00a0ed51db66bdba4ed5e4845a72" + integrity sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.52.0" + "@typescript-eslint/types" "5.52.0" + "@typescript-eslint/typescript-estree" "5.52.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz#e38c971259f44f80cfe49d97dbffa38e3e75030f" + integrity sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA== + dependencies: + "@typescript-eslint/types" "5.52.0" + eslint-visitor-keys "^3.3.0" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -172,16 +339,31 @@ accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^8.4.1: +acorn@^8.4.1, acorn@^8.8.0: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -252,7 +434,7 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -366,6 +548,11 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.0, array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -667,7 +854,7 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -750,6 +937,11 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.2" +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camel-case@^1.0.0, camel-case@^1.1.1: version "1.2.2" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-1.2.2.tgz#1aca7c4d195359a2ce9955793433c6e5542511f2" @@ -854,7 +1046,7 @@ chalk@^2.0.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1129,6 +1321,11 @@ commander@^2.8.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +common-tags@^1.4.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + component-emitter@^1.2.1, component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -1267,6 +1464,15 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + cryptiles@0.2.x: version "0.2.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" @@ -1356,7 +1562,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4.3.4, debug@^4.3.4: +debug@4.3.4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1465,6 +1671,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -1547,6 +1758,25 @@ diff@~1.0.8: resolved "https://registry.yarnpkg.com/diff/-/diff-1.0.8.tgz#343276308ec991b7bc82267ed55bc1411f971666" integrity sha512-1zEb73vemXFpUmfh3fsta4YHz3lwebxXvaWmPbFv9apujQBWDnkrPDLXLQs1gZo4RCWMDsT89r0Pf/z8/02TGA== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dom-serializer@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" @@ -1737,7 +1967,7 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@4.0.0: +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== @@ -1747,6 +1977,93 @@ escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.0.0, eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.34.0, eslint@^8.7.0: + version "8.34.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6" + integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg== + dependencies: + "@eslint/eslintrc" "^1.4.1" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.4.0" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +espree@^9.0.0, espree@^9.4.0: + version "9.4.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" + integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -1762,6 +2079,35 @@ esprima@~1.2.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" integrity sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ== +esquery@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.2.tgz#c6d3fee05dd665808e2ad870631f221f5617b1d1" + integrity sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" @@ -1928,11 +2274,44 @@ fancy-log@^1.1.0: parse-node-version "^1.0.0" time-stamp "^1.0.0" +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + fast-safe-stringify@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + faye-websocket@~0.4.3: version "0.4.4" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.4.4.tgz#c14c5b3bf14d7417ffbfd990c0a7495cd9f337bc" @@ -1953,6 +2332,13 @@ figures@^1.3.5: escape-string-regexp "^1.0.5" object-assign "^4.1.0" +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + file-type@^3.1.0: version "3.9.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" @@ -2023,7 +2409,7 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -find-up@5.0.0: +find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -2062,11 +2448,24 @@ first-chunk-stream@^1.0.0: resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" integrity sha512-ArRi5axuv66gEsyl3UuK80CzW7t56hem73YGNYxNWTGNKFJUadSb9Gu9SHijYEUi8ulQMf1bJomYNwSCPHhtTQ== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2247,13 +2646,20 @@ glob-parent@^3.0.0, glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-stream@^5.3.2: version "5.3.5" resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" @@ -2337,6 +2743,25 @@ global-dirs@^0.1.0: dependencies: ini "^1.3.4" +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + globule@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" @@ -2413,6 +2838,11 @@ graceful-fs@~3.0.2: dependencies: natives "^1.1.3" +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + grunt-angular-templates@^0.5.4: version "0.5.9" resolved "https://registry.yarnpkg.com/grunt-angular-templates/-/grunt-angular-templates-0.5.9.tgz#2899be20d9438ad19b0d0a806aa8ec7a23b25b2a" @@ -2922,6 +3352,11 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + imagemin-gifsicle@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/imagemin-gifsicle/-/imagemin-gifsicle-4.2.0.tgz#0fef9bbad3476e6b76885736cc5b0b87a08757ca" @@ -2981,6 +3416,14 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -2998,6 +3441,11 @@ indent-string@^2.1.0: dependencies: repeating "^2.0.0" +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3195,7 +3643,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -3273,6 +3721,11 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" @@ -3408,7 +3861,12 @@ jpegtran-bin@^3.0.0: bin-wrapper "^3.0.0" logalot "^2.0.0" -js-yaml@4.1.0: +js-sdsl@^4.1.4: + version "4.3.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" + integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== + +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -3444,6 +3902,11 @@ jsmin2@^1.2.1: resolved "https://registry.yarnpkg.com/jsmin2/-/jsmin2-1.2.1.tgz#88fbe2fbf75f0a91f66020fd981cd693f4bfe57e" integrity sha512-27lUmduLlYXvSPlKP53PiV2jGHZR8J0M8xPy/ccRy2AUaQRWWvVLK4ps53n8yn/Rx870z6uTLr5tpKkWVPLrnA== +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -3534,6 +3997,14 @@ less@^1.7.2: request "~2.40.0" source-map "0.1.x" +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -3635,6 +4106,11 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.merge@^4.6.0, lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -3663,7 +4139,7 @@ lodash.templatesettings@^3.0.0: lodash._reinterpolate "^3.0.0" lodash.escape "^3.0.0" -lodash@4.17.21, lodash@^4.17.4, lodash@~4.17.10: +lodash@4.17.21, lodash@^4.17.21, lodash@^4.17.4, lodash@~4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3704,6 +4180,19 @@ logalot@^2.0.0: figures "^1.3.5" squeak "^1.0.0" +loglevel-colored-level-prefix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz#6a40218fdc7ae15fc76c3d0f3e676c465388603e" + integrity sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA== + dependencies: + chalk "^1.1.3" + loglevel "^1.4.1" + +loglevel@^1.4.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" + integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== + longest@^1.0.0, longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -3838,6 +4327,11 @@ merge-stream@^1.0.0: dependencies: readable-stream "^2.0.1" +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -3881,6 +4375,14 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -3921,7 +4423,7 @@ minimatch@0.3: lru-cache "2" sigmund "~1.0.0" -"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.1.1: +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -4077,6 +4579,16 @@ natives@^1.1.3: resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb" integrity sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA== +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + ncp@0.5.1, ncp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.5.1.tgz#743985316e3db459281b587169e845735a05439f" @@ -4293,6 +4805,18 @@ optional@^0.1.0: resolved "https://registry.yarnpkg.com/optional/-/optional-0.1.4.tgz#cdb1a9bedc737d2025f690ceeb50e049444fd5b3" integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + optipng-bin@^3.0.0: version "3.1.4" resolved "https://registry.yarnpkg.com/optipng-bin/-/optipng-bin-3.1.4.tgz#95d34f2c488704f6fd70606bfea0c659f1d95d84" @@ -4385,6 +4909,13 @@ param-case@^1.0.0: dependencies: sentence-case "^1.1.2" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -4464,6 +4995,11 @@ path-key@^2.0.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -4483,12 +5019,17 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -4528,6 +5069,11 @@ postcss@~0.3.5: base64-js "~0.0.6" source-map "~0.1.33" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -4538,6 +5084,36 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ== +prettier-eslint@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-15.0.1.tgz#2543a43e9acec2a9767ad6458165ce81f353db9c" + integrity sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg== + dependencies: + "@types/eslint" "^8.4.2" + "@types/prettier" "^2.6.0" + "@typescript-eslint/parser" "^5.10.0" + common-tags "^1.4.0" + dlv "^1.1.0" + eslint "^8.7.0" + indent-string "^4.0.0" + lodash.merge "^4.6.0" + loglevel-colored-level-prefix "^1.0.0" + prettier "^2.5.1" + pretty-format "^23.0.1" + require-relative "^0.8.7" + typescript "^4.5.4" + vue-eslint-parser "^8.0.1" + +prettier-plugin-organize-imports@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.2.tgz#91993365e017daa5d0d28d8183179834224d8dd1" + integrity sha512-e97lE6odGSiHonHJMTYC0q0iLXQyw0u5z/PJpvP/3vRy6/Zi9kLBwFAbEGjDzIowpjQv8b+J04PDamoUSQbzGA== + +prettier@^2.5.1, prettier@^2.8.4: + version "2.8.4" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" + integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== + pretty-bytes@^0.1.0, pretty-bytes@~0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-0.1.2.tgz#cd90294d58a1ca4e8a5d0fb9c8225998881acf00" @@ -4550,6 +5126,14 @@ pretty-bytes@^3.0.1: dependencies: number-is-nan "^1.0.0" +pretty-format@^23.0.1: + version "23.6.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" + integrity sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw== + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + pretty-ms@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-0.1.0.tgz#7c69cc866ba6794e9eef0168feeeade0bafa7e22" @@ -4593,7 +5177,7 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== -punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== @@ -4630,6 +5214,11 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -4768,6 +5357,11 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + registry-auth-token@^3.0.1: version "3.4.0" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" @@ -4840,11 +5434,21 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-relative@^0.8.7: + version "0.8.7" + resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" + integrity sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -4864,6 +5468,11 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -4883,11 +5492,25 @@ rimraf@^2.2.6, rimraf@^2.2.8: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@~2.2.1, rimraf@~2.2.8: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" integrity sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg== +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -4956,7 +5579,7 @@ semver@^4.0.3: resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" integrity sha512-IrpJ+yoG4EOH8DFWuVg+8H1kW1Oaof0Wxe7cPcXW3x9BjkN/eVo54F15LyqemnDIUYskQWr9qvl/RihmSy6+xQ== -semver@^7.3.8: +semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -5038,11 +5661,23 @@ shebang-command@^1.2.0: dependencies: shebang-regex "^1.0.0" +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + should-equal@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" @@ -5116,6 +5751,11 @@ simple-is@~0.2.0: resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" integrity sha512-GJXhv3r5vdj5tGWO+rcrWgjU2azLB+fb7Ehh3SmZpXE0o4KrrFLti0w4mdDCbR29X/z0Ls20ApjZitlpAXhAeg== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + snake-case@^1.0.0, snake-case@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-1.1.2.tgz#0c2f25e305158d9a18d3d977066187fef8a5a66a" @@ -5425,7 +6065,7 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -5761,11 +6401,35 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.4.0, tunnel-agent@~0.4.0: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" integrity sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -5779,7 +6443,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@^4.9.5: +typescript@^4.5.4, typescript@^4.9.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -5925,6 +6589,13 @@ upper-case@^1.0.0, upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1: resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" integrity sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA== +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -6052,6 +6723,19 @@ vinyl@^1.0.0: clone-stats "^0.0.1" replace-ext "0.0.1" +vue-eslint-parser@^8.0.1: + version "8.3.0" + resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d" + integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g== + dependencies: + debug "^4.3.2" + eslint-scope "^7.0.0" + eslint-visitor-keys "^3.1.0" + espree "^9.0.0" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^7.3.5" + ware@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ware/-/ware-1.3.0.tgz#d1b14f39d2e2cb4ab8c4098f756fe4b164e473d4" @@ -6071,6 +6755,13 @@ which@^1.2.9: dependencies: isexe "^2.0.0" +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + which@~1.0.5: version "1.0.9" resolved "https://registry.yarnpkg.com/which/-/which-1.0.9.tgz#460c1da0f810103d0321a9b633af9e575e64486f" @@ -6109,6 +6800,11 @@ wiredep@~0.4.2: chalk "~0.1.1" lodash "~1.3.0" +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"