From 073c5cdd8234e75c51f6eae274318b9a3cae4137 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:07:49 +0530 Subject: [PATCH 01/43] Add preliminary test for Wikipedia API --- src/tests/WikipediaAPI.test.ts | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/tests/WikipediaAPI.test.ts diff --git a/src/tests/WikipediaAPI.test.ts b/src/tests/WikipediaAPI.test.ts new file mode 100644 index 0000000..9696347 --- /dev/null +++ b/src/tests/WikipediaAPI.test.ts @@ -0,0 +1,95 @@ +import { enableFetchMocks } from 'jest-fetch-mock'; +import fetchMock from 'jest-fetch-mock'; +import { WikipediaAPI } from '../api/apis/WikipediaAPI'; +import { WikiModel } from '../models/WikiModel'; +import { MediaTypeModel } from '../models/MediaTypeModel'; + +enableFetchMocks() +let wikiInstance: WikipediaAPI; + +beforeEach(() => { + fetchMock.resetMocks(); + wikiInstance = new WikipediaAPI(new (jest.fn())()); +}) + +test("searchByTitle behavior when given garbage data", async () => { + fetchMock.mockResponseOnce(JSON.stringify({ + data: "string" + })) + await expect(async () => await wikiInstance.searchByTitle("sample")).rejects.toThrow(); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle when fetch returns non-200", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), {status: 400}); + await expect(async () => await wikiInstance.searchByTitle("sample")).rejects.toThrow(); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle with successful request and valid response", async () => { + let response = { + "batchcomplete": "", + "continue": { + "sroffset": 20, + "continue": "-||" + }, + "query": { + "searchinfo": { + "totalhits": 214380 + }, + "search": [ + { + "ns": 0, + "title": "Jackson", + "pageid": 15772, + "size": 3524, + "wordcount": 392, + "timestamp": "2022-06-16T07:22:28Z" + }, + { + "ns": 0, + "title": "Michael Jackson", + "pageid": 14995351, + "size": 257103, + "wordcount": 23309, + "timestamp": "2022-06-29T01:15:25Z" + }, + { + "ns": 0, + "title": "Andrew Jackson", + "pageid": 1623, + "size": 200137, + "wordcount": 22743, + "timestamp": "2022-07-03T17:53:13Z" + }, + { + "ns": 0, + "title": "Janet Jackson", + "pageid": 60070, + "size": 206594, + "wordcount": 21067, + "timestamp": "2022-06-24T19:40:30Z" + } + ] + } + }; + fetchMock.mockResponse(JSON.stringify(response)); + let ret: MediaTypeModel[] = []; + + for (const result of response.query.search) { + ret.push(new WikiModel({ + type: 'wiki', + title: result.title, + englishTitle: result.title, + year: '', + dataSource: 'Wikipedia API', + id: result.pageid, + } as unknown as WikiModel)); + } + let dt = await wikiInstance.searchByTitle("Jackson"); + expect(dt).toStrictEqual(ret); + +}) From 5b6e49f47e4636b5e0feb82657a0dc141b344c8c Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:47:48 +0530 Subject: [PATCH 02/43] Add sample tests in JS --- src/tests/OMDbAPI.test.js | 101 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/tests/OMDbAPI.test.js diff --git a/src/tests/OMDbAPI.test.js b/src/tests/OMDbAPI.test.js new file mode 100644 index 0000000..816a522 --- /dev/null +++ b/src/tests/OMDbAPI.test.js @@ -0,0 +1,101 @@ +require('jest-fetch-mock').enableMocks() + +let OMDbApiInstance; + +beforeEach(() => { + fetchMock.resetMocks(); + let OMDbAPI = require("../api/apis/OMDbAPI").OMDbAPI; + let MediaDbPluginMock = {}; + MediaDbPluginMock = { + settings: { + OMDbKey: "string" + } + }; + OMDbApiInstance = new OMDbAPI(MediaDbPluginMock); +}) + +test("searchByTitle behavior when given garbage data", async () => { + fetchMock.mockResponseOnce(JSON.stringify({ + data: "string" + })) + let res = await OMDbApiInstance.searchByTitle("sample"); + expect(res).toEqual([]); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle when fetch returns 401", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); + // TODO: Check API name and fix message + // TODO: Externalize string + await expect(async () => await OMDbApiInstance.searchByTitle("sample")).rejects.toThrowError("MDB | Authentication for OMDbAPI failed. Check the API key."); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle when fetch returns other non-200", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 400 }); + await expect(async () => await OMDbApiInstance.searchByTitle("sample")).rejects.toThrow(); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle with successful request and valid response", async () => { + let response = { + "Search": [ + { + "Title": "Guardians of the Galaxy", + "Year": "2014", + "imdbID": "tt2015381", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg" + }, + { + "Title": "Guardians of the Galaxy Vol. 2", + "Year": "2017", + "imdbID": "tt3896198", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BNjM0NTc0NzItM2FlYS00YzEwLWE0YmUtNTA2ZWIzODc2OTgxXkEyXkFqcGdeQXVyNTgwNzIyNzg@._V1_SX300.jpg" + }, + { + "Title": "Guardians of the Galaxy: Inferno", + "Year": "2017", + "imdbID": "tt7131308", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BZGQ0YzEyNWQtNGJiMi00NTAxLThkNDctNGY2ODkzYWMxZmZkXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg" + }, + { + "Title": "LEGO Marvel Super Heroes - Guardians of the Galaxy: The Thanos Threat", + "Year": "2017", + "imdbID": "tt7387224", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMjhlYzVhNTMtMmFkYy00NDhiLTkyNDgtYzhhMTZiMzM2OTA5XkEyXkFqcGdeQXVyNjI2OTgxNzY@._V1_SX300.jpg" + }, + ], + "totalResults": "4", + "Response": "True" + } + fetchMock.mockResponse(JSON.stringify(response)); + let ret = []; + + // import { MovieModel } from '../models/MovieModel'; + // const MovieModel = require('../models/MovieModel') + for (const result of response.Search) { + ret.push({ + type: 'movie', + title: result.Title, + englishTitle: result.Title, + year: result.Year, + dataSource: 'OMDbAPI', + id: result.imdbID, + }); + } + + let dt = await OMDbApiInstance.searchByTitle("Jackson"); + expect(dt).toEqual(ret); + +}) + From f5a44187ed2ac6b877832a660e075d81cea5cf52 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:48:52 +0530 Subject: [PATCH 03/43] Add rudimentary TS tests - Mocks need rewriting as they are not being created from module. Not scalable. --- src/tests/OMDbAPI.test.ts | 103 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/tests/OMDbAPI.test.ts diff --git a/src/tests/OMDbAPI.test.ts b/src/tests/OMDbAPI.test.ts new file mode 100644 index 0000000..9db5663 --- /dev/null +++ b/src/tests/OMDbAPI.test.ts @@ -0,0 +1,103 @@ +import { enableFetchMocks } from 'jest-fetch-mock'; +import fetchMock from 'jest-fetch-mock'; +import { OMDbAPI } from '../api/apis/OMDbAPI'; +import { MovieModel } from '../models/MovieModel'; +import { MediaTypeModel } from '../models/MediaTypeModel'; +import MediaDbPlugin from '../main'; +import { MediaDbPluginSettings } from 'src/settings/Settings'; + +enableFetchMocks() +let OMDbApiMock: OMDbAPI; + +beforeEach(() => { + fetchMock.resetMocks(); + let settingsMock: MediaDbPluginSettings = { + OMDbKey: "string" + } as MediaDbPluginSettings; + let pluginMock: MediaDbPlugin = {} as MediaDbPlugin; + pluginMock.settings = settingsMock; + OMDbApiMock = new OMDbAPI(pluginMock); +}) + +test("searchByTitle behavior when given garbage data", async () => { + fetchMock.mockResponseOnce(JSON.stringify({ + data: "string" + })) + let res = await OMDbApiMock.searchByTitle("sample"); + expect(res).toEqual([]); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle when fetch returns 401", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); + // TODO: Check API name and fix message + // TODO: Externalize string + await expect(async () => await OMDbApiMock.searchByTitle("sample")).rejects.toThrowError("MDB | Authentication for OMDbAPI failed. Check the API key."); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle when fetch returns other non-200", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 400 }); + await expect(async () => await OMDbApiMock.searchByTitle("sample")).rejects.toThrow(); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test("searchByTitle with successful request and valid response", async () => { + let response = { + "Search": [ + { + "Title": "Guardians of the Galaxy", + "Year": "2014", + "imdbID": "tt2015381", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg" + }, + { + "Title": "Guardians of the Galaxy Vol. 2", + "Year": "2017", + "imdbID": "tt3896198", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BNjM0NTc0NzItM2FlYS00YzEwLWE0YmUtNTA2ZWIzODc2OTgxXkEyXkFqcGdeQXVyNTgwNzIyNzg@._V1_SX300.jpg" + }, + { + "Title": "Guardians of the Galaxy: Inferno", + "Year": "2017", + "imdbID": "tt7131308", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BZGQ0YzEyNWQtNGJiMi00NTAxLThkNDctNGY2ODkzYWMxZmZkXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg" + }, + { + "Title": "LEGO Marvel Super Heroes - Guardians of the Galaxy: The Thanos Threat", + "Year": "2017", + "imdbID": "tt7387224", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMjhlYzVhNTMtMmFkYy00NDhiLTkyNDgtYzhhMTZiMzM2OTA5XkEyXkFqcGdeQXVyNjI2OTgxNzY@._V1_SX300.jpg" + }, + ], + "totalResults": "4", + "Response": "True" + } + fetchMock.mockResponse(JSON.stringify(response)); + let ret: MediaTypeModel[] = []; + + for (const result of response.Search) { + ret.push(new MovieModel({ + type: 'wiki', + title: result.Title, + englishTitle: result.Title, + year: result.Year, + dataSource: 'OMDbAPI', + id: result.imdbID, + } as unknown as MovieModel)); + } + let dt = await OMDbApiMock.searchByTitle("Jackson"); + expect(dt).toStrictEqual(ret); + +}) + From 93c0b3bf293d2fc8009077f1045c16f2ff8b1623 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:49:07 +0530 Subject: [PATCH 04/43] Add a few basic util tests --- src/tests/utils.test.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/tests/utils.test.ts diff --git a/src/tests/utils.test.ts b/src/tests/utils.test.ts new file mode 100644 index 0000000..ce7a247 --- /dev/null +++ b/src/tests/utils.test.ts @@ -0,0 +1,24 @@ +import { wrapAround, containsOnlyLettersAndUnderscores, replaceIllegalFileNameCharactersInString} from '../utils/Utils'; + +test('If wrapAround wraps correctly', () => { + expect(wrapAround(100,5)).toBe(0); + expect(wrapAround(100,7)).toBe(2); +}); + +test('If wrapAround errors out when dividing by zero', () => { + expect(wrapAround(100,0)).toThrow(); +}); + +test('Letter and underscore string validity', () => { + expect(containsOnlyLettersAndUnderscores("asdkfj_")).toBe(true); + expect(containsOnlyLettersAndUnderscores("asdkfj0")).toBe(false); +}); + +test('Letter and underscore unicode char test', () =>{ + expect(containsOnlyLettersAndUnderscores("asdkaÈj")).toBe(true); + expect(containsOnlyLettersAndUnderscores("asdkaÈj0")).toBe(false); +}); + +test('Valid filename test', ()=>{ + expect(replaceIllegalFileNameCharactersInString("what?is\\this:")).toBe("whatisthis -"); +}) \ No newline at end of file From 80898492bea8838c07587d2f7f0b34ecddaf8b00 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:49:38 +0530 Subject: [PATCH 05/43] Update dependencies --- package-lock.json | 5813 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 11 +- 2 files changed, 5734 insertions(+), 90 deletions(-) diff --git a/package-lock.json b/package-lock.json index 18cae84..4b4e6d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,613 @@ { "name": "obsidian-media-db-plugin", - "version": "0.1.0", + "version": "0.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-media-db-plugin", - "version": "0.1.0", - "license": "MIT", + "version": "0.3.0", + "license": "GPL-3.0", + "dependencies": { + "ts-node": "^10.8.1", + "yarn": "^1.22.19" + }, "devDependencies": { "@popperjs/core": "^2.11.5", + "@types/jest": "^28.1.3", "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "^5.2.0", "@typescript-eslint/parser": "^5.2.0", "builtin-modules": "^3.2.0", "esbuild": "0.13.12", + "jest": "^28.1.2", + "jest-fetch-mock": "^3.0.3", "obsidian": "latest", + "ts-jest": "^28.0.5", "tslib": "2.3.1", "typescript": "4.4.4" } }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz", + "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", + "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helpers": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", + "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", + "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", + "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", + "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz", + "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", + "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", + "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz", + "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", + "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-function-name": "^7.18.6", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.18.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", + "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "node_modules/@codemirror/rangeset": { "version": "0.19.9", "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.9.tgz", @@ -57,6 +645,26 @@ "w3c-keyname": "^2.2.4" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", @@ -100,6 +708,386 @@ "dev": true, "peer": true }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.1.tgz", + "integrity": "sha512-0RiUocPVFEm3WRMOStIHbRWllG6iW6E3/gUPnf4lkrVFyXIIDeCe+vlKeYyFOMhB2EPE6FLFCNADSOOQMaqvyA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.2.tgz", + "integrity": "sha512-Xo4E+Sb/nZODMGOPt2G3cMmCBqL4/W2Ijwr7/mrXlq4jdJwcFQ/9KrrJZT2adQRk2otVBXXOz1GRQ4Z5iOgvRQ==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.1", + "@jest/reporters": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.0.2", + "jest-config": "^28.1.2", + "jest-haste-map": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.1", + "jest-resolve-dependencies": "^28.1.2", + "jest-runner": "^28.1.2", + "jest-runtime": "^28.1.2", + "jest-snapshot": "^28.1.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "jest-watcher": "^28.1.1", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.1", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.2.tgz", + "integrity": "sha512-I0CR1RUMmOzd0tRpz10oUfaChBWs+/Hrvn5xYhMEF/ZqrDaaeHwS8yDBqEWCrEnkH2g+WE/6g90oBv3nKpcm8Q==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "jest-mock": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.2.tgz", + "integrity": "sha512-HBzyZBeFBiOelNbBKN0pilWbbrGvwDUwAqMC46NVJmWm8AVkuE58NbG1s7DR4cxFt4U5cVLxofAoHxgvC5MyOw==", + "dev": true, + "dependencies": { + "expect": "^28.1.1", + "jest-snapshot": "^28.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.1.tgz", + "integrity": "sha512-n/ghlvdhCdMI/hTcnn4qV57kQuV9OTsZzH1TTCVARANKhl6hXJqLKUkwX69ftMGpsbpt96SsDD8n8LD2d9+FRw==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.2.tgz", + "integrity": "sha512-xSYEI7Y0D5FbZN2LsCUj/EKRR1zfQYmGuAUVh6xTqhx7V5JhjgMcK5Pa0iR6WIk0GXiHDe0Ke4A+yERKE9saqg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.1", + "jest-mock": "^28.1.1", + "jest-util": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.2.tgz", + "integrity": "sha512-cz0lkJVDOtDaYhvT3Fv2U1B6FtBnV+OpEyJCzTHM1fdoTsU4QNLAt/H4RkiwEUU+dL4g/MFsoTuHeT2pvbo4Hg==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.2", + "@jest/expect": "^28.1.2", + "@jest/types": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.2.tgz", + "integrity": "sha512-/whGLhiwAqeCTmQEouSigUZJPVl7sW8V26EiboImL+UyXznnr1a03/YZ2BX8OlFw0n+Zlwu+EZAITZtaeRTxyA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.1", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@jridgewell/trace-mapping": "^0.3.13", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1", + "jest-worker": "^28.1.1", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", + "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.23.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.1.tgz", + "integrity": "sha512-hPmkugBktqL6rRzwWAtp1JtYT4VHwv8OQ+9lE5Gymj6dHzubI/oJHMUpPOt8NrdVWSrz9S7bHjJUmv2ggFoUNQ==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.1", + "@jest/types": "^28.1.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.1.tgz", + "integrity": "sha512-nuL+dNSVMcWB7OOtgb0EGH5AjO4UBCt68SLP08rwmC+iRhyuJWS9MtZ/MpipxFwKAlHFftbMsydXqWre8B0+XA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.2.tgz", + "integrity": "sha512-3o+lKF6iweLeJFHBlMJysdaPbpoMmtbHEFsjzSv37HIq/wWt5ijTeO2Yf7MO5yyczCopD507cNwNLeX8Y/CuIg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.1", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.1.tgz", + "integrity": "sha512-vRXVqSg1VhDnB8bWcmvLzmg0Bt9CRKVgHPXqYwvWMX3TvAjeO+nRuK6+VdTKCtWOvYlmkF/HqNAL/z+N3B53Kw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz", + "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -145,6 +1133,91 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@sinclair/typebox": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", + "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, "node_modules/@types/codemirror": { "version": "0.0.108", "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", @@ -160,6 +1233,49 @@ "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-Tsbjk8Y2hkBaY/gJsataeb4q9Mubw9EOz7+4RjPkzD5KjTvHHs7cpws22InaoXxAVAhF5HfFbzJjo6oKWqSZLw==", + "dev": true, + "dependencies": { + "jest-matcher-utils": "^28.0.0", + "pretty-format": "^28.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -169,7 +1285,18 @@ "node_modules/@types/node": { "version": "16.11.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.33.tgz", - "integrity": "sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA==", + "integrity": "sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA==" + }, + "node_modules/@types/prettier": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", + "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "node_modules/@types/tern": { @@ -181,6 +1308,21 @@ "@types/estree": "*" } }, + "node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz", @@ -369,8 +1511,6 @@ "version": "8.7.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -388,6 +1528,14 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -405,12 +1553,38 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -420,7 +1594,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -431,6 +1604,24 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -447,19 +1638,108 @@ "node": ">=8" } }, + "node_modules/babel-jest": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.2.tgz", + "integrity": "sha512-pfmoo6sh4L/+5/G2OOfQrGJgvH7fTa1oChnuYH2G/6gA+JwDvO8PELwvwnofKBMNrQsam0Wy/Rw+QSrBNewq2Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^28.1.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.1.tgz", + "integrity": "sha512-NovGCy5Hn25uMJSAU8FaHqzs13cFoOI4lhIujiepssjCKRsAo3TA734RDWSGxuFTsUJXerYOqQQodlxgmtqbzw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.1.tgz", + "integrity": "sha512-FCq9Oud0ReTeWtcneYf/48981aTfXYuB9gbU4rBNNJVBSQ6ssv7E6v/qvbBxtOWwZFXjLZwpg+W3q7J6vhH25g==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^28.1.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -477,6 +1757,61 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", + "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001359", + "electron-to-chromium": "^1.4.172", + "node-releases": "^2.0.5", + "update-browserslist-db": "^1.0.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "node_modules/builtin-modules": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", @@ -494,17 +1829,40 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "peer": true, "engines": { "node": ">=6" } }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001361", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz", + "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -516,12 +1874,59 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", + "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -533,22 +1938,42 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, - "peer": true + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "dependencies": { + "node-fetch": "2.6.7" + } }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -575,6 +2000,12 @@ } } }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -582,6 +2013,41 @@ "dev": true, "peer": true }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -607,6 +2073,39 @@ "node": ">=6.0.0" } }, + "node_modules/electron-to-chromium": { + "version": "1.4.174", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.174.tgz", + "integrity": "sha512-JER+w+9MV2MBVFOXxP036bLlNOnzbYAWrWU8sNUwoOO69T3w4564WhM5H5atd8VVS8U4vpi0i0kdoYzm1NPQgQ==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/esbuild": { "version": "0.13.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.12.tgz", @@ -857,6 +2356,15 @@ "win32" ] }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1011,6 +2519,19 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -1074,6 +2595,54 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.1.tgz", + "integrity": "sha512-/AANEwGL0tWBwzLNOvO0yUdy2D52jVdNXppOqswC49sxMN2cPWsGCQdzuIf9tj6hHoBQzNvx75JUYuQAckPo3w==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.1", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1113,8 +2682,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -1132,6 +2700,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1157,6 +2734,19 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1182,8 +2772,27 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "peer": true + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -1191,12 +2800,50 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1261,16 +2908,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "peer": true, "engines": { "node": ">=8" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -1297,12 +2976,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true, - "peer": true, "engines": { "node": ">=0.8.19" } @@ -1312,7 +3009,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "peer": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1322,8 +3018,25 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, - "peer": true + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-extglob": { "version": "2.1.1", @@ -1334,6 +3047,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1355,12 +3086,669 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, - "peer": true + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.2.tgz", + "integrity": "sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.2", + "@jest/types": "^28.1.1", + "import-local": "^3.0.2", + "jest-cli": "^28.1.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", + "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.2.tgz", + "integrity": "sha512-E2vdPIJG5/69EMpslFhaA46WkcrN74LI5V/cSJ59L7uS8UNoXbzTxmwhpi9XrIL3zqvMt5T0pl5k2l2u2GwBNQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.2", + "@jest/expect": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.1", + "jest-matcher-utils": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-runtime": "^28.1.2", + "jest-snapshot": "^28.1.2", + "jest-util": "^28.1.1", + "pretty-format": "^28.1.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-cli": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.2.tgz", + "integrity": "sha512-l6eoi5Do/IJUXAFL9qRmDiFpBeEJAnjJb1dcd9i/VWfVWbp3mJhuH50dNtX67Ali4Ecvt4eBkWb4hXhPHkAZTw==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/types": "^28.1.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.2.tgz", + "integrity": "sha512-g6EfeRqddVbjPVBVY4JWpUY4IvQoFRIZcv4V36QkqzE0IGhEC/VkugFeBMAeUE7PRgC8KJF0yvJNDeQRbamEVA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.1", + "@jest/types": "^28.1.1", + "babel-jest": "^28.1.2", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.2", + "jest-environment-node": "^28.1.2", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.1", + "jest-runner": "^28.1.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.1.tgz", + "integrity": "sha512-/MUUxeR2fHbqHoMMiffe/Afm+U8U4olFRJ0hiVG2lZatPJcnGxx292ustVu7bULhjV65IYMxRdploAKLbcrsyg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.1.tgz", + "integrity": "sha512-A042rqh17ZvEhRceDMi784ppoXR7MWGDEKTXEZXb4svt0eShMZvijGxzKsx+yIjeE8QYmHPrnHiTSQVhN4nqaw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.1", + "pretty-format": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.2.tgz", + "integrity": "sha512-oYsZz9Qw27XKmOgTtnl0jW7VplJkN2oeof+SwAwKFQacq3CLlG9u4kTGuuLWfvu3J7bVutWlrbEQMOCL/jughw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.2", + "@jest/fake-timers": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "jest-mock": "^28.1.1", + "jest-util": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "dev": true, + "dependencies": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" + } + }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.1.tgz", + "integrity": "sha512-ZrRSE2o3Ezh7sb1KmeLEZRZ4mgufbrMwolcFHNRSjKZhpLa8TdooXOOFlSwoUzlbVs1t0l7upVRW2K7RWGHzbQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.1", + "jest-worker": "^28.1.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.1.tgz", + "integrity": "sha512-4jvs8V8kLbAaotE+wFR7vfUGf603cwYtFf1/PYEsyX2BAjSzj8hQSVTP6OWzseTl0xL6dyHuKs2JAks7Pfubmw==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.1.tgz", + "integrity": "sha512-NPJPRWrbmR2nAJ+1nmnfcKKzSwgfaciCCrYZzVnNoxVoyusYWIjkBMNvu0RHJe7dNj4hH3uZOPZsQA+xAYWqsw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.1.tgz", + "integrity": "sha512-xoDOOT66fLfmTRiqkoLIU7v42mal/SqwDKvfmfiWAdJMSJiU+ozgluO7KbvoAgiwIrrGZsV7viETjc8GNrA/IQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-mock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.1.tgz", + "integrity": "sha512-bDCb0FjfsmKweAvE09dZT59IMkzgN0fYBH6t5S45NoJfd2DHkS3ySG2K+hucortryhO3fVuXdlxWcbtIuV/Skw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.1.tgz", + "integrity": "sha512-/d1UbyUkf9nvsgdBildLe6LAD4DalgkgZcKd0nZ8XUGPyA/7fsnaQIlKVnDiuUXv/IeZhPEDrRJubVSulxrShA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.2.tgz", + "integrity": "sha512-OXw4vbOZuyRTBi3tapWBqdyodU+T33ww5cPZORuTWkg+Y8lmsxQlVu3MWtJh6NMlKRTHQetF96yGPv01Ye7Mbg==", + "dev": true, + "dependencies": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.2.tgz", + "integrity": "sha512-6/k3DlAsAEr5VcptCMdhtRhOoYClZQmxnVMZvZ/quvPGRpN7OBQYPIC32tWSgOnbgqLXNs5RAniC+nkdFZpD4A==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.1", + "@jest/environment": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.2", + "jest-haste-map": "^28.1.1", + "jest-leak-detector": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-resolve": "^28.1.1", + "jest-runtime": "^28.1.2", + "jest-util": "^28.1.1", + "jest-watcher": "^28.1.1", + "jest-worker": "^28.1.1", + "source-map-support": "0.5.13", + "throat": "^6.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.2.tgz", + "integrity": "sha512-i4w93OsWzLOeMXSi9epmakb2+3z0AchZtUQVF1hesBmcQQy4vtaql5YdVe9KexdJaVRyPDw8DoBR0j3lYsZVYw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.2", + "@jest/fake-timers": "^28.1.2", + "@jest/globals": "^28.1.2", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-mock": "^28.1.1", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.1", + "jest-snapshot": "^28.1.2", + "jest-util": "^28.1.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.2.tgz", + "integrity": "sha512-wzrieFttZYfLvrCVRJxX+jwML2YTArOUqFpCoSVy1QUapx+LlV9uLbV/mMEhYj4t7aMeE9aSQFHSvV/oNoDAMA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.1", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.1", + "jest-matcher-utils": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.1", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-util": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.1.tgz", + "integrity": "sha512-FktOu7ca1DZSyhPAxgxB6hfh2+9zMoJ7aEQA759Z6p45NuO8mWcqujH+UdHlCm/V6JTWwDztM2ITCzU1ijJAfw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.1.tgz", + "integrity": "sha512-Kpf6gcClqFCIZ4ti5++XemYJWUPCFUW+N2gknn+KgnDf549iLul3cBuKVe1YcWRlaF8tZV8eJCap0eECOEE3Ug==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.1.tgz", + "integrity": "sha512-RQIpeZ8EIJMxbQrXpJQYIIlubBnB9imEHsxxE41f54ZwcqWLysL/A0ZcdMirf+XsMn3xfphVQVV4EW0/p7i7Ug==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.1", + "@jest/types": "^28.1.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.1.tgz", + "integrity": "sha512-Au7slXB08C6h+xbJPp7VIb6U0XX5Kc9uel/WFc6/rcTzGiaVCBRngBExSYuXSLFPULPSYU3cJ3ybS988lNFQhQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", @@ -1375,6 +3763,24 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1389,6 +3795,36 @@ "dev": true, "peer": true }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1403,6 +3839,30 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1422,6 +3882,50 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1444,12 +3948,20 @@ "node": ">=8.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1476,8 +3988,60 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, - "peer": true + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/obsidian": { "version": "0.14.8", @@ -1496,11 +4060,25 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "peer": true, "dependencies": { "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -1519,6 +4097,42 @@ "node": ">= 0.8.0" } }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1532,12 +4146,38 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -1547,11 +4187,16 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "peer": true, "engines": { "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -1561,6 +4206,12 @@ "node": ">=8" } }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -1573,6 +4224,27 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1583,6 +4255,52 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.1.tgz", + "integrity": "sha512-wwJbVTGFHeucr5Jw2bQ9P+VYHyLdAqedFLEkdQUVaBF/eiidDwH5OpilINq4mEfhbCjLnirt6HTTDhv1HaTIQw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==", + "dev": true + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -1613,6 +4331,12 @@ } ] }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -1625,6 +4349,53 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1635,6 +4406,15 @@ "node": ">=4" } }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -1650,7 +4430,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -1684,6 +4463,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -1704,7 +4489,6 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1717,11 +4501,22 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "peer": true, "engines": { "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1731,12 +4526,84 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1744,12 +4611,29 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "peer": true, "engines": { "node": ">=8" }, @@ -1768,7 +4652,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -1776,6 +4659,61 @@ "node": ">=8" } }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -1783,6 +4721,27 @@ "dev": true, "peer": true }, + "node_modules/throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1795,6 +4754,93 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/ts-jest": { + "version": "28.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.5.tgz", + "integrity": "sha512-Sx9FyP9pCY7pUzQpy4FgRZf2bhHY3za576HMKJFs+OnQ9jS96Du5vNsDKkyedQkik+sEabbKAnCliv9BEsHZgQ==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -1835,6 +4881,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -1852,7 +4907,6 @@ "version": "4.4.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1861,6 +4915,32 @@ "node": ">=4.2.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz", + "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1878,18 +4958,61 @@ "dev": true, "peer": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/w3c-keyname": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==", "dev": true }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -1910,21 +5033,549 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", "dev": true, - "peer": true + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yarn": { + "version": "1.22.19", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.19.tgz", + "integrity": "sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ==", + "hasInstallScript": true, + "bin": { + "yarn": "bin/yarn.js", + "yarnpkg": "bin/yarn.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } } }, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz", + "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==", + "dev": true + }, + "@babel/core": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", + "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helpers": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.18.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", + "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "dev": true, + "requires": { + "@babel/types": "^7.18.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", + "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", + "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", + "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "dev": true, + "requires": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz", + "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", + "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", + "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", + "dev": true, + "requires": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz", + "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/traverse": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", + "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-function-name": "^7.18.6", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.18.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", + "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "@codemirror/rangeset": { "version": "0.19.9", "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.9.tgz", @@ -1962,6 +5613,25 @@ "w3c-keyname": "^2.2.4" } }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@eslint/eslintrc": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", @@ -1999,6 +5669,309 @@ "dev": true, "peer": true }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.1.tgz", + "integrity": "sha512-0RiUocPVFEm3WRMOStIHbRWllG6iW6E3/gUPnf4lkrVFyXIIDeCe+vlKeYyFOMhB2EPE6FLFCNADSOOQMaqvyA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.2.tgz", + "integrity": "sha512-Xo4E+Sb/nZODMGOPt2G3cMmCBqL4/W2Ijwr7/mrXlq4jdJwcFQ/9KrrJZT2adQRk2otVBXXOz1GRQ4Z5iOgvRQ==", + "dev": true, + "requires": { + "@jest/console": "^28.1.1", + "@jest/reporters": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.0.2", + "jest-config": "^28.1.2", + "jest-haste-map": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.1", + "jest-resolve-dependencies": "^28.1.2", + "jest-runner": "^28.1.2", + "jest-runtime": "^28.1.2", + "jest-snapshot": "^28.1.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "jest-watcher": "^28.1.1", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.1", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.2.tgz", + "integrity": "sha512-I0CR1RUMmOzd0tRpz10oUfaChBWs+/Hrvn5xYhMEF/ZqrDaaeHwS8yDBqEWCrEnkH2g+WE/6g90oBv3nKpcm8Q==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "jest-mock": "^28.1.1" + } + }, + "@jest/expect": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.2.tgz", + "integrity": "sha512-HBzyZBeFBiOelNbBKN0pilWbbrGvwDUwAqMC46NVJmWm8AVkuE58NbG1s7DR4cxFt4U5cVLxofAoHxgvC5MyOw==", + "dev": true, + "requires": { + "expect": "^28.1.1", + "jest-snapshot": "^28.1.2" + } + }, + "@jest/expect-utils": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.1.tgz", + "integrity": "sha512-n/ghlvdhCdMI/hTcnn4qV57kQuV9OTsZzH1TTCVARANKhl6hXJqLKUkwX69ftMGpsbpt96SsDD8n8LD2d9+FRw==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + } + }, + "@jest/fake-timers": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.2.tgz", + "integrity": "sha512-xSYEI7Y0D5FbZN2LsCUj/EKRR1zfQYmGuAUVh6xTqhx7V5JhjgMcK5Pa0iR6WIk0GXiHDe0Ke4A+yERKE9saqg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.1", + "jest-mock": "^28.1.1", + "jest-util": "^28.1.1" + } + }, + "@jest/globals": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.2.tgz", + "integrity": "sha512-cz0lkJVDOtDaYhvT3Fv2U1B6FtBnV+OpEyJCzTHM1fdoTsU4QNLAt/H4RkiwEUU+dL4g/MFsoTuHeT2pvbo4Hg==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.2", + "@jest/expect": "^28.1.2", + "@jest/types": "^28.1.1" + } + }, + "@jest/reporters": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.2.tgz", + "integrity": "sha512-/whGLhiwAqeCTmQEouSigUZJPVl7sW8V26EiboImL+UyXznnr1a03/YZ2BX8OlFw0n+Zlwu+EZAITZtaeRTxyA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.1", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@jridgewell/trace-mapping": "^0.3.13", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1", + "jest-worker": "^28.1.1", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + } + }, + "@jest/schemas": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", + "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.23.3" + } + }, + "@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.1.tgz", + "integrity": "sha512-hPmkugBktqL6rRzwWAtp1JtYT4VHwv8OQ+9lE5Gymj6dHzubI/oJHMUpPOt8NrdVWSrz9S7bHjJUmv2ggFoUNQ==", + "dev": true, + "requires": { + "@jest/console": "^28.1.1", + "@jest/types": "^28.1.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.1.tgz", + "integrity": "sha512-nuL+dNSVMcWB7OOtgb0EGH5AjO4UBCt68SLP08rwmC+iRhyuJWS9MtZ/MpipxFwKAlHFftbMsydXqWre8B0+XA==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.2.tgz", + "integrity": "sha512-3o+lKF6iweLeJFHBlMJysdaPbpoMmtbHEFsjzSv37HIq/wWt5ijTeO2Yf7MO5yyczCopD507cNwNLeX8Y/CuIg==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.1", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "@jest/types": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.1.tgz", + "integrity": "sha512-vRXVqSg1VhDnB8bWcmvLzmg0Bt9CRKVgHPXqYwvWMX3TvAjeO+nRuK6+VdTKCtWOvYlmkF/HqNAL/z+N3B53Kw==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz", + "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2031,6 +6004,91 @@ "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", "dev": true }, + "@sinclair/typebox": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", + "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, "@types/codemirror": { "version": "0.0.108", "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", @@ -2046,6 +6104,49 @@ "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-Tsbjk8Y2hkBaY/gJsataeb4q9Mubw9EOz7+4RjPkzD5KjTvHHs7cpws22InaoXxAVAhF5HfFbzJjo6oKWqSZLw==", + "dev": true, + "requires": { + "jest-matcher-utils": "^28.0.0", + "pretty-format": "^28.0.0" + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -2055,7 +6156,18 @@ "@types/node": { "version": "16.11.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.33.tgz", - "integrity": "sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA==", + "integrity": "sha512-0PJ0vg+JyU0MIan58IOIFRtSvsb7Ri+7Wltx2qAg94eMOrpg4+uuP3aUHCpxXc1i0jCXiC+zIamSZh3l9AbcQA==" + }, + "@types/prettier": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", + "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "@types/tern": { @@ -2067,6 +6179,21 @@ "@types/estree": "*" } }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz", @@ -2165,9 +6292,7 @@ "acorn": { "version": "8.7.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true, - "peer": true + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" }, "acorn-jsx": { "version": "5.3.2", @@ -2177,6 +6302,11 @@ "peer": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2190,23 +6320,53 @@ "uri-js": "^4.2.2" } }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "peer": true + "dev": true }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "peer": true, "requires": { "color-convert": "^2.0.1" } }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2220,19 +6380,87 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "babel-jest": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.2.tgz", + "integrity": "sha512-pfmoo6sh4L/+5/G2OOfQrGJgvH7fTa1oChnuYH2G/6gA+JwDvO8PELwvwnofKBMNrQsam0Wy/Rw+QSrBNewq2Q==", + "dev": true, + "requires": { + "@jest/transform": "^28.1.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.1.tgz", + "integrity": "sha512-NovGCy5Hn25uMJSAU8FaHqzs13cFoOI4lhIujiepssjCKRsAo3TA734RDWSGxuFTsUJXerYOqQQodlxgmtqbzw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.1.tgz", + "integrity": "sha512-FCq9Oud0ReTeWtcneYf/48981aTfXYuB9gbU4rBNNJVBSQ6ssv7E6v/qvbBxtOWwZFXjLZwpg+W3q7J6vhH25g==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^28.1.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "peer": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "peer": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2247,6 +6475,42 @@ "fill-range": "^7.0.1" } }, + "browserslist": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", + "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001359", + "electron-to-chromium": "^1.4.172", + "node-releases": "^2.0.5", + "update-browserslist-db": "^1.0.4" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "builtin-modules": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", @@ -2257,26 +6521,76 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "peer": true + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001361", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz", + "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==", + "dev": true }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "ci-info": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", + "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -2285,22 +6599,42 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "peer": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, - "peer": true + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "requires": { + "node-fetch": "2.6.7" + } }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "peer": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2316,6 +6650,12 @@ "ms": "2.1.2" } }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2323,6 +6663,29 @@ "dev": true, "peer": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2342,6 +6705,33 @@ "esutils": "^2.0.2" } }, + "electron-to-chromium": { + "version": "1.4.174", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.174.tgz", + "integrity": "sha512-JER+w+9MV2MBVFOXxP036bLlNOnzbYAWrWU8sNUwoOO69T3w4564WhM5H5atd8VVS8U4vpi0i0kdoYzm1NPQgQ==", + "dev": true + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "esbuild": { "version": "0.13.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.12.tgz", @@ -2486,6 +6876,12 @@ "dev": true, "optional": true }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2602,6 +6998,12 @@ "eslint-visitor-keys": "^3.3.0" } }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, "esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -2651,6 +7053,42 @@ "dev": true, "peer": true }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.1.tgz", + "integrity": "sha512-/AANEwGL0tWBwzLNOvO0yUdy2D52jVdNXppOqswC49sxMN2cPWsGCQdzuIf9tj6hHoBQzNvx75JUYuQAckPo3w==", + "dev": true, + "requires": { + "@jest/expect-utils": "^28.1.1", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2686,8 +7124,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "peer": true + "dev": true }, "fast-levenshtein": { "version": "2.0.6", @@ -2705,6 +7142,15 @@ "reusify": "^1.0.4" } }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2724,6 +7170,16 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -2746,8 +7202,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "peer": true + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -2755,12 +7223,35 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, - "peer": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2804,12 +7295,38 @@ "slash": "^3.0.0" } }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "peer": true + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true }, "ignore": { "version": "5.2.0", @@ -2828,19 +7345,27 @@ "resolve-from": "^4.0.0" } }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "peer": true + "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "peer": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -2850,8 +7375,22 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, - "peer": true + "requires": { + "has": "^1.0.3" + } }, "is-extglob": { "version": "2.1.1", @@ -2859,6 +7398,18 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2874,12 +7425,518 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, - "peer": true + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.2.tgz", + "integrity": "sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg==", + "dev": true, + "requires": { + "@jest/core": "^28.1.2", + "@jest/types": "^28.1.1", + "import-local": "^3.0.2", + "jest-cli": "^28.1.2" + } + }, + "jest-changed-files": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", + "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.2.tgz", + "integrity": "sha512-E2vdPIJG5/69EMpslFhaA46WkcrN74LI5V/cSJ59L7uS8UNoXbzTxmwhpi9XrIL3zqvMt5T0pl5k2l2u2GwBNQ==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.2", + "@jest/expect": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.1", + "jest-matcher-utils": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-runtime": "^28.1.2", + "jest-snapshot": "^28.1.2", + "jest-util": "^28.1.1", + "pretty-format": "^28.1.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-cli": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.2.tgz", + "integrity": "sha512-l6eoi5Do/IJUXAFL9qRmDiFpBeEJAnjJb1dcd9i/VWfVWbp3mJhuH50dNtX67Ali4Ecvt4eBkWb4hXhPHkAZTw==", + "dev": true, + "requires": { + "@jest/core": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/types": "^28.1.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.2.tgz", + "integrity": "sha512-g6EfeRqddVbjPVBVY4JWpUY4IvQoFRIZcv4V36QkqzE0IGhEC/VkugFeBMAeUE7PRgC8KJF0yvJNDeQRbamEVA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.1", + "@jest/types": "^28.1.1", + "babel-jest": "^28.1.2", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.2", + "jest-environment-node": "^28.1.2", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.1", + "jest-runner": "^28.1.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.1.tgz", + "integrity": "sha512-/MUUxeR2fHbqHoMMiffe/Afm+U8U4olFRJ0hiVG2lZatPJcnGxx292ustVu7bULhjV65IYMxRdploAKLbcrsyg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.1" + } + }, + "jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.1.tgz", + "integrity": "sha512-A042rqh17ZvEhRceDMi784ppoXR7MWGDEKTXEZXb4svt0eShMZvijGxzKsx+yIjeE8QYmHPrnHiTSQVhN4nqaw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.1", + "pretty-format": "^28.1.1" + } + }, + "jest-environment-node": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.2.tgz", + "integrity": "sha512-oYsZz9Qw27XKmOgTtnl0jW7VplJkN2oeof+SwAwKFQacq3CLlG9u4kTGuuLWfvu3J7bVutWlrbEQMOCL/jughw==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.2", + "@jest/fake-timers": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "jest-mock": "^28.1.1", + "jest-util": "^28.1.1" + } + }, + "jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-haste-map": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.1.tgz", + "integrity": "sha512-ZrRSE2o3Ezh7sb1KmeLEZRZ4mgufbrMwolcFHNRSjKZhpLa8TdooXOOFlSwoUzlbVs1t0l7upVRW2K7RWGHzbQ==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.1", + "jest-worker": "^28.1.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.1.tgz", + "integrity": "sha512-4jvs8V8kLbAaotE+wFR7vfUGf603cwYtFf1/PYEsyX2BAjSzj8hQSVTP6OWzseTl0xL6dyHuKs2JAks7Pfubmw==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.1" + } + }, + "jest-matcher-utils": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.1.tgz", + "integrity": "sha512-NPJPRWrbmR2nAJ+1nmnfcKKzSwgfaciCCrYZzVnNoxVoyusYWIjkBMNvu0RHJe7dNj4hH3uZOPZsQA+xAYWqsw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.1" + } + }, + "jest-message-util": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.1.tgz", + "integrity": "sha512-xoDOOT66fLfmTRiqkoLIU7v42mal/SqwDKvfmfiWAdJMSJiU+ozgluO7KbvoAgiwIrrGZsV7viETjc8GNrA/IQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.1.tgz", + "integrity": "sha512-bDCb0FjfsmKweAvE09dZT59IMkzgN0fYBH6t5S45NoJfd2DHkS3ySG2K+hucortryhO3fVuXdlxWcbtIuV/Skw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-resolve": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.1.tgz", + "integrity": "sha512-/d1UbyUkf9nvsgdBildLe6LAD4DalgkgZcKd0nZ8XUGPyA/7fsnaQIlKVnDiuUXv/IeZhPEDrRJubVSulxrShA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.1", + "jest-validate": "^28.1.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.2.tgz", + "integrity": "sha512-OXw4vbOZuyRTBi3tapWBqdyodU+T33ww5cPZORuTWkg+Y8lmsxQlVu3MWtJh6NMlKRTHQetF96yGPv01Ye7Mbg==", + "dev": true, + "requires": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.2" + } + }, + "jest-runner": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.2.tgz", + "integrity": "sha512-6/k3DlAsAEr5VcptCMdhtRhOoYClZQmxnVMZvZ/quvPGRpN7OBQYPIC32tWSgOnbgqLXNs5RAniC+nkdFZpD4A==", + "dev": true, + "requires": { + "@jest/console": "^28.1.1", + "@jest/environment": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.2", + "jest-haste-map": "^28.1.1", + "jest-leak-detector": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-resolve": "^28.1.1", + "jest-runtime": "^28.1.2", + "jest-util": "^28.1.1", + "jest-watcher": "^28.1.1", + "jest-worker": "^28.1.1", + "source-map-support": "0.5.13", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.2.tgz", + "integrity": "sha512-i4w93OsWzLOeMXSi9epmakb2+3z0AchZtUQVF1hesBmcQQy4vtaql5YdVe9KexdJaVRyPDw8DoBR0j3lYsZVYw==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.2", + "@jest/fake-timers": "^28.1.2", + "@jest/globals": "^28.1.2", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-mock": "^28.1.1", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.1", + "jest-snapshot": "^28.1.2", + "jest-util": "^28.1.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-snapshot": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.2.tgz", + "integrity": "sha512-wzrieFttZYfLvrCVRJxX+jwML2YTArOUqFpCoSVy1QUapx+LlV9uLbV/mMEhYj4t7aMeE9aSQFHSvV/oNoDAMA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.1", + "@jest/transform": "^28.1.2", + "@jest/types": "^28.1.1", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.1", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.1", + "jest-matcher-utils": "^28.1.1", + "jest-message-util": "^28.1.1", + "jest-util": "^28.1.1", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.1", + "semver": "^7.3.5" + } + }, + "jest-util": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.1.tgz", + "integrity": "sha512-FktOu7ca1DZSyhPAxgxB6hfh2+9zMoJ7aEQA759Z6p45NuO8mWcqujH+UdHlCm/V6JTWwDztM2ITCzU1ijJAfw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.1.tgz", + "integrity": "sha512-Kpf6gcClqFCIZ4ti5++XemYJWUPCFUW+N2gknn+KgnDf549iLul3cBuKVe1YcWRlaF8tZV8eJCap0eECOEE3Ug==", + "dev": true, + "requires": { + "@jest/types": "^28.1.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.1" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.1.tgz", + "integrity": "sha512-RQIpeZ8EIJMxbQrXpJQYIIlubBnB9imEHsxxE41f54ZwcqWLysL/A0ZcdMirf+XsMn3xfphVQVV4EW0/p7i7Ug==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.1", + "@jest/types": "^28.1.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.1", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.1.tgz", + "integrity": "sha512-Au7slXB08C6h+xbJPp7VIb6U0XX5Kc9uel/WFc6/rcTzGiaVCBRngBExSYuXSLFPULPSYU3cJ3ybS988lNFQhQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "4.1.0", @@ -2891,6 +7948,18 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2905,6 +7974,24 @@ "dev": true, "peer": true }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2916,6 +8003,27 @@ "type-check": "~0.4.0" } }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2932,6 +8040,43 @@ "yallist": "^4.0.0" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2948,12 +8093,17 @@ "picomatch": "^2.3.1" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "peer": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2974,8 +8124,43 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, - "peer": true + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } }, "obsidian": { "version": "0.14.8", @@ -2994,11 +8179,19 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "peer": true, "requires": { "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3014,6 +8207,30 @@ "word-wrap": "^1.2.3" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3024,19 +8241,41 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "peer": true + "dev": true }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "peer": true + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "path-type": { "version": "4.0.0", @@ -3044,12 +8283,33 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3057,6 +8317,42 @@ "dev": true, "peer": true }, + "pretty-format": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.1.tgz", + "integrity": "sha512-wwJbVTGFHeucr5Jw2bQ9P+VYHyLdAqedFLEkdQUVaBF/eiidDwH5OpilINq4mEfhbCjLnirt6HTTDhv1HaTIQw==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==", + "dev": true + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -3070,12 +8366,52 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3083,6 +8419,12 @@ "dev": true, "peer": true }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3094,7 +8436,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, - "peer": true, "requires": { "glob": "^7.1.3" } @@ -3108,6 +8449,12 @@ "queue-microtask": "^1.2.2" } }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -3122,7 +8469,6 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "peer": true, "requires": { "shebang-regex": "^3.0.0" } @@ -3131,8 +8477,19 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "peer": true + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true }, "slash": { "version": "3.0.0", @@ -3140,22 +8497,92 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "peer": true, "requires": { "ansi-regex": "^5.0.1" } }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "peer": true + "dev": true }, "style-mod": { "version": "4.0.0", @@ -3168,11 +8595,47 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "peer": true, "requires": { "has-flag": "^4.0.0" } }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3180,6 +8643,24 @@ "dev": true, "peer": true }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3189,6 +8670,48 @@ "is-number": "^7.0.0" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "ts-jest": { + "version": "28.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.5.tgz", + "integrity": "sha512-Sx9FyP9pCY7pUzQpy4FgRZf2bhHY3za576HMKJFs+OnQ9jS96Du5vNsDKkyedQkik+sEabbKAnCliv9BEsHZgQ==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + } + }, + "ts-node": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -3222,6 +8745,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3232,8 +8761,17 @@ "typescript": { "version": "4.4.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", - "dev": true + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==" + }, + "update-browserslist-db": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz", + "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } }, "uri-js": { "version": "4.4.1", @@ -3252,18 +8790,58 @@ "dev": true, "peer": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, "w3c-keyname": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==", "dev": true }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "peer": true, "requires": { "isexe": "^2.0.0" } @@ -3275,18 +8853,75 @@ "dev": true, "peer": true }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", "dev": true, - "peer": true + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true + }, + "yarn": { + "version": "1.22.19", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.19.tgz", + "integrity": "sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" } } } diff --git a/package.json b/package.json index b627065..5f91563 100644 --- a/package.json +++ b/package.json @@ -6,20 +6,29 @@ "scripts": { "dev": "node esbuild.config.mjs", "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", - "version": "node version-bump.mjs && git add manifest.json versions.json" + "version": "node version-bump.mjs && git add manifest.json versions.json", + "test": "jest" }, "keywords": [], "author": "Moritz Jung", "license": "GPL-3.0", "devDependencies": { "@popperjs/core": "^2.11.5", + "@types/jest": "^28.1.3", "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "^5.2.0", "@typescript-eslint/parser": "^5.2.0", "builtin-modules": "^3.2.0", "esbuild": "0.13.12", + "jest": "^28.1.2", + "jest-fetch-mock": "^3.0.3", "obsidian": "latest", + "ts-jest": "^28.0.5", "tslib": "2.3.1", "typescript": "4.4.4" + }, + "dependencies": { + "ts-node": "^10.8.1", + "yarn": "^1.22.19" } } From 0c25f2ae48e0dd58e1aaa1e9d9208a0b3f7ddcb5 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Fri, 9 Sep 2022 16:19:37 +0530 Subject: [PATCH 06/43] feat: add generic test suite --- src/tests/ParameterizedAPI.test.ts | 67 ++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/tests/ParameterizedAPI.test.ts diff --git a/src/tests/ParameterizedAPI.test.ts b/src/tests/ParameterizedAPI.test.ts new file mode 100644 index 0000000..0e5e7d1 --- /dev/null +++ b/src/tests/ParameterizedAPI.test.ts @@ -0,0 +1,67 @@ +import { enableFetchMocks } from 'jest-fetch-mock'; +import fetchMock from 'jest-fetch-mock'; +import { OMDbAPI } from '../api/apis/OMDbAPI'; +import MediaDbPlugin from '../main'; +import { MediaDbPluginSettings } from 'src/settings/Settings'; +import { MALAPI } from '../api/apis/MALAPI'; +import { LocGovAPI } from '../api/apis/LocGovAPI'; +import { MusicBrainzAPI } from '../api/apis/MusicBrainzAPI'; +import { SteamAPI } from '../api/apis/SteamAPI'; +import { WikipediaAPI } from '../api/apis/WikipediaAPI'; + +enableFetchMocks() +let apiMock: OMDbAPI | MALAPI | LocGovAPI | MusicBrainzAPI | SteamAPI | WikipediaAPI; +let api: typeof OMDbAPI | typeof MALAPI | typeof LocGovAPI | typeof MusicBrainzAPI | typeof SteamAPI | typeof WikipediaAPI; + +describe.each( + [ + { name: OMDbAPI }, + { name: MALAPI }, + { name: LocGovAPI }, + { name: MusicBrainzAPI }, + { name: SteamAPI }, + { name: WikipediaAPI } + ] +)('$name.name', ({ name: parameterizedApi }) => { + beforeAll(() => { + api = parameterizedApi; + let settingsMock: MediaDbPluginSettings = { + } as MediaDbPluginSettings; + let pluginMock = {} as MediaDbPlugin; + pluginMock.settings = settingsMock; + // TODO: add fake API key + apiMock = new parameterizedApi(pluginMock); + }) + + beforeEach(() => { + fetchMock.resetMocks(); + }) + + test("searchByTitle behavior when given garbage data", async () => { + const garbageResponse = JSON.stringify({ + data: "string" + }); + fetchMock.mockResponseOnce(garbageResponse) + let res; + // LocGovAPI throws an error because not implemented + if (parameterizedApi.name === "LocGovAPI") { + await expect(apiMock.searchByTitle("sample")).rejects.toThrow(); + + } else { + res = await apiMock.searchByTitle("sample"); + expect(res).toEqual([]); + } + expect(fetch).toHaveBeenCalledTimes(1); + }); + + test("searchByTitle when fetch returns 401", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); + // TODO: Check API name and fix message + // TODO: Externalize string + await expect(async () => await apiMock.searchByTitle("sample")).rejects.toThrow(); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); +}) \ No newline at end of file From 83e7dfac46c808d1d46299ca624b80cee6ae8dcd Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:38:26 +0530 Subject: [PATCH 07/43] test: add mock resposes --- src/tests/ResponseMocks/MALMockMovie.json | 30 ++++++++++++ .../MusicBrainzMockResponse.json | 49 +++++++++++++++++++ src/tests/ResponseMocks/OMDBMockResponse.json | 13 +++++ .../ResponseMocks/SteamAPIMockResponse.json | 14 ++++++ .../ResponseMocks/WikipediaMockResponse.json | 20 ++++++++ 5 files changed, 126 insertions(+) create mode 100644 src/tests/ResponseMocks/MALMockMovie.json create mode 100644 src/tests/ResponseMocks/MusicBrainzMockResponse.json create mode 100644 src/tests/ResponseMocks/OMDBMockResponse.json create mode 100644 src/tests/ResponseMocks/SteamAPIMockResponse.json create mode 100644 src/tests/ResponseMocks/WikipediaMockResponse.json diff --git a/src/tests/ResponseMocks/MALMockMovie.json b/src/tests/ResponseMocks/MALMockMovie.json new file mode 100644 index 0000000..b4d2ccf --- /dev/null +++ b/src/tests/ResponseMocks/MALMockMovie.json @@ -0,0 +1,30 @@ +{ + "data": [ + { + "mal_id": 2890, + "url": "https://myanimelist.net/anime/2890/Gake_no_Ue_no_Ponyo", + "title": "Gake no Ue no Ponyo", + "title_english": "Ponyo", + "type": "Movie", + "source": "Original", + "episodes": 1, + "aired": { + "from": "2008-07-19T00:00:00+00:00", + "to": null, + "prop": { + "from": { + "day": 19, + "month": 7, + "year": 2008 + }, + "to": { + "day": null, + "month": null, + "year": null + } + }, + "string": "Jul 19, 2008" + } + } + ] +} \ No newline at end of file diff --git a/src/tests/ResponseMocks/MusicBrainzMockResponse.json b/src/tests/ResponseMocks/MusicBrainzMockResponse.json new file mode 100644 index 0000000..7ca66fe --- /dev/null +++ b/src/tests/ResponseMocks/MusicBrainzMockResponse.json @@ -0,0 +1,49 @@ +{ + "created": "2022-09-16T13:51:15.522Z", + "count": 921, + "offset": 0, + "release-groups": [ + { + "id": "9cf08bf9-1948-4087-abe1-783210ea1fae", + "type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc", + "score": 100, + "primary-type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc", + "count": 1, + "title": "Halo Halo", + "first-release-date": "2013-07-08", + "primary-type": "Album", + "artist-credit": [ + { + "name": "Halo Halo", + "artist": { + "id": "177d61ad-7e38-4bb5-a53c-8dd4e4ab9566", + "name": "Halo Halo", + "sort-name": "Halo Halo" + } + } + ], + "releases": [ + { + "id": "58dd1d57-2201-472e-9e36-5d497dcedb6f", + "status-id": "4e304316-386d-3409-af2e-78857eec5cfe", + "title": "Halo Halo", + "status": "Official" + } + ], + "tags": [ + { + "count": 1, + "name": "dance" + }, + { + "count": 1, + "name": "pop" + }, + { + "count": 1, + "name": "punk" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/tests/ResponseMocks/OMDBMockResponse.json b/src/tests/ResponseMocks/OMDBMockResponse.json new file mode 100644 index 0000000..28f96fd --- /dev/null +++ b/src/tests/ResponseMocks/OMDBMockResponse.json @@ -0,0 +1,13 @@ +{ + "Search": [ + { + "Title": "Guardians of the Galaxy", + "Year": "2014", + "imdbID": "tt2015381", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg" + } + ], + "totalResults": "1", + "Response": "True" +} \ No newline at end of file diff --git a/src/tests/ResponseMocks/SteamAPIMockResponse.json b/src/tests/ResponseMocks/SteamAPIMockResponse.json new file mode 100644 index 0000000..c9796ec --- /dev/null +++ b/src/tests/ResponseMocks/SteamAPIMockResponse.json @@ -0,0 +1,14 @@ +{ + "applist": { + "apps": [ + { + "appid": 2076590, + "name": "Hooking Season Playtest" + }, + { + "appid": 2076600, + "name": "MonsterTamer" + } + ] + } +} \ No newline at end of file diff --git a/src/tests/ResponseMocks/WikipediaMockResponse.json b/src/tests/ResponseMocks/WikipediaMockResponse.json new file mode 100644 index 0000000..64bd473 --- /dev/null +++ b/src/tests/ResponseMocks/WikipediaMockResponse.json @@ -0,0 +1,20 @@ +{ + "query": { + "searchinfo": { + "totalhits": 1199001, + "suggestion": "book", + "suggestionsnippet": "book" + }, + "search": [ + { + "ns": 0, + "title": "Book", + "pageid": 3778, + "size": 68829, + "wordcount": 8821, + "snippet": "called books or chapters or parts, are parts. The intellectual content in a physical book need not be a composition, nor even be called a book. Books can", + "timestamp": "2022-08-19T19:13:56Z" + } + ] + } +} \ No newline at end of file From 00647d370e6ffda6efc2ed4676174e0734c2816c Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:39:41 +0530 Subject: [PATCH 08/43] test: add mock helper methods for setting mocks --- src/tests/mockHelpers.ts | 87 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/tests/mockHelpers.ts diff --git a/src/tests/mockHelpers.ts b/src/tests/mockHelpers.ts new file mode 100644 index 0000000..df4755a --- /dev/null +++ b/src/tests/mockHelpers.ts @@ -0,0 +1,87 @@ +import { GameModel } from "../models/GameModel"; +import { MovieModel } from '../models/MovieModel'; +import { MusicReleaseModel } from "../models/MusicReleaseModel"; +import { WikiModel } from '../models/WikiModel'; +import { MediaType } from "../utils/MediaType"; +import { apiMock } from "./ParameterizedAPI.test"; +import MALMockMovie from "./ResponseMocks/MALMockMovie.json"; +import MusicBrainzResponseMock from "./ResponseMocks/MusicBrainzMockResponse.json"; +import OMDBMockMovie from "./ResponseMocks/OMDBMockResponse.json"; +import SteamAPIResponseMock from "./ResponseMocks/SteamAPIMockResponse.json"; +import WikipediaMockResponse from "./ResponseMocks/WikipediaMockResponse.json"; + +export function setWikipediaResponseMock() { + let ret = []; + let wikiresponse = WikipediaMockResponse.query.search[0]; + ret.push(new WikiModel({ + type: 'wiki', + title: wikiresponse.title, + englishTitle: wikiresponse.title, + year: '', + dataSource: apiMock.apiName, + id: wikiresponse.pageid, + })); + return ret; +} + +export function setOMDbResponseMock() { + let ret = []; + let omdbresponse = OMDBMockMovie.Search[0]; + ret.push(new MovieModel({ + type: 'wiki', + title: omdbresponse.Title, + englishTitle: omdbresponse.Title, + year: omdbresponse.Year, + dataSource: apiMock.apiName, + id: omdbresponse.imdbID, + })); + return ret; +} + +export function setMALResponseMock() { + let ret = []; + let result = MALMockMovie.data[0]; + ret.push(new MovieModel({ + type: result.type, + title: result.title, + englishTitle: result.title_english, + year: result.aired.prop.from.year, + dataSource: apiMock.apiName, + id: result.mal_id, + })); + return ret; +} + +export function setSteamResponseMock() { + let ret = []; + let steamResponse = SteamAPIResponseMock.applist.apps[0]; + ret.push( + new GameModel({ + type: MediaType.Game, + title: steamResponse.name, + englishTitle: steamResponse.name, + year: '', + dataSource: apiMock.apiName, + id: steamResponse.appid, + }) + ) + return ret; +} + +export function setMusicBrainzResponseMock() { + let ret = []; + let result = MusicBrainzResponseMock["release-groups"][0]; + ret.push(new MusicReleaseModel({ + type: 'musicRelease', + title: result.title, + englishTitle: result.title, + year: (new Date(result['first-release-date'])).getFullYear().toString(), + dataSource: apiMock.apiName, + url: '', + id: result.id, + + artists: result['artist-credit'].map((a: any) => a.name), + subType: result['primary-type'], + } as MusicReleaseModel)); + return ret; +} From 395bad135bd95d50b7e22ef3824d7b7c3193a52f Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:43:56 +0530 Subject: [PATCH 09/43] feat: set config for jest - Allows using JSON as objects - Allows jest to resolve node_modules --- tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tsconfig.json b/tsconfig.json index 1383e2f..732e408 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,8 @@ "moduleResolution": "node", "importHelpers": true, "isolatedModules": true, + "esModuleInterop": true, + "resolveJsonModule": true, "lib": [ "DOM", "ES5", From 8accba7da6a69c59a03c76ebc389ef172b80ccdc Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:44:33 +0530 Subject: [PATCH 10/43] test: add mock requestUrl method by @Fevol --- __mocks__/obsidian.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 __mocks__/obsidian.ts diff --git a/__mocks__/obsidian.ts b/__mocks__/obsidian.ts new file mode 100644 index 0000000..08af600 --- /dev/null +++ b/__mocks__/obsidian.ts @@ -0,0 +1,32 @@ +import { RequestUrlParam, RequestUrlResponse } from "obsidian"; + +export function requestUrl(request: RequestUrlParam): Promise { + return fetch(request.url, { + method: request.method, + headers: request.headers, + body: request.body, + }).then(async (response) => { + if (response.status >= 400 && request.throw) { + throw new Error(`Request failed, ${response.status}`); + } + + // Turn response headers into Record object + const headers: Record = {}; + response.headers.forEach((value, key) => { + headers[key] = value; + }); + + const arraybuffer = await response.arrayBuffer(); + const text = arraybuffer ? new TextDecoder().decode(arraybuffer) : ''; + const json = text ? JSON.parse(text) : {}; + + let response_body: RequestUrlResponse = { + status: response.status, + headers: headers, + arrayBuffer: arraybuffer, + json: json, + text: text, + }; + return response_body; + }); +} \ No newline at end of file From 002f28a02b4109705851453c0e1ce020a4fc30de Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:44:50 +0530 Subject: [PATCH 11/43] test: add jest config --- jest.config.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 jest.config.js diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..332efa0 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,13 @@ +module.exports = { + "roots": [ + "/src", + "" + ], + "testMatch": [ + "**/__tests__/**/*.+(ts|tsx|js)", + "**/?(*.)+(spec|test).+(ts|tsx|js)" + ], + "transform": { + "^.+\\.(ts|tsx)$": "ts-jest" + }, +} \ No newline at end of file From 801991213d417ea902cfe21b46ac85979d7b458c Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:45:24 +0530 Subject: [PATCH 12/43] test: add generic test suite implementation --- src/tests/ParameterizedAPI.test.ts | 91 ++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/src/tests/ParameterizedAPI.test.ts b/src/tests/ParameterizedAPI.test.ts index 0e5e7d1..bf1703e 100644 --- a/src/tests/ParameterizedAPI.test.ts +++ b/src/tests/ParameterizedAPI.test.ts @@ -1,17 +1,21 @@ -import { enableFetchMocks } from 'jest-fetch-mock'; -import fetchMock from 'jest-fetch-mock'; -import { OMDbAPI } from '../api/apis/OMDbAPI'; -import MediaDbPlugin from '../main'; +import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; import { MediaDbPluginSettings } from 'src/settings/Settings'; -import { MALAPI } from '../api/apis/MALAPI'; import { LocGovAPI } from '../api/apis/LocGovAPI'; +import { MALAPI } from '../api/apis/MALAPI'; import { MusicBrainzAPI } from '../api/apis/MusicBrainzAPI'; +import { OMDbAPI } from '../api/apis/OMDbAPI'; import { SteamAPI } from '../api/apis/SteamAPI'; import { WikipediaAPI } from '../api/apis/WikipediaAPI'; +import MediaDbPlugin from '../main'; +import { setMALResponseMock, setMusicBrainzResponseMock, setOMDbResponseMock, setSteamResponseMock, setWikipediaResponseMock } from "./mockHelpers"; +import MALMockMovie from "./ResponseMocks/MALMockMovie.json"; +import MusicBrainzResponseMock from "./ResponseMocks/MusicBrainzMockResponse.json"; +import OMDBMockMovie from "./ResponseMocks/OMDBMockResponse.json"; +import SteamAPIResponseMock from "./ResponseMocks/SteamAPIMockResponse.json"; +import WikipediaMockResponse from "./ResponseMocks/WikipediaMockResponse.json"; -enableFetchMocks() -let apiMock: OMDbAPI | MALAPI | LocGovAPI | MusicBrainzAPI | SteamAPI | WikipediaAPI; -let api: typeof OMDbAPI | typeof MALAPI | typeof LocGovAPI | typeof MusicBrainzAPI | typeof SteamAPI | typeof WikipediaAPI; +enableFetchMocks(); +export let apiMock: OMDbAPI | MALAPI | LocGovAPI | MusicBrainzAPI | SteamAPI | WikipediaAPI; describe.each( [ @@ -24,12 +28,10 @@ describe.each( ] )('$name.name', ({ name: parameterizedApi }) => { beforeAll(() => { - api = parameterizedApi; - let settingsMock: MediaDbPluginSettings = { - } as MediaDbPluginSettings; + let settingsMock: MediaDbPluginSettings = {} as MediaDbPluginSettings; let pluginMock = {} as MediaDbPlugin; pluginMock.settings = settingsMock; - // TODO: add fake API key + // TODO: add fake API key? apiMock = new parameterizedApi(pluginMock); }) @@ -37,31 +39,72 @@ describe.each( fetchMock.resetMocks(); }) - test("searchByTitle behavior when given garbage data", async () => { + test("searchByTitle behavior when API returns garbage data", async () => { const garbageResponse = JSON.stringify({ data: "string" }); fetchMock.mockResponseOnce(garbageResponse) - let res; - // LocGovAPI throws an error because not implemented - if (parameterizedApi.name === "LocGovAPI") { - await expect(apiMock.searchByTitle("sample")).rejects.toThrow(); - - } else { - res = await apiMock.searchByTitle("sample"); - expect(res).toEqual([]); - } + await expect(apiMock.searchByTitle("sample")).resolves.toEqual([]); + // } expect(fetch).toHaveBeenCalledTimes(1); }); - test("searchByTitle when fetch returns 401", async () => { + test("searchByTitle behavior when requestUrl/fetch returns 401", async () => { let sampleResponse = { data: "string" }; fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); // TODO: Check API name and fix message // TODO: Externalize string - await expect(async () => await apiMock.searchByTitle("sample")).rejects.toThrow(); + await expect(apiMock.searchByTitle("sample")).rejects.toThrow(`MDB | Received status code ${401} from an API.`); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); + + test("searchByTitle behavior when requestUrl/fetch returns 403", async () => { + let sampleResponse = { + data: "string" + }; + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 403 }); + // TODO: Check API name and fix message + // TODO: Externalize string/import? + await expect(apiMock.searchByTitle("sample")).rejects.toThrow(`MDB | Received status code ${403} from an API.`); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); + + test("searchByTitle behavior when requestUrl/fetch returns 200", async () => { + let sampleResponse; + let ret; + switch (parameterizedApi) { + case OMDbAPI: + ret = setOMDbResponseMock(); + sampleResponse = OMDBMockMovie; + break; + case WikipediaAPI: + ret = setWikipediaResponseMock(); + sampleResponse = WikipediaMockResponse; + break; + case MALAPI: + // TODO: MAL needs more tests for different types of content + ret = setMALResponseMock(); + sampleResponse = MALMockMovie; + case LocGovAPI: + // TODO: Add soon + break; + case SteamAPI: + sampleResponse = SteamAPIResponseMock; + ret = setSteamResponseMock(); + break; + case MusicBrainzAPI: + sampleResponse = MusicBrainzResponseMock; + ret = setMusicBrainzResponseMock(); + break; + default: + throw Error(); + } + fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 200 }); + // TODO: Check API name and fix message + // TODO: Externalize string + await expect(apiMock.searchByTitle("Hooking Season Playtest")).resolves.toEqual(ret); expect(fetchMock).toHaveBeenCalledTimes(1); }); }) \ No newline at end of file From 89db1a2009e4460407d3911d43cbc054b0750949 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:54:41 +0530 Subject: [PATCH 13/43] test: remove singular test suites --- src/tests/OMDbAPI.test.js | 101 -------------------------------- src/tests/OMDbAPI.test.ts | 103 --------------------------------- src/tests/WikipediaAPI.test.ts | 95 ------------------------------ 3 files changed, 299 deletions(-) delete mode 100644 src/tests/OMDbAPI.test.js delete mode 100644 src/tests/OMDbAPI.test.ts delete mode 100644 src/tests/WikipediaAPI.test.ts diff --git a/src/tests/OMDbAPI.test.js b/src/tests/OMDbAPI.test.js deleted file mode 100644 index 816a522..0000000 --- a/src/tests/OMDbAPI.test.js +++ /dev/null @@ -1,101 +0,0 @@ -require('jest-fetch-mock').enableMocks() - -let OMDbApiInstance; - -beforeEach(() => { - fetchMock.resetMocks(); - let OMDbAPI = require("../api/apis/OMDbAPI").OMDbAPI; - let MediaDbPluginMock = {}; - MediaDbPluginMock = { - settings: { - OMDbKey: "string" - } - }; - OMDbApiInstance = new OMDbAPI(MediaDbPluginMock); -}) - -test("searchByTitle behavior when given garbage data", async () => { - fetchMock.mockResponseOnce(JSON.stringify({ - data: "string" - })) - let res = await OMDbApiInstance.searchByTitle("sample"); - expect(res).toEqual([]); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle when fetch returns 401", async () => { - let sampleResponse = { - data: "string" - }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); - // TODO: Check API name and fix message - // TODO: Externalize string - await expect(async () => await OMDbApiInstance.searchByTitle("sample")).rejects.toThrowError("MDB | Authentication for OMDbAPI failed. Check the API key."); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle when fetch returns other non-200", async () => { - let sampleResponse = { - data: "string" - }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 400 }); - await expect(async () => await OMDbApiInstance.searchByTitle("sample")).rejects.toThrow(); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle with successful request and valid response", async () => { - let response = { - "Search": [ - { - "Title": "Guardians of the Galaxy", - "Year": "2014", - "imdbID": "tt2015381", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg" - }, - { - "Title": "Guardians of the Galaxy Vol. 2", - "Year": "2017", - "imdbID": "tt3896198", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BNjM0NTc0NzItM2FlYS00YzEwLWE0YmUtNTA2ZWIzODc2OTgxXkEyXkFqcGdeQXVyNTgwNzIyNzg@._V1_SX300.jpg" - }, - { - "Title": "Guardians of the Galaxy: Inferno", - "Year": "2017", - "imdbID": "tt7131308", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BZGQ0YzEyNWQtNGJiMi00NTAxLThkNDctNGY2ODkzYWMxZmZkXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg" - }, - { - "Title": "LEGO Marvel Super Heroes - Guardians of the Galaxy: The Thanos Threat", - "Year": "2017", - "imdbID": "tt7387224", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BMjhlYzVhNTMtMmFkYy00NDhiLTkyNDgtYzhhMTZiMzM2OTA5XkEyXkFqcGdeQXVyNjI2OTgxNzY@._V1_SX300.jpg" - }, - ], - "totalResults": "4", - "Response": "True" - } - fetchMock.mockResponse(JSON.stringify(response)); - let ret = []; - - // import { MovieModel } from '../models/MovieModel'; - // const MovieModel = require('../models/MovieModel') - for (const result of response.Search) { - ret.push({ - type: 'movie', - title: result.Title, - englishTitle: result.Title, - year: result.Year, - dataSource: 'OMDbAPI', - id: result.imdbID, - }); - } - - let dt = await OMDbApiInstance.searchByTitle("Jackson"); - expect(dt).toEqual(ret); - -}) - diff --git a/src/tests/OMDbAPI.test.ts b/src/tests/OMDbAPI.test.ts deleted file mode 100644 index 9db5663..0000000 --- a/src/tests/OMDbAPI.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { enableFetchMocks } from 'jest-fetch-mock'; -import fetchMock from 'jest-fetch-mock'; -import { OMDbAPI } from '../api/apis/OMDbAPI'; -import { MovieModel } from '../models/MovieModel'; -import { MediaTypeModel } from '../models/MediaTypeModel'; -import MediaDbPlugin from '../main'; -import { MediaDbPluginSettings } from 'src/settings/Settings'; - -enableFetchMocks() -let OMDbApiMock: OMDbAPI; - -beforeEach(() => { - fetchMock.resetMocks(); - let settingsMock: MediaDbPluginSettings = { - OMDbKey: "string" - } as MediaDbPluginSettings; - let pluginMock: MediaDbPlugin = {} as MediaDbPlugin; - pluginMock.settings = settingsMock; - OMDbApiMock = new OMDbAPI(pluginMock); -}) - -test("searchByTitle behavior when given garbage data", async () => { - fetchMock.mockResponseOnce(JSON.stringify({ - data: "string" - })) - let res = await OMDbApiMock.searchByTitle("sample"); - expect(res).toEqual([]); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle when fetch returns 401", async () => { - let sampleResponse = { - data: "string" - }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); - // TODO: Check API name and fix message - // TODO: Externalize string - await expect(async () => await OMDbApiMock.searchByTitle("sample")).rejects.toThrowError("MDB | Authentication for OMDbAPI failed. Check the API key."); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle when fetch returns other non-200", async () => { - let sampleResponse = { - data: "string" - }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 400 }); - await expect(async () => await OMDbApiMock.searchByTitle("sample")).rejects.toThrow(); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle with successful request and valid response", async () => { - let response = { - "Search": [ - { - "Title": "Guardians of the Galaxy", - "Year": "2014", - "imdbID": "tt2015381", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg" - }, - { - "Title": "Guardians of the Galaxy Vol. 2", - "Year": "2017", - "imdbID": "tt3896198", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BNjM0NTc0NzItM2FlYS00YzEwLWE0YmUtNTA2ZWIzODc2OTgxXkEyXkFqcGdeQXVyNTgwNzIyNzg@._V1_SX300.jpg" - }, - { - "Title": "Guardians of the Galaxy: Inferno", - "Year": "2017", - "imdbID": "tt7131308", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BZGQ0YzEyNWQtNGJiMi00NTAxLThkNDctNGY2ODkzYWMxZmZkXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX300.jpg" - }, - { - "Title": "LEGO Marvel Super Heroes - Guardians of the Galaxy: The Thanos Threat", - "Year": "2017", - "imdbID": "tt7387224", - "Type": "movie", - "Poster": "https://m.media-amazon.com/images/M/MV5BMjhlYzVhNTMtMmFkYy00NDhiLTkyNDgtYzhhMTZiMzM2OTA5XkEyXkFqcGdeQXVyNjI2OTgxNzY@._V1_SX300.jpg" - }, - ], - "totalResults": "4", - "Response": "True" - } - fetchMock.mockResponse(JSON.stringify(response)); - let ret: MediaTypeModel[] = []; - - for (const result of response.Search) { - ret.push(new MovieModel({ - type: 'wiki', - title: result.Title, - englishTitle: result.Title, - year: result.Year, - dataSource: 'OMDbAPI', - id: result.imdbID, - } as unknown as MovieModel)); - } - let dt = await OMDbApiMock.searchByTitle("Jackson"); - expect(dt).toStrictEqual(ret); - -}) - diff --git a/src/tests/WikipediaAPI.test.ts b/src/tests/WikipediaAPI.test.ts deleted file mode 100644 index 9696347..0000000 --- a/src/tests/WikipediaAPI.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { enableFetchMocks } from 'jest-fetch-mock'; -import fetchMock from 'jest-fetch-mock'; -import { WikipediaAPI } from '../api/apis/WikipediaAPI'; -import { WikiModel } from '../models/WikiModel'; -import { MediaTypeModel } from '../models/MediaTypeModel'; - -enableFetchMocks() -let wikiInstance: WikipediaAPI; - -beforeEach(() => { - fetchMock.resetMocks(); - wikiInstance = new WikipediaAPI(new (jest.fn())()); -}) - -test("searchByTitle behavior when given garbage data", async () => { - fetchMock.mockResponseOnce(JSON.stringify({ - data: "string" - })) - await expect(async () => await wikiInstance.searchByTitle("sample")).rejects.toThrow(); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle when fetch returns non-200", async () => { - let sampleResponse = { - data: "string" - }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), {status: 400}); - await expect(async () => await wikiInstance.searchByTitle("sample")).rejects.toThrow(); - expect(fetchMock).toHaveBeenCalledTimes(1); -}); - -test("searchByTitle with successful request and valid response", async () => { - let response = { - "batchcomplete": "", - "continue": { - "sroffset": 20, - "continue": "-||" - }, - "query": { - "searchinfo": { - "totalhits": 214380 - }, - "search": [ - { - "ns": 0, - "title": "Jackson", - "pageid": 15772, - "size": 3524, - "wordcount": 392, - "timestamp": "2022-06-16T07:22:28Z" - }, - { - "ns": 0, - "title": "Michael Jackson", - "pageid": 14995351, - "size": 257103, - "wordcount": 23309, - "timestamp": "2022-06-29T01:15:25Z" - }, - { - "ns": 0, - "title": "Andrew Jackson", - "pageid": 1623, - "size": 200137, - "wordcount": 22743, - "timestamp": "2022-07-03T17:53:13Z" - }, - { - "ns": 0, - "title": "Janet Jackson", - "pageid": 60070, - "size": 206594, - "wordcount": 21067, - "timestamp": "2022-06-24T19:40:30Z" - } - ] - } - }; - fetchMock.mockResponse(JSON.stringify(response)); - let ret: MediaTypeModel[] = []; - - for (const result of response.query.search) { - ret.push(new WikiModel({ - type: 'wiki', - title: result.title, - englishTitle: result.title, - year: '', - dataSource: 'Wikipedia API', - id: result.pageid, - } as unknown as WikiModel)); - } - let dt = await wikiInstance.searchByTitle("Jackson"); - expect(dt).toStrictEqual(ret); - -}) From 97ed243ea851e9ea284691508f749faa1e56912f Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 17 Sep 2022 16:08:38 +0530 Subject: [PATCH 14/43] test: shorten MusicBrainz mock --- .../MusicBrainzMockResponse.json | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/src/tests/ResponseMocks/MusicBrainzMockResponse.json b/src/tests/ResponseMocks/MusicBrainzMockResponse.json index 7ca66fe..02a81ec 100644 --- a/src/tests/ResponseMocks/MusicBrainzMockResponse.json +++ b/src/tests/ResponseMocks/MusicBrainzMockResponse.json @@ -1,14 +1,8 @@ { - "created": "2022-09-16T13:51:15.522Z", - "count": 921, - "offset": 0, "release-groups": [ { "id": "9cf08bf9-1948-4087-abe1-783210ea1fae", - "type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc", - "score": 100, "primary-type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc", - "count": 1, "title": "Halo Halo", "first-release-date": "2013-07-08", "primary-type": "Album", @@ -16,32 +10,14 @@ { "name": "Halo Halo", "artist": { - "id": "177d61ad-7e38-4bb5-a53c-8dd4e4ab9566", - "name": "Halo Halo", - "sort-name": "Halo Halo" + "name": "Halo Halo" } } ], "releases": [ { "id": "58dd1d57-2201-472e-9e36-5d497dcedb6f", - "status-id": "4e304316-386d-3409-af2e-78857eec5cfe", - "title": "Halo Halo", - "status": "Official" - } - ], - "tags": [ - { - "count": 1, - "name": "dance" - }, - { - "count": 1, - "name": "pop" - }, - { - "count": 1, - "name": "punk" + "title": "Halo Halo" } ] } From da16b2af6ae0c11335fd3d60d5ef4c3a0fa028ed Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Thu, 22 Sep 2022 13:55:16 +0200 Subject: [PATCH 15/43] Clean-up after merge --- package-lock.json | 4 +- package.json | 2 +- src/api/apis/BoardGameGeekAPI.ts | 26 +++--- src/main.ts | 8 +- src/modals/MediaDbAdvancedSearchModal.ts | 6 +- src/modals/MediaDbIdSearchModal.ts | 4 +- src/models/MusicReleaseModel.ts | 4 +- src/tests/ParameterizedAPI.test.ts | 80 +++++++++---------- .../MusicBrainzMockResponse.json | 48 +++++------ src/tests/ResponseMocks/OMDBMockResponse.json | 4 +- .../ResponseMocks/SteamAPIMockResponse.json | 26 +++--- .../ResponseMocks/WikipediaMockResponse.json | 38 ++++----- src/tests/mockHelpers.ts | 64 +++++++-------- src/tests/utils.test.ts | 29 ++++--- src/utils/Utils.ts | 5 +- 15 files changed, 177 insertions(+), 171 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b4e6d1..c15d2d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-media-db-plugin", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-media-db-plugin", - "version": "0.3.0", + "version": "0.3.1", "license": "GPL-3.0", "dependencies": { "ts-node": "^10.8.1", diff --git a/package.json b/package.json index e2a88d0..6e5a9db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-media-db-plugin", - "version": "0.3.1", + "version": "0.3.2", "description": "A plugin that can query multiple APIs for movies, series, anime, games, music and wiki articles, and import them into your vault.", "main": "main.js", "scripts": { diff --git a/src/api/apis/BoardGameGeekAPI.ts b/src/api/apis/BoardGameGeekAPI.ts index 174bbff..4996eb6 100644 --- a/src/api/apis/BoardGameGeekAPI.ts +++ b/src/api/apis/BoardGameGeekAPI.ts @@ -32,16 +32,16 @@ export class BoardGameGeekAPI extends APIModel { } const data = fetchData.text; - const response = new window.DOMParser().parseFromString(data, "text/xml") + const response = new window.DOMParser().parseFromString(data, 'text/xml'); debugLog(response); let ret: MediaTypeModel[] = []; - for (const boardgame of Array.from(response.querySelectorAll("boardgame"))) { - const id = boardgame.attributes.getNamedItem("objectid")!.value; - const title = boardgame.querySelector("name")!.textContent!; - const year = boardgame.querySelector("yearpublished")?.textContent ?? ""; + for (const boardgame of Array.from(response.querySelectorAll('boardgame'))) { + const id = boardgame.attributes.getNamedItem('objectid')!.value; + const title = boardgame.querySelector('name')!.textContent!; + const year = boardgame.querySelector('yearpublished')?.textContent ?? ''; ret.push(new BoardGameModel({ dataSource: this.apiName, @@ -68,21 +68,21 @@ export class BoardGameGeekAPI extends APIModel { } const data = fetchData.text; - const response = new window.DOMParser().parseFromString(data, "text/xml") + const response = new window.DOMParser().parseFromString(data, 'text/xml'); debugLog(response); - const boardgame = response.querySelector("boardgame")!; - const title = boardgame.querySelector("name")!.textContent!; - const year = boardgame.querySelector("yearpublished")?.textContent ?? ""; - const image = boardgame.querySelector("image")?.textContent ?? undefined; - const onlineRating = Number.parseFloat(boardgame.querySelector("statistics ratings average")?.textContent ?? ""); - const genres = Array.from(boardgame.querySelectorAll("boardgamecategory")).map(n => n!.textContent!); + const boardgame = response.querySelector('boardgame')!; + const title = boardgame.querySelector('name')!.textContent!; + const year = boardgame.querySelector('yearpublished')?.textContent ?? ''; + const image = boardgame.querySelector('image')?.textContent ?? undefined; + const onlineRating = Number.parseFloat(boardgame.querySelector('statistics ratings average')?.textContent ?? ''); + const genres = Array.from(boardgame.querySelectorAll('boardgamecategory')).map(n => n!.textContent!); const model = new BoardGameModel({ type: MediaType.BoardGame, title, englishTitle: title, - year: year === "0" ? "" : year, + year: year === '0' ? '' : year, dataSource: this.apiName, url: `https://boardgamegeek.com/boardgame/${id}`, id, diff --git a/src/main.ts b/src/main.ts index aba9251..218dddb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -305,7 +305,7 @@ export default class MediaDbPlugin extends Plugin { const erroredFiles: { filePath: string, error: string }[] = []; let canceled: boolean = false; - const {selectedAPI, titleFieldName, appendContent} = await new Promise<{selectedAPI: string, titleFieldName: string, appendContent: boolean}>((resolve, reject) => { + const {selectedAPI, titleFieldName, appendContent} = await new Promise<{ selectedAPI: string, titleFieldName: string, appendContent: boolean }>((resolve, reject) => { new MediaDbFolderImportModal(this.app, this, ((selectedAPI: string, titleFieldName: string, appendContent: boolean) => { resolve({selectedAPI, titleFieldName, appendContent}); })).open(); @@ -402,7 +402,7 @@ export default class MediaDbPlugin extends Plugin { if (err) { return reject(err); } - resolve(res) + resolve(res); }).open(); }); } @@ -413,7 +413,7 @@ export default class MediaDbPlugin extends Plugin { if (err) { return reject(err); } - resolve(res) + resolve(res); }).open(); }); } @@ -426,7 +426,7 @@ export default class MediaDbPlugin extends Plugin { } resolve(res); }, () => { - resolve([]) + resolve([]); }).open(); }); } diff --git a/src/modals/MediaDbAdvancedSearchModal.ts b/src/modals/MediaDbAdvancedSearchModal.ts index c463f4c..246590b 100644 --- a/src/modals/MediaDbAdvancedSearchModal.ts +++ b/src/modals/MediaDbAdvancedSearchModal.ts @@ -8,10 +8,10 @@ export class MediaDbAdvancedSearchModal extends Modal { isBusy: boolean; plugin: MediaDbPlugin; searchBtn: ButtonComponent; - selectedApis: {name: string, selected: boolean}[]; - onSubmit: (res: {query: string, apis: string[]}, err?: Error) => void; + selectedApis: { name: string, selected: boolean }[]; + onSubmit: (res: { query: string, apis: string[] }, err?: Error) => void; - constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (res: {query: string, apis: string[]}, err?: Error) => void) { + constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (res: { query: string, apis: string[] }, err?: Error) => void) { super(app); this.plugin = plugin; this.onSubmit = onSubmit; diff --git a/src/modals/MediaDbIdSearchModal.ts b/src/modals/MediaDbIdSearchModal.ts index 87fb4ce..19b3d58 100644 --- a/src/modals/MediaDbIdSearchModal.ts +++ b/src/modals/MediaDbIdSearchModal.ts @@ -9,9 +9,9 @@ export class MediaDbIdSearchModal extends Modal { plugin: MediaDbPlugin; searchBtn: ButtonComponent; selectedApi: string; - onSubmit: (res: {query: string, api: string}, err?: Error) => void; + onSubmit: (res: { query: string, api: string }, err?: Error) => void; - constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (res: {query: string, api: string}, err?: Error) => void) { + constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (res: { query: string, api: string }, err?: Error) => void) { super(app); this.plugin = plugin; this.onSubmit = onSubmit; diff --git a/src/models/MusicReleaseModel.ts b/src/models/MusicReleaseModel.ts index 9aa03bf..2d134b6 100644 --- a/src/models/MusicReleaseModel.ts +++ b/src/models/MusicReleaseModel.ts @@ -39,8 +39,8 @@ export class MusicReleaseModel extends MediaTypeModel { getSummary(): string { var summary = this.title + ' (' + this.year + ')'; - if(this.artists.length > 0) - summary += ' - ' + this.artists.join(', ') + if (this.artists.length > 0) + summary += ' - ' + this.artists.join(', '); return summary; } } diff --git a/src/tests/ParameterizedAPI.test.ts b/src/tests/ParameterizedAPI.test.ts index bf1703e..72b2549 100644 --- a/src/tests/ParameterizedAPI.test.ts +++ b/src/tests/ParameterizedAPI.test.ts @@ -1,77 +1,77 @@ -import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -import { MediaDbPluginSettings } from 'src/settings/Settings'; -import { LocGovAPI } from '../api/apis/LocGovAPI'; -import { MALAPI } from '../api/apis/MALAPI'; -import { MusicBrainzAPI } from '../api/apis/MusicBrainzAPI'; -import { OMDbAPI } from '../api/apis/OMDbAPI'; -import { SteamAPI } from '../api/apis/SteamAPI'; -import { WikipediaAPI } from '../api/apis/WikipediaAPI'; +import fetchMock, {enableFetchMocks} from 'jest-fetch-mock'; +import {MediaDbPluginSettings} from 'src/settings/Settings'; +import {LocGovAPI} from '../api/apis/LocGovAPI'; +import {MALAPI} from '../api/apis/MALAPI'; +import {MusicBrainzAPI} from '../api/apis/MusicBrainzAPI'; +import {OMDbAPI} from '../api/apis/OMDbAPI'; +import {SteamAPI} from '../api/apis/SteamAPI'; +import {WikipediaAPI} from '../api/apis/WikipediaAPI'; import MediaDbPlugin from '../main'; -import { setMALResponseMock, setMusicBrainzResponseMock, setOMDbResponseMock, setSteamResponseMock, setWikipediaResponseMock } from "./mockHelpers"; -import MALMockMovie from "./ResponseMocks/MALMockMovie.json"; -import MusicBrainzResponseMock from "./ResponseMocks/MusicBrainzMockResponse.json"; -import OMDBMockMovie from "./ResponseMocks/OMDBMockResponse.json"; -import SteamAPIResponseMock from "./ResponseMocks/SteamAPIMockResponse.json"; -import WikipediaMockResponse from "./ResponseMocks/WikipediaMockResponse.json"; +import {setMALResponseMock, setMusicBrainzResponseMock, setOMDbResponseMock, setSteamResponseMock, setWikipediaResponseMock} from './mockHelpers'; +import MALMockMovie from './ResponseMocks/MALMockMovie.json'; +import MusicBrainzResponseMock from './ResponseMocks/MusicBrainzMockResponse.json'; +import OMDBMockMovie from './ResponseMocks/OMDBMockResponse.json'; +import SteamAPIResponseMock from './ResponseMocks/SteamAPIMockResponse.json'; +import WikipediaMockResponse from './ResponseMocks/WikipediaMockResponse.json'; enableFetchMocks(); export let apiMock: OMDbAPI | MALAPI | LocGovAPI | MusicBrainzAPI | SteamAPI | WikipediaAPI; describe.each( [ - { name: OMDbAPI }, - { name: MALAPI }, - { name: LocGovAPI }, - { name: MusicBrainzAPI }, - { name: SteamAPI }, - { name: WikipediaAPI } - ] -)('$name.name', ({ name: parameterizedApi }) => { + {name: OMDbAPI}, + {name: MALAPI}, + {name: LocGovAPI}, + {name: MusicBrainzAPI}, + {name: SteamAPI}, + {name: WikipediaAPI}, + ], +)('$name.name', ({name: parameterizedApi}) => { beforeAll(() => { let settingsMock: MediaDbPluginSettings = {} as MediaDbPluginSettings; let pluginMock = {} as MediaDbPlugin; pluginMock.settings = settingsMock; // TODO: add fake API key? apiMock = new parameterizedApi(pluginMock); - }) + }); beforeEach(() => { fetchMock.resetMocks(); - }) + }); - test("searchByTitle behavior when API returns garbage data", async () => { + test('searchByTitle behavior when API returns garbage data', async () => { const garbageResponse = JSON.stringify({ - data: "string" + data: 'string', }); - fetchMock.mockResponseOnce(garbageResponse) - await expect(apiMock.searchByTitle("sample")).resolves.toEqual([]); + fetchMock.mockResponseOnce(garbageResponse); + await expect(apiMock.searchByTitle('sample')).resolves.toEqual([]); // } expect(fetch).toHaveBeenCalledTimes(1); }); - test("searchByTitle behavior when requestUrl/fetch returns 401", async () => { + test('searchByTitle behavior when requestUrl/fetch returns 401', async () => { let sampleResponse = { - data: "string" + data: 'string', }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 }); + fetchMock.mockResponse(JSON.stringify(sampleResponse), {status: 401}); // TODO: Check API name and fix message // TODO: Externalize string - await expect(apiMock.searchByTitle("sample")).rejects.toThrow(`MDB | Received status code ${401} from an API.`); + await expect(apiMock.searchByTitle('sample')).rejects.toThrow(`MDB | Received status code ${401} from an API.`); expect(fetchMock).toHaveBeenCalledTimes(1); }); - test("searchByTitle behavior when requestUrl/fetch returns 403", async () => { + test('searchByTitle behavior when requestUrl/fetch returns 403', async () => { let sampleResponse = { - data: "string" + data: 'string', }; - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 403 }); + fetchMock.mockResponse(JSON.stringify(sampleResponse), {status: 403}); // TODO: Check API name and fix message // TODO: Externalize string/import? - await expect(apiMock.searchByTitle("sample")).rejects.toThrow(`MDB | Received status code ${403} from an API.`); + await expect(apiMock.searchByTitle('sample')).rejects.toThrow(`MDB | Received status code ${403} from an API.`); expect(fetchMock).toHaveBeenCalledTimes(1); }); - test("searchByTitle behavior when requestUrl/fetch returns 200", async () => { + test('searchByTitle behavior when requestUrl/fetch returns 200', async () => { let sampleResponse; let ret; switch (parameterizedApi) { @@ -101,10 +101,10 @@ describe.each( default: throw Error(); } - fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 200 }); + fetchMock.mockResponse(JSON.stringify(sampleResponse), {status: 200}); // TODO: Check API name and fix message // TODO: Externalize string - await expect(apiMock.searchByTitle("Hooking Season Playtest")).resolves.toEqual(ret); + await expect(apiMock.searchByTitle('Hooking Season Playtest')).resolves.toEqual(ret); expect(fetchMock).toHaveBeenCalledTimes(1); }); -}) \ No newline at end of file +}); diff --git a/src/tests/ResponseMocks/MusicBrainzMockResponse.json b/src/tests/ResponseMocks/MusicBrainzMockResponse.json index 02a81ec..ec89553 100644 --- a/src/tests/ResponseMocks/MusicBrainzMockResponse.json +++ b/src/tests/ResponseMocks/MusicBrainzMockResponse.json @@ -1,25 +1,25 @@ { - "release-groups": [ - { - "id": "9cf08bf9-1948-4087-abe1-783210ea1fae", - "primary-type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc", - "title": "Halo Halo", - "first-release-date": "2013-07-08", - "primary-type": "Album", - "artist-credit": [ - { - "name": "Halo Halo", - "artist": { - "name": "Halo Halo" - } - } - ], - "releases": [ - { - "id": "58dd1d57-2201-472e-9e36-5d497dcedb6f", - "title": "Halo Halo" - } - ] - } - ] -} \ No newline at end of file + "release-groups": [ + { + "id": "9cf08bf9-1948-4087-abe1-783210ea1fae", + "primary-type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc", + "title": "Halo Halo", + "first-release-date": "2013-07-08", + "primary-type": "Album", + "artist-credit": [ + { + "name": "Halo Halo", + "artist": { + "name": "Halo Halo" + } + } + ], + "releases": [ + { + "id": "58dd1d57-2201-472e-9e36-5d497dcedb6f", + "title": "Halo Halo" + } + ] + } + ] +} diff --git a/src/tests/ResponseMocks/OMDBMockResponse.json b/src/tests/ResponseMocks/OMDBMockResponse.json index 28f96fd..6f43f5b 100644 --- a/src/tests/ResponseMocks/OMDBMockResponse.json +++ b/src/tests/ResponseMocks/OMDBMockResponse.json @@ -7,7 +7,7 @@ "Type": "movie", "Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg" } - ], + ], "totalResults": "1", "Response": "True" -} \ No newline at end of file +} diff --git a/src/tests/ResponseMocks/SteamAPIMockResponse.json b/src/tests/ResponseMocks/SteamAPIMockResponse.json index c9796ec..af2fc9c 100644 --- a/src/tests/ResponseMocks/SteamAPIMockResponse.json +++ b/src/tests/ResponseMocks/SteamAPIMockResponse.json @@ -1,14 +1,14 @@ { - "applist": { - "apps": [ - { - "appid": 2076590, - "name": "Hooking Season Playtest" - }, - { - "appid": 2076600, - "name": "MonsterTamer" - } - ] - } -} \ No newline at end of file + "applist": { + "apps": [ + { + "appid": 2076590, + "name": "Hooking Season Playtest" + }, + { + "appid": 2076600, + "name": "MonsterTamer" + } + ] + } +} diff --git a/src/tests/ResponseMocks/WikipediaMockResponse.json b/src/tests/ResponseMocks/WikipediaMockResponse.json index 64bd473..7f8e91e 100644 --- a/src/tests/ResponseMocks/WikipediaMockResponse.json +++ b/src/tests/ResponseMocks/WikipediaMockResponse.json @@ -1,20 +1,20 @@ { - "query": { - "searchinfo": { - "totalhits": 1199001, - "suggestion": "book", - "suggestionsnippet": "book" - }, - "search": [ - { - "ns": 0, - "title": "Book", - "pageid": 3778, - "size": 68829, - "wordcount": 8821, - "snippet": "called books or chapters or parts, are parts. The intellectual content in a physical book need not be a composition, nor even be called a book. Books can", - "timestamp": "2022-08-19T19:13:56Z" - } - ] - } -} \ No newline at end of file + "query": { + "searchinfo": { + "totalhits": 1199001, + "suggestion": "book", + "suggestionsnippet": "book" + }, + "search": [ + { + "ns": 0, + "title": "Book", + "pageid": 3778, + "size": 68829, + "wordcount": 8821, + "snippet": "called books or chapters or parts, are parts. The intellectual content in a physical book need not be a composition, nor even be called a book. Books can", + "timestamp": "2022-08-19T19:13:56Z" + } + ] + } +} diff --git a/src/tests/mockHelpers.ts b/src/tests/mockHelpers.ts index df4755a..ec763e3 100644 --- a/src/tests/mockHelpers.ts +++ b/src/tests/mockHelpers.ts @@ -1,14 +1,14 @@ -import { GameModel } from "../models/GameModel"; -import { MovieModel } from '../models/MovieModel'; -import { MusicReleaseModel } from "../models/MusicReleaseModel"; -import { WikiModel } from '../models/WikiModel'; -import { MediaType } from "../utils/MediaType"; -import { apiMock } from "./ParameterizedAPI.test"; -import MALMockMovie from "./ResponseMocks/MALMockMovie.json"; -import MusicBrainzResponseMock from "./ResponseMocks/MusicBrainzMockResponse.json"; -import OMDBMockMovie from "./ResponseMocks/OMDBMockResponse.json"; -import SteamAPIResponseMock from "./ResponseMocks/SteamAPIMockResponse.json"; -import WikipediaMockResponse from "./ResponseMocks/WikipediaMockResponse.json"; +import {GameModel} from '../models/GameModel'; +import {MovieModel} from '../models/MovieModel'; +import {MusicReleaseModel} from '../models/MusicReleaseModel'; +import {WikiModel} from '../models/WikiModel'; +import {MediaType} from '../utils/MediaType'; +import {apiMock} from './ParameterizedAPI.test'; +import MALMockMovie from './ResponseMocks/MALMockMovie.json'; +import MusicBrainzResponseMock from './ResponseMocks/MusicBrainzMockResponse.json'; +import OMDBMockMovie from './ResponseMocks/OMDBMockResponse.json'; +import SteamAPIResponseMock from './ResponseMocks/SteamAPIMockResponse.json'; +import WikipediaMockResponse from './ResponseMocks/WikipediaMockResponse.json'; export function setWikipediaResponseMock() { let ret = []; @@ -55,33 +55,31 @@ export function setMALResponseMock() { export function setSteamResponseMock() { let ret = []; let steamResponse = SteamAPIResponseMock.applist.apps[0]; - ret.push( - new GameModel({ - type: MediaType.Game, - title: steamResponse.name, - englishTitle: steamResponse.name, - year: '', - dataSource: apiMock.apiName, - id: steamResponse.appid, - }) - ) + ret.push(new GameModel({ + type: MediaType.Game, + title: steamResponse.name, + englishTitle: steamResponse.name, + year: '', + dataSource: apiMock.apiName, + id: steamResponse.appid, + })); return ret; } export function setMusicBrainzResponseMock() { let ret = []; - let result = MusicBrainzResponseMock["release-groups"][0]; - ret.push(new MusicReleaseModel({ - type: 'musicRelease', - title: result.title, - englishTitle: result.title, - year: (new Date(result['first-release-date'])).getFullYear().toString(), - dataSource: apiMock.apiName, - url: '', - id: result.id, + let result = MusicBrainzResponseMock['release-groups'][0]; + ret.push(new MusicReleaseModel({ + type: 'musicRelease', + title: result.title, + englishTitle: result.title, + year: (new Date(result['first-release-date'])).getFullYear().toString(), + dataSource: apiMock.apiName, + url: '', + id: result.id, - artists: result['artist-credit'].map((a: any) => a.name), - subType: result['primary-type'], - } as MusicReleaseModel)); + artists: result['artist-credit'].map((a: any) => a.name), + subType: result['primary-type'], + } as MusicReleaseModel)); return ret; } diff --git a/src/tests/utils.test.ts b/src/tests/utils.test.ts index ce7a247..eb9bbd1 100644 --- a/src/tests/utils.test.ts +++ b/src/tests/utils.test.ts @@ -1,24 +1,29 @@ -import { wrapAround, containsOnlyLettersAndUnderscores, replaceIllegalFileNameCharactersInString} from '../utils/Utils'; +import {containsOnlyLettersAndUnderscores, replaceIllegalFileNameCharactersInString, wrapAround} from '../utils/Utils'; test('If wrapAround wraps correctly', () => { - expect(wrapAround(100,5)).toBe(0); - expect(wrapAround(100,7)).toBe(2); + expect(wrapAround(100, 5)).toBe(0); + expect(wrapAround(100, 7)).toBe(2); }); test('If wrapAround errors out when dividing by zero', () => { - expect(wrapAround(100,0)).toThrow(); + expect(wrapAround(100, 0)).toThrow(); +}); + +test('If wrapAround errors out when size is negative', () => { + expect(wrapAround(100, -5)).toThrow(); }); test('Letter and underscore string validity', () => { - expect(containsOnlyLettersAndUnderscores("asdkfj_")).toBe(true); - expect(containsOnlyLettersAndUnderscores("asdkfj0")).toBe(false); + expect(containsOnlyLettersAndUnderscores('asdkfj_')).toBe(true); + expect(containsOnlyLettersAndUnderscores('asdkfj0')).toBe(false); }); -test('Letter and underscore unicode char test', () =>{ - expect(containsOnlyLettersAndUnderscores("asdkaÈj")).toBe(true); - expect(containsOnlyLettersAndUnderscores("asdkaÈj0")).toBe(false); +// since this is used to check if a string is a valid name for an object property, unicode characters shouldn't be allowed, thus the name of the function is misleading +test('Letter and underscore unicode char test', () => { + expect(containsOnlyLettersAndUnderscores('asdkaÈj')).toBe(true); + expect(containsOnlyLettersAndUnderscores('asdkaÈj0')).toBe(false); }); -test('Valid filename test', ()=>{ - expect(replaceIllegalFileNameCharactersInString("what?is\\this:")).toBe("whatisthis -"); -}) \ No newline at end of file +test('Valid filename test', () => { + expect(replaceIllegalFileNameCharactersInString('what?is\\this:')).toBe('whatisthis -'); +}); diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index e37a28c..fda6c35 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -8,7 +8,10 @@ export const mediaDbVersion: string = '0.3.2'; export const debug: boolean = true; export function wrapAround(value: number, size: number): number { - return ((value % size) + size) % size; + if (size <= 0) { + throw Error('size may not be zero or negative'); + } + return mod(value, size); } export function debugLog(o: any): void { From 2f0c15c883f90b19cd931bd84d176301cf7b323d Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Thu, 22 Sep 2022 16:41:03 +0200 Subject: [PATCH 16/43] Update to the modals --- src/main.ts | 134 ++++++++++++++++------- src/modals/MediaDbAdvancedSearchModal.ts | 38 ++++--- src/modals/MediaDbIdSearchModal.ts | 38 ++++--- src/modals/MediaDbSearchResultModal.ts | 48 ++++---- src/modals/SelectModal.ts | 22 ++-- 5 files changed, 175 insertions(+), 105 deletions(-) diff --git a/src/main.ts b/src/main.ts index 218dddb..678a5a8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -95,38 +95,72 @@ export default class MediaDbPlugin extends Plugin { async createEntryWithAdvancedSearchModal() { let results: MediaTypeModel[] = []; + + const {advancedSearchOptions, advancedSearchModal} = await this.openMediaDbAdvancedSearchModal(); + if (!advancedSearchOptions) { + advancedSearchModal.close(); + return; + } + + let apiSearchResults: MediaTypeModel[] = undefined; try { - const {query, apis} = await this.openMediaDbAdvancedSearchModal(); - - new Notice('MediaDB Searching...'); - - const apiSearchResults = await this.apiManager.query(query, apis); - const selectResults = await this.openMediaDbSelectModal(apiSearchResults, false); - results = await this.queryDetails(selectResults); + apiSearchResults = await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); } catch (e) { console.warn(e); new Notice(e.toString()); + advancedSearchModal.close(); + return; } + advancedSearchModal.close(); + + const {selectRes, selectModal} = await this.openMediaDbSelectModal(apiSearchResults, false); + if (!selectRes) { + selectModal.close(); + return; + } + + try { + results = await this.queryDetails(selectRes); + } catch (e) { + console.warn(e); + new Notice(e.toString()); + selectModal.close(); + return; + } + + selectModal.close(); + debugLog(results); - await this.createMediaDbNotes(results); + if (results) { + await this.createMediaDbNotes(results); + } } async createEntryWithIdSearchModal() { let result: MediaTypeModel = undefined; + + const {idSearchOptions, idSearchModal} = await this.openMediaDbIdSearchModal(); + if (!idSearchOptions) { + idSearchModal.close(); + return; + } + try { - const {query, api} = await this.openMediaDbIdSearchModal(); - - new Notice('MediaDB Searching...'); - - result = await this.apiManager.queryDetailedInfoById(query, api); + result = await this.apiManager.queryDetailedInfoById(idSearchOptions.query, idSearchOptions.api); } catch (e) { console.warn(e); new Notice(e.toString()); + idSearchModal.close(); + return; } + idSearchModal.close(); + debugLog(result); - await this.createMediaDbNoteFromModel(result); + if (result) { + await this.createMediaDbNoteFromModel(result); + } } async createMediaDbNotes(models: MediaTypeModel[], attachFile?: TFile): Promise { @@ -340,23 +374,23 @@ export default class MediaDbPlugin extends Plugin { } let selectedResults: MediaTypeModel[] = []; + const modal = new MediaDbSearchResultModal(this, results, true); try { selectedResults = await new Promise((resolve, reject) => { - const searchResultModal = new MediaDbSearchResultModal(this.app, this, results, true, (res, err) => { + modal.title = `Results for \'${title}\'`; + modal.setSubmitCallback(res => resolve(res)); + modal.setSkipCallback(() => reject(new UserCancelError('user skipped'))); + modal.setCloseCallback(err => { if (err) { - return reject(err); + reject(err); } - resolve(res); - }, () => { reject(new UserCancelError('user canceled')); - }, () => { - reject(new UserSkipError('user skipped')); }); - searchResultModal.title = `Results for \'${title}\'`; - searchResultModal.open(); + modal.open(); }); } catch (e) { + modal.close(); if (e instanceof UserCancelError) { erroredFiles.push({filePath: file.path, error: e.message}); canceled = true; @@ -377,6 +411,8 @@ export default class MediaDbPlugin extends Plugin { const detailedResults = await this.queryDetails(selectedResults); await this.createMediaDbNotes(detailedResults, appendContent ? file : null); + + modal.close(); } } @@ -396,39 +432,53 @@ export default class MediaDbPlugin extends Plugin { const targetFile = await this.app.vault.create(filePath, fileContent); } - async openMediaDbAdvancedSearchModal(): Promise<{ query: string, apis: string[] }> { - return await new Promise((resolve, reject) => { - new MediaDbAdvancedSearchModal(this.app, this, (res, err) => { + async openMediaDbAdvancedSearchModal(): Promise<{ advancedSearchOptions: { query: string, apis: string[] }, advancedSearchModal: MediaDbAdvancedSearchModal }> { + const modal = new MediaDbAdvancedSearchModal(this); + const res: { query: string, apis: string[] } = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setCloseCallback(err => { if (err) { - return reject(err); + reject(err); } - resolve(res); - }).open(); + resolve(undefined); + }); + + modal.open(); }); + return {advancedSearchOptions: res, advancedSearchModal: modal}; } - async openMediaDbIdSearchModal(): Promise<{ query: string, api: string }> { - return await new Promise((resolve, reject) => { - new MediaDbIdSearchModal(this.app, this, (res, err) => { + async openMediaDbIdSearchModal(): Promise<{ idSearchOptions: { query: string, api: string }, idSearchModal: MediaDbIdSearchModal }> { + const modal = new MediaDbIdSearchModal(this); + const res: { query: string, api: string } = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setCloseCallback(err => { if (err) { - return reject(err); + reject(err); } - resolve(res); - }).open(); + resolve(undefined); + }); + + modal.open(); }); + return {idSearchOptions: res, idSearchModal: modal}; } - async openMediaDbSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false): Promise { - return await new Promise((resolve, reject) => { - new MediaDbSearchResultModal(this.app, this, resultsToDisplay, skipButton, (res, err) => { + async openMediaDbSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false): Promise<{ selectRes: MediaTypeModel[], selectModal: MediaDbSearchResultModal }> { + const modal = new MediaDbSearchResultModal(this, resultsToDisplay, skipButton); + const res: MediaTypeModel[] = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setSkipCallback(() => resolve([])); + modal.setCloseCallback(err => { if (err) { - return reject(err); + reject(err); } - resolve(res); - }, () => { - resolve([]); - }).open(); + resolve(undefined); + }); + + modal.open(); }); + return {selectRes: res, selectModal: modal}; } async loadSettings() { diff --git a/src/modals/MediaDbAdvancedSearchModal.ts b/src/modals/MediaDbAdvancedSearchModal.ts index 246590b..37c1900 100644 --- a/src/modals/MediaDbAdvancedSearchModal.ts +++ b/src/modals/MediaDbAdvancedSearchModal.ts @@ -1,4 +1,4 @@ -import {App, ButtonComponent, Component, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian'; +import {ButtonComponent, Component, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; import {debugLog} from '../utils/Utils'; import MediaDbPlugin from '../main'; @@ -9,19 +9,27 @@ export class MediaDbAdvancedSearchModal extends Modal { plugin: MediaDbPlugin; searchBtn: ButtonComponent; selectedApis: { name: string, selected: boolean }[]; - onSubmit: (res: { query: string, apis: string[] }, err?: Error) => void; + submitCallback?: (res: { query: string, apis: string[] }) => void; + closeCallback?: (err?: Error) => void; - constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (res: { query: string, apis: string[] }, err?: Error) => void) { - super(app); + constructor(plugin: MediaDbPlugin) { + super(plugin.app); this.plugin = plugin; - this.onSubmit = onSubmit; this.selectedApis = []; for (const api of this.plugin.apiManager.apis) { this.selectedApis.push({name: api.apiName, selected: false}); } } - submitCallback(event: KeyboardEvent) { + setSubmitCallback(submitCallback: (res: { query: string, apis: string[] }) => void): void { + this.submitCallback = submitCallback; + } + + setCloseCallback(closeCallback: (err?: Error) => void): void { + this.closeCallback = closeCallback; + } + + keyPressCallback(event: KeyboardEvent) { if (event.key === 'Enter') { this.search(); } @@ -44,17 +52,11 @@ export class MediaDbAdvancedSearchModal extends Modal { } if (!this.isBusy) { - try { - this.isBusy = true; - this.searchBtn.setDisabled(false); - this.searchBtn.setButtonText('Searching...'); + this.isBusy = true; + this.searchBtn.setDisabled(false); + this.searchBtn.setButtonText('Searching...'); - this.onSubmit({query: this.query, apis: apis}); - } catch (e) { - this.onSubmit(null, e); - } finally { - this.close(); - } + this.submitCallback({query: this.query, apis: apis}); } } @@ -68,7 +70,7 @@ export class MediaDbAdvancedSearchModal extends Modal { searchComponent.inputEl.style.width = '100%'; searchComponent.setPlaceholder(placeholder); searchComponent.onChange(value => (this.query = value)); - searchComponent.inputEl.addEventListener('keydown', this.submitCallback.bind(this)); + searchComponent.inputEl.addEventListener('keydown', this.keyPressCallback.bind(this)); contentEl.appendChild(searchComponent.inputEl); searchComponent.inputEl.focus(); @@ -110,9 +112,9 @@ export class MediaDbAdvancedSearchModal extends Modal { } onClose() { + this.closeCallback(); const {contentEl} = this; contentEl.empty(); } - } diff --git a/src/modals/MediaDbIdSearchModal.ts b/src/modals/MediaDbIdSearchModal.ts index 19b3d58..7190918 100644 --- a/src/modals/MediaDbIdSearchModal.ts +++ b/src/modals/MediaDbIdSearchModal.ts @@ -1,4 +1,4 @@ -import {App, ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian'; +import {ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; import {debugLog} from '../utils/Utils'; import MediaDbPlugin from '../main'; @@ -9,16 +9,24 @@ export class MediaDbIdSearchModal extends Modal { plugin: MediaDbPlugin; searchBtn: ButtonComponent; selectedApi: string; - onSubmit: (res: { query: string, api: string }, err?: Error) => void; + submitCallback?: (res: { query: string, api: string }, err?: Error) => void; + closeCallback?: (err?: Error) => void; - constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (res: { query: string, api: string }, err?: Error) => void) { - super(app); + constructor(plugin: MediaDbPlugin) { + super(plugin.app); this.plugin = plugin; - this.onSubmit = onSubmit; this.selectedApi = plugin.apiManager.apis[0].apiName; } - submitCallback(event: KeyboardEvent) { + setSubmitCallback(submitCallback: (res: { query: string, api: string }, err?: Error) => void): void { + this.submitCallback = submitCallback; + } + + setCloseCallback(closeCallback: (err?: Error) => void): void { + this.closeCallback = closeCallback; + } + + keyPressCallback(event: KeyboardEvent) { if (event.key === 'Enter') { this.search(); } @@ -39,17 +47,11 @@ export class MediaDbIdSearchModal extends Modal { } if (!this.isBusy) { - try { - this.isBusy = true; - this.searchBtn.setDisabled(false); - this.searchBtn.setButtonText('Searching...'); + this.isBusy = true; + this.searchBtn.setDisabled(false); + this.searchBtn.setButtonText('Searching...'); - this.onSubmit({query: this.query, api: this.selectedApi}); - } catch (e) { - this.onSubmit(null, e); - } finally { - this.close(); - } + this.submitCallback({query: this.query, api: this.selectedApi}); } } @@ -63,7 +65,7 @@ export class MediaDbIdSearchModal extends Modal { searchComponent.inputEl.style.width = '100%'; searchComponent.setPlaceholder(placeholder); searchComponent.onChange(value => (this.query = value)); - searchComponent.inputEl.addEventListener('keydown', this.submitCallback.bind(this)); + searchComponent.inputEl.addEventListener('keydown', this.keyPressCallback.bind(this)); contentEl.appendChild(searchComponent.inputEl); searchComponent.inputEl.focus(); @@ -98,9 +100,9 @@ export class MediaDbIdSearchModal extends Modal { } onClose() { + this.closeCallback(); const {contentEl} = this; contentEl.empty(); } - } diff --git a/src/modals/MediaDbSearchResultModal.ts b/src/modals/MediaDbSearchResultModal.ts index e45a551..53e19bc 100644 --- a/src/modals/MediaDbSearchResultModal.ts +++ b/src/modals/MediaDbSearchResultModal.ts @@ -1,4 +1,3 @@ -import {App} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; import MediaDbPlugin from '../main'; import {SelectModal} from './SelectModal'; @@ -6,26 +5,38 @@ import {SelectModal} from './SelectModal'; export class MediaDbSearchResultModal extends SelectModal { plugin: MediaDbPlugin; heading: string; - onSubmit: (res: MediaTypeModel[], err?: Error) => void; - onCancel: () => void; - onSkip: () => void; + busy: boolean; + submitCallback: (res: MediaTypeModel[]) => void; + closeCallback: (err?: Error) => void; + skipCallback: () => void; sendCallback: boolean; - constructor(app: App, plugin: MediaDbPlugin, elements: MediaTypeModel[], skipButton: boolean, onSubmit: (res: MediaTypeModel[], err?: Error) => void, onCancel: () => void, onSkip?: () => void) { - super(app, elements); + constructor(plugin: MediaDbPlugin, elements: MediaTypeModel[], skipButton: boolean) { + super(plugin.app, elements); this.plugin = plugin; - this.onSubmit = onSubmit; - this.onCancel = onCancel; - this.onSkip = onSkip; this.title = 'Search Results'; this.description = 'Select one or multiple search results.'; - this.skipButton = skipButton; + this.addSkipButton = skipButton; + + this.busy = false; this.sendCallback = false; } + setSubmitCallback(submitCallback: (res: MediaTypeModel[]) => void): void { + this.submitCallback = submitCallback; + } + + setCloseCallback(closeCallback: (err?: Error) => void): void { + this.closeCallback = closeCallback; + } + + setSkipCallback(skipCallback: () => void): void { + this.skipCallback = skipCallback; + } + // Renders each suggestion item. renderElement(item: MediaTypeModel, el: HTMLElement) { el.createEl('div', {text: this.plugin.mediaTypeManager.getFileName(item)}); @@ -35,20 +46,19 @@ export class MediaDbSearchResultModal extends SelectModal { // Perform action on the selected suggestion. submit() { - this.onSubmit(this.selectModalElements.filter(x => x.isActive()).map(x => x.value)); - this.sendCallback = true; - this.close(); + if (!this.busy) { + this.busy = true; + this.submitButton.setButtonText('Creating entry...'); + this.submitCallback(this.selectModalElements.filter(x => x.isActive()).map(x => x.value)); + } } skip() { - this.onSkip(); - this.sendCallback = true; - this.close(); + this.skipButton.setButtonText('Skipping...'); + this.skipCallback(); } onClose() { - if (!this.sendCallback) { - this.onCancel(); - } + this.closeCallback(); } } diff --git a/src/modals/SelectModal.ts b/src/modals/SelectModal.ts index 572d568..761f3b8 100644 --- a/src/modals/SelectModal.ts +++ b/src/modals/SelectModal.ts @@ -1,4 +1,4 @@ -import {App, Modal, Setting} from 'obsidian'; +import {App, ButtonComponent, Modal, Setting} from 'obsidian'; import {SelectModalElement} from './SelectModalElement'; import {mod} from '../utils/Utils'; @@ -7,7 +7,10 @@ export abstract class SelectModal extends Modal { title: string; description: string; - skipButton: boolean; + addSkipButton: boolean; + cancelButton?: ButtonComponent; + skipButton?: ButtonComponent; + submitButton?: ButtonComponent; elements: T[]; selectModalElements: SelectModalElement[]; @@ -19,7 +22,10 @@ export abstract class SelectModal extends Modal { this.title = ''; this.description = ''; - this.skipButton = false; + this.addSkipButton = false; + this.cancelButton = undefined; + this.skipButton = undefined; + this.submitButton = undefined; this.elements = elements; this.selectModalElements = []; @@ -89,12 +95,12 @@ export abstract class SelectModal extends Modal { this.selectModalElements.first()?.element.scrollIntoView(); - const bottomSetting = new Setting(contentEl); - bottomSetting.addButton(btn => btn.setButtonText('Cancel').onClick(() => this.close())); - if (this.skipButton) { - bottomSetting.addButton(btn => btn.setButtonText('Skip').onClick(() => this.skip())); + const bottomSettingRow = new Setting(contentEl); + bottomSettingRow.addButton(btn => this.cancelButton = btn.setButtonText('Cancel').onClick(() => this.close())); + if (this.addSkipButton) { + bottomSettingRow.addButton(btn => this.skipButton = btn.setButtonText('Skip').onClick(() => this.skip())); } - bottomSetting.addButton(btn => btn.setButtonText('Ok').setCta().onClick(() => this.submit())); + bottomSettingRow.addButton(btn => this.submitButton = btn.setButtonText('Ok').setCta().onClick(() => this.submit())); } activateHighlighted() { From 3a73df616948529e6a036032a6a318a662b5bcc7 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Fri, 23 Sep 2022 16:15:04 +0530 Subject: [PATCH 17/43] fix: add argument for updating note Additionally: - some comments removed - minor fixes - refactored file content generation --- src/main.ts | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/main.ts b/src/main.ts index 678a5a8..40cfb5e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -185,16 +185,10 @@ export default class MediaDbPlugin extends Plugin { async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, attachFile?: TFile): Promise { try { console.log('MDB | Creating new note...'); - // console.log(mediaTypeModel); - let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); - let fileContent = ''; - - ({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, attachFile)); - ({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app))); - - fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent; + let fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, attachFile); + console.log("Inside createMediaDbNote", fileContent) await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent); } catch (e) { console.warn(e); @@ -202,6 +196,18 @@ export default class MediaDbPlugin extends Plugin { } } + private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, attachFile: TFile) { + let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); + let fileContent = ''; + + ({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, attachFile)); + console.log("Inside createYAML", attachFile); + ({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app))); + + fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---` + fileContent; + return fileContent; + } + async attachFile(fileMetadata: any, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: any, fileContent: string }> { if (!fileToAttach) { return {fileMetadata: fileMetadata, fileContent: fileContent}; @@ -219,7 +225,8 @@ export default class MediaDbPlugin extends Plugin { let attachFileContent: string = await this.app.vault.read(fileToAttach); const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); attachFileContent = attachFileContent.replace(regExp, ''); - fileContent += '\n' + attachFileContent; + fileContent += attachFileContent; + console.log("Inside attachfile", fileContent) return {fileMetadata: fileMetadata, fileContent: fileContent}; } @@ -234,7 +241,7 @@ export default class MediaDbPlugin extends Plugin { const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); const attachFileContent = template.replace(regExp, ''); - fileContent += '\n' + attachFileContent; + fileContent += attachFileContent; return {fileMetadata: fileMetadata, fileContent: fileContent}; } @@ -331,8 +338,7 @@ export default class MediaDbPlugin extends Plugin { newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData()); console.log('MDB | deleting old entry'); - await this.app.vault.delete(activeFile); - await this.createMediaDbNoteFromModel(newMediaTypeModel); + await this.createMediaDbNoteFromModel(newMediaTypeModel, activeFile); } async createEntriesFromFolder(folder: TFolder) { @@ -347,7 +353,7 @@ export default class MediaDbPlugin extends Plugin { for (const child of folder.children) { if (child instanceof TFile) { - const file = child as TFile; + const file: TFile = child; if (canceled) { erroredFiles.push({filePath: file.path, error: 'user canceled'}); continue; @@ -426,7 +432,7 @@ export default class MediaDbPlugin extends Plugin { const filePath = `${this.settings.folder.replace(/\/$/, '')}/${title}.md`; const table = [['file', 'error']].concat(erroredFiles.map(x => [x.filePath, x.error])); - // console.log(table) + let fileContent = `# ${title}\n\n${markdownTable(table)}`; const targetFile = await this.app.vault.create(filePath, fileContent); From e00c5ce2c2c08609626ec20a3e9bfff3f3d4c37e Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Fri, 23 Sep 2022 19:10:19 +0200 Subject: [PATCH 18/43] Start of #48 --- esbuild.config.mjs | 18 +- package-lock.json | 380 +++++++++++++++++- package.json | 4 + src/main.ts | 22 +- src/settings/ModelPropertyConversionRule.ts | 27 -- src/settings/ModelPropertyMapper.ts | 130 ------ src/settings/PropertyBindingsComponent.svelte | 74 ++++ src/settings/PropertyMapper.ts | 98 +++++ src/settings/PropertyMapping.ts | 75 ++++ src/settings/Settings.ts | 75 ++++ src/utils/MediaTypeManager.ts | 2 + src/utils/Utils.ts | 4 + tsconfig.json | 51 +-- 13 files changed, 764 insertions(+), 196 deletions(-) delete mode 100644 src/settings/ModelPropertyConversionRule.ts delete mode 100644 src/settings/ModelPropertyMapper.ts create mode 100644 src/settings/PropertyBindingsComponent.svelte create mode 100644 src/settings/PropertyMapper.ts create mode 100644 src/settings/PropertyMapping.ts diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 645372f..09c99bc 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -1,9 +1,11 @@ -import esbuild from "esbuild"; -import process from "process"; -import builtins from 'builtin-modules' +import esbuild from 'esbuild'; +import process from 'process'; +import builtins from 'builtin-modules'; +import esbuildSvelte from 'esbuild-svelte'; +import sveltePreprocess from 'svelte-preprocess'; const banner = -`/* + `/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ @@ -45,8 +47,14 @@ esbuild.build({ format: 'cjs', watch: !prod, target: 'es2016', - logLevel: "info", + logLevel: 'info', sourcemap: prod ? false : 'inline', treeShaking: true, outfile: 'main.js', + plugins: [ + esbuildSvelte({ + compilerOptions: { css: true }, + preprocess: sveltePreprocess(), + }), + ], }).catch(() => process.exit(1)); diff --git a/package-lock.json b/package-lock.json index c15d2d7..1ec9025 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-media-db-plugin", - "version": "0.3.1", + "version": "0.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-media-db-plugin", - "version": "0.3.1", + "version": "0.3.2", "license": "GPL-3.0", "dependencies": { "ts-node": "^10.8.1", @@ -14,15 +14,19 @@ }, "devDependencies": { "@popperjs/core": "^2.11.5", + "@tsconfig/svelte": "^3.0.0", "@types/jest": "^28.1.3", "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "^5.2.0", "@typescript-eslint/parser": "^5.2.0", "builtin-modules": "^3.2.0", "esbuild": "0.13.12", + "esbuild-svelte": "^0.7.1", "jest": "^28.1.2", "jest-fetch-mock": "^3.0.3", "obsidian": "latest", + "svelte": "^3.50.1", + "svelte-preprocess": "^4.10.7", "ts-jest": "^28.0.5", "tslib": "2.3.1", "typescript": "4.4.4" @@ -1177,6 +1181,12 @@ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" }, + "node_modules/@tsconfig/svelte": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-3.0.0.tgz", + "integrity": "sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -1293,6 +1303,21 @@ "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, + "node_modules/@types/pug": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", + "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", + "dev": true + }, + "node_modules/@types/sass": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz", + "integrity": "sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -1806,6 +1831,15 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2022,6 +2056,15 @@ "node": ">=0.10.0" } }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2106,6 +2149,12 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, "node_modules/esbuild": { "version": "0.13.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.12.tgz", @@ -2317,6 +2366,19 @@ "sunos" ] }, + "node_modules/esbuild-svelte": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.7.1.tgz", + "integrity": "sha512-83vRAJ2OmoKxmK+rLFZVmyv5bJ8ahsYQwJ2RGmNAlHBIHq4ENUwA/hiwA2+AohrWD1BgZnGPMj8DL3l0I0xkug==", + "dev": true, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "esbuild": ">=0.9.6", + "svelte": ">=3.43.0" + } + }, "node_modules/esbuild-windows-32": { "version": "0.13.12", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.12.tgz", @@ -3882,6 +3944,15 @@ "node": ">=10" } }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -3957,6 +4028,15 @@ "node": ">=6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3969,6 +4049,24 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/moment": { "version": "2.29.2", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", @@ -4469,6 +4567,30 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "node_modules/sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "dependencies": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/sander/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -4526,6 +4648,21 @@ "node": ">=8" } }, + "node_modules/sorcery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", + "integrity": "sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==", + "dev": true, + "dependencies": { + "buffer-crc32": "^0.2.5", + "minimist": "^1.2.0", + "sander": "^0.5.0", + "sourcemap-codec": "^1.3.0" + }, + "bin": { + "sorcery": "bin/index.js" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4545,6 +4682,12 @@ "source-map": "^0.6.0" } }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -4629,6 +4772,18 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4684,6 +4839,81 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svelte": { + "version": "3.50.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.50.1.tgz", + "integrity": "sha512-bS4odcsdj5D5jEg6riZuMg5NKelzPtmsCbD9RG+8umU03TeNkdWnP6pqbCm0s8UQNBkqk29w/Bdubn3C+HWSwA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/svelte-preprocess": { + "version": "4.10.7", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.7.tgz", + "integrity": "sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/pug": "^2.0.4", + "@types/sass": "^1.16.0", + "detect-indent": "^6.0.0", + "magic-string": "^0.25.7", + "sorcery": "^0.10.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">= 9.11.2" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": "^0.55.0", + "sugarss": "^2.0.0", + "svelte": "^3.23.0", + "typescript": "^3.9.5 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -6048,6 +6278,12 @@ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" }, + "@tsconfig/svelte": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-3.0.0.tgz", + "integrity": "sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg==", + "dev": true + }, "@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -6164,6 +6400,21 @@ "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, + "@types/pug": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", + "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", + "dev": true + }, + "@types/sass": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz", + "integrity": "sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -6505,6 +6756,12 @@ "node-int64": "^0.4.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -6669,6 +6926,12 @@ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -6732,6 +6995,12 @@ "is-arrayish": "^0.2.1" } }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, "esbuild": { "version": "0.13.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.12.tgz", @@ -6855,6 +7124,13 @@ "dev": true, "optional": true }, + "esbuild-svelte": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.7.1.tgz", + "integrity": "sha512-83vRAJ2OmoKxmK+rLFZVmyv5bJ8ahsYQwJ2RGmNAlHBIHq4ENUwA/hiwA2+AohrWD1BgZnGPMj8DL3l0I0xkug==", + "dev": true, + "requires": {} + }, "esbuild-windows-32": { "version": "0.13.12", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.12.tgz", @@ -8040,6 +8316,15 @@ "yallist": "^4.0.0" } }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -8099,6 +8384,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -8108,6 +8399,21 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, "moment": { "version": "2.29.2", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", @@ -8455,6 +8761,29 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "requires": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, "semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -8497,6 +8826,18 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "sorcery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", + "integrity": "sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==", + "dev": true, + "requires": { + "buffer-crc32": "^0.2.5", + "minimist": "^1.2.0", + "sander": "^0.5.0", + "sourcemap-codec": "^1.3.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8513,6 +8854,12 @@ "source-map": "^0.6.0" } }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -8578,6 +8925,15 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8615,6 +8971,26 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "svelte": { + "version": "3.50.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.50.1.tgz", + "integrity": "sha512-bS4odcsdj5D5jEg6riZuMg5NKelzPtmsCbD9RG+8umU03TeNkdWnP6pqbCm0s8UQNBkqk29w/Bdubn3C+HWSwA==", + "dev": true + }, + "svelte-preprocess": { + "version": "4.10.7", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.7.tgz", + "integrity": "sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==", + "dev": true, + "requires": { + "@types/pug": "^2.0.4", + "@types/sass": "^1.16.0", + "detect-indent": "^6.0.0", + "magic-string": "^0.25.7", + "sorcery": "^0.10.0", + "strip-indent": "^3.0.0" + } + }, "terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", diff --git a/package.json b/package.json index 6e5a9db..e5c0d4d 100644 --- a/package.json +++ b/package.json @@ -14,15 +14,19 @@ "license": "GPL-3.0", "devDependencies": { "@popperjs/core": "^2.11.5", + "@tsconfig/svelte": "^3.0.0", "@types/jest": "^28.1.3", "@types/node": "^16.11.6", "@typescript-eslint/eslint-plugin": "^5.2.0", "@typescript-eslint/parser": "^5.2.0", "builtin-modules": "^3.2.0", "esbuild": "0.13.12", + "esbuild-svelte": "^0.7.1", "jest": "^28.1.2", "jest-fetch-mock": "^3.0.3", "obsidian": "latest", + "svelte": "^3.50.1", + "svelte-preprocess": "^4.10.7", "ts-jest": "^28.0.5", "tslib": "2.3.1", "typescript": "4.4.4" diff --git a/src/main.ts b/src/main.ts index 40cfb5e..cdbb942 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,7 +13,7 @@ import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI'; import {MediaTypeManager} from './utils/MediaTypeManager'; import {SteamAPI} from './api/apis/SteamAPI'; import {BoardGameGeekAPI} from './api/apis/BoardGameGeekAPI'; -import {ModelPropertyMapper} from './settings/ModelPropertyMapper'; +import {PropertyMapper} from './settings/PropertyMapper'; import {YAMLConverter} from './utils/YAMLConverter'; import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal'; @@ -21,7 +21,7 @@ export default class MediaDbPlugin extends Plugin { settings: MediaDbPluginSettings; apiManager: APIManager; mediaTypeManager: MediaTypeManager; - modelPropertyMapper: ModelPropertyMapper; + modelPropertyMapper: PropertyMapper; frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---'; @@ -30,6 +30,9 @@ export default class MediaDbPlugin extends Plugin { // register the settings tab this.addSettingTab(new MediaDbSettingTab(this.app, this)); + // TESTING + this.settings.propertyMappings = DEFAULT_SETTINGS.propertyMappings; + this.apiManager = new APIManager(); // register APIs @@ -42,7 +45,7 @@ export default class MediaDbPlugin extends Plugin { // this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data this.mediaTypeManager = new MediaTypeManager(this.settings); - this.modelPropertyMapper = new ModelPropertyMapper(this.settings); + this.modelPropertyMapper = new PropertyMapper(this); // add icon to the left ribbon @@ -188,7 +191,7 @@ export default class MediaDbPlugin extends Plugin { let fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, attachFile); - console.log("Inside createMediaDbNote", fileContent) + console.log('Inside createMediaDbNote', fileContent); await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent); } catch (e) { console.warn(e); @@ -200,9 +203,9 @@ export default class MediaDbPlugin extends Plugin { let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); let fileContent = ''; - ({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, attachFile)); - console.log("Inside createYAML", attachFile); - ({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app))); + ({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, attachFile)); + console.log('Inside createYAML', attachFile); + ({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app))); fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---` + fileContent; return fileContent; @@ -226,7 +229,7 @@ export default class MediaDbPlugin extends Plugin { const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); attachFileContent = attachFileContent.replace(regExp, ''); fileContent += attachFileContent; - console.log("Inside attachfile", fileContent) + console.log('Inside attachfile', fileContent); return {fileMetadata: fileMetadata, fileContent: fileContent}; } @@ -488,12 +491,13 @@ export default class MediaDbPlugin extends Plugin { } async loadSettings() { + console.log(DEFAULT_SETTINGS); this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { this.mediaTypeManager.updateTemplates(this.settings); - this.modelPropertyMapper.updateConversionRules(this.settings); + //this.modelPropertyMapper.updateConversionRules(this.settings); await this.saveData(this.settings); } diff --git a/src/settings/ModelPropertyConversionRule.ts b/src/settings/ModelPropertyConversionRule.ts deleted file mode 100644 index d749918..0000000 --- a/src/settings/ModelPropertyConversionRule.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {containsOnlyLettersAndUnderscores} from '../utils/Utils'; - -export class ModelPropertyConversionRule { - property: string; - newProperty: string; - - constructor(conversionRule: string) { - const conversionRuleParts = conversionRule.split('->'); - if (conversionRuleParts.length !== 2) { - throw Error(`Conversion rule "${conversionRule}" may only have exactly one "->"`); - } - - let property = conversionRuleParts[0].trim(); - let newProperty = conversionRuleParts[1].trim(); - - if (!property || !containsOnlyLettersAndUnderscores(property)) { - throw Error(`Error in conversion rule "${conversionRule}": property may not be empty and only contain letters and underscores.`); - } - - if (!newProperty || !containsOnlyLettersAndUnderscores(newProperty)) { - throw Error(`Error in conversion rule "${conversionRule}": new property may not be empty and only contain letters and underscores.`); - } - - this.property = property; - this.newProperty = newProperty; - } -} diff --git a/src/settings/ModelPropertyMapper.ts b/src/settings/ModelPropertyMapper.ts deleted file mode 100644 index 39b8b51..0000000 --- a/src/settings/ModelPropertyMapper.ts +++ /dev/null @@ -1,130 +0,0 @@ -import {MediaType} from '../utils/MediaType'; -import {MediaDbPluginSettings} from './Settings'; -import {ModelPropertyConversionRule} from './ModelPropertyConversionRule'; - -export class ModelPropertyMapper { - conversionRulesMap: Map; - - constructor(settings: MediaDbPluginSettings) { - this.updateConversionRules(settings); - } - - updateConversionRules(settings: MediaDbPluginSettings) { - this.conversionRulesMap = new Map(); - this.conversionRulesMap.set(MediaType.Movie, settings.moviePropertyConversionRules); - this.conversionRulesMap.set(MediaType.Series, settings.seriesPropertyConversionRules); - this.conversionRulesMap.set(MediaType.Game, settings.gamePropertyConversionRules); - this.conversionRulesMap.set(MediaType.Wiki, settings.wikiPropertyConversionRules); - this.conversionRulesMap.set(MediaType.MusicRelease, settings.musicReleasePropertyConversionRules); - this.conversionRulesMap.set(MediaType.BoardGame, settings.boardgamePropertyConversionRules); - } - - /** - * Converts an object using the conversion rules for its type. - * Returns an unaltered object if object.type is null or undefined or if there are no conversion rules for the type. - * - * @param obj - */ - convertObject(obj: object): object { - if (!obj.hasOwnProperty('type')) { - return obj; - } - - // @ts-ignore - // get conversion rules from settings corresponding to the object type - const conversionRulesString: string = this.conversionRulesMap.get(obj['type']); - if (!conversionRulesString) { - return obj; - } - - // parse the conversion rules - const conversionRules: ModelPropertyConversionRule[] = []; - for (const conversionRuleString of conversionRulesString.split('\n')) { - if (conversionRuleString) { - conversionRules.push(new ModelPropertyConversionRule(conversionRuleString)); - } - } - - const newObj: object = {}; - - for (const [key, value] of Object.entries(obj)) { - // property 'type' can not be remapped - if (key === 'type') { - // @ts-ignore - newObj[key] = value; - continue; - } - - let hasConversionRule = false; - for (const conversionRule of conversionRules) { - if (conversionRule.property === key) { - hasConversionRule = true; - // if the conversion rule maps to 'x', then that means it should be ignored - if (conversionRule.newProperty.toLowerCase() !== 'x') { - // @ts-ignore - newObj[conversionRule.newProperty] = value; - } - } - } - if (!hasConversionRule) { - // @ts-ignore - newObj[key] = value; - } - } - - return newObj; - } - - /** - * Converts an object back using the conversion rules for its type. - * Returns an unaltered object if object.type is null or undefined or if there are no conversion rules for the type. - * - * @param obj - */ - convertObjectBack(obj: object): object { - if (!obj.hasOwnProperty('type')) { - return obj; - } - - // @ts-ignore - // get conversion rules from settings corresponding to the object type - const conversionRulesString: string = this.conversionRulesMap.get(obj['type']); - if (!conversionRulesString) { - return obj; - } - - const conversionRules: ModelPropertyConversionRule[] = []; - // parse the conversion rules - for (const conversionRuleString of conversionRulesString.split('\n')) { - if (conversionRuleString) { - conversionRules.push(new ModelPropertyConversionRule(conversionRuleString)); - } - } - - const originalObj: object = {}; - - for (const [key, value] of Object.entries(obj)) { - // property 'type' can not be remapped - if (key === 'type') { - // @ts-ignore - originalObj[key] = value; - continue; - } - - let hasConversionRule = false; - for (const conversionRule of conversionRules) { - if (conversionRule.newProperty === key) { - hasConversionRule = true; - // @ts-ignore - originalObj[conversionRule.property] = value; - } - } - if (!hasConversionRule) { - // @ts-ignore - originalObj[key] = value; - } - } - - return originalObj; - } -} diff --git a/src/settings/PropertyBindingsComponent.svelte b/src/settings/PropertyBindingsComponent.svelte new file mode 100644 index 0000000..26770e3 --- /dev/null +++ b/src/settings/PropertyBindingsComponent.svelte @@ -0,0 +1,74 @@ + + + + +
+ { #each models as model } +
{capitalizeFirstLetter(model.type)}
+
+ { #each model.properties as property } +
+
+
{property.property}
+
+ {#if property.locked} +
+ property can not be remapped +
+ {:else} + + + {#if property.mapping === PropertyMappingOption.Map} +
+ -> +
+
+ +
+ {/if} + {/if} +
+ { /each } +
+ { /each } + +
{JSON.stringify(models, null, 4)}
+
diff --git a/src/settings/PropertyMapper.ts b/src/settings/PropertyMapper.ts new file mode 100644 index 0000000..66da472 --- /dev/null +++ b/src/settings/PropertyMapper.ts @@ -0,0 +1,98 @@ +import {PropertyMappingOption} from './PropertyMapping'; +import {MEDIA_TYPES} from '../utils/MediaTypeManager'; +import MediaDbPlugin from '../main'; + +export class PropertyMapper { + plugin: MediaDbPlugin; + + constructor(plugin: MediaDbPlugin) { + this.plugin = plugin; + } + + /** + * Converts an object using the conversion rules for its type. + * Returns an unaltered object if object.type is null or undefined or if there are no conversion rules for the type. + * + * @param obj + */ + convertObject(obj: object): object { + if (!obj.hasOwnProperty('type')) { + return obj; + } + + // @ts-ignore + if (MEDIA_TYPES.contains(obj.type)) { + return obj; + } + + // @ts-ignore + const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties; + + const newObj: object = {}; + + for (const [key, value] of Object.entries(obj)) { + for (const propertyMapping of propertyMappings) { + if (propertyMapping.property === key) { + if (propertyMapping.mapping === PropertyMappingOption.Map) { + // @ts-ignore + newObj[propertyMapping.newProperty] = value; + } else if (propertyMapping.mapping === PropertyMappingOption.Remove) { + + } else if (propertyMapping.mapping === PropertyMappingOption.None) { + // @ts-ignore + newObj[key] = value; + } + break; + } + } + } + + return newObj; + } + + /** + * Converts an object back using the conversion rules for its type. + * Returns an unaltered object if object.type is null or undefined or if there are no conversion rules for the type. + * + * @param obj + */ + convertObjectBack(obj: object): object { + if (!obj.hasOwnProperty('type')) { + return obj; + } + + // @ts-ignore + if (MEDIA_TYPES.contains(obj.type)) { + return obj; + } + + // @ts-ignore + const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties; + + const originalObj: object = {}; + + objLoop: for (const [key, value] of Object.entries(obj)) { + // first try if it is a normal property + for (const propertyMapping of propertyMappings) { + if (propertyMapping.property === key) { + // @ts-ignore + originalObj[key] = value; + + continue objLoop; + } + } + + // otherwise see if it is a mapped property + for (const propertyMapping of propertyMappings) { + if (propertyMapping.newProperty === key) { + // @ts-ignore + originalObj[propertyMapping.property] = value; + + continue objLoop; + } + } + } + + return originalObj; + } +} diff --git a/src/settings/PropertyMapping.ts b/src/settings/PropertyMapping.ts new file mode 100644 index 0000000..582718f --- /dev/null +++ b/src/settings/PropertyMapping.ts @@ -0,0 +1,75 @@ +import {containsOnlyLettersAndUnderscores} from '../utils/Utils'; +import {MediaType} from '../utils/MediaType'; + +export enum PropertyMappingOption { + None = 'none', + Map = 'remap', + Remove = 'remove', +} + +export const propertyMappingOptions = [PropertyMappingOption.None, PropertyMappingOption.Map, PropertyMappingOption.Remove]; + +export interface PropertyMappingModel { + type: MediaType, + properties: PropertyMapping[], +} + +export class PropertyMapping { + property: string; + newProperty: string; + locked: boolean; + mapping: PropertyMappingOption; + + constructor(property: string, newProperty: string, mapping: PropertyMappingOption, locked?: boolean) { + this.property = property; + this.newProperty = newProperty; + this.mapping = mapping; + this.locked = locked ?? false; + + /* + const conversionRuleParts = conversionRule.split('->'); + if (conversionRuleParts.length !== 2) { + throw Error(`Conversion rule "${conversionRule}" may only have exactly one "->"`); + } + + let property = conversionRuleParts[0].trim(); + let newProperty = conversionRuleParts[1].trim(); + + if (!property || !containsOnlyLettersAndUnderscores(property)) { + throw Error(`Error in conversion rule "${conversionRule}": property may not be empty and only contain letters and underscores.`); + } + + if (!newProperty || !containsOnlyLettersAndUnderscores(newProperty)) { + throw Error(`Error in conversion rule "${conversionRule}": new property may not be empty and only contain letters and underscores.`); + } + + this.property = property; + this.newProperty = newProperty; + + */ + } + + validate(): string { + if (!this.property || !containsOnlyLettersAndUnderscores(this.property)) { + return `Error in conversion rule "${this.toString()}": property may not be empty and only contain letters and underscores.`; + } + + if (!this.newProperty || !containsOnlyLettersAndUnderscores(this.newProperty)) { + return `Error in conversion rule "${this.toString()}": new property may not be empty and only contain letters and underscores.`; + } + + return ''; + } + + toString(): string { + if (this.mapping === PropertyMappingOption.None) { + return this.property; + } else if (this.mapping === PropertyMappingOption.Map) { + return `${this.property} -> ${this.newProperty}`; + } else if (this.mapping === PropertyMappingOption.Remove) { + return `remove ${this.property}`; + } + + return this.property; + } +} diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index b030311..b35ab04 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -3,6 +3,9 @@ import {App, PluginSettingTab, Setting} from 'obsidian'; import MediaDbPlugin from '../main'; import {FolderSuggest} from './suggesters/FolderSuggest'; import {FileSuggest} from './suggesters/FileSuggest'; +import PropertyBindingsComponent from './PropertyBindingsComponent.svelte'; +import {PropertyMapping, PropertyMappingModel, PropertyMappingOption} from './PropertyMapping'; +import {MediaType} from '../utils/MediaType'; export interface MediaDbPluginSettings { @@ -34,6 +37,8 @@ export interface MediaDbPluginSettings { musicReleasePropertyConversionRules: string, boardgamePropertyConversionRules: string, + propertyMappings: PropertyMappingModel[], + } export const DEFAULT_SETTINGS: MediaDbPluginSettings = { @@ -64,6 +69,60 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = { musicReleasePropertyConversionRules: '', boardgamePropertyConversionRules: '', + propertyMappings: [ + { + type: MediaType.Movie, + properties: [ + new PropertyMapping('type', '', PropertyMappingOption.None, true), + new PropertyMapping('subType', '', PropertyMappingOption.None), + new PropertyMapping('title', '', PropertyMappingOption.None), + new PropertyMapping('englishTitle', '', PropertyMappingOption.None), + new PropertyMapping('year', '', PropertyMappingOption.None), + new PropertyMapping('dataSource', '', PropertyMappingOption.None, true), + new PropertyMapping('url', '', PropertyMappingOption.None), + new PropertyMapping('id', '', PropertyMappingOption.None, true), + + new PropertyMapping('genres', '', PropertyMappingOption.None), + new PropertyMapping('producer', '', PropertyMappingOption.None), + new PropertyMapping('duration', '', PropertyMappingOption.None), + new PropertyMapping('onlineRating', '', PropertyMappingOption.None), + new PropertyMapping('image', '', PropertyMappingOption.None), + new PropertyMapping('released', '', PropertyMappingOption.None), + new PropertyMapping('premiere', '', PropertyMappingOption.None), + new PropertyMapping('watched', '', PropertyMappingOption.None), + new PropertyMapping('lastWatched', '', PropertyMappingOption.None), + new PropertyMapping('personalRating', '', PropertyMappingOption.None), + ], + }, + { + type: MediaType.Series, + properties: [ + new PropertyMapping('type', '', PropertyMappingOption.None, true), + new PropertyMapping('subType', '', PropertyMappingOption.None), + new PropertyMapping('title', '', PropertyMappingOption.None), + new PropertyMapping('englishTitle', '', PropertyMappingOption.None), + new PropertyMapping('year', '', PropertyMappingOption.None), + new PropertyMapping('dataSource', '', PropertyMappingOption.None, true), + new PropertyMapping('url', '', PropertyMappingOption.None), + new PropertyMapping('id', '', PropertyMappingOption.None, true), + + new PropertyMapping('genres', '', PropertyMappingOption.None), + new PropertyMapping('studios', '', PropertyMappingOption.None), + new PropertyMapping('episodes', '', PropertyMappingOption.None), + new PropertyMapping('duration', '', PropertyMappingOption.None), + new PropertyMapping('onlineRating', '', PropertyMappingOption.None), + new PropertyMapping('image', '', PropertyMappingOption.None), + new PropertyMapping('released', '', PropertyMappingOption.None), + new PropertyMapping('airing', '', PropertyMappingOption.None), + new PropertyMapping('airedFrom', '', PropertyMappingOption.None), + new PropertyMapping('airedTo', '', PropertyMappingOption.None), + new PropertyMapping('watched', '', PropertyMappingOption.None), + new PropertyMapping('lastWatched', '', PropertyMappingOption.None), + new PropertyMapping('personalRating', '', PropertyMappingOption.None), + ], + }, + ], + }; export class MediaDbSettingTab extends PluginSettingTab { @@ -298,6 +357,7 @@ export class MediaDbSettingTab extends PluginSettingTab { containerEl.createEl('h3', {text: 'Property Mappings'}); // region Property Mappings + /* new Setting(containerEl) .setName('Movie model property mappings') .setDesc('Mappings for the property names of a movie.') @@ -369,8 +429,23 @@ export class MediaDbSettingTab extends PluginSettingTab { this.plugin.saveSettings(); }); }); + + */ // endregion + console.log(this.plugin.settings.propertyMappings); + + new PropertyBindingsComponent({ + target: this.containerEl, + props: { + models: this.plugin.settings.propertyMappings, + save: (models: PropertyMappingModel[]) => { + this.plugin.settings.propertyMappings = models; + this.plugin.saveSettings(); + }, + }, + }); + } } diff --git a/src/utils/MediaTypeManager.ts b/src/utils/MediaTypeManager.ts index 9d576b0..08a4f1e 100644 --- a/src/utils/MediaTypeManager.ts +++ b/src/utils/MediaTypeManager.ts @@ -10,6 +10,8 @@ import {WikiModel} from '../models/WikiModel'; import {MusicReleaseModel} from '../models/MusicReleaseModel'; import {BoardGameModel} from '../models/BoardGameModel'; +export const MEDIA_TYPES = [MediaType.Movie, MediaType.Series, MediaType.Game, MediaType.Wiki, MediaType.MusicRelease, MediaType.BoardGame]; + export class MediaTypeManager { mediaFileNameTemplateMap: Map; mediaTemplateMap: Map; diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index fda6c35..feb99d6 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -172,3 +172,7 @@ export function mod(n: number, m: number): number { return ((n % m) + m) % m; } +export function capitalizeFirstLetter(string: string): string { + return string.charAt(0).toUpperCase() + string.slice(1); +} + diff --git a/tsconfig.json b/tsconfig.json index 732e408..9300189 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,25 +1,30 @@ { - "compilerOptions": { - "baseUrl": ".", - "inlineSourceMap": true, - "inlineSources": true, - "module": "ESNext", - "target": "ES6", - "allowJs": true, - "noImplicitAny": true, - "moduleResolution": "node", - "importHelpers": true, - "isolatedModules": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "lib": [ - "DOM", - "ES5", - "ES6", - "ES7" - ] - }, - "include": [ - "**/*.ts" - ] + "compilerOptions": { + "types": [ + "svelte", + "node", + "jest" + ], + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "module": "ESNext", + "target": "ES6", + "allowJs": true, + "noImplicitAny": true, + "moduleResolution": "node", + "importHelpers": true, + "isolatedModules": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "lib": [ + "DOM", + "ES5", + "ES6", + "ES7" + ] + }, + "include": [ + "**/*.ts" + ] } From 28b25a9138faaabda346dac5ef21613a6ceb4981 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 24 Sep 2022 17:50:52 +0530 Subject: [PATCH 19/43] Remove extra console logs --- src/main.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main.ts b/src/main.ts index cdbb942..507f440 100644 --- a/src/main.ts +++ b/src/main.ts @@ -191,7 +191,6 @@ export default class MediaDbPlugin extends Plugin { let fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, attachFile); - console.log('Inside createMediaDbNote', fileContent); await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent); } catch (e) { console.warn(e); @@ -204,7 +203,6 @@ export default class MediaDbPlugin extends Plugin { let fileContent = ''; ({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, attachFile)); - console.log('Inside createYAML', attachFile); ({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app))); fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---` + fileContent; @@ -229,7 +227,6 @@ export default class MediaDbPlugin extends Plugin { const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); attachFileContent = attachFileContent.replace(regExp, ''); fileContent += attachFileContent; - console.log('Inside attachfile', fileContent); return {fileMetadata: fileMetadata, fileContent: fileContent}; } From 14719efa226078f4c5124213a89fdaf62b1e3996 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Sat, 24 Sep 2022 20:33:06 +0200 Subject: [PATCH 20/43] more changes for #48, the UI now works \o/ --- src/main.ts | 55 ++++-- src/models/BoardGameModel.ts | 9 + src/models/GameModel.ts | 19 ++- src/models/MediaTypeModel.ts | 15 +- src/models/MovieModel.ts | 22 ++- src/models/MusicReleaseModel.ts | 7 + src/models/SeriesModel.ts | 16 ++ src/models/WikiModel.ts | 8 +- src/settings/Icon.svelte | 36 ++++ src/settings/PropertyBindingsComponent.svelte | 74 --------- src/settings/PropertyMapper.ts | 6 +- src/settings/PropertyMapping.ts | 6 +- .../PropertyMappingModelsComponent.svelte | 106 ++++++++++++ src/settings/Settings.ts | 157 ++++++++++++------ src/settings/suggesters/Suggest.ts | 2 +- src/utils/MediaTypeManager.ts | 5 +- src/utils/Utils.ts | 3 + 17 files changed, 381 insertions(+), 165 deletions(-) create mode 100644 src/settings/Icon.svelte delete mode 100644 src/settings/PropertyBindingsComponent.svelte create mode 100644 src/settings/PropertyMappingModelsComponent.svelte diff --git a/src/main.ts b/src/main.ts index cdbb942..9426507 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ import {Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} from 'obsidian'; -import {DEFAULT_SETTINGS, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings'; +import {getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings'; import {APIManager} from './api/APIManager'; import {MediaTypeModel} from './models/MediaTypeModel'; import {dateTimeToString, debugLog, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils'; @@ -16,6 +16,7 @@ import {BoardGameGeekAPI} from './api/apis/BoardGameGeekAPI'; import {PropertyMapper} from './settings/PropertyMapper'; import {YAMLConverter} from './utils/YAMLConverter'; import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal'; +import {PropertyMapping, PropertyMappingModel} from './settings/PropertyMapping'; export default class MediaDbPlugin extends Plugin { settings: MediaDbPluginSettings; @@ -26,14 +27,6 @@ export default class MediaDbPlugin extends Plugin { frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---'; async onload() { - await this.loadSettings(); - // register the settings tab - this.addSettingTab(new MediaDbSettingTab(this.app, this)); - - // TESTING - this.settings.propertyMappings = DEFAULT_SETTINGS.propertyMappings; - - this.apiManager = new APIManager(); // register APIs this.apiManager.registerAPI(new OMDbAPI(this)); @@ -44,9 +37,18 @@ export default class MediaDbPlugin extends Plugin { this.apiManager.registerAPI(new BoardGameGeekAPI(this)); // this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data - this.mediaTypeManager = new MediaTypeManager(this.settings); + this.mediaTypeManager = new MediaTypeManager(); this.modelPropertyMapper = new PropertyMapper(this); + await this.loadSettings(); + // register the settings tab + this.addSettingTab(new MediaDbSettingTab(this.app, this)); + + // TESTING + // this.settings.propertyMappingModels = getDefaultSettings(this).propertyMappingModels; + + this.mediaTypeManager.updateTemplates(this.settings); + // add icon to the left ribbon const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', (evt: MouseEvent) => @@ -491,8 +493,37 @@ export default class MediaDbPlugin extends Plugin { } async loadSettings() { - console.log(DEFAULT_SETTINGS); - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + // console.log(DEFAULT_SETTINGS); + const diskSettings: MediaDbPluginSettings = await this.loadData(); + const defaultSettings: MediaDbPluginSettings = getDefaultSettings(this); + const loadedSettings: MediaDbPluginSettings = Object.assign({}, defaultSettings, diskSettings); + + // migrate the settings loaded from the disk to match the structure of the default settings + let newPropertyMappings: PropertyMappingModel[] = []; + for (const defaultPropertyMappingModel of defaultSettings.propertyMappingModels) { + let newPropertyMappingModel: PropertyMappingModel = loadedSettings.propertyMappingModels.find(x => x.type === defaultPropertyMappingModel.type); + if (newPropertyMappingModel === undefined) { // if the propertyMappingModel exists in the default settings but not the loaded settings, add it + newPropertyMappings.push(defaultPropertyMappingModel); + } else { // if the propertyMappingModel also exists in the loaded settings, add it from there + let newProperties: PropertyMapping[] = []; + + for (const defaultProperty of defaultPropertyMappingModel.properties) { + let newProperty = newPropertyMappingModel.properties.find(x => x.property === defaultProperty.property); + if (newProperty === undefined) { + newProperties.push(defaultProperty); + } else { + newProperties.push(newProperty); + } + } + + newPropertyMappingModel.properties = newProperties; + + newPropertyMappings.push(newPropertyMappingModel); + } + } + loadedSettings.propertyMappingModels = newPropertyMappings; + + this.settings = loadedSettings; } async saveSettings() { diff --git a/src/models/BoardGameModel.ts b/src/models/BoardGameModel.ts index a2ffad3..bba4f17 100644 --- a/src/models/BoardGameModel.ts +++ b/src/models/BoardGameModel.ts @@ -19,6 +19,15 @@ export class BoardGameModel extends MediaTypeModel { constructor(obj: any = {}) { super(); + this.genres = undefined; + this.onlineRating = undefined; + this.image = undefined; + this.released = undefined; + this.userData = { + played: undefined, + personalRating: undefined, + }; + Object.assign(this, obj); this.type = this.getMediaType(); diff --git a/src/models/GameModel.ts b/src/models/GameModel.ts index 2d2e68c..86332f6 100644 --- a/src/models/GameModel.ts +++ b/src/models/GameModel.ts @@ -4,15 +4,6 @@ import {MediaType} from '../utils/MediaType'; export class GameModel extends MediaTypeModel { - type: string; - subType: string; - title: string; - englishTitle: string; - year: string; - dataSource: string; - url: string; - id: string; - genres: string[]; onlineRating: number; image: string; @@ -29,6 +20,16 @@ export class GameModel extends MediaTypeModel { constructor(obj: any = {}) { super(); + this.genres = undefined; + this.onlineRating = undefined; + this.image = undefined; + this.released = undefined; + this.releaseDate = undefined; + this.userData = { + played: undefined, + personalRating: undefined, + }; + Object.assign(this, obj); this.type = this.getMediaType(); diff --git a/src/models/MediaTypeModel.ts b/src/models/MediaTypeModel.ts index f1c4bd2..fc4f87a 100644 --- a/src/models/MediaTypeModel.ts +++ b/src/models/MediaTypeModel.ts @@ -12,6 +12,19 @@ export abstract class MediaTypeModel { userData: object; + + constructor() { + this.type = undefined; + this.subType = undefined; + this.title = undefined; + this.englishTitle = undefined; + this.year = undefined; + this.dataSource = undefined; + this.url = undefined; + this.id = undefined; + this.userData = {}; + } + abstract getMediaType(): MediaType; //a string that contains enough info to disambiguate from similar media @@ -24,7 +37,7 @@ export abstract class MediaTypeModel { } getWithOutUserData(): object { - const copy = JSON.parse(JSON.stringify(this)); + const copy = Object.assign({}, this); delete copy.userData; return copy; } diff --git a/src/models/MovieModel.ts b/src/models/MovieModel.ts index 4300801..242a0c4 100644 --- a/src/models/MovieModel.ts +++ b/src/models/MovieModel.ts @@ -4,15 +4,6 @@ import {MediaType} from '../utils/MediaType'; export class MovieModel extends MediaTypeModel { - type: string; - subType: string; - title: string; - englishTitle: string; - year: string; - dataSource: string; - url: string; - id: string; - genres: string[]; producer: string; duration: string; @@ -31,6 +22,19 @@ export class MovieModel extends MediaTypeModel { constructor(obj: any = {}) { super(); + this.genres = undefined; + this.producer = undefined; + this.duration = undefined; + this.onlineRating = undefined; + this.image = undefined; + this.released = undefined; + this.premiere = undefined; + this.userData = { + watched: undefined, + lastWatched: undefined, + personalRating: undefined, + }; + Object.assign(this, obj); this.type = this.getMediaType(); diff --git a/src/models/MusicReleaseModel.ts b/src/models/MusicReleaseModel.ts index 2d134b6..42e91e1 100644 --- a/src/models/MusicReleaseModel.ts +++ b/src/models/MusicReleaseModel.ts @@ -24,6 +24,13 @@ export class MusicReleaseModel extends MediaTypeModel { constructor(obj: any = {}) { super(); + this.genres = undefined; + this.artists = undefined; + this.rating = undefined; + this.userData = { + personalRating: undefined, + }; + Object.assign(this, obj); this.type = this.getMediaType(); diff --git a/src/models/SeriesModel.ts b/src/models/SeriesModel.ts index 43fcfae..4fbeaba 100644 --- a/src/models/SeriesModel.ts +++ b/src/models/SeriesModel.ts @@ -34,6 +34,22 @@ export class SeriesModel extends MediaTypeModel { constructor(obj: any = {}) { super(); + this.genres = undefined; + this.studios = undefined; + this.episodes = undefined; + this.duration = undefined; + this.onlineRating = undefined; + this.image = undefined; + this.released = undefined; + this.airing = undefined; + this.airedFrom = undefined; + this.airedTo = undefined; + this.userData = { + watched: undefined, + lastWatched: undefined, + personalRating: undefined, + }; + Object.assign(this, obj); this.type = this.getMediaType(); diff --git a/src/models/WikiModel.ts b/src/models/WikiModel.ts index 3121873..54d756d 100644 --- a/src/models/WikiModel.ts +++ b/src/models/WikiModel.ts @@ -23,6 +23,12 @@ export class WikiModel extends MediaTypeModel { constructor(obj: any = {}) { super(); + this.wikiUrl = undefined; + this.lastUpdated = undefined; + this.length = undefined; + this.article = undefined; + this.userData = {}; + Object.assign(this, obj); this.type = this.getMediaType(); @@ -37,7 +43,7 @@ export class WikiModel extends MediaTypeModel { } override getWithOutUserData(): object { - const copy = JSON.parse(JSON.stringify(this)); + const copy = Object.assign({}, this); delete copy.userData; delete copy.article; return copy; diff --git a/src/settings/Icon.svelte b/src/settings/Icon.svelte new file mode 100644 index 0000000..23f2002 --- /dev/null +++ b/src/settings/Icon.svelte @@ -0,0 +1,36 @@ + + + + + + +{#if iconName.length > 0} +
+
+
+{/if} diff --git a/src/settings/PropertyBindingsComponent.svelte b/src/settings/PropertyBindingsComponent.svelte deleted file mode 100644 index 26770e3..0000000 --- a/src/settings/PropertyBindingsComponent.svelte +++ /dev/null @@ -1,74 +0,0 @@ - - - - -
- { #each models as model } -
{capitalizeFirstLetter(model.type)}
-
- { #each model.properties as property } -
-
-
{property.property}
-
- {#if property.locked} -
- property can not be remapped -
- {:else} - - - {#if property.mapping === PropertyMappingOption.Map} -
- -> -
-
- -
- {/if} - {/if} -
- { /each } -
- { /each } - -
{JSON.stringify(models, null, 4)}
-
diff --git a/src/settings/PropertyMapper.ts b/src/settings/PropertyMapper.ts index 66da472..12aa4e2 100644 --- a/src/settings/PropertyMapper.ts +++ b/src/settings/PropertyMapper.ts @@ -26,7 +26,7 @@ export class PropertyMapper { } // @ts-ignore - const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties; + const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties; const newObj: object = {}; @@ -38,7 +38,7 @@ export class PropertyMapper { newObj[propertyMapping.newProperty] = value; } else if (propertyMapping.mapping === PropertyMappingOption.Remove) { - } else if (propertyMapping.mapping === PropertyMappingOption.None) { + } else if (propertyMapping.mapping === PropertyMappingOption.Default) { // @ts-ignore newObj[key] = value; } @@ -67,7 +67,7 @@ export class PropertyMapper { } // @ts-ignore - const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties; + const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties; const originalObj: object = {}; diff --git a/src/settings/PropertyMapping.ts b/src/settings/PropertyMapping.ts index 582718f..e68bdfc 100644 --- a/src/settings/PropertyMapping.ts +++ b/src/settings/PropertyMapping.ts @@ -2,12 +2,12 @@ import {containsOnlyLettersAndUnderscores} from '../utils/Utils'; import {MediaType} from '../utils/MediaType'; export enum PropertyMappingOption { - None = 'none', + Default = 'default', Map = 'remap', Remove = 'remove', } -export const propertyMappingOptions = [PropertyMappingOption.None, PropertyMappingOption.Map, PropertyMappingOption.Remove]; +export const propertyMappingOptions = [PropertyMappingOption.Default, PropertyMappingOption.Map, PropertyMappingOption.Remove]; export interface PropertyMappingModel { type: MediaType, @@ -62,7 +62,7 @@ export class PropertyMapping { } toString(): string { - if (this.mapping === PropertyMappingOption.None) { + if (this.mapping === PropertyMappingOption.Default) { return this.property; } else if (this.mapping === PropertyMappingOption.Map) { return `${this.property} -> ${this.newProperty}`; diff --git a/src/settings/PropertyMappingModelsComponent.svelte b/src/settings/PropertyMappingModelsComponent.svelte new file mode 100644 index 0000000..1e14b20 --- /dev/null +++ b/src/settings/PropertyMappingModelsComponent.svelte @@ -0,0 +1,106 @@ + + + + +
+ { #each models as model } +
+
{capitalizeFirstLetter(model.type)}
+
+ { #each model.properties as property } +
+
+
{property.property}
+
+ {#if property.locked} +
+ property can not be remapped +
+ {:else} + + + {#if property.mapping === PropertyMappingOption.Map} + +
+ +
+ {/if} + {/if} +
+ { /each } +
+ +
+ { /each } + +
{JSON.stringify(models, null, 4)}
+ + +
diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index b35ab04..30d31c6 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -1,11 +1,12 @@ -import {App, PluginSettingTab, Setting} from 'obsidian'; +import {App, Notice, PluginSettingTab, Setting} from 'obsidian'; import MediaDbPlugin from '../main'; import {FolderSuggest} from './suggesters/FolderSuggest'; import {FileSuggest} from './suggesters/FileSuggest'; -import PropertyBindingsComponent from './PropertyBindingsComponent.svelte'; +import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte'; import {PropertyMapping, PropertyMappingModel, PropertyMappingOption} from './PropertyMapping'; -import {MediaType} from '../utils/MediaType'; +import {MEDIA_TYPES} from '../utils/MediaTypeManager'; +import {MediaTypeModel} from '../models/MediaTypeModel'; export interface MediaDbPluginSettings { @@ -37,7 +38,7 @@ export interface MediaDbPluginSettings { musicReleasePropertyConversionRules: string, boardgamePropertyConversionRules: string, - propertyMappings: PropertyMappingModel[], + propertyMappingModels: PropertyMappingModel[], } @@ -69,62 +70,96 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = { musicReleasePropertyConversionRules: '', boardgamePropertyConversionRules: '', - propertyMappings: [ + propertyMappingModels: [ + /* { type: MediaType.Movie, properties: [ - new PropertyMapping('type', '', PropertyMappingOption.None, true), - new PropertyMapping('subType', '', PropertyMappingOption.None), - new PropertyMapping('title', '', PropertyMappingOption.None), - new PropertyMapping('englishTitle', '', PropertyMappingOption.None), - new PropertyMapping('year', '', PropertyMappingOption.None), - new PropertyMapping('dataSource', '', PropertyMappingOption.None, true), - new PropertyMapping('url', '', PropertyMappingOption.None), - new PropertyMapping('id', '', PropertyMappingOption.None, true), + new PropertyMapping('type', '', PropertyMappingOption.Default, true), + new PropertyMapping('subType', '', PropertyMappingOption.Default), + new PropertyMapping('title', '', PropertyMappingOption.Default), + new PropertyMapping('englishTitle', '', PropertyMappingOption.Default), + new PropertyMapping('year', '', PropertyMappingOption.Default), + new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true), + new PropertyMapping('url', '', PropertyMappingOption.Default), + new PropertyMapping('id', '', PropertyMappingOption.Default, true), - new PropertyMapping('genres', '', PropertyMappingOption.None), - new PropertyMapping('producer', '', PropertyMappingOption.None), - new PropertyMapping('duration', '', PropertyMappingOption.None), - new PropertyMapping('onlineRating', '', PropertyMappingOption.None), - new PropertyMapping('image', '', PropertyMappingOption.None), - new PropertyMapping('released', '', PropertyMappingOption.None), - new PropertyMapping('premiere', '', PropertyMappingOption.None), - new PropertyMapping('watched', '', PropertyMappingOption.None), - new PropertyMapping('lastWatched', '', PropertyMappingOption.None), - new PropertyMapping('personalRating', '', PropertyMappingOption.None), + new PropertyMapping('genres', '', PropertyMappingOption.Default), + new PropertyMapping('producer', '', PropertyMappingOption.Default), + new PropertyMapping('duration', '', PropertyMappingOption.Default), + new PropertyMapping('onlineRating', '', PropertyMappingOption.Default), + new PropertyMapping('image', '', PropertyMappingOption.Default), + new PropertyMapping('released', '', PropertyMappingOption.Default), + new PropertyMapping('premiere', '', PropertyMappingOption.Default), + new PropertyMapping('watched', '', PropertyMappingOption.Default), + new PropertyMapping('lastWatched', '', PropertyMappingOption.Default), + new PropertyMapping('personalRating', '', PropertyMappingOption.Default), ], }, { type: MediaType.Series, properties: [ - new PropertyMapping('type', '', PropertyMappingOption.None, true), - new PropertyMapping('subType', '', PropertyMappingOption.None), - new PropertyMapping('title', '', PropertyMappingOption.None), - new PropertyMapping('englishTitle', '', PropertyMappingOption.None), - new PropertyMapping('year', '', PropertyMappingOption.None), - new PropertyMapping('dataSource', '', PropertyMappingOption.None, true), - new PropertyMapping('url', '', PropertyMappingOption.None), - new PropertyMapping('id', '', PropertyMappingOption.None, true), + new PropertyMapping('type', '', PropertyMappingOption.Default, true), + new PropertyMapping('subType', '', PropertyMappingOption.Default), + new PropertyMapping('title', '', PropertyMappingOption.Default), + new PropertyMapping('englishTitle', '', PropertyMappingOption.Default), + new PropertyMapping('year', '', PropertyMappingOption.Default), + new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true), + new PropertyMapping('url', '', PropertyMappingOption.Default), + new PropertyMapping('id', '', PropertyMappingOption.Default, true), - new PropertyMapping('genres', '', PropertyMappingOption.None), - new PropertyMapping('studios', '', PropertyMappingOption.None), - new PropertyMapping('episodes', '', PropertyMappingOption.None), - new PropertyMapping('duration', '', PropertyMappingOption.None), - new PropertyMapping('onlineRating', '', PropertyMappingOption.None), - new PropertyMapping('image', '', PropertyMappingOption.None), - new PropertyMapping('released', '', PropertyMappingOption.None), - new PropertyMapping('airing', '', PropertyMappingOption.None), - new PropertyMapping('airedFrom', '', PropertyMappingOption.None), - new PropertyMapping('airedTo', '', PropertyMappingOption.None), - new PropertyMapping('watched', '', PropertyMappingOption.None), - new PropertyMapping('lastWatched', '', PropertyMappingOption.None), - new PropertyMapping('personalRating', '', PropertyMappingOption.None), + new PropertyMapping('genres', '', PropertyMappingOption.Default), + new PropertyMapping('studios', '', PropertyMappingOption.Default), + new PropertyMapping('episodes', '', PropertyMappingOption.Default), + new PropertyMapping('duration', '', PropertyMappingOption.Default), + new PropertyMapping('onlineRating', '', PropertyMappingOption.Default), + new PropertyMapping('image', '', PropertyMappingOption.Default), + new PropertyMapping('released', '', PropertyMappingOption.Default), + new PropertyMapping('airing', '', PropertyMappingOption.Default), + new PropertyMapping('airedFrom', '', PropertyMappingOption.Default), + new PropertyMapping('airedTo', '', PropertyMappingOption.Default), + new PropertyMapping('watched', '', PropertyMappingOption.Default), + new PropertyMapping('lastWatched', '', PropertyMappingOption.Default), + new PropertyMapping('personalRating', '', PropertyMappingOption.Default), ], }, + + */ ], }; +export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource']; + +export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings { + let defaultSettings = DEFAULT_SETTINGS; + + // construct property mapping defaults + const propertyMappingModels: PropertyMappingModel[] = []; + for (const mediaType of MEDIA_TYPES) { + const model: MediaTypeModel = plugin.mediaTypeManager.createMediaTypeModelFromMediaType({}, mediaType); + const metadataObj = model.toMetaDataObject(); + // console.log(metadataObj); + // console.log(model); + + const propertyMappingModel: PropertyMappingModel = { + type: mediaType, + properties: [], + }; + + for (const key of Object.keys(metadataObj)) { + propertyMappingModel.properties.push( + new PropertyMapping(key, '', PropertyMappingOption.Default, lockedPropertyMappings.contains(key)), + ); + } + + propertyMappingModels.push(propertyMappingModel); + } + + defaultSettings.propertyMappingModels = propertyMappingModels; + return defaultSettings; +} + export class MediaDbSettingTab extends PluginSettingTab { plugin: MediaDbPlugin; @@ -433,14 +468,38 @@ export class MediaDbSettingTab extends PluginSettingTab { */ // endregion - console.log(this.plugin.settings.propertyMappings); + console.log(this.plugin.settings.propertyMappingModels); + // console.log(getDefaultSettings(this.plugin)); - new PropertyBindingsComponent({ + let propertyMappingExplanation = containerEl.createEl('div'); + propertyMappingExplanation.innerHTML = `

Allow you to remap the metadata fields of newly created media db entries.

+

+ The different options are: + +

  • "default": does no remapping and keeps the metadata field as it is
  • +
  • "remap": renames the metadata field to what ever you specify
  • +
  • "remove": removes the metadata field entirely
  • + +

    `; + + + new PropertyMappingModelsComponent({ target: this.containerEl, props: { - models: this.plugin.settings.propertyMappings, - save: (models: PropertyMappingModel[]) => { - this.plugin.settings.propertyMappings = models; + models: JSON.parse(JSON.stringify(this.plugin.settings.propertyMappingModels)), + save: (model: PropertyMappingModel) => { + let propertyMappingModels: PropertyMappingModel[] = []; + + for (const model2 of this.plugin.settings.propertyMappingModels) { + if (model2.type === model.type) { + propertyMappingModels.push(model); + } else { + propertyMappingModels.push(model2); + } + } + + this.plugin.settings.propertyMappingModels = propertyMappingModels; + new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`); this.plugin.saveSettings(); }, }, diff --git a/src/settings/suggesters/Suggest.ts b/src/settings/suggesters/Suggest.ts index 366da4b..cd5ce70 100644 --- a/src/settings/suggesters/Suggest.ts +++ b/src/settings/suggesters/Suggest.ts @@ -80,7 +80,7 @@ export class Suggest { } setSelectedItem(selectedIndex: number, scrollIntoView: boolean) { - const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length); + const normalizedIndex = this.suggestions.length > 0 ? wrapAround(selectedIndex, this.suggestions.length) : 0; const prevSelectedSuggestion = this.suggestions[this.selectedItem]; const selectedSuggestion = this.suggestions[normalizedIndex]; diff --git a/src/utils/MediaTypeManager.ts b/src/utils/MediaTypeManager.ts index 08a4f1e..2f88d5e 100644 --- a/src/utils/MediaTypeManager.ts +++ b/src/utils/MediaTypeManager.ts @@ -10,14 +10,13 @@ import {WikiModel} from '../models/WikiModel'; import {MusicReleaseModel} from '../models/MusicReleaseModel'; import {BoardGameModel} from '../models/BoardGameModel'; -export const MEDIA_TYPES = [MediaType.Movie, MediaType.Series, MediaType.Game, MediaType.Wiki, MediaType.MusicRelease, MediaType.BoardGame]; +export const MEDIA_TYPES: MediaType[] = [MediaType.Movie, MediaType.Series, MediaType.Game, MediaType.Wiki, MediaType.MusicRelease, MediaType.BoardGame]; export class MediaTypeManager { mediaFileNameTemplateMap: Map; mediaTemplateMap: Map; - constructor(settings: MediaDbPluginSettings) { - this.updateTemplates(settings); + constructor() { } updateTemplates(settings: MediaDbPluginSettings) { diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index feb99d6..e8f67ac 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -176,3 +176,6 @@ export function capitalizeFirstLetter(string: string): string { return string.charAt(0).toUpperCase() + string.slice(1); } +// credits to phibr0 on discord +export const ICON_LIST = ['activity', 'airplay', 'alarm-check', 'alarm-clock-off', 'alarm-clock', 'alarm-minus', 'alarm-plus', 'album', 'alert-circle', 'alert-octagon', 'alert-triangle', 'align-center-horizontal', 'align-center-vertical', 'align-center', 'align-end-horizontal', 'align-end-vertical', 'align-horizontal-distribute-center', 'align-horizontal-distribute-end', 'align-horizontal-distribute-start', 'align-horizontal-justify-center', 'align-horizontal-justify-end', 'align-horizontal-justify-start', 'align-horizontal-space-around', 'align-horizontal-space-between', 'align-justify', 'align-left', 'align-right', 'align-start-horizontal', 'align-start-vertical', 'align-vertical-distribute-center', 'align-vertical-distribute-end', 'align-vertical-distribute-start', 'align-vertical-justify-center', 'align-vertical-justify-end', 'align-vertical-justify-start', 'align-vertical-space-around', 'align-vertical-space-between', 'anchor', 'aperture', 'archive', 'arrow-big-down', 'arrow-big-left', 'arrow-big-right', 'arrow-big-up', 'arrow-down-circle', 'arrow-down-left', 'arrow-down-right', 'arrow-down', 'arrow-left-circle', 'arrow-left-right', 'arrow-left', 'arrow-right-circle', 'arrow-right', 'arrow-up-circle', 'arrow-up-left', 'arrow-up-right', 'arrow-up', 'asterisk', 'at-sign', 'award', 'axe', 'banknote', 'bar-chart-2', 'bar-chart', 'baseline', 'battery-charging', 'battery-full', 'battery-low', 'battery-medium', 'battery', 'beaker', 'bell-minus', 'bell-off', 'bell-plus', 'bell-ring', 'bell', 'bike', 'binary', 'bitcoin', 'bluetooth-connected', 'bluetooth-off', 'bluetooth-searching', 'bluetooth', 'bold', 'book-open', 'book', 'bookmark-minus', 'bookmark-plus', 'bookmark', 'bot', 'box-select', 'box', 'briefcase', 'brush', 'bug', 'building-2', 'building', 'bus', 'calculator', 'calendar', 'camera-off', 'camera', 'car', 'carrot', 'cast', 'check-circle-2', 'check-circle', 'check-square', 'check', 'chevron-down', 'chevron-first', 'chevron-last', 'chevron-left', 'chevron-right', 'chevron-up', 'chevrons-down-up', 'chevrons-down', 'chevrons-left', 'chevrons-right', 'chevrons-up-down', 'chevrons-up', 'chrome', 'circle-slashed', 'circle', 'clipboard-check', 'clipboard-copy', 'clipboard-list', 'clipboard-x', 'clipboard', 'clock-1', 'clock-10', 'clock-11', 'clock-12', 'clock-2', 'clock-3', 'clock-4', 'clock-5', 'clock-6', 'clock-7', 'clock-8', 'clock-9', 'clock', 'cloud-drizzle', 'cloud-fog', 'cloud-hail', 'cloud-lightning', 'cloud-moon', 'cloud-off', 'cloud-rain-wind', 'cloud-rain', 'cloud-snow', 'cloud-sun', 'cloud', 'cloudy', 'clover', 'code-2', 'code', 'codepen', 'codesandbox', 'coffee', 'coins', 'columns', 'command', 'compass', 'contact', 'contrast', 'cookie', 'copy', 'copyleft', 'copyright', 'corner-down-left', 'corner-down-right', 'corner-left-down', 'corner-left-up', 'corner-right-down', 'corner-right-up', 'corner-up-left', 'corner-up-right', 'cpu', 'credit-card', 'crop', 'cross', 'crosshair', 'crown', 'currency', 'database', 'delete', 'dice-1', 'dice-2', 'dice-3', 'dice-4', 'dice-5', 'dice-6', 'disc', 'divide-circle', 'divide-square', 'divide', 'dollar-sign', 'download-cloud', 'download', 'dribbble', 'droplet', 'droplets', 'drumstick', 'edit-2', 'edit-3', 'edit', 'egg', 'equal-not', 'equal', 'eraser', 'euro', 'expand', 'external-link', 'eye-off', 'eye', 'facebook', 'fast-forward', 'feather', 'figma', 'file-check-2', 'file-check', 'file-code', 'file-digit', 'file-input', 'file-minus-2', 'file-minus', 'file-output', 'file-plus-2', 'file-plus', 'file-search', 'file-text', 'file-x-2', 'file-x', 'file', 'files', 'film', 'filter', 'flag-off', 'flag-triangle-left', 'flag-triangle-right', 'flag', 'flame', 'flashlight-off', 'flashlight', 'flask-conical', 'flask-round', 'folder-minus', 'folder-open', 'folder-plus', 'folder', 'form-input', 'forward', 'frame', 'framer', 'frown', 'function-square', 'gamepad-2', 'gamepad', 'gauge', 'gavel', 'gem', 'ghost', 'gift', 'git-branch-plus', 'git-branch', 'git-commit', 'git-fork', 'git-merge', 'git-pull-request', 'github', 'gitlab', 'glasses', 'globe-2', 'globe', 'grab', 'graduation-cap', 'grid', 'grip-horizontal', 'grip-vertical', 'hammer', 'hand-metal', 'hand', 'hard-drive', 'hard-hat', 'hash', 'haze', 'headphones', 'heart', 'help-circle', 'hexagon', 'highlighter', 'history', 'home', 'image-minus', 'image-off', 'image-plus', 'image', 'import', 'inbox', 'indent', 'indian-rupee', 'infinity', 'info', 'inspect', 'instagram', 'italic', 'japanese-yen', 'key', 'keyboard', 'landmark', 'languages', 'laptop-2', 'laptop', 'lasso-select', 'lasso', 'layers', 'layout-dashboard', 'layout-grid', 'layout-list', 'layout-template', 'layout', 'library', 'life-buoy', 'lightbulb-off', 'lightbulb', 'link-2-off', 'link-2', 'link', 'linkedin', 'list-checks', 'list-minus', 'list-ordered', 'list-plus', 'list-x', 'list', 'loader-2', 'loader', 'locate-fixed', 'locate-off', 'locate', 'lock', 'log-in', 'log-out', 'mail', 'map-pin', 'map', 'maximize-2', 'maximize', 'megaphone', 'meh', 'menu', 'message-circle', 'message-square', 'mic-off', 'mic', 'minimize-2', 'minimize', 'minus-circle', 'minus-square', 'minus', 'monitor-off', 'monitor-speaker', 'monitor', 'moon', 'more-horizontal', 'more-vertical', 'mountain-snow', 'mountain', 'mouse-pointer-2', 'mouse-pointer-click', 'mouse-pointer', 'mouse', 'move-diagonal-2', 'move-diagonal', 'move-horizontal', 'move-vertical', 'move', 'music', 'navigation-2', 'navigation', 'network', 'octagon', 'option', 'outdent', 'package-check', 'package-minus', 'package-plus', 'package-search', 'package-x', 'package', 'palette', 'palmtree', 'paperclip', 'pause-circle', 'pause-octagon', 'pause', 'pen-tool', 'pencil', 'percent', 'person-standing', 'phone-call', 'phone-forwarded', 'phone-incoming', 'phone-missed', 'phone-off', 'phone-outgoing', 'phone', 'pie-chart', 'piggy-bank', 'pin', 'pipette', 'plane', 'play-circle', 'play', 'plug-zap', 'plus-circle', 'plus-square', 'plus', 'pocket', 'podcast', 'pointer', 'pound-sterling', 'power-off', 'power', 'printer', 'qr-code', 'quote', 'radio-receiver', 'radio', 'redo', 'refresh-ccw', 'refresh-cw', 'regex', 'repeat-1', 'repeat', 'reply-all', 'reply', 'rewind', 'rocket', 'rocking-chair', 'rotate-ccw', 'rotate-cw', 'rss', 'ruler', 'russian-ruble', 'save', 'scale', 'scan-line', 'scan', 'scissors', 'screen-share-off', 'screen-share', 'search', 'send', 'separator-horizontal', 'separator-vertical', 'server-crash', 'server-off', 'server', 'settings-2', 'settings', 'share-2', 'share', 'sheet', 'shield-alert', 'shield-check', 'shield-close', 'shield-off', 'shield', 'shirt', 'shopping-bag', 'shopping-cart', 'shovel', 'shrink', 'shuffle', 'sidebar-close', 'sidebar-open', 'sidebar', 'sigma', 'signal-high', 'signal-low', 'signal-medium', 'signal-zero', 'signal', 'skip-back', 'skip-forward', 'skull', 'slack', 'slash', 'sliders', 'smartphone-charging', 'smartphone', 'smile', 'snowflake', 'sort-asc', 'sort-desc', 'speaker', 'sprout', 'square', 'star-half', 'star', 'stop-circle', 'stretch-horizontal', 'stretch-vertical', 'strikethrough', 'subscript', 'sun', 'sunrise', 'sunset', 'superscript', 'swiss-franc', 'switch-camera', 'table', 'tablet', 'tag', 'target', 'tent', 'terminal-square', 'terminal', 'text-cursor-input', 'text-cursor', 'thermometer-snowflake', 'thermometer-sun', 'thermometer', 'thumbs-down', 'thumbs-up', 'ticket', 'timer-off', 'timer-reset', 'timer', 'toggle-left', 'toggle-right', 'tornado', 'trash-2', 'trash', 'trello', 'trending-down', 'trending-up', 'triangle', 'truck', 'tv-2', 'tv', 'twitch', 'twitter', 'type', 'umbrella', 'underline', 'undo', 'unlink-2', 'unlink', 'unlock', 'upload-cloud', 'upload', 'user-check', 'user-minus', 'user-plus', 'user-x', 'user', 'users', 'verified', 'vibrate', 'video-off', 'video', 'view', 'voicemail', 'volume-1', 'volume-2', 'volume-x', 'volume', 'wallet', 'wand', 'watch', 'waves', 'webcam', 'wifi-off', 'wifi', 'wind', 'wrap-text', 'wrench', 'x-circle', 'x-octagon', 'x-square', 'x', 'youtube', 'zap-off', 'zap', 'zoom-in', 'zoom-out', 'search-large', 'search', 'activity', 'airplay', 'alarm-check', 'alarm-clock-off', 'alarm-clock', 'alarm-minus', 'alarm-plus', 'album', 'alert-circle', 'alert-octagon', 'alert-triangle', 'align-center-horizontal', 'align-center-vertical', 'align-center', 'align-end-horizontal', 'align-end-vertical', 'align-horizontal-distribute-center', 'align-horizontal-distribute-end', 'align-horizontal-distribute-start', 'align-horizontal-justify-center', 'align-horizontal-justify-end', 'align-horizontal-justify-start', 'align-horizontal-space-around', 'align-horizontal-space-between', 'align-justify', 'align-left', 'align-right', 'align-start-horizontal', 'align-start-vertical', 'align-vertical-distribute-center', 'align-vertical-distribute-end', 'align-vertical-distribute-start', 'align-vertical-justify-center', 'align-vertical-justify-end', 'align-vertical-justify-start', 'align-vertical-space-around', 'align-vertical-space-between', 'anchor', 'aperture', 'archive', 'arrow-big-down', 'arrow-big-left', 'arrow-big-right', 'arrow-big-up', 'arrow-down-circle', 'arrow-down-left', 'arrow-down-right', 'arrow-down', 'arrow-left-circle', 'arrow-left-right', 'arrow-left', 'arrow-right-circle', 'arrow-right', 'arrow-up-circle', 'arrow-up-left', 'arrow-up-right', 'arrow-up', 'asterisk', 'at-sign', 'award', 'axe', 'banknote', 'bar-chart-2', 'bar-chart', 'baseline', 'battery-charging', 'battery-full', 'battery-low', 'battery-medium', 'battery', 'beaker', 'bell-minus', 'bell-off', 'bell-plus', 'bell-ring', 'bell', 'bike', 'binary', 'bitcoin', 'bluetooth-connected', 'bluetooth-off', 'bluetooth-searching', 'bluetooth', 'bold', 'book-open', 'book', 'bookmark-minus', 'bookmark-plus', 'bookmark', 'bot', 'box-select', 'box', 'briefcase', 'brush', 'bug', 'building-2', 'building', 'bus', 'calculator', 'calendar', 'camera-off', 'camera', 'car', 'carrot', 'cast', 'check-circle-2', 'check-circle', 'check-square', 'check', 'chevron-down', 'chevron-first', 'chevron-last', 'chevron-left', 'chevron-right', 'chevron-up', 'chevrons-down-up', 'chevrons-down', 'chevrons-left', 'chevrons-right', 'chevrons-up-down', 'chevrons-up', 'chrome', 'circle-slashed', 'circle', 'clipboard-check', 'clipboard-copy', 'clipboard-list', 'clipboard-x', 'clipboard', 'clock-1', 'clock-10', 'clock-11', 'clock-12', 'clock-2', 'clock-3', 'clock-4', 'clock-5', 'clock-6', 'clock-7', 'clock-8', 'clock-9', 'lucide-clock', 'cloud-drizzle', 'cloud-fog', 'cloud-hail', 'cloud-lightning', 'cloud-moon', 'cloud-off', 'cloud-rain-wind', 'cloud-rain', 'cloud-snow', 'cloud-sun', 'lucide-cloud', 'cloudy', 'clover', 'code-2', 'code', 'codepen', 'codesandbox', 'coffee', 'coins', 'columns', 'command', 'compass', 'contact', 'contrast', 'cookie', 'copy', 'copyleft', 'copyright', 'corner-down-left', 'corner-down-right', 'corner-left-down', 'corner-left-up', 'corner-right-down', 'corner-right-up', 'corner-up-left', 'corner-up-right', 'cpu', 'credit-card', 'crop', 'lucide-cross', 'crosshair', 'crown', 'currency', 'database', 'delete', 'dice-1', 'dice-2', 'dice-3', 'dice-4', 'dice-5', 'dice-6', 'disc', 'divide-circle', 'divide-square', 'divide', 'dollar-sign', 'download-cloud', 'download', 'dribbble', 'droplet', 'droplets', 'drumstick', 'edit-2', 'edit-3', 'edit', 'egg', 'equal-not', 'equal', 'eraser', 'euro', 'expand', 'external-link', 'eye-off', 'eye', 'facebook', 'fast-forward', 'feather', 'figma', 'file-check-2', 'file-check', 'file-code', 'file-digit', 'file-input', 'file-minus-2', 'file-minus', 'file-output', 'file-plus-2', 'file-plus', 'file-search', 'file-text', 'file-x-2', 'file-x', 'file', 'files', 'film', 'filter', 'flag-off', 'flag-triangle-left', 'flag-triangle-right', 'flag', 'flame', 'flashlight-off', 'flashlight', 'flask-conical', 'flask-round', 'folder-minus', 'folder-open', 'folder-plus', 'lucide-folder', 'form-input', 'forward', 'frame', 'framer', 'frown', 'function-square', 'gamepad-2', 'gamepad', 'gauge', 'gavel', 'gem', 'ghost', 'gift', 'git-branch-plus', 'git-branch', 'git-commit', 'git-fork', 'git-merge', 'git-pull-request', 'github', 'gitlab', 'glasses', 'globe-2', 'globe', 'grab', 'graduation-cap', 'grid', 'grip-horizontal', 'grip-vertical', 'hammer', 'hand-metal', 'hand', 'hard-drive', 'hard-hat', 'hash', 'haze', 'headphones', 'heart', 'help-circle', 'hexagon', 'highlighter', 'history', 'home', 'image-minus', 'image-off', 'image-plus', 'image', 'import', 'inbox', 'indent', 'indian-rupee', 'infinity', 'lucide-info', 'inspect', 'instagram', 'italic', 'japanese-yen', 'key', 'keyboard', 'landmark', 'lucide-languages', 'laptop-2', 'laptop', 'lasso-select', 'lasso', 'layers', 'layout-dashboard', 'layout-grid', 'layout-list', 'layout-template', 'layout', 'library', 'life-buoy', 'lightbulb-off', 'lightbulb', 'link-2-off', 'link-2', 'lucide-link', 'linkedin', 'list-checks', 'list-minus', 'list-ordered', 'list-plus', 'list-x', 'list', 'loader-2', 'loader', 'locate-fixed', 'locate-off', 'locate', 'lock', 'log-in', 'log-out', 'mail', 'map-pin', 'map', 'maximize-2', 'maximize', 'megaphone', 'meh', 'menu', 'message-circle', 'message-square', 'mic-off', 'mic', 'minimize-2', 'minimize', 'minus-circle', 'minus-square', 'minus', 'monitor-off', 'monitor-speaker', 'monitor', 'moon', 'more-horizontal', 'more-vertical', 'mountain-snow', 'mountain', 'mouse-pointer-2', 'mouse-pointer-click', 'mouse-pointer', 'mouse', 'move-diagonal-2', 'move-diagonal', 'move-horizontal', 'move-vertical', 'move', 'music', 'navigation-2', 'navigation', 'network', 'octagon', 'option', 'outdent', 'package-check', 'package-minus', 'package-plus', 'package-search', 'package-x', 'package', 'palette', 'palmtree', 'paperclip', 'pause-circle', 'pause-octagon', 'pause', 'pen-tool', 'lucide-pencil', 'percent', 'person-standing', 'phone-call', 'phone-forwarded', 'phone-incoming', 'phone-missed', 'phone-off', 'phone-outgoing', 'phone', 'pie-chart', 'piggy-bank', 'lucide-pin', 'pipette', 'plane', 'play-circle', 'play', 'plug-zap', 'plus-circle', 'plus-square', 'plus', 'pocket', 'podcast', 'pointer', 'pound-sterling', 'power-off', 'power', 'printer', 'qr-code', 'quote', 'radio-receiver', 'radio', 'redo', 'refresh-ccw', 'refresh-cw', 'regex', 'repeat-1', 'repeat', 'reply-all', 'reply', 'rewind', 'rocket', 'rocking-chair', 'rotate-ccw', 'rotate-cw', 'rss', 'ruler', 'russian-ruble', 'save', 'scale', 'scan-line', 'scan', 'scissors', 'screen-share-off', 'screen-share', 'lucide-search', 'send', 'separator-horizontal', 'separator-vertical', 'server-crash', 'server-off', 'server', 'settings-2', 'settings', 'share-2', 'share', 'sheet', 'shield-alert', 'shield-check', 'shield-close', 'shield-off', 'shield', 'shirt', 'shopping-bag', 'shopping-cart', 'shovel', 'shrink', 'shuffle', 'sidebar-close', 'sidebar-open', 'sidebar', 'sigma', 'signal-high', 'signal-low', 'signal-medium', 'signal-zero', 'signal', 'skip-back', 'skip-forward', 'skull', 'slack', 'slash', 'sliders', 'smartphone-charging', 'smartphone', 'smile', 'snowflake', 'sort-asc', 'sort-desc', 'speaker', 'sprout', 'square', 'star-half', 'lucide-star', 'stop-circle', 'stretch-horizontal', 'stretch-vertical', 'strikethrough', 'subscript', 'sun', 'sunrise', 'sunset', 'superscript', 'swiss-franc', 'switch-camera', 'table', 'tablet', 'tag', 'target', 'tent', 'terminal-square', 'terminal', 'text-cursor-input', 'text-cursor', 'thermometer-snowflake', 'thermometer-sun', 'thermometer', 'thumbs-down', 'thumbs-up', 'ticket', 'timer-off', 'timer-reset', 'timer', 'toggle-left', 'toggle-right', 'tornado', 'trash-2', 'lucide-trash', 'trello', 'trending-down', 'trending-up', 'triangle', 'truck', 'tv-2', 'tv', 'twitch', 'twitter', 'type', 'umbrella', 'underline', 'undo', 'unlink-2', 'unlink', 'unlock', 'upload-cloud', 'upload', 'user-check', 'user-minus', 'user-plus', 'user-x', 'user', 'users', 'verified', 'vibrate', 'video-off', 'video', 'view', 'voicemail', 'volume-1', 'volume-2', 'volume-x', 'volume', 'wallet', 'wand', 'watch', 'waves', 'webcam', 'wifi-off', 'wifi', 'wind', 'wrap-text', 'wrench', 'x-circle', 'x-octagon', 'x-square', 'x', 'youtube', 'zap-off', 'zap', 'zoom-in', 'zoom-out', 'search-large', 'lucide-search']; + From 68ec5135cca467682182f759ea885844dc89a703 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Mon, 26 Sep 2022 15:44:12 +0200 Subject: [PATCH 21/43] property mapping validation #48 --- src/main.ts | 8 +- src/settings/PropertyMapper.ts | 10 +- src/settings/PropertyMapping.ts | 111 ++++++++++++++++-- .../PropertyMappingModelsComponent.svelte | 22 +++- src/settings/Settings.ts | 7 +- src/utils/Utils.ts | 11 ++ 6 files changed, 146 insertions(+), 23 deletions(-) diff --git a/src/main.ts b/src/main.ts index 4af8c5b..cb5e80d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -507,15 +507,15 @@ export default class MediaDbPlugin extends Plugin { for (const defaultProperty of defaultPropertyMappingModel.properties) { let newProperty = newPropertyMappingModel.properties.find(x => x.property === defaultProperty.property); if (newProperty === undefined) { + // default property is an instance newProperties.push(defaultProperty); } else { - newProperties.push(newProperty); + // newProperty is just an object and take locked status from default property + newProperties.push(new PropertyMapping(newProperty.property, newProperty.newProperty, newProperty.mapping, defaultProperty.locked)); } } - newPropertyMappingModel.properties = newProperties; - - newPropertyMappings.push(newPropertyMappingModel); + newPropertyMappings.push(new PropertyMappingModel(newPropertyMappingModel.type, newProperties)); } } loadedSettings.propertyMappingModels = newPropertyMappings; diff --git a/src/settings/PropertyMapper.ts b/src/settings/PropertyMapper.ts index 12aa4e2..a1e41a6 100644 --- a/src/settings/PropertyMapper.ts +++ b/src/settings/PropertyMapper.ts @@ -16,15 +16,23 @@ export class PropertyMapper { * @param obj */ convertObject(obj: object): object { + console.log('test1'); + if (!obj.hasOwnProperty('type')) { return obj; } + console.log('test2'); // @ts-ignore - if (MEDIA_TYPES.contains(obj.type)) { + console.log(obj.type); + + // @ts-ignore + if (MEDIA_TYPES.filter(x => x.toString() == obj.type).length < 1) { return obj; } + console.log('test3'); + // @ts-ignore const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties; diff --git a/src/settings/PropertyMapping.ts b/src/settings/PropertyMapping.ts index e68bdfc..a221918 100644 --- a/src/settings/PropertyMapping.ts +++ b/src/settings/PropertyMapping.ts @@ -1,4 +1,4 @@ -import {containsOnlyLettersAndUnderscores} from '../utils/Utils'; +import {containsOnlyLettersAndUnderscores, PropertyMappingNameConflictError, PropertyMappingValidationError} from '../utils/Utils'; import {MediaType} from '../utils/MediaType'; export enum PropertyMappingOption { @@ -9,9 +9,73 @@ export enum PropertyMappingOption { export const propertyMappingOptions = [PropertyMappingOption.Default, PropertyMappingOption.Map, PropertyMappingOption.Remove]; -export interface PropertyMappingModel { - type: MediaType, - properties: PropertyMapping[], +export class PropertyMappingModel { + type: MediaType; + properties: PropertyMapping[]; + + constructor(type: MediaType, properties?: PropertyMapping[]) { + this.type = type; + this.properties = properties ?? []; + } + + validate(): { res: boolean, err?: Error } { + // check properties + for (const property of this.properties) { + const propertyValidation = property.validate(); + if (!propertyValidation.res) { + return { + res: false, + err: propertyValidation.err, + }; + } + } + + // check for name collisions + for (const property of this.getMappedProperties()) { + const propertiesWithSameTarget = this.getMappedProperties().filter(x => x.newProperty === property.newProperty); + if (propertiesWithSameTarget.length === 0) { + // if we get there, then something in this code is wrong + } else if (propertiesWithSameTarget.length === 1) { + // all good + } else { + // two or more properties are mapped to the same property + return { + res: false, + err: new PropertyMappingNameConflictError(`Multiple remapped properties (${propertiesWithSameTarget.map(x => x.toString()).toString()}) may not share the same name.`), + }; + } + } + // remapped properties may not have the same name as any original property + for (const property of this.getMappedProperties()) { + const propertiesWithSameTarget = this.properties.filter(x => x.newProperty === property.property); + if (propertiesWithSameTarget.length === 0) { + // all good + } else { + // a mapped property shares the same name with an original property + return { + res: false, + err: new PropertyMappingNameConflictError(`Remapped property (${property}) may not share it's new name with an existing property.`), + }; + } + } + + return { + res: true, + }; + } + + getMappedProperties() { + return this.properties.filter(x => x.mapping === PropertyMappingOption.Map); + } + + copy(): PropertyMappingModel { + const copy = new PropertyMappingModel(this.type); + for (const property of this.properties) { + const propertyCopy = new PropertyMapping(property.property, property.newProperty, property.mapping, property.locked); + copy.properties.push(propertyCopy); + } + return copy; + } } export class PropertyMapping { @@ -49,16 +113,47 @@ export class PropertyMapping { */ } - validate(): string { + validate(): { res: boolean, err?: Error } { + // locked property may only be default + if (this.locked) { + if (this.mapping === PropertyMappingOption.Remove) { + return { + res: false, + err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": locked property may not be removed.`), + }; + } + if (this.mapping === PropertyMappingOption.Map) { + return { + res: false, + err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": locked property may not be remapped.`), + }; + } + } + + if (this.mapping === PropertyMappingOption.Default) { + return {res: true}; + } + if (this.mapping === PropertyMappingOption.Remove) { + return {res: true}; + } + if (!this.property || !containsOnlyLettersAndUnderscores(this.property)) { - return `Error in conversion rule "${this.toString()}": property may not be empty and only contain letters and underscores.`; + return { + res: false, + err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": property may not be empty and only contain letters and underscores.`), + }; } if (!this.newProperty || !containsOnlyLettersAndUnderscores(this.newProperty)) { - return `Error in conversion rule "${this.toString()}": new property may not be empty and only contain letters and underscores.`; + return { + res: false, + err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": new property may not be empty and only contain letters and underscores.`), + }; } - return ''; + return { + res: true, + }; } toString(): string { diff --git a/src/settings/PropertyMappingModelsComponent.svelte b/src/settings/PropertyMappingModelsComponent.svelte index 1e14b20..f5d1af8 100644 --- a/src/settings/PropertyMappingModelsComponent.svelte +++ b/src/settings/PropertyMappingModelsComponent.svelte @@ -49,10 +49,15 @@ margin: 0; } - .media-db-plugin-property-binding-to { + .media-db-plugin-property-mapping-to { display: flex; align-items: center; } + + .media-db-plugin-property-mapping-validation { + color: var(--text-error); + margin-bottom: 5px; + }
    @@ -81,18 +86,25 @@ {#if property.mapping === PropertyMappingOption.Map} -
    +
    {/if} {/if}
    - { /each } + { /each }
    - - { /each } + { /each }
    {JSON.stringify(models, null, 4)}
    diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 30d31c6..7fe871a 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -142,10 +142,7 @@ export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings // console.log(metadataObj); // console.log(model); - const propertyMappingModel: PropertyMappingModel = { - type: mediaType, - properties: [], - }; + const propertyMappingModel: PropertyMappingModel = new PropertyMappingModel(mediaType); for (const key of Object.keys(metadataObj)) { propertyMappingModel.properties.push( @@ -486,7 +483,7 @@ export class MediaDbSettingTab extends PluginSettingTab { new PropertyMappingModelsComponent({ target: this.containerEl, props: { - models: JSON.parse(JSON.stringify(this.plugin.settings.propertyMappingModels)), + models: this.plugin.settings.propertyMappingModels.map(x => x.copy()), save: (model: PropertyMappingModel) => { let propertyMappingModels: PropertyMappingModel[] = []; diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index e8f67ac..37426df 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -179,3 +179,14 @@ export function capitalizeFirstLetter(string: string): string { // credits to phibr0 on discord export const ICON_LIST = ['activity', 'airplay', 'alarm-check', 'alarm-clock-off', 'alarm-clock', 'alarm-minus', 'alarm-plus', 'album', 'alert-circle', 'alert-octagon', 'alert-triangle', 'align-center-horizontal', 'align-center-vertical', 'align-center', 'align-end-horizontal', 'align-end-vertical', 'align-horizontal-distribute-center', 'align-horizontal-distribute-end', 'align-horizontal-distribute-start', 'align-horizontal-justify-center', 'align-horizontal-justify-end', 'align-horizontal-justify-start', 'align-horizontal-space-around', 'align-horizontal-space-between', 'align-justify', 'align-left', 'align-right', 'align-start-horizontal', 'align-start-vertical', 'align-vertical-distribute-center', 'align-vertical-distribute-end', 'align-vertical-distribute-start', 'align-vertical-justify-center', 'align-vertical-justify-end', 'align-vertical-justify-start', 'align-vertical-space-around', 'align-vertical-space-between', 'anchor', 'aperture', 'archive', 'arrow-big-down', 'arrow-big-left', 'arrow-big-right', 'arrow-big-up', 'arrow-down-circle', 'arrow-down-left', 'arrow-down-right', 'arrow-down', 'arrow-left-circle', 'arrow-left-right', 'arrow-left', 'arrow-right-circle', 'arrow-right', 'arrow-up-circle', 'arrow-up-left', 'arrow-up-right', 'arrow-up', 'asterisk', 'at-sign', 'award', 'axe', 'banknote', 'bar-chart-2', 'bar-chart', 'baseline', 'battery-charging', 'battery-full', 'battery-low', 'battery-medium', 'battery', 'beaker', 'bell-minus', 'bell-off', 'bell-plus', 'bell-ring', 'bell', 'bike', 'binary', 'bitcoin', 'bluetooth-connected', 'bluetooth-off', 'bluetooth-searching', 'bluetooth', 'bold', 'book-open', 'book', 'bookmark-minus', 'bookmark-plus', 'bookmark', 'bot', 'box-select', 'box', 'briefcase', 'brush', 'bug', 'building-2', 'building', 'bus', 'calculator', 'calendar', 'camera-off', 'camera', 'car', 'carrot', 'cast', 'check-circle-2', 'check-circle', 'check-square', 'check', 'chevron-down', 'chevron-first', 'chevron-last', 'chevron-left', 'chevron-right', 'chevron-up', 'chevrons-down-up', 'chevrons-down', 'chevrons-left', 'chevrons-right', 'chevrons-up-down', 'chevrons-up', 'chrome', 'circle-slashed', 'circle', 'clipboard-check', 'clipboard-copy', 'clipboard-list', 'clipboard-x', 'clipboard', 'clock-1', 'clock-10', 'clock-11', 'clock-12', 'clock-2', 'clock-3', 'clock-4', 'clock-5', 'clock-6', 'clock-7', 'clock-8', 'clock-9', 'clock', 'cloud-drizzle', 'cloud-fog', 'cloud-hail', 'cloud-lightning', 'cloud-moon', 'cloud-off', 'cloud-rain-wind', 'cloud-rain', 'cloud-snow', 'cloud-sun', 'cloud', 'cloudy', 'clover', 'code-2', 'code', 'codepen', 'codesandbox', 'coffee', 'coins', 'columns', 'command', 'compass', 'contact', 'contrast', 'cookie', 'copy', 'copyleft', 'copyright', 'corner-down-left', 'corner-down-right', 'corner-left-down', 'corner-left-up', 'corner-right-down', 'corner-right-up', 'corner-up-left', 'corner-up-right', 'cpu', 'credit-card', 'crop', 'cross', 'crosshair', 'crown', 'currency', 'database', 'delete', 'dice-1', 'dice-2', 'dice-3', 'dice-4', 'dice-5', 'dice-6', 'disc', 'divide-circle', 'divide-square', 'divide', 'dollar-sign', 'download-cloud', 'download', 'dribbble', 'droplet', 'droplets', 'drumstick', 'edit-2', 'edit-3', 'edit', 'egg', 'equal-not', 'equal', 'eraser', 'euro', 'expand', 'external-link', 'eye-off', 'eye', 'facebook', 'fast-forward', 'feather', 'figma', 'file-check-2', 'file-check', 'file-code', 'file-digit', 'file-input', 'file-minus-2', 'file-minus', 'file-output', 'file-plus-2', 'file-plus', 'file-search', 'file-text', 'file-x-2', 'file-x', 'file', 'files', 'film', 'filter', 'flag-off', 'flag-triangle-left', 'flag-triangle-right', 'flag', 'flame', 'flashlight-off', 'flashlight', 'flask-conical', 'flask-round', 'folder-minus', 'folder-open', 'folder-plus', 'folder', 'form-input', 'forward', 'frame', 'framer', 'frown', 'function-square', 'gamepad-2', 'gamepad', 'gauge', 'gavel', 'gem', 'ghost', 'gift', 'git-branch-plus', 'git-branch', 'git-commit', 'git-fork', 'git-merge', 'git-pull-request', 'github', 'gitlab', 'glasses', 'globe-2', 'globe', 'grab', 'graduation-cap', 'grid', 'grip-horizontal', 'grip-vertical', 'hammer', 'hand-metal', 'hand', 'hard-drive', 'hard-hat', 'hash', 'haze', 'headphones', 'heart', 'help-circle', 'hexagon', 'highlighter', 'history', 'home', 'image-minus', 'image-off', 'image-plus', 'image', 'import', 'inbox', 'indent', 'indian-rupee', 'infinity', 'info', 'inspect', 'instagram', 'italic', 'japanese-yen', 'key', 'keyboard', 'landmark', 'languages', 'laptop-2', 'laptop', 'lasso-select', 'lasso', 'layers', 'layout-dashboard', 'layout-grid', 'layout-list', 'layout-template', 'layout', 'library', 'life-buoy', 'lightbulb-off', 'lightbulb', 'link-2-off', 'link-2', 'link', 'linkedin', 'list-checks', 'list-minus', 'list-ordered', 'list-plus', 'list-x', 'list', 'loader-2', 'loader', 'locate-fixed', 'locate-off', 'locate', 'lock', 'log-in', 'log-out', 'mail', 'map-pin', 'map', 'maximize-2', 'maximize', 'megaphone', 'meh', 'menu', 'message-circle', 'message-square', 'mic-off', 'mic', 'minimize-2', 'minimize', 'minus-circle', 'minus-square', 'minus', 'monitor-off', 'monitor-speaker', 'monitor', 'moon', 'more-horizontal', 'more-vertical', 'mountain-snow', 'mountain', 'mouse-pointer-2', 'mouse-pointer-click', 'mouse-pointer', 'mouse', 'move-diagonal-2', 'move-diagonal', 'move-horizontal', 'move-vertical', 'move', 'music', 'navigation-2', 'navigation', 'network', 'octagon', 'option', 'outdent', 'package-check', 'package-minus', 'package-plus', 'package-search', 'package-x', 'package', 'palette', 'palmtree', 'paperclip', 'pause-circle', 'pause-octagon', 'pause', 'pen-tool', 'pencil', 'percent', 'person-standing', 'phone-call', 'phone-forwarded', 'phone-incoming', 'phone-missed', 'phone-off', 'phone-outgoing', 'phone', 'pie-chart', 'piggy-bank', 'pin', 'pipette', 'plane', 'play-circle', 'play', 'plug-zap', 'plus-circle', 'plus-square', 'plus', 'pocket', 'podcast', 'pointer', 'pound-sterling', 'power-off', 'power', 'printer', 'qr-code', 'quote', 'radio-receiver', 'radio', 'redo', 'refresh-ccw', 'refresh-cw', 'regex', 'repeat-1', 'repeat', 'reply-all', 'reply', 'rewind', 'rocket', 'rocking-chair', 'rotate-ccw', 'rotate-cw', 'rss', 'ruler', 'russian-ruble', 'save', 'scale', 'scan-line', 'scan', 'scissors', 'screen-share-off', 'screen-share', 'search', 'send', 'separator-horizontal', 'separator-vertical', 'server-crash', 'server-off', 'server', 'settings-2', 'settings', 'share-2', 'share', 'sheet', 'shield-alert', 'shield-check', 'shield-close', 'shield-off', 'shield', 'shirt', 'shopping-bag', 'shopping-cart', 'shovel', 'shrink', 'shuffle', 'sidebar-close', 'sidebar-open', 'sidebar', 'sigma', 'signal-high', 'signal-low', 'signal-medium', 'signal-zero', 'signal', 'skip-back', 'skip-forward', 'skull', 'slack', 'slash', 'sliders', 'smartphone-charging', 'smartphone', 'smile', 'snowflake', 'sort-asc', 'sort-desc', 'speaker', 'sprout', 'square', 'star-half', 'star', 'stop-circle', 'stretch-horizontal', 'stretch-vertical', 'strikethrough', 'subscript', 'sun', 'sunrise', 'sunset', 'superscript', 'swiss-franc', 'switch-camera', 'table', 'tablet', 'tag', 'target', 'tent', 'terminal-square', 'terminal', 'text-cursor-input', 'text-cursor', 'thermometer-snowflake', 'thermometer-sun', 'thermometer', 'thumbs-down', 'thumbs-up', 'ticket', 'timer-off', 'timer-reset', 'timer', 'toggle-left', 'toggle-right', 'tornado', 'trash-2', 'trash', 'trello', 'trending-down', 'trending-up', 'triangle', 'truck', 'tv-2', 'tv', 'twitch', 'twitter', 'type', 'umbrella', 'underline', 'undo', 'unlink-2', 'unlink', 'unlock', 'upload-cloud', 'upload', 'user-check', 'user-minus', 'user-plus', 'user-x', 'user', 'users', 'verified', 'vibrate', 'video-off', 'video', 'view', 'voicemail', 'volume-1', 'volume-2', 'volume-x', 'volume', 'wallet', 'wand', 'watch', 'waves', 'webcam', 'wifi-off', 'wifi', 'wind', 'wrap-text', 'wrench', 'x-circle', 'x-octagon', 'x-square', 'x', 'youtube', 'zap-off', 'zap', 'zoom-in', 'zoom-out', 'search-large', 'search', 'activity', 'airplay', 'alarm-check', 'alarm-clock-off', 'alarm-clock', 'alarm-minus', 'alarm-plus', 'album', 'alert-circle', 'alert-octagon', 'alert-triangle', 'align-center-horizontal', 'align-center-vertical', 'align-center', 'align-end-horizontal', 'align-end-vertical', 'align-horizontal-distribute-center', 'align-horizontal-distribute-end', 'align-horizontal-distribute-start', 'align-horizontal-justify-center', 'align-horizontal-justify-end', 'align-horizontal-justify-start', 'align-horizontal-space-around', 'align-horizontal-space-between', 'align-justify', 'align-left', 'align-right', 'align-start-horizontal', 'align-start-vertical', 'align-vertical-distribute-center', 'align-vertical-distribute-end', 'align-vertical-distribute-start', 'align-vertical-justify-center', 'align-vertical-justify-end', 'align-vertical-justify-start', 'align-vertical-space-around', 'align-vertical-space-between', 'anchor', 'aperture', 'archive', 'arrow-big-down', 'arrow-big-left', 'arrow-big-right', 'arrow-big-up', 'arrow-down-circle', 'arrow-down-left', 'arrow-down-right', 'arrow-down', 'arrow-left-circle', 'arrow-left-right', 'arrow-left', 'arrow-right-circle', 'arrow-right', 'arrow-up-circle', 'arrow-up-left', 'arrow-up-right', 'arrow-up', 'asterisk', 'at-sign', 'award', 'axe', 'banknote', 'bar-chart-2', 'bar-chart', 'baseline', 'battery-charging', 'battery-full', 'battery-low', 'battery-medium', 'battery', 'beaker', 'bell-minus', 'bell-off', 'bell-plus', 'bell-ring', 'bell', 'bike', 'binary', 'bitcoin', 'bluetooth-connected', 'bluetooth-off', 'bluetooth-searching', 'bluetooth', 'bold', 'book-open', 'book', 'bookmark-minus', 'bookmark-plus', 'bookmark', 'bot', 'box-select', 'box', 'briefcase', 'brush', 'bug', 'building-2', 'building', 'bus', 'calculator', 'calendar', 'camera-off', 'camera', 'car', 'carrot', 'cast', 'check-circle-2', 'check-circle', 'check-square', 'check', 'chevron-down', 'chevron-first', 'chevron-last', 'chevron-left', 'chevron-right', 'chevron-up', 'chevrons-down-up', 'chevrons-down', 'chevrons-left', 'chevrons-right', 'chevrons-up-down', 'chevrons-up', 'chrome', 'circle-slashed', 'circle', 'clipboard-check', 'clipboard-copy', 'clipboard-list', 'clipboard-x', 'clipboard', 'clock-1', 'clock-10', 'clock-11', 'clock-12', 'clock-2', 'clock-3', 'clock-4', 'clock-5', 'clock-6', 'clock-7', 'clock-8', 'clock-9', 'lucide-clock', 'cloud-drizzle', 'cloud-fog', 'cloud-hail', 'cloud-lightning', 'cloud-moon', 'cloud-off', 'cloud-rain-wind', 'cloud-rain', 'cloud-snow', 'cloud-sun', 'lucide-cloud', 'cloudy', 'clover', 'code-2', 'code', 'codepen', 'codesandbox', 'coffee', 'coins', 'columns', 'command', 'compass', 'contact', 'contrast', 'cookie', 'copy', 'copyleft', 'copyright', 'corner-down-left', 'corner-down-right', 'corner-left-down', 'corner-left-up', 'corner-right-down', 'corner-right-up', 'corner-up-left', 'corner-up-right', 'cpu', 'credit-card', 'crop', 'lucide-cross', 'crosshair', 'crown', 'currency', 'database', 'delete', 'dice-1', 'dice-2', 'dice-3', 'dice-4', 'dice-5', 'dice-6', 'disc', 'divide-circle', 'divide-square', 'divide', 'dollar-sign', 'download-cloud', 'download', 'dribbble', 'droplet', 'droplets', 'drumstick', 'edit-2', 'edit-3', 'edit', 'egg', 'equal-not', 'equal', 'eraser', 'euro', 'expand', 'external-link', 'eye-off', 'eye', 'facebook', 'fast-forward', 'feather', 'figma', 'file-check-2', 'file-check', 'file-code', 'file-digit', 'file-input', 'file-minus-2', 'file-minus', 'file-output', 'file-plus-2', 'file-plus', 'file-search', 'file-text', 'file-x-2', 'file-x', 'file', 'files', 'film', 'filter', 'flag-off', 'flag-triangle-left', 'flag-triangle-right', 'flag', 'flame', 'flashlight-off', 'flashlight', 'flask-conical', 'flask-round', 'folder-minus', 'folder-open', 'folder-plus', 'lucide-folder', 'form-input', 'forward', 'frame', 'framer', 'frown', 'function-square', 'gamepad-2', 'gamepad', 'gauge', 'gavel', 'gem', 'ghost', 'gift', 'git-branch-plus', 'git-branch', 'git-commit', 'git-fork', 'git-merge', 'git-pull-request', 'github', 'gitlab', 'glasses', 'globe-2', 'globe', 'grab', 'graduation-cap', 'grid', 'grip-horizontal', 'grip-vertical', 'hammer', 'hand-metal', 'hand', 'hard-drive', 'hard-hat', 'hash', 'haze', 'headphones', 'heart', 'help-circle', 'hexagon', 'highlighter', 'history', 'home', 'image-minus', 'image-off', 'image-plus', 'image', 'import', 'inbox', 'indent', 'indian-rupee', 'infinity', 'lucide-info', 'inspect', 'instagram', 'italic', 'japanese-yen', 'key', 'keyboard', 'landmark', 'lucide-languages', 'laptop-2', 'laptop', 'lasso-select', 'lasso', 'layers', 'layout-dashboard', 'layout-grid', 'layout-list', 'layout-template', 'layout', 'library', 'life-buoy', 'lightbulb-off', 'lightbulb', 'link-2-off', 'link-2', 'lucide-link', 'linkedin', 'list-checks', 'list-minus', 'list-ordered', 'list-plus', 'list-x', 'list', 'loader-2', 'loader', 'locate-fixed', 'locate-off', 'locate', 'lock', 'log-in', 'log-out', 'mail', 'map-pin', 'map', 'maximize-2', 'maximize', 'megaphone', 'meh', 'menu', 'message-circle', 'message-square', 'mic-off', 'mic', 'minimize-2', 'minimize', 'minus-circle', 'minus-square', 'minus', 'monitor-off', 'monitor-speaker', 'monitor', 'moon', 'more-horizontal', 'more-vertical', 'mountain-snow', 'mountain', 'mouse-pointer-2', 'mouse-pointer-click', 'mouse-pointer', 'mouse', 'move-diagonal-2', 'move-diagonal', 'move-horizontal', 'move-vertical', 'move', 'music', 'navigation-2', 'navigation', 'network', 'octagon', 'option', 'outdent', 'package-check', 'package-minus', 'package-plus', 'package-search', 'package-x', 'package', 'palette', 'palmtree', 'paperclip', 'pause-circle', 'pause-octagon', 'pause', 'pen-tool', 'lucide-pencil', 'percent', 'person-standing', 'phone-call', 'phone-forwarded', 'phone-incoming', 'phone-missed', 'phone-off', 'phone-outgoing', 'phone', 'pie-chart', 'piggy-bank', 'lucide-pin', 'pipette', 'plane', 'play-circle', 'play', 'plug-zap', 'plus-circle', 'plus-square', 'plus', 'pocket', 'podcast', 'pointer', 'pound-sterling', 'power-off', 'power', 'printer', 'qr-code', 'quote', 'radio-receiver', 'radio', 'redo', 'refresh-ccw', 'refresh-cw', 'regex', 'repeat-1', 'repeat', 'reply-all', 'reply', 'rewind', 'rocket', 'rocking-chair', 'rotate-ccw', 'rotate-cw', 'rss', 'ruler', 'russian-ruble', 'save', 'scale', 'scan-line', 'scan', 'scissors', 'screen-share-off', 'screen-share', 'lucide-search', 'send', 'separator-horizontal', 'separator-vertical', 'server-crash', 'server-off', 'server', 'settings-2', 'settings', 'share-2', 'share', 'sheet', 'shield-alert', 'shield-check', 'shield-close', 'shield-off', 'shield', 'shirt', 'shopping-bag', 'shopping-cart', 'shovel', 'shrink', 'shuffle', 'sidebar-close', 'sidebar-open', 'sidebar', 'sigma', 'signal-high', 'signal-low', 'signal-medium', 'signal-zero', 'signal', 'skip-back', 'skip-forward', 'skull', 'slack', 'slash', 'sliders', 'smartphone-charging', 'smartphone', 'smile', 'snowflake', 'sort-asc', 'sort-desc', 'speaker', 'sprout', 'square', 'star-half', 'lucide-star', 'stop-circle', 'stretch-horizontal', 'stretch-vertical', 'strikethrough', 'subscript', 'sun', 'sunrise', 'sunset', 'superscript', 'swiss-franc', 'switch-camera', 'table', 'tablet', 'tag', 'target', 'tent', 'terminal-square', 'terminal', 'text-cursor-input', 'text-cursor', 'thermometer-snowflake', 'thermometer-sun', 'thermometer', 'thumbs-down', 'thumbs-up', 'ticket', 'timer-off', 'timer-reset', 'timer', 'toggle-left', 'toggle-right', 'tornado', 'trash-2', 'lucide-trash', 'trello', 'trending-down', 'trending-up', 'triangle', 'truck', 'tv-2', 'tv', 'twitch', 'twitter', 'type', 'umbrella', 'underline', 'undo', 'unlink-2', 'unlink', 'unlock', 'upload-cloud', 'upload', 'user-check', 'user-minus', 'user-plus', 'user-x', 'user', 'users', 'verified', 'vibrate', 'video-off', 'video', 'view', 'voicemail', 'volume-1', 'volume-2', 'volume-x', 'volume', 'wallet', 'wand', 'watch', 'waves', 'webcam', 'wifi-off', 'wifi', 'wind', 'wrap-text', 'wrench', 'x-circle', 'x-octagon', 'x-square', 'x', 'youtube', 'zap-off', 'zap', 'zoom-in', 'zoom-out', 'search-large', 'lucide-search']; +export class PropertyMappingValidationError extends Error { + constructor(message: string) { + super(message); + } +} + +export class PropertyMappingNameConflictError extends Error { + constructor(message: string) { + super(message); + } +} From 3db3496e0d3649c53bae8c433a018585df2772d4 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Tue, 27 Sep 2022 15:04:56 +0200 Subject: [PATCH 22/43] cleanup and reduced number of settings validations --- src/api/APIManager.ts | 3 +- src/main.ts | 50 +++--- src/modals/MediaDbAdvancedSearchModal.ts | 8 +- src/modals/MediaDbIdSearchModal.ts | 4 - src/models/MediaTypeModel.ts | 2 +- src/models/MusicReleaseModel.ts | 2 +- src/settings/PropertyMapping.ts | 24 +-- .../PropertyMappingModelComponent.svelte | 63 ++++++++ .../PropertyMappingModelsComponent.svelte | 110 ++----------- src/settings/Settings.ts | 147 ++---------------- src/utils/Utils.ts | 4 + styles.css | 51 ++++++ 12 files changed, 171 insertions(+), 297 deletions(-) create mode 100644 src/settings/PropertyMappingModelComponent.svelte diff --git a/src/api/APIManager.ts b/src/api/APIManager.ts index d1727b7..4220f12 100644 --- a/src/api/APIManager.ts +++ b/src/api/APIManager.ts @@ -1,6 +1,5 @@ import {APIModel} from './APIModel'; import {MediaTypeModel} from '../models/MediaTypeModel'; -import {debugLog} from '../utils/Utils'; export class APIManager { apis: APIModel[]; @@ -10,7 +9,7 @@ export class APIManager { } async query(query: string, apisToQuery: string[]): Promise { - debugLog(`MDB | api manager queried with "${query}"`); + console.debug(`MDB | api manager queried with "${query}"`); let res: MediaTypeModel[] = []; diff --git a/src/main.ts b/src/main.ts index cb5e80d..c6f62a9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ import {Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} from 'obsidian import {getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings'; import {APIManager} from './api/APIManager'; import {MediaTypeModel} from './models/MediaTypeModel'; -import {dateTimeToString, debugLog, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils'; +import {dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils'; import {OMDbAPI} from './api/apis/OMDbAPI'; import {MediaDbAdvancedSearchModal} from './modals/MediaDbAdvancedSearchModal'; import {MediaDbSearchResultModal} from './modals/MediaDbSearchResultModal'; @@ -44,12 +44,8 @@ export default class MediaDbPlugin extends Plugin { // register the settings tab this.addSettingTab(new MediaDbSettingTab(this.app, this)); - // TESTING - // this.settings.propertyMappingModels = getDefaultSettings(this).propertyMappingModels; - this.mediaTypeManager.updateTemplates(this.settings); - // add icon to the left ribbon const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', (evt: MouseEvent) => this.createEntryWithAdvancedSearchModal(), @@ -136,7 +132,6 @@ export default class MediaDbPlugin extends Plugin { selectModal.close(); - debugLog(results); if (results) { await this.createMediaDbNotes(results); } @@ -162,7 +157,6 @@ export default class MediaDbPlugin extends Plugin { idSearchModal.close(); - debugLog(result); if (result) { await this.createMediaDbNoteFromModel(result); } @@ -189,7 +183,7 @@ export default class MediaDbPlugin extends Plugin { async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, attachFile?: TFile): Promise { try { - console.log('MDB | Creating new note...'); + console.debug('MDB | creating new note'); let fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, attachFile); @@ -216,13 +210,7 @@ export default class MediaDbPlugin extends Plugin { return {fileMetadata: fileMetadata, fileContent: fileContent}; } - let attachFileMetadata: any = this.app.metadataCache.getFileCache(fileToAttach).frontmatter; - if (attachFileMetadata) { - attachFileMetadata = JSON.parse(JSON.stringify(attachFileMetadata)); // deep copy - delete attachFileMetadata.position; - } else { - attachFileMetadata = {}; - } + let attachFileMetadata: any = this.getMetadataFromFileCache(fileToAttach); fileMetadata = Object.assign(attachFileMetadata, fileMetadata); let attachFileContent: string = await this.app.vault.read(fileToAttach); @@ -241,7 +229,7 @@ export default class MediaDbPlugin extends Plugin { let templateMetadata: any = this.getMetaDataFromFileContent(template); fileMetadata = Object.assign(templateMetadata, fileMetadata); - const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); + const regExp = new RegExp(this.frontMatterRexExpPattern); const attachFileContent = template.replace(regExp, ''); fileContent += attachFileContent; @@ -251,7 +239,7 @@ export default class MediaDbPlugin extends Plugin { getMetaDataFromFileContent(fileContent: string): any { let metadata: any; - const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); + const regExp = new RegExp(this.frontMatterRexExpPattern); const frontMatterRegExpResult = regExp.exec(fileContent); if (!frontMatterRegExpResult) { return {}; @@ -269,6 +257,19 @@ export default class MediaDbPlugin extends Plugin { metadata = {}; } + console.debug(`MDB | metadata read from file content`, metadata); + + return metadata; + } + + getMetadataFromFileCache(file: TFile) { + let metadata: any = this.app.metadataCache.getFileCache(file).frontmatter; + if (metadata) { + metadata = Object.assign({}, metadata); // copy + delete metadata.position; + } else { + metadata = {}; + } return metadata; } @@ -297,12 +298,13 @@ export default class MediaDbPlugin extends Plugin { // create the file const targetFile = await this.app.vault.create(filePath, fileContent); + console.debug(`MDB | created new file at ${filePath}`); // open newly crated file if (openFile) { const activeLeaf = this.app.workspace.getUnpinnedLeaf(); if (!activeLeaf) { - console.warn('MDB | no active leaf, not opening media db note'); + console.warn('MDB | no active leaf, not opening newly created note'); return; } await activeLeaf.openFile(targetFile, {state: {mode: 'source'}}); @@ -319,12 +321,10 @@ export default class MediaDbPlugin extends Plugin { throw new Error('MDB | there is no active note'); } - let metadata: any = this.app.metadataCache.getFileCache(activeFile).frontmatter; - metadata = JSON.parse(JSON.stringify(metadata)); // deep copy - delete metadata.position; // remove unnecessary data from the FrontMatterCache + let metadata: any = this.getMetadataFromFileCache(activeFile); metadata = this.modelPropertyMapper.convertObjectBack(metadata); - debugLog(metadata); + console.debug(`MDB | read metadata`, metadata); if (!metadata?.type || !metadata?.dataSource || !metadata?.id) { throw new Error('MDB | active note is not a Media DB entry or is missing metadata'); @@ -339,7 +339,8 @@ export default class MediaDbPlugin extends Plugin { newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData()); - console.log('MDB | deleting old entry'); + // deletion not happening anymore why is this log statement still here + console.debug('MDB | deleting old entry'); await this.createMediaDbNoteFromModel(newMediaTypeModel, activeFile); } @@ -361,7 +362,7 @@ export default class MediaDbPlugin extends Plugin { continue; } - let metadata: any = this.app.metadataCache.getFileCache(file).frontmatter; + let metadata: any = this.getMetadataFromFileCache(file); let title = metadata[titleFieldName]; if (!title) { @@ -525,7 +526,6 @@ export default class MediaDbPlugin extends Plugin { async saveSettings() { this.mediaTypeManager.updateTemplates(this.settings); - //this.modelPropertyMapper.updateConversionRules(this.settings); await this.saveData(this.settings); } diff --git a/src/modals/MediaDbAdvancedSearchModal.ts b/src/modals/MediaDbAdvancedSearchModal.ts index 37c1900..3711e55 100644 --- a/src/modals/MediaDbAdvancedSearchModal.ts +++ b/src/modals/MediaDbAdvancedSearchModal.ts @@ -1,6 +1,5 @@ -import {ButtonComponent, Component, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian'; +import {ButtonComponent, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; -import {debugLog} from '../utils/Utils'; import MediaDbPlugin from '../main'; export class MediaDbAdvancedSearchModal extends Modal { @@ -36,9 +35,6 @@ export class MediaDbAdvancedSearchModal extends Modal { } async search(): Promise { - - debugLog(this.selectedApis); - if (!this.query || this.query.length < 3) { new Notice('MDB | Query to short'); return; @@ -78,7 +74,7 @@ export class MediaDbAdvancedSearchModal extends Modal { contentEl.createDiv({cls: 'media-db-plugin-spacer'}); contentEl.createEl('h3', {text: 'APIs to search'}); - const apiToggleComponents: Component[] = []; + // const apiToggleComponents: Component[] = []; for (const api of this.plugin.apiManager.apis) { const apiToggleListElementWrapper = contentEl.createEl('div', {cls: 'media-db-plugin-list-wrapper'}); diff --git a/src/modals/MediaDbIdSearchModal.ts b/src/modals/MediaDbIdSearchModal.ts index 7190918..9437e2a 100644 --- a/src/modals/MediaDbIdSearchModal.ts +++ b/src/modals/MediaDbIdSearchModal.ts @@ -1,6 +1,5 @@ import {ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; -import {debugLog} from '../utils/Utils'; import MediaDbPlugin from '../main'; export class MediaDbIdSearchModal extends Modal { @@ -33,9 +32,6 @@ export class MediaDbIdSearchModal extends Modal { } async search(): Promise { - - debugLog(this.selectedApi); - if (!this.query) { new Notice('MDB | no Id entered'); return; diff --git a/src/models/MediaTypeModel.ts b/src/models/MediaTypeModel.ts index fc4f87a..75a749d 100644 --- a/src/models/MediaTypeModel.ts +++ b/src/models/MediaTypeModel.ts @@ -13,7 +13,7 @@ export abstract class MediaTypeModel { userData: object; - constructor() { + protected constructor() { this.type = undefined; this.subType = undefined; this.title = undefined; diff --git a/src/models/MusicReleaseModel.ts b/src/models/MusicReleaseModel.ts index 42e91e1..babb602 100644 --- a/src/models/MusicReleaseModel.ts +++ b/src/models/MusicReleaseModel.ts @@ -45,7 +45,7 @@ export class MusicReleaseModel extends MediaTypeModel { } getSummary(): string { - var summary = this.title + ' (' + this.year + ')'; + let summary = this.title + ' (' + this.year + ')'; if (this.artists.length > 0) summary += ' - ' + this.artists.join(', '); return summary; diff --git a/src/settings/PropertyMapping.ts b/src/settings/PropertyMapping.ts index a221918..f92f626 100644 --- a/src/settings/PropertyMapping.ts +++ b/src/settings/PropertyMapping.ts @@ -19,6 +19,8 @@ export class PropertyMappingModel { } validate(): { res: boolean, err?: Error } { + console.debug(`MDB | validated property mappings for ${this.type}`); + // check properties for (const property of this.properties) { const propertyValidation = property.validate(); @@ -89,28 +91,6 @@ export class PropertyMapping { this.newProperty = newProperty; this.mapping = mapping; this.locked = locked ?? false; - - /* - const conversionRuleParts = conversionRule.split('->'); - if (conversionRuleParts.length !== 2) { - throw Error(`Conversion rule "${conversionRule}" may only have exactly one "->"`); - } - - let property = conversionRuleParts[0].trim(); - let newProperty = conversionRuleParts[1].trim(); - - if (!property || !containsOnlyLettersAndUnderscores(property)) { - throw Error(`Error in conversion rule "${conversionRule}": property may not be empty and only contain letters and underscores.`); - } - - if (!newProperty || !containsOnlyLettersAndUnderscores(newProperty)) { - throw Error(`Error in conversion rule "${conversionRule}": new property may not be empty and only contain letters and underscores.`); - } - - this.property = property; - this.newProperty = newProperty; - - */ } validate(): { res: boolean, err?: Error } { diff --git a/src/settings/PropertyMappingModelComponent.svelte b/src/settings/PropertyMappingModelComponent.svelte new file mode 100644 index 0000000..da8797b --- /dev/null +++ b/src/settings/PropertyMappingModelComponent.svelte @@ -0,0 +1,63 @@ + + + + +
    +
    {capitalizeFirstLetter(model.type)}
    +
    + { #each model.properties as property } +
    +
    +
    {property.property}
    +
    + { #if property.locked } +
    + property can not be remapped +
    + { :else } + + + { #if property.mapping === PropertyMappingOption.Map } + +
    + +
    + { /if } + { /if } +
    + { /each } +
    + { #if !validationResult?.res } +
    + {validationResult?.err?.message} +
    + { /if } + +
    diff --git a/src/settings/PropertyMappingModelsComponent.svelte b/src/settings/PropertyMappingModelsComponent.svelte index f5d1af8..9bc5644 100644 --- a/src/settings/PropertyMappingModelsComponent.svelte +++ b/src/settings/PropertyMappingModelsComponent.svelte @@ -1,7 +1,6 @@
    { #each models as model } -
    -
    {capitalizeFirstLetter(model.type)}
    -
    - { #each model.properties as property } -
    -
    -
    {property.property}
    -
    - {#if property.locked} -
    - property can not be remapped -
    - {:else} - - - {#if property.mapping === PropertyMappingOption.Map} - -
    - -
    - {/if} - {/if} -
    - { /each } -
    - { #if !model.validate().res } -
    - {model.validate().err?.message} -
    - {/if} - -
    - { /each } - -
    {JSON.stringify(models, null, 4)}
    + + { /each }
    diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 7fe871a..b3a08bb 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -42,7 +42,7 @@ export interface MediaDbPluginSettings { } -export const DEFAULT_SETTINGS: MediaDbPluginSettings = { +const DEFAULT_SETTINGS: MediaDbPluginSettings = { folder: 'Media DB', OMDbKey: '', sfwFilter: true, @@ -70,63 +70,7 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = { musicReleasePropertyConversionRules: '', boardgamePropertyConversionRules: '', - propertyMappingModels: [ - /* - { - type: MediaType.Movie, - properties: [ - new PropertyMapping('type', '', PropertyMappingOption.Default, true), - new PropertyMapping('subType', '', PropertyMappingOption.Default), - new PropertyMapping('title', '', PropertyMappingOption.Default), - new PropertyMapping('englishTitle', '', PropertyMappingOption.Default), - new PropertyMapping('year', '', PropertyMappingOption.Default), - new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true), - new PropertyMapping('url', '', PropertyMappingOption.Default), - new PropertyMapping('id', '', PropertyMappingOption.Default, true), - - new PropertyMapping('genres', '', PropertyMappingOption.Default), - new PropertyMapping('producer', '', PropertyMappingOption.Default), - new PropertyMapping('duration', '', PropertyMappingOption.Default), - new PropertyMapping('onlineRating', '', PropertyMappingOption.Default), - new PropertyMapping('image', '', PropertyMappingOption.Default), - new PropertyMapping('released', '', PropertyMappingOption.Default), - new PropertyMapping('premiere', '', PropertyMappingOption.Default), - new PropertyMapping('watched', '', PropertyMappingOption.Default), - new PropertyMapping('lastWatched', '', PropertyMappingOption.Default), - new PropertyMapping('personalRating', '', PropertyMappingOption.Default), - ], - }, - { - type: MediaType.Series, - properties: [ - new PropertyMapping('type', '', PropertyMappingOption.Default, true), - new PropertyMapping('subType', '', PropertyMappingOption.Default), - new PropertyMapping('title', '', PropertyMappingOption.Default), - new PropertyMapping('englishTitle', '', PropertyMappingOption.Default), - new PropertyMapping('year', '', PropertyMappingOption.Default), - new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true), - new PropertyMapping('url', '', PropertyMappingOption.Default), - new PropertyMapping('id', '', PropertyMappingOption.Default, true), - - new PropertyMapping('genres', '', PropertyMappingOption.Default), - new PropertyMapping('studios', '', PropertyMappingOption.Default), - new PropertyMapping('episodes', '', PropertyMappingOption.Default), - new PropertyMapping('duration', '', PropertyMappingOption.Default), - new PropertyMapping('onlineRating', '', PropertyMappingOption.Default), - new PropertyMapping('image', '', PropertyMappingOption.Default), - new PropertyMapping('released', '', PropertyMappingOption.Default), - new PropertyMapping('airing', '', PropertyMappingOption.Default), - new PropertyMapping('airedFrom', '', PropertyMappingOption.Default), - new PropertyMapping('airedTo', '', PropertyMappingOption.Default), - new PropertyMapping('watched', '', PropertyMappingOption.Default), - new PropertyMapping('lastWatched', '', PropertyMappingOption.Default), - new PropertyMapping('personalRating', '', PropertyMappingOption.Default), - ], - }, - - */ - ], - + propertyMappingModels: [], }; export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource']; @@ -387,89 +331,13 @@ export class MediaDbSettingTab extends PluginSettingTab { }); // endregion - containerEl.createEl('h3', {text: 'Property Mappings'}); // region Property Mappings - /* - new Setting(containerEl) - .setName('Movie model property mappings') - .setDesc('Mappings for the property names of a movie.') - .addTextArea(cb => { - cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) - .setValue(this.plugin.settings.moviePropertyConversionRules) - .onChange(data => { - this.plugin.settings.moviePropertyConversionRules = data; - this.plugin.saveSettings(); - }); - }); - new Setting(containerEl) - .setName('Series model property mappings') - .setDesc('Mappings for the property names of a series.') - .addTextArea(cb => { - cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) - .setValue(this.plugin.settings.seriesPropertyConversionRules) - .onChange(data => { - this.plugin.settings.seriesPropertyConversionRules = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Game model property mappings') - .setDesc('Mappings for the property names of a game.') - .addTextArea(cb => { - cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) - .setValue(this.plugin.settings.gamePropertyConversionRules) - .onChange(data => { - this.plugin.settings.gamePropertyConversionRules = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Wiki model property mappings') - .setDesc('Mappings for the property names of a wiki entry.') - .addTextArea(cb => { - cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) - .setValue(this.plugin.settings.wikiPropertyConversionRules) - .onChange(data => { - this.plugin.settings.wikiPropertyConversionRules = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Music Release model property mappings') - .setDesc('Mappings for the property names of a music release.') - .addTextArea(cb => { - cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) - .setValue(this.plugin.settings.musicReleasePropertyConversionRules) - .onChange(data => { - this.plugin.settings.musicReleasePropertyConversionRules = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Board Game model property mappings') - .setDesc('Mappings for the property names of a boardgame.') - .addTextArea(cb => { - cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) - .setValue(this.plugin.settings.boardgamePropertyConversionRules) - .onChange(data => { - this.plugin.settings.boardgamePropertyConversionRules = data; - this.plugin.saveSettings(); - }); - }); - - */ - // endregion - - console.log(this.plugin.settings.propertyMappingModels); - // console.log(getDefaultSettings(this.plugin)); + containerEl.createEl('h3', {text: 'Property Mappings'}); let propertyMappingExplanation = containerEl.createEl('div'); - propertyMappingExplanation.innerHTML = `

    Allow you to remap the metadata fields of newly created media db entries.

    + propertyMappingExplanation.innerHTML = ` +

    Allow you to remap the metadata fields of newly created media db entries.

    The different options are: @@ -477,6 +345,9 @@ export class MediaDbSettingTab extends PluginSettingTab {

  • "remap": renames the metadata field to what ever you specify
  • "remove": removes the metadata field entirely
  • +

    +

    + Don't forget to save your changes using the save button for each individual category.

    `; @@ -502,6 +373,8 @@ export class MediaDbSettingTab extends PluginSettingTab { }, }); + // endregion + } } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 37426df..7dc60d2 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -14,6 +14,10 @@ export function wrapAround(value: number, size: number): number { return mod(value, size); } +/** + * @deprecated use console.debug instead + * @param o + */ export function debugLog(o: any): void { if (debug) { console.log(o); diff --git a/styles.css b/styles.css index 5ee2836..afe1e39 100644 --- a/styles.css +++ b/styles.css @@ -55,3 +55,54 @@ small.media-db-plugin-list-text{ .media-db-plugin-spacer { margin-bottom: 10px; } + +/* region property mappings */ +.media-db-plugin-property-mappings-model-container { + border: 1px solid var(--background-modifier-border); + border-radius: 5px; + padding: 10px; + width: 100%; +} + +.media-db-plugin-property-mappings-container { + margin: 10px 0; + display: flex; + flex-direction: column; + gap: 5px; +} + +.media-db-plugin-property-mapping-element { + display: flex; + flex-direction: row; + gap: 10px; +} + +.media-db-plugin-property-mapping-element-property-name-wrapper { + min-width: 160px; + background: var(--background-modifier-form-field); + padding: 2px 5px; + border-radius: 5px; + + display: flex; + align-items: center; +} + +.media-db-plugin-property-mapping-element-property-name { + margin: 0; +} + +.media-db-plugin-property-mappings-save-button { + margin: 0; +} + +.media-db-plugin-property-mapping-to { + display: flex; + align-items: center; +} + +.media-db-plugin-property-mapping-validation { + color: var(--text-error); + margin-bottom: 5px; +} + +/* endregion */ From b5d5cc5ca273ebb7659e6e009ca86f54e34f9d32 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Wed, 28 Sep 2022 23:43:59 +0200 Subject: [PATCH 23/43] first prove of concept O_O implementation --- src/api/apis/WikipediaAPI.ts | 1 + src/main.ts | 78 +++++++++++++++++++++++++- src/modals/MediaDbSearchResultModal.ts | 4 +- src/modals/SelectModal.ts | 4 +- 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/api/apis/WikipediaAPI.ts b/src/api/apis/WikipediaAPI.ts index 835e225..cd73890 100644 --- a/src/api/apis/WikipediaAPI.ts +++ b/src/api/apis/WikipediaAPI.ts @@ -66,6 +66,7 @@ export class WikipediaAPI extends APIModel { englishTitle: result.title, year: '', dataSource: this.apiName, + url: result.fullurl, id: result.pageid, wikiUrl: result.fullurl, diff --git a/src/main.ts b/src/main.ts index c6f62a9..f5913fd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import {Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} from 'obsidian'; +import {MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} from 'obsidian'; import {getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings'; import {APIManager} from './api/APIManager'; import {MediaTypeModel} from './models/MediaTypeModel'; @@ -88,6 +88,78 @@ export default class MediaDbPlugin extends Plugin { return true; }, }); + // register link insert command + this.addCommand({ + id: 'add-media-db-link', + name: 'Add a link.', + checkCallback: (checking: boolean) => { + if (!this.app.workspace.getActiveFile()) { + return false; + } + if (!checking) { + this.createLinkWithSearchModal(); + } + return true; + }, + }); + } + + /** + * first very simple approach + * - replace the detail query + * - maybe custom link syntax + */ + async createLinkWithSearchModal() { + let results: MediaTypeModel[] = []; + + const {advancedSearchOptions, advancedSearchModal} = await this.openMediaDbAdvancedSearchModal(); + if (!advancedSearchOptions) { + advancedSearchModal.close(); + return; + } + + let apiSearchResults: MediaTypeModel[] = undefined; + try { + apiSearchResults = await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); + } catch (e) { + console.warn(e); + new Notice(e.toString()); + advancedSearchModal.close(); + return; + } + + advancedSearchModal.close(); + + const {selectRes, selectModal} = await this.openMediaDbSelectModal(apiSearchResults, false, false); + if (!selectRes) { + selectModal.close(); + return; + } + + // TODO: let's try to not query details for this + try { + results = await this.queryDetails(selectRes); + } catch (e) { + console.warn(e); + new Notice(e.toString()); + selectModal.close(); + return; + } + + selectModal.close(); + + if (!results || results.length < 1) { + return; + } + + const link = `[${results[0].title}](${results[0].url})` + + const view = this.app.workspace.getActiveViewOfType(MarkdownView); + + // Make sure the user is editing a Markdown file. + if (view) { + view.editor.replaceRange(link, view.editor.getCursor()); + } } async createEntryWithSearchModal() { @@ -473,8 +545,8 @@ export default class MediaDbPlugin extends Plugin { return {idSearchOptions: res, idSearchModal: modal}; } - async openMediaDbSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false): Promise<{ selectRes: MediaTypeModel[], selectModal: MediaDbSearchResultModal }> { - const modal = new MediaDbSearchResultModal(this, resultsToDisplay, skipButton); + async openMediaDbSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false, allowMultiSelect: boolean = true): Promise<{ selectRes: MediaTypeModel[], selectModal: MediaDbSearchResultModal }> { + const modal = new MediaDbSearchResultModal(this, resultsToDisplay, skipButton, allowMultiSelect); const res: MediaTypeModel[] = await new Promise((resolve, reject) => { modal.setSubmitCallback(res => resolve(res)); modal.setSkipCallback(() => resolve([])); diff --git a/src/modals/MediaDbSearchResultModal.ts b/src/modals/MediaDbSearchResultModal.ts index 53e19bc..4ffe578 100644 --- a/src/modals/MediaDbSearchResultModal.ts +++ b/src/modals/MediaDbSearchResultModal.ts @@ -12,8 +12,8 @@ export class MediaDbSearchResultModal extends SelectModal { sendCallback: boolean; - constructor(plugin: MediaDbPlugin, elements: MediaTypeModel[], skipButton: boolean) { - super(plugin.app, elements); + constructor(plugin: MediaDbPlugin, elements: MediaTypeModel[], skipButton: boolean, allowMultiSelect: boolean = true) { + super(plugin.app, elements, allowMultiSelect); this.plugin = plugin; this.title = 'Search Results'; diff --git a/src/modals/SelectModal.ts b/src/modals/SelectModal.ts index 761f3b8..07f189c 100644 --- a/src/modals/SelectModal.ts +++ b/src/modals/SelectModal.ts @@ -16,9 +16,9 @@ export abstract class SelectModal extends Modal { selectModalElements: SelectModalElement[]; - protected constructor(app: App, elements: T[]) { + protected constructor(app: App, elements: T[], allowMultiSelect: boolean = true) { super(app); - this.allowMultiSelect = true; + this.allowMultiSelect = allowMultiSelect; this.title = ''; this.description = ''; From 25b899daa51ae90092c53b4fdd176a587a3189a5 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Wed, 28 Sep 2022 23:51:10 +0200 Subject: [PATCH 24/43] some TODOs for tomorrow --- src/main.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index f5913fd..784811c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -106,8 +106,9 @@ export default class MediaDbPlugin extends Plugin { /** * first very simple approach - * - replace the detail query - * - maybe custom link syntax + * TODO: + * - replace the detail query + * - maybe custom link syntax */ async createLinkWithSearchModal() { let results: MediaTypeModel[] = []; @@ -166,6 +167,9 @@ export default class MediaDbPlugin extends Plugin { } + /** + * TODO: further refactor: extract it into own method, pass the action (api query) as lambda as well as an options object + */ async createEntryWithAdvancedSearchModal() { let results: MediaTypeModel[] = []; From 5aa91085091a845b1d0df9c12e060a206a1ddbef Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Sat, 1 Oct 2022 21:50:59 +0200 Subject: [PATCH 25/43] Modal helper --- src/api/apis/BoardGameGeekAPI.ts | 9 +- src/main.ts | 169 ++++++------------------------- src/utils/ModalHelper.ts | 135 ++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 144 deletions(-) create mode 100644 src/utils/ModalHelper.ts diff --git a/src/api/apis/BoardGameGeekAPI.ts b/src/api/apis/BoardGameGeekAPI.ts index 4996eb6..57c5a5b 100644 --- a/src/api/apis/BoardGameGeekAPI.ts +++ b/src/api/apis/BoardGameGeekAPI.ts @@ -79,17 +79,16 @@ export class BoardGameGeekAPI extends APIModel { const genres = Array.from(boardgame.querySelectorAll('boardgamecategory')).map(n => n!.textContent!); const model = new BoardGameModel({ - type: MediaType.BoardGame, title, englishTitle: title, year: year === '0' ? '' : year, dataSource: this.apiName, url: `https://boardgamegeek.com/boardgame/${id}`, - id, + id: id, - genres, - onlineRating, - image, + genres: genres, + onlineRating: onlineRating, + image: image, released: true, userData: { diff --git a/src/main.ts b/src/main.ts index 784811c..f3507ba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,10 +4,8 @@ import {APIManager} from './api/APIManager'; import {MediaTypeModel} from './models/MediaTypeModel'; import {dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils'; import {OMDbAPI} from './api/apis/OMDbAPI'; -import {MediaDbAdvancedSearchModal} from './modals/MediaDbAdvancedSearchModal'; import {MediaDbSearchResultModal} from './modals/MediaDbSearchResultModal'; import {MALAPI} from './api/apis/MALAPI'; -import {MediaDbIdSearchModal} from './modals/MediaDbIdSearchModal'; import {WikipediaAPI} from './api/apis/WikipediaAPI'; import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI'; import {MediaTypeManager} from './utils/MediaTypeManager'; @@ -17,12 +15,14 @@ import {PropertyMapper} from './settings/PropertyMapper'; import {YAMLConverter} from './utils/YAMLConverter'; import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal'; import {PropertyMapping, PropertyMappingModel} from './settings/PropertyMapping'; +import {ModalHelper} from './utils/ModalHelper'; export default class MediaDbPlugin extends Plugin { settings: MediaDbPluginSettings; apiManager: APIManager; mediaTypeManager: MediaTypeManager; modelPropertyMapper: PropertyMapper; + modalHelper: ModalHelper; frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---'; @@ -39,6 +39,7 @@ export default class MediaDbPlugin extends Plugin { this.mediaTypeManager = new MediaTypeManager(); this.modelPropertyMapper = new PropertyMapper(this); + this.modalHelper = new ModalHelper(this); await this.loadSettings(); // register the settings tab @@ -91,7 +92,7 @@ export default class MediaDbPlugin extends Plugin { // register link insert command this.addCommand({ id: 'add-media-db-link', - name: 'Add a link.', + name: 'Insert link', checkCallback: (checking: boolean) => { if (!this.app.workspace.getActiveFile()) { return false; @@ -111,49 +112,24 @@ export default class MediaDbPlugin extends Plugin { * - maybe custom link syntax */ async createLinkWithSearchModal() { - let results: MediaTypeModel[] = []; - const {advancedSearchOptions, advancedSearchModal} = await this.openMediaDbAdvancedSearchModal(); - if (!advancedSearchOptions) { - advancedSearchModal.close(); + let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal(async (advancedSearchOptions) => { + return await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); + }); + + if (!apiSearchResults) { return; } - let apiSearchResults: MediaTypeModel[] = undefined; - try { - apiSearchResults = await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); - } catch (e) { - console.warn(e); - new Notice(e.toString()); - advancedSearchModal.close(); + const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal(apiSearchResults, async (selectedMediaTypeModels) => { + return await this.queryDetails(selectedMediaTypeModels); + }); + + if (!selectResults || selectResults.length < 1) { return; } - advancedSearchModal.close(); - - const {selectRes, selectModal} = await this.openMediaDbSelectModal(apiSearchResults, false, false); - if (!selectRes) { - selectModal.close(); - return; - } - - // TODO: let's try to not query details for this - try { - results = await this.queryDetails(selectRes); - } catch (e) { - console.warn(e); - new Notice(e.toString()); - selectModal.close(); - return; - } - - selectModal.close(); - - if (!results || results.length < 1) { - return; - } - - const link = `[${results[0].title}](${results[0].url})` + const link = `[${selectResults[0].title}](${selectResults[0].url})` const view = this.app.workspace.getActiveViewOfType(MarkdownView); @@ -171,71 +147,35 @@ export default class MediaDbPlugin extends Plugin { * TODO: further refactor: extract it into own method, pass the action (api query) as lambda as well as an options object */ async createEntryWithAdvancedSearchModal() { - let results: MediaTypeModel[] = []; + const apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal(async (advancedSearchOptions) => { + return await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); + }); - const {advancedSearchOptions, advancedSearchModal} = await this.openMediaDbAdvancedSearchModal(); - if (!advancedSearchOptions) { - advancedSearchModal.close(); + if (!apiSearchResults) { return; } - let apiSearchResults: MediaTypeModel[] = undefined; - try { - apiSearchResults = await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); - } catch (e) { - console.warn(e); - new Notice(e.toString()); - advancedSearchModal.close(); + const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal(apiSearchResults, async (selectedMediaTypeModels) => { + return await this.queryDetails(selectedMediaTypeModels); + }); + + if (!selectResults) { return; } - advancedSearchModal.close(); - - const {selectRes, selectModal} = await this.openMediaDbSelectModal(apiSearchResults, false); - if (!selectRes) { - selectModal.close(); - return; - } - - try { - results = await this.queryDetails(selectRes); - } catch (e) { - console.warn(e); - new Notice(e.toString()); - selectModal.close(); - return; - } - - selectModal.close(); - - if (results) { - await this.createMediaDbNotes(results); - } + await this.createMediaDbNotes(selectResults); } async createEntryWithIdSearchModal() { - let result: MediaTypeModel = undefined; + const idSearchResult: MediaTypeModel = await this.modalHelper.openIdSearchModal(async (idSearchOptions) => { + return await this.apiManager.queryDetailedInfoById(idSearchOptions.query, idSearchOptions.api); + }) - const {idSearchOptions, idSearchModal} = await this.openMediaDbIdSearchModal(); - if (!idSearchOptions) { - idSearchModal.close(); + if (!idSearchResult) { return; } - try { - result = await this.apiManager.queryDetailedInfoById(idSearchOptions.query, idSearchOptions.api); - } catch (e) { - console.warn(e); - new Notice(e.toString()); - idSearchModal.close(); - return; - } - - idSearchModal.close(); - - if (result) { - await this.createMediaDbNoteFromModel(result); - } + await this.createMediaDbNoteFromModel(idSearchResult); } async createMediaDbNotes(models: MediaTypeModel[], attachFile?: TFile): Promise { @@ -517,55 +457,6 @@ export default class MediaDbPlugin extends Plugin { const targetFile = await this.app.vault.create(filePath, fileContent); } - async openMediaDbAdvancedSearchModal(): Promise<{ advancedSearchOptions: { query: string, apis: string[] }, advancedSearchModal: MediaDbAdvancedSearchModal }> { - const modal = new MediaDbAdvancedSearchModal(this); - const res: { query: string, apis: string[] } = await new Promise((resolve, reject) => { - modal.setSubmitCallback(res => resolve(res)); - modal.setCloseCallback(err => { - if (err) { - reject(err); - } - resolve(undefined); - }); - - modal.open(); - }); - return {advancedSearchOptions: res, advancedSearchModal: modal}; - } - - async openMediaDbIdSearchModal(): Promise<{ idSearchOptions: { query: string, api: string }, idSearchModal: MediaDbIdSearchModal }> { - const modal = new MediaDbIdSearchModal(this); - const res: { query: string, api: string } = await new Promise((resolve, reject) => { - modal.setSubmitCallback(res => resolve(res)); - modal.setCloseCallback(err => { - if (err) { - reject(err); - } - resolve(undefined); - }); - - modal.open(); - }); - return {idSearchOptions: res, idSearchModal: modal}; - } - - async openMediaDbSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false, allowMultiSelect: boolean = true): Promise<{ selectRes: MediaTypeModel[], selectModal: MediaDbSearchResultModal }> { - const modal = new MediaDbSearchResultModal(this, resultsToDisplay, skipButton, allowMultiSelect); - const res: MediaTypeModel[] = await new Promise((resolve, reject) => { - modal.setSubmitCallback(res => resolve(res)); - modal.setSkipCallback(() => resolve([])); - modal.setCloseCallback(err => { - if (err) { - reject(err); - } - resolve(undefined); - }); - - modal.open(); - }); - return {selectRes: res, selectModal: modal}; - } - async loadSettings() { // console.log(DEFAULT_SETTINGS); const diskSettings: MediaDbPluginSettings = await this.loadData(); diff --git a/src/utils/ModalHelper.ts b/src/utils/ModalHelper.ts new file mode 100644 index 0000000..2529679 --- /dev/null +++ b/src/utils/ModalHelper.ts @@ -0,0 +1,135 @@ +import {MediaDbAdvancedSearchModal} from '../modals/MediaDbAdvancedSearchModal'; +import {MediaDbIdSearchModal} from '../modals/MediaDbIdSearchModal'; +import {MediaTypeModel} from '../models/MediaTypeModel'; +import {MediaDbSearchResultModal} from '../modals/MediaDbSearchResultModal'; +import {Notice} from 'obsidian'; +import MediaDbPlugin from '../main'; + +interface AdvancedSearchOptions { + query: string, + apis: string[], +} + +interface IdSearchOptions { + query: string, + api: string, +} + +export class ModalHelper { + plugin: MediaDbPlugin; + + + constructor(plugin: MediaDbPlugin) { + this.plugin = plugin; + } + + async createAdvancedSearchModal(): Promise<{ advancedSearchOptions: AdvancedSearchOptions, advancedSearchModal: MediaDbAdvancedSearchModal }> { + const modal = new MediaDbAdvancedSearchModal(this.plugin); + const res: { query: string, apis: string[] } = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setCloseCallback(err => { + if (err) { + reject(err); + } + resolve(undefined); + }); + + modal.open(); + }); + return {advancedSearchOptions: res, advancedSearchModal: modal}; + } + + async openAdvancedSearchModal(submitCallback: (advancedSearchOptions: AdvancedSearchOptions) => Promise): Promise { + const {advancedSearchOptions, advancedSearchModal} = await this.createAdvancedSearchModal(); + if (!advancedSearchOptions) { + advancedSearchModal.close(); + return; + } + + try { + let callbackRes: T; + callbackRes = await submitCallback(advancedSearchOptions); + advancedSearchModal.close(); + return callbackRes; + } catch (e) { + console.warn(e); + new Notice(e.toString()); + advancedSearchModal.close(); + return undefined; + } + } + + async createIdSearchModal(): Promise<{ idSearchOptions: { query: string, api: string }, idSearchModal: MediaDbIdSearchModal }> { + const modal = new MediaDbIdSearchModal(this.plugin); + const res: { query: string, api: string } = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setCloseCallback(err => { + if (err) { + reject(err); + } + resolve(undefined); + }); + + modal.open(); + }); + return {idSearchOptions: res, idSearchModal: modal}; + } + + async openIdSearchModal(submitCallback: (idSearchOptions: IdSearchOptions) => Promise): Promise { + const {idSearchOptions, idSearchModal} = await this.createIdSearchModal(); + if (!idSearchOptions) { + idSearchModal.close(); + return; + } + + try { + let callbackRes: T; + callbackRes = await submitCallback(idSearchOptions); + idSearchModal.close(); + return callbackRes; + } catch (e) { + console.warn(e); + new Notice(e.toString()); + idSearchModal.close(); + return undefined; + } + } + + async createSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false, allowMultiSelect: boolean = true): Promise<{ selectRes: MediaTypeModel[], selectModal: MediaDbSearchResultModal }> { + const modal = new MediaDbSearchResultModal(this.plugin, resultsToDisplay, skipButton, allowMultiSelect); + const res: MediaTypeModel[] = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setSkipCallback(() => resolve([])); + modal.setCloseCallback(err => { + if (err) { + reject(err); + } + resolve(undefined); + }); + + modal.open(); + }); + return {selectRes: res, selectModal: modal}; + } + + async openSelectModal(mediaModels: MediaTypeModel[], submitCallback: (selectedMediaTypeModels: MediaTypeModel[]) => Promise): Promise { + const {selectRes, selectModal} = await this.createSelectModal(mediaModels, false); + if (!selectRes) { + selectModal.close(); + return; + } + + try { + let callbackRes: MediaTypeModel[]; + callbackRes = await submitCallback(selectRes); + selectModal.close(); + return callbackRes; + } catch (e) { + console.warn(e); + new Notice(e.toString()); + selectModal.close(); + return; + } + } +} + From 805d9d3fb83551630a57ba69e4bb3de9c6f2184d Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Sun, 2 Oct 2022 22:07:11 +0200 Subject: [PATCH 26/43] Modal keyboard navigation changes --- src/modals/MediaDbAdvancedSearchModal.ts | 19 +++++---- src/modals/MediaDbFolderImportModal.ts | 16 +++++++- src/modals/MediaDbIdSearchModal.ts | 19 +++++---- src/modals/MediaDbSearchResultModal.ts | 1 + src/modals/SelectModal.ts | 51 +++++++++++++++++------- styles.css | 4 ++ 6 files changed, 79 insertions(+), 31 deletions(-) diff --git a/src/modals/MediaDbAdvancedSearchModal.ts b/src/modals/MediaDbAdvancedSearchModal.ts index 3711e55..52c9786 100644 --- a/src/modals/MediaDbAdvancedSearchModal.ts +++ b/src/modals/MediaDbAdvancedSearchModal.ts @@ -96,14 +96,19 @@ export class MediaDbAdvancedSearchModal extends Modal { contentEl.createDiv({cls: 'media-db-plugin-spacer'}); new Setting(contentEl) - .addButton(btn => btn.setButtonText('Cancel').onClick(() => this.close())) .addButton(btn => { - return (this.searchBtn = btn - .setButtonText('Ok') - .setCta() - .onClick(() => { - this.search(); - })); + btn.setButtonText('Cancel'); + btn.onClick(() => this.close()); + btn.buttonEl.addClass('media-db-plugin-button'); + }) + .addButton(btn => { + btn.setButtonText('Ok'); + btn.setCta(); + btn.onClick(() => { + this.search(); + }); + btn.buttonEl.addClass('media-db-plugin-button'); + this.searchBtn = btn; }); } diff --git a/src/modals/MediaDbFolderImportModal.ts b/src/modals/MediaDbFolderImportModal.ts index 415e4df..9c1f64a 100644 --- a/src/modals/MediaDbFolderImportModal.ts +++ b/src/modals/MediaDbFolderImportModal.ts @@ -76,8 +76,20 @@ export class MediaDbFolderImportModal extends Modal { contentEl.createDiv({cls: 'media-db-plugin-spacer'}); new Setting(contentEl) - .addButton(btn => btn.setButtonText('Cancel').onClick(() => this.close())) - .addButton(btn => btn.setButtonText('Ok').setCta().onClick(() => this.submit())); + .addButton(btn => { + btn.setButtonText('Cancel'); + btn.onClick(() => this.close()); + btn.buttonEl.addClass('media-db-plugin-button'); + }) + .addButton(btn => { + btn.setButtonText('Ok'); + btn.setCta(); + btn.onClick(() => { + this.submit(); + }); + btn.buttonEl.addClass('media-db-plugin-button'); + this.searchBtn = btn; + }); } onClose() { diff --git a/src/modals/MediaDbIdSearchModal.ts b/src/modals/MediaDbIdSearchModal.ts index 9437e2a..f53197a 100644 --- a/src/modals/MediaDbIdSearchModal.ts +++ b/src/modals/MediaDbIdSearchModal.ts @@ -84,14 +84,19 @@ export class MediaDbIdSearchModal extends Modal { contentEl.createDiv({cls: 'media-db-plugin-spacer'}); new Setting(contentEl) - .addButton(btn => btn.setButtonText('Cancel').onClick(() => this.close())) .addButton(btn => { - return (this.searchBtn = btn - .setButtonText('Ok') - .setCta() - .onClick(() => { - this.search(); - })); + btn.setButtonText('Cancel'); + btn.onClick(() => this.close()); + btn.buttonEl.addClass('media-db-plugin-button'); + }) + .addButton(btn => { + btn.setButtonText('Ok'); + btn.setCta(); + btn.onClick(() => { + this.search(); + }); + btn.buttonEl.addClass('media-db-plugin-button'); + this.searchBtn = btn; }); } diff --git a/src/modals/MediaDbSearchResultModal.ts b/src/modals/MediaDbSearchResultModal.ts index 4ffe578..546c394 100644 --- a/src/modals/MediaDbSearchResultModal.ts +++ b/src/modals/MediaDbSearchResultModal.ts @@ -59,6 +59,7 @@ export class MediaDbSearchResultModal extends SelectModal { } onClose() { + console.log('close'); this.closeCallback(); } } diff --git a/src/modals/SelectModal.ts b/src/modals/SelectModal.ts index 07f189c..5f726ee 100644 --- a/src/modals/SelectModal.ts +++ b/src/modals/SelectModal.ts @@ -12,6 +12,8 @@ export abstract class SelectModal extends Modal { skipButton?: ButtonComponent; submitButton?: ButtonComponent; + elementWrapper?: HTMLDivElement; + elements: T[]; selectModalElements: SelectModalElement[]; @@ -27,18 +29,28 @@ export abstract class SelectModal extends Modal { this.skipButton = undefined; this.submitButton = undefined; + this.elementWrapper = undefined; + this.elements = elements; this.selectModalElements = []; - this.scope.register([], 'ArrowUp', () => { + this.scope.register([], 'ArrowUp', (evt) => { this.highlightUp(); + evt.preventDefault(); }); - this.scope.register([], 'ArrowDown', () => { + this.scope.register([], 'ArrowDown', (evt) => { this.highlightDown(); + evt.preventDefault(); }); this.scope.register([], 'ArrowRight', () => { this.activateHighlighted(); }); + this.scope.register([], ' ', (evt) => { + if (this.elementWrapper && this.elementWrapper === document.activeElement) { + this.activateHighlighted(); + evt.preventDefault(); + } + }); this.scope.register([], 'Enter', () => this.submit()); } @@ -67,24 +79,17 @@ export abstract class SelectModal extends Modal { async onOpen() { const {contentEl} = this; - /* - contentEl.id = 'media-db-plugin-modal' - - contentEl.on('keydown', '#' + contentEl.id, (ev, delegateTarget) => { - console.log(ev.key); - }); - */ - contentEl.createEl('h2', {text: this.title}); contentEl.createEl('p', {text: this.description}); contentEl.addClass('media-db-plugin-select-modal'); - const elementWrapper = contentEl.createDiv({cls: 'media-db-plugin-select-wrapper'}); + this.elementWrapper = contentEl.createDiv({cls: 'media-db-plugin-select-wrapper'}); + this.elementWrapper.tabIndex = 0; let i = 0; for (const element of this.elements) { - const selectModalElement = new SelectModalElement(element, elementWrapper, i, this, false); + const selectModalElement = new SelectModalElement(element, this.elementWrapper, i, this, false); this.selectModalElements.push(selectModalElement); @@ -96,11 +101,27 @@ export abstract class SelectModal extends Modal { this.selectModalElements.first()?.element.scrollIntoView(); const bottomSettingRow = new Setting(contentEl); - bottomSettingRow.addButton(btn => this.cancelButton = btn.setButtonText('Cancel').onClick(() => this.close())); + bottomSettingRow.addButton(btn => { + btn.setButtonText('Cancel'); + btn.onClick(() => this.close()); + btn.buttonEl.addClass('media-db-plugin-button'); + this.cancelButton = btn; + }); if (this.addSkipButton) { - bottomSettingRow.addButton(btn => this.skipButton = btn.setButtonText('Skip').onClick(() => this.skip())); + bottomSettingRow.addButton(btn => { + btn.setButtonText('Skip'); + btn.onClick(() => this.skip()); + btn.buttonEl.addClass('media-db-plugin-button'); + this.skipButton = btn; + }); } - bottomSettingRow.addButton(btn => this.submitButton = btn.setButtonText('Ok').setCta().onClick(() => this.submit())); + bottomSettingRow.addButton(btn => { + btn.setButtonText('Ok'); + btn.setCta(); + btn.onClick(() => this.submit()); + btn.buttonEl.addClass('media-db-plugin-button'); + this.submitButton = btn; + }); } activateHighlighted() { diff --git a/styles.css b/styles.css index afe1e39..3414a7c 100644 --- a/styles.css +++ b/styles.css @@ -105,4 +105,8 @@ small.media-db-plugin-list-text{ margin-bottom: 5px; } +.media-db-plugin-button:focus { + outline: 1px solid white; +} + /* endregion */ From db4a6c98a3385c82dc4597c2b435d446cdce38b0 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Tue, 4 Oct 2022 15:08:48 +0200 Subject: [PATCH 27/43] fix for #56 --- src/main.ts | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/main.ts b/src/main.ts index f3507ba..30fefa0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,13 +78,26 @@ export default class MediaDbPlugin extends Plugin { // register command to update the open note this.addCommand({ id: 'update-media-db-note', - name: 'Update the open note, if it is a Media DB entry.', + name: 'Update open note (this will recreate the note)', checkCallback: (checking: boolean) => { if (!this.app.workspace.getActiveFile()) { return false; } if (!checking) { - this.updateActiveNote(); + this.updateActiveNote(false); + } + return true; + }, + }); + this.addCommand({ + id: 'update-media-db-note-metadata', + name: 'Update metadata', + checkCallback: (checking: boolean) => { + if (!this.app.workspace.getActiveFile()) { + return false; + } + if (!checking) { + this.updateActiveNote(true); } return true; }, @@ -175,12 +188,12 @@ export default class MediaDbPlugin extends Plugin { return; } - await this.createMediaDbNoteFromModel(idSearchResult); + await this.createMediaDbNoteFromModel(idSearchResult, {attachTemplate: true, openNote: true}); } async createMediaDbNotes(models: MediaTypeModel[], attachFile?: TFile): Promise { for (const model of models) { - await this.createMediaDbNoteFromModel(model, attachFile); + await this.createMediaDbNoteFromModel(model, {attachTemplate: true, attachFile: attachFile}); } } @@ -197,27 +210,27 @@ export default class MediaDbPlugin extends Plugin { return detailModels; } - async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, attachFile?: TFile): Promise { + async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, options: {attachTemplate?: boolean, attachFile?: TFile, openNote?: boolean}): Promise { try { console.debug('MDB | creating new note'); - let fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, attachFile); + let fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, {attachTemplate: options.attachTemplate, attachFile: options.attachFile}); - await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent); + await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options.openNote); } catch (e) { console.warn(e); new Notice(e.toString()); } } - private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, attachFile: TFile) { + private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: {attachTemplate?: boolean, attachFile?: TFile}) { let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); let fileContent = ''; - ({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, attachFile)); - ({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app))); + ({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, options.attachFile)); + ({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '')); - fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---` + fileContent; + fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent; return fileContent; } @@ -230,8 +243,9 @@ export default class MediaDbPlugin extends Plugin { fileMetadata = Object.assign(attachFileMetadata, fileMetadata); let attachFileContent: string = await this.app.vault.read(fileToAttach); - const regExp = new RegExp('^(---)\\n[\\s\\S]*\\n---'); + const regExp = new RegExp(this.frontMatterRexExpPattern); attachFileContent = attachFileContent.replace(regExp, ''); + attachFileContent = attachFileContent.startsWith('\n') ? attachFileContent.substring(1) : attachFileContent; fileContent += attachFileContent; return {fileMetadata: fileMetadata, fileContent: fileContent}; @@ -331,7 +345,7 @@ export default class MediaDbPlugin extends Plugin { * Update the active note by querying the API again. * Tries to read the type, id and dataSource of the active note. If successful it will query the api, delete the old note and create a new one. */ - async updateActiveNote() { + async updateActiveNote(onlyMetadata: boolean = false) { const activeFile: TFile = this.app.workspace.getActiveFile(); if (!activeFile) { throw new Error('MDB | there is no active note'); @@ -357,7 +371,12 @@ export default class MediaDbPlugin extends Plugin { // deletion not happening anymore why is this log statement still here console.debug('MDB | deleting old entry'); - await this.createMediaDbNoteFromModel(newMediaTypeModel, activeFile); + if (onlyMetadata) { + await this.createMediaDbNoteFromModel(newMediaTypeModel, {attachFile: activeFile, openNote: true}); + } else { + await this.createMediaDbNoteFromModel(newMediaTypeModel, {attachTemplate: true, openNote: true}); + } + } async createEntriesFromFolder(folder: TFolder) { From 7c926f00afc48d53b572d46d7d26f3d75aea2c13 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:45:04 +0530 Subject: [PATCH 28/43] feat: add previewModal logic to advancedModal --- src/main.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.ts b/src/main.ts index 30fefa0..9348b9e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -176,6 +176,12 @@ export default class MediaDbPlugin extends Plugin { return; } + const proceed: boolean = await this.modalHelper.openPreviewModal(selectResults, async (result) => { + return true; + }) + if (!proceed) + return; + await this.createMediaDbNotes(selectResults); } From 3ceeb3c51cac0a0c3eda87709bee35124ffbea85 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:46:46 +0530 Subject: [PATCH 29/43] feat: add previewModal handler to ModalHelper --- src/utils/ModalHelper.ts | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/utils/ModalHelper.ts b/src/utils/ModalHelper.ts index 2529679..a573e12 100644 --- a/src/utils/ModalHelper.ts +++ b/src/utils/ModalHelper.ts @@ -131,5 +131,42 @@ export class ModalHelper { return; } } + + async createPreviewModal(mediaTypeModel: MediaTypeModel[]): Promise<{ result: boolean, previewModal: MediaDbPreviewModal }> { + //todo: handle attachFile for existing files + const modal = new MediaDbPreviewModal(this.plugin, mediaTypeModel, { attachTemplate: true, attachFile: false }); + const booleanResult: boolean = await new Promise((resolve, reject) => { + modal.setSubmitCallback(res => resolve(res)); + modal.setCloseCallback(err => { + if (err) { + reject(err); + } + resolve(undefined); + }); + + modal.open(); + }); + return { result: booleanResult, previewModal: modal }; + } + + async openPreviewModal(mediaModels: MediaTypeModel[], submitCallback: (result: boolean) => Promise): Promise { + const { result, previewModal } = await this.createPreviewModal(mediaModels); + if (!result) { + previewModal.close(); + return; + } + + try { + let callbackRes: boolean; + callbackRes = await submitCallback(result); + previewModal.close(); + return callbackRes; + } catch (e) { + console.warn(e); + new Notice(e.toString()); + previewModal.close(); + return; + } + } } From e597da5609adb0299fd44ebd596c8a5abfcb8066 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:47:52 +0530 Subject: [PATCH 30/43] fix: spelling --- src/modals/MediaDbAdvancedSearchModal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modals/MediaDbAdvancedSearchModal.ts b/src/modals/MediaDbAdvancedSearchModal.ts index 52c9786..3db3235 100644 --- a/src/modals/MediaDbAdvancedSearchModal.ts +++ b/src/modals/MediaDbAdvancedSearchModal.ts @@ -36,7 +36,7 @@ export class MediaDbAdvancedSearchModal extends Modal { async search(): Promise { if (!this.query || this.query.length < 3) { - new Notice('MDB | Query to short'); + new Notice('MDB | Query too short'); return; } From 7fe9a7791fddea0da4938559980c7a66cb613a34 Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:49:07 +0530 Subject: [PATCH 31/43] feat: add PreviewModal --- src/modals/MediaDbPreviewModal.ts | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/modals/MediaDbPreviewModal.ts diff --git a/src/modals/MediaDbPreviewModal.ts b/src/modals/MediaDbPreviewModal.ts new file mode 100644 index 0000000..0bc91b4 --- /dev/null +++ b/src/modals/MediaDbPreviewModal.ts @@ -0,0 +1,71 @@ +import { MarkdownRenderer, Modal, Setting, TFile } from "obsidian"; +import MediaDbPlugin from "src/main"; +import { MediaTypeModel } from "src/models/MediaTypeModel"; + +export class MediaDbPreviewModal extends Modal { + selectedSearchResults: MediaTypeModel[]; + options: { attachTemplate: boolean, attachFile: TFile}; + submitCallback: (res: boolean) => void; + closeCallback: (err?: Error) => void; + skipCallback: () => void; + plugin: MediaDbPlugin; + searchBtn: any; + cancelButton: any; + submitButton: any; + busy: any; + + constructor(plugin: MediaDbPlugin, mediaTypeModel: MediaTypeModel[], options: any) { + super(plugin.app); + this.plugin = plugin; + this.selectedSearchResults = mediaTypeModel; + this.options = options; + } + + setSubmitCallback(submitCallback: (res: boolean) => void): void { + this.submitCallback = submitCallback; + } + + setCloseCallback(closeCallback: (err?: Error) => void): void { + this.closeCallback = closeCallback; + } + + async preview(): Promise { + let { contentEl } = this; + for (let result of this.selectedSearchResults) { + let fileContent = await this.plugin.generateMediaDbNoteContents(result, { attachTemplate: this.options.attachTemplate, attachFile: this.options.attachFile }); + this.contentEl.createEl("h3", {text: result.englishTitle}); + const fileDiv = this.contentEl.createDiv(); + fileContent = `\n${fileContent}\n`; + MarkdownRenderer.renderMarkdown(fileContent, fileDiv, null, null); + } + + contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); + + const bottomSettingRow = new Setting(contentEl); + bottomSettingRow.addButton(btn => { + btn.setButtonText('Cancel'); + btn.onClick(() => this.close()); + btn.buttonEl.addClass('media-db-plugin-button'); + this.cancelButton = btn; + }); + bottomSettingRow.addButton(btn => { + btn.setButtonText('Ok'); + btn.setCta(); + btn.onClick(() => this.submit()); + btn.buttonEl.addClass('media-db-plugin-button'); + this.submitButton = btn; + }) + } + + submit() { + if (!this.busy) { + this.busy = true; + this.submitButton.setButtonText('Creating entry...'); + this.submitCallback(true); + } + } + + onOpen(): void { + this.preview() + } +} \ No newline at end of file From 4de23fa9977bb2622f658388cb62f9097d94bffb Mon Sep 17 00:00:00 2001 From: AB1908 <14124383+AB1908@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:51:15 +0530 Subject: [PATCH 32/43] fix: add PreviewModal import --- src/utils/ModalHelper.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/ModalHelper.ts b/src/utils/ModalHelper.ts index a573e12..fd44dbd 100644 --- a/src/utils/ModalHelper.ts +++ b/src/utils/ModalHelper.ts @@ -4,6 +4,7 @@ import {MediaTypeModel} from '../models/MediaTypeModel'; import {MediaDbSearchResultModal} from '../modals/MediaDbSearchResultModal'; import {Notice} from 'obsidian'; import MediaDbPlugin from '../main'; +import { MediaDbPreviewModal } from 'src/modals/MediaDbPreviewModal'; interface AdvancedSearchOptions { query: string, From a3905daf5b41b8fd990d1f1c3fd0b3fb238540a8 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Sat, 8 Oct 2022 22:04:03 +0200 Subject: [PATCH 33/43] Some more modal changes (look at those doc comments :o) How did this work the first time i tested it??? --- src/api/apis/BoardGameGeekAPI.ts | 1 - src/main.ts | 90 ++--- src/modals/MediaDbAdvancedSearchModal.ts | 26 +- src/modals/MediaDbIdSearchModal.ts | 23 +- src/modals/MediaDbSearchResultModal.ts | 21 +- .../PropertyMappingModelComponent.svelte | 8 +- .../PropertyMappingModelsComponent.svelte | 2 +- src/utils/ModalHelper.ts | 363 ++++++++++++++---- 8 files changed, 374 insertions(+), 160 deletions(-) diff --git a/src/api/apis/BoardGameGeekAPI.ts b/src/api/apis/BoardGameGeekAPI.ts index 57c5a5b..4198720 100644 --- a/src/api/apis/BoardGameGeekAPI.ts +++ b/src/api/apis/BoardGameGeekAPI.ts @@ -4,7 +4,6 @@ import MediaDbPlugin from '../../main'; import {BoardGameModel} from 'src/models/BoardGameModel'; import {debugLog} from '../../utils/Utils'; import {requestUrl} from 'obsidian'; -import {MediaType} from '../../utils/MediaType'; export class BoardGameGeekAPI extends APIModel { plugin: MediaDbPlugin; diff --git a/src/main.ts b/src/main.ts index 30fefa0..d9cfe58 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,9 +2,8 @@ import {MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} import {getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings'; import {APIManager} from './api/APIManager'; import {MediaTypeModel} from './models/MediaTypeModel'; -import {dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils'; +import {dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString} from './utils/Utils'; import {OMDbAPI} from './api/apis/OMDbAPI'; -import {MediaDbSearchResultModal} from './modals/MediaDbSearchResultModal'; import {MALAPI} from './api/apis/MALAPI'; import {WikipediaAPI} from './api/apis/WikipediaAPI'; import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI'; @@ -15,7 +14,7 @@ import {PropertyMapper} from './settings/PropertyMapper'; import {YAMLConverter} from './utils/YAMLConverter'; import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal'; import {PropertyMapping, PropertyMappingModel} from './settings/PropertyMapping'; -import {ModalHelper} from './utils/ModalHelper'; +import {ModalHelper, ModalResultCode} from './utils/ModalHelper'; export default class MediaDbPlugin extends Plugin { settings: MediaDbPluginSettings; @@ -126,23 +125,23 @@ export default class MediaDbPlugin extends Plugin { */ async createLinkWithSearchModal() { - let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal(async (advancedSearchOptions) => { - return await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); + let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async (advancedSearchModalData) => { + return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis); }); if (!apiSearchResults) { return; } - const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal(apiSearchResults, async (selectedMediaTypeModels) => { - return await this.queryDetails(selectedMediaTypeModels); + const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal({elements: apiSearchResults, multiSelect: false}, async (selectModalData) => { + return await this.queryDetails(selectModalData.selected); }); if (!selectResults || selectResults.length < 1) { return; } - const link = `[${selectResults[0].title}](${selectResults[0].url})` + const link = `[${selectResults[0].title}](${selectResults[0].url})`; const view = this.app.workspace.getActiveViewOfType(MarkdownView); @@ -160,16 +159,16 @@ export default class MediaDbPlugin extends Plugin { * TODO: further refactor: extract it into own method, pass the action (api query) as lambda as well as an options object */ async createEntryWithAdvancedSearchModal() { - const apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal(async (advancedSearchOptions) => { - return await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis); + let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async (advancedSearchModalData) => { + return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis); }); if (!apiSearchResults) { return; } - const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal(apiSearchResults, async (selectedMediaTypeModels) => { - return await this.queryDetails(selectedMediaTypeModels); + const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal({elements: apiSearchResults}, async (selectModalData) => { + return await this.queryDetails(selectModalData.selected); }); if (!selectResults) { @@ -180,9 +179,9 @@ export default class MediaDbPlugin extends Plugin { } async createEntryWithIdSearchModal() { - const idSearchResult: MediaTypeModel = await this.modalHelper.openIdSearchModal(async (idSearchOptions) => { - return await this.apiManager.queryDetailedInfoById(idSearchOptions.query, idSearchOptions.api); - }) + const idSearchResult: MediaTypeModel = await this.modalHelper.openIdSearchModal({}, async (idSearchModalData) => { + return await this.apiManager.queryDetailedInfoById(idSearchModalData.query, idSearchModalData.api); + }); if (!idSearchResult) { return; @@ -210,7 +209,7 @@ export default class MediaDbPlugin extends Plugin { return detailModels; } - async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, options: {attachTemplate?: boolean, attachFile?: TFile, openNote?: boolean}): Promise { + async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, options: { attachTemplate?: boolean, attachFile?: TFile, openNote?: boolean }): Promise { try { console.debug('MDB | creating new note'); @@ -223,12 +222,15 @@ export default class MediaDbPlugin extends Plugin { } } - private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: {attachTemplate?: boolean, attachFile?: TFile}) { + private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: { attachTemplate?: boolean, attachFile?: TFile }) { let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); let fileContent = ''; ({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, options.attachFile)); - ({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '')); + ({ + fileMetadata, + fileContent, + } = await this.attachTemplate(fileMetadata, fileContent, options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '')); fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent; return fileContent; @@ -417,46 +419,36 @@ export default class MediaDbPlugin extends Plugin { continue; } - let selectedResults: MediaTypeModel[] = []; - const modal = new MediaDbSearchResultModal(this, results, true); - try { - selectedResults = await new Promise((resolve, reject) => { - modal.title = `Results for \'${title}\'`; - modal.setSubmitCallback(res => resolve(res)); - modal.setSkipCallback(() => reject(new UserCancelError('user skipped'))); - modal.setCloseCallback(err => { - if (err) { - reject(err); - } - reject(new UserCancelError('user canceled')); - }); + let {selectModalResult, selectModal} = await this.modalHelper.createSelectModal({elements: results, skipButton: true, modalTitle: `Results for \'${title}\'`}); - modal.open(); - }); - } catch (e) { - modal.close(); - if (e instanceof UserCancelError) { - erroredFiles.push({filePath: file.path, error: e.message}); - canceled = true; - continue; - } else if (e instanceof UserSkipError) { - erroredFiles.push({filePath: file.path, error: e.message}); - continue; - } else { - erroredFiles.push({filePath: file.path, error: e.message}); - continue; - } + if (selectModalResult.code === ModalResultCode.ERROR) { + erroredFiles.push({filePath: file.path, error: selectModalResult.error.message}); + selectModal.close(); + continue; } - if (selectedResults.length === 0) { + if (selectModalResult.code === ModalResultCode.CLOSE) { + erroredFiles.push({filePath: file.path, error: 'user canceled'}); + selectModal.close(); + canceled = true; + continue; + } + + if (selectModalResult.code === ModalResultCode.SKIP) { + erroredFiles.push({filePath: file.path, error: 'user skipped'}); + selectModal.close(); + continue; + } + + if (selectModalResult.data.selected.length === 0) { erroredFiles.push({filePath: file.path, error: `no search results selected`}); continue; } - const detailedResults = await this.queryDetails(selectedResults); + const detailedResults = await this.queryDetails(selectModalResult.data.selected); await this.createMediaDbNotes(detailedResults, appendContent ? file : null); - modal.close(); + selectModal.close(); } } diff --git a/src/modals/MediaDbAdvancedSearchModal.ts b/src/modals/MediaDbAdvancedSearchModal.ts index 52c9786..e25f0a2 100644 --- a/src/modals/MediaDbAdvancedSearchModal.ts +++ b/src/modals/MediaDbAdvancedSearchModal.ts @@ -1,26 +1,37 @@ import {ButtonComponent, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; import MediaDbPlugin from '../main'; +import {ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS, AdvancedSearchModalData, AdvancedSearchModalOptions} from '../utils/ModalHelper'; export class MediaDbAdvancedSearchModal extends Modal { + plugin: MediaDbPlugin; + query: string; isBusy: boolean; - plugin: MediaDbPlugin; - searchBtn: ButtonComponent; + title: string; selectedApis: { name: string, selected: boolean }[]; - submitCallback?: (res: { query: string, apis: string[] }) => void; + + searchBtn: ButtonComponent; + + submitCallback?: (res: AdvancedSearchModalData) => void; closeCallback?: (err?: Error) => void; - constructor(plugin: MediaDbPlugin) { + + constructor(plugin: MediaDbPlugin, advancedSearchModalOptions: AdvancedSearchModalOptions) { + advancedSearchModalOptions = Object.assign({}, ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS, advancedSearchModalOptions); super(plugin.app); + this.plugin = plugin; this.selectedApis = []; + this.title = advancedSearchModalOptions.modalTitle; + this.query = advancedSearchModalOptions.prefilledSearchString; + for (const api of this.plugin.apiManager.apis) { - this.selectedApis.push({name: api.apiName, selected: false}); + this.selectedApis.push({name: api.apiName, selected: advancedSearchModalOptions.preselectedAPIs.contains(api.apiName)}); } } - setSubmitCallback(submitCallback: (res: { query: string, apis: string[] }) => void): void { + setSubmitCallback(submitCallback: (res: AdvancedSearchModalData) => void): void { this.submitCallback = submitCallback; } @@ -59,12 +70,13 @@ export class MediaDbAdvancedSearchModal extends Modal { onOpen() { const {contentEl} = this; - contentEl.createEl('h2', {text: 'Search media db'}); + contentEl.createEl('h2', {text: this.title}); const placeholder = 'Search by title'; const searchComponent = new TextComponent(contentEl); searchComponent.inputEl.style.width = '100%'; searchComponent.setPlaceholder(placeholder); + searchComponent.setValue(this.query); searchComponent.onChange(value => (this.query = value)); searchComponent.inputEl.addEventListener('keydown', this.keyPressCallback.bind(this)); diff --git a/src/modals/MediaDbIdSearchModal.ts b/src/modals/MediaDbIdSearchModal.ts index f53197a..ec29cac 100644 --- a/src/modals/MediaDbIdSearchModal.ts +++ b/src/modals/MediaDbIdSearchModal.ts @@ -1,23 +1,32 @@ import {ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian'; import {MediaTypeModel} from '../models/MediaTypeModel'; import MediaDbPlugin from '../main'; +import {ID_SEARCH_MODAL_DEFAULT_OPTIONS, IdSearchModalData, IdSearchModalOptions} from '../utils/ModalHelper'; export class MediaDbIdSearchModal extends Modal { + plugin: MediaDbPlugin; + query: string; isBusy: boolean; - plugin: MediaDbPlugin; - searchBtn: ButtonComponent; + title: string; selectedApi: string; - submitCallback?: (res: { query: string, api: string }, err?: Error) => void; + + searchBtn: ButtonComponent; + + submitCallback?: (res: IdSearchModalData, err?: Error) => void; closeCallback?: (err?: Error) => void; - constructor(plugin: MediaDbPlugin) { + + constructor(plugin: MediaDbPlugin, idSearchModalOptions: IdSearchModalOptions) { + idSearchModalOptions = Object.assign({}, ID_SEARCH_MODAL_DEFAULT_OPTIONS, idSearchModalOptions); super(plugin.app); + this.plugin = plugin; - this.selectedApi = plugin.apiManager.apis[0].apiName; + this.title = idSearchModalOptions.modalTitle; + this.selectedApi = idSearchModalOptions.preselectedAPI || plugin.apiManager.apis[0].apiName; } - setSubmitCallback(submitCallback: (res: { query: string, api: string }, err?: Error) => void): void { + setSubmitCallback(submitCallback: (res: IdSearchModalData, err?: Error) => void): void { this.submitCallback = submitCallback; } @@ -54,7 +63,7 @@ export class MediaDbIdSearchModal extends Modal { onOpen() { const {contentEl} = this; - contentEl.createEl('h2', {text: 'Search media db by id'}); + contentEl.createEl('h2', {text: this.title}); const placeholder = 'Search by id'; const searchComponent = new TextComponent(contentEl); diff --git a/src/modals/MediaDbSearchResultModal.ts b/src/modals/MediaDbSearchResultModal.ts index 546c394..c44a91f 100644 --- a/src/modals/MediaDbSearchResultModal.ts +++ b/src/modals/MediaDbSearchResultModal.ts @@ -1,31 +1,34 @@ import {MediaTypeModel} from '../models/MediaTypeModel'; import MediaDbPlugin from '../main'; import {SelectModal} from './SelectModal'; +import {SELECT_MODAL_OPTIONS_DEFAULT, SelectModalData, SelectModalOptions} from '../utils/ModalHelper'; export class MediaDbSearchResultModal extends SelectModal { plugin: MediaDbPlugin; - heading: string; + busy: boolean; - submitCallback: (res: MediaTypeModel[]) => void; + sendCallback: boolean; + + submitCallback: (res: SelectModalData) => void; closeCallback: (err?: Error) => void; skipCallback: () => void; - sendCallback: boolean; - constructor(plugin: MediaDbPlugin, elements: MediaTypeModel[], skipButton: boolean, allowMultiSelect: boolean = true) { - super(plugin.app, elements, allowMultiSelect); + constructor(plugin: MediaDbPlugin, selectModalOptions: SelectModalOptions) { + selectModalOptions = Object.assign({}, SELECT_MODAL_OPTIONS_DEFAULT, selectModalOptions); + super(plugin.app, selectModalOptions.elements, selectModalOptions.multiSelect); this.plugin = plugin; - this.title = 'Search Results'; + this.title = selectModalOptions.modalTitle; this.description = 'Select one or multiple search results.'; - this.addSkipButton = skipButton; + this.addSkipButton = selectModalOptions.skipButton; this.busy = false; this.sendCallback = false; } - setSubmitCallback(submitCallback: (res: MediaTypeModel[]) => void): void { + setSubmitCallback(submitCallback: (res: SelectModalData) => void): void { this.submitCallback = submitCallback; } @@ -49,7 +52,7 @@ export class MediaDbSearchResultModal extends SelectModal { if (!this.busy) { this.busy = true; this.submitButton.setButtonText('Creating entry...'); - this.submitCallback(this.selectModalElements.filter(x => x.isActive()).map(x => x.value)); + this.submitCallback({selected: this.selectModalElements.filter(x => x.isActive()).map(x => x.value)}); } } diff --git a/src/settings/PropertyMappingModelComponent.svelte b/src/settings/PropertyMappingModelComponent.svelte index da8797b..a0a3b68 100644 --- a/src/settings/PropertyMappingModelComponent.svelte +++ b/src/settings/PropertyMappingModelComponent.svelte @@ -46,16 +46,16 @@
    - { /if } - { /if } + { /if } + { /if } - { /each } + { /each } { #if !validationResult?.res }
    {validationResult?.err?.message}
    - { /if } + { /if }