├── .github
└── workflows
│ └── blank.yml
├── .gitignore
├── .npmignore
├── .prettierrc
├── LICENSE
├── README.md
├── cli.ts
├── docs
├── autocomplete.gif
└── readme_0.gif
├── index.ts
├── lib
├── autocomplete.ts
├── cache.ts
├── create.ts
├── directiveParser.ts
├── make_fake_expression.ts
└── utils.ts
├── package-lock.json
├── package.json
├── sql.ts
├── test
├── cache.ts
├── directives.ts
└── utils.ts
├── tsconfig.json
└── typings.d.ts
/.github/workflows/blank.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node: ["12", "14", "16"]
11 | name: Node ${{ matrix.node }} tests
12 | steps:
13 | - uses: actions/checkout@v1
14 | - name: Tests
15 | uses: actions/setup-node@v1
16 | with:
17 | node-version: ${{ matrix.node }}
18 | - run: npm install
19 | - run: npm test
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # common
2 | .cache/
3 | .vscode/
4 | .gitignore.d/
5 | node_modules/
6 | dist/
7 | *.map
8 |
9 | # specific
10 | *.js
11 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # common
2 | .cache/
3 | .vscode/
4 | .github/
5 | .gitignore.d/
6 |
7 | # specific
8 | .prettierrc
9 | node_modules
10 | test
11 | tsconfig.json
12 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "useTabs": false,
4 | "printWidth": 120,
5 | "arrowParens": "avoid",
6 | "trailingComma": "all",
7 | "endOfLine": "lf",
8 | "bracketSpacing": true
9 | }
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 xialvjun
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ts-sql-plugin
2 | TypeScript Language Service Plugin for SQL with a tagged template strings SQL builder. Inspired by [andywer/squid](https://github.com/andywer/squid)
3 |
4 | #### check sql error demo:
5 | 
6 |
7 | #### autocomplete demo:
8 | 
9 |
10 | # Usage
11 |
12 | ## run as a language service plugin
13 |
14 | Install the plugin, run:
15 |
16 | ```sh
17 | npm install ts-sql-plugin -D
18 | ```
19 |
20 | Then, configure the `plugins` section in your *tsconfig.json*:
21 |
22 | ```json
23 | {
24 | "compilerOptions": {
25 | "module": "commonjs",
26 | "target": "es5",
27 | "plugins": [
28 | {
29 | "name": "ts-sql-plugin",
30 | "command": "psql -c", // optionnal
31 | "tags": { // optionnal
32 | "sql": "sql",
33 | "raw": "raw",
34 | "cond": "cond",
35 | "and": "and",
36 | "or": "or",
37 | "ins": "ins",
38 | "upd": "upd",
39 | "mock": "mock"
40 | },
41 | "mock": "0",
42 | "cost_pattern": "/\\(cost=\\d+\\.?\\d*\\.\\.(\\d+\\.?\\d*)/",
43 | "error_cost": null, // 100,
44 | "warn_cost": null, // 50,
45 | "info_cost": null, // -1,
46 | "schema_command": "pg" // pg | mysql | custom - read the source
47 | }
48 | ]
49 | }
50 | }
51 | ```
52 |
53 | **Note**: If you're using Visual Studio Code, you'll have to use the first approach above, with a
54 | path to the module, or run the "TypeScript: Select TypeScript Version" command and choose "Use
55 | Workspace Version", or click the version number between "TypeScript" and 😃 in the lower-right
56 | corner. Otherwise, VS Code will not be able to find your plugin. See https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin#testing-locally
57 |
58 | ## run as a command line application
59 |
60 | Install the plugin, run:
61 |
62 | ```sh
63 | npm install ts-sql-plugin -g
64 | ```
65 |
66 | Then run:
67 |
68 | ```sh
69 | ts-sql-plugin -p ./my_ts_project -c 'psql -U postgres -c'
70 | ```
71 |
72 | # Then in your code:
73 |
74 | In the code below, some of the table names or column names are intentionally wrong. `ts-sql-plugin` will show you the errors.
75 |
76 | ```ts
77 | import sql from 'ts-sql-plugin/sql';
78 |
79 | sql`select * from wrong_table_name where wrong_column_name=${name}`;
80 | // { text: "select * from wrong_table_name where wrong_column_name=??", values: [name] }
81 | // you should transform the text to pg specific or mysql specific query text
82 |
83 | // sql.and
84 | sql`select * from person where ${sql.and({ wrong_column_name: value, name: name })}`;
85 |
86 | // sql.or
87 | sql`select * from person where ${sql.or([{ 'name like': 'abc%', age: 23 }, { 'age >': 23 }])}`;
88 | sql`select * from person where (name like ${'abc%'} and age=${23}) or age > ${23}`;
89 |
90 | // sql.ins
91 | sql`insert into person ${sql.ins({ id: uuid(), name: name, ageeee: wrong_column_name_value })}`;
92 | sql`insert into person ${sql.ins([{ id: uuid(), name, age: 23 }, {id, name:'ppp', age:30}])}`;
93 |
94 | // sql.upd
95 | sql`update person set ${sql.upd({ wrong_name_column: name, age: 23 })} where id=${id}`;
96 |
97 | // like, >, < etc
98 | sql`select * from person where ${sql.and({ 'name like': '%'+name_like+'%', 'ageee >': age_bigger_than })}`;
99 |
100 | // sql.raw with ?: operator
101 | sql`select * from person order by age ${reverse ? sql.raw`desc` : sql.raw`asc`}`;
102 |
103 | // sql.cond
104 | sql`select * from person where name=${name} ${sql.cond(!!age_bigger_than)` and ageeee > ${age_bigger_than}`}`;
105 |
106 | // ! where in will produce error because of node-postgres doesn't support it. use where column=any()
107 | sql`select * from person where id in (${[uuid(), uuid()]})`;
108 | sql`select * from person where id = any(${[uuid(), uuid()]})`;
109 | sql`select * from ${sql.mock<'person' | 'book'>(sql.raw([table_name]))}`
110 | sql`select * from person where age = ${sql.mock<'12'>(some_value_can_not_use_the_default_mock__0)}`
111 |
112 | // you can use sql queries inside each other
113 | const s1 = sql`select * from subscriptions.attribute where entity_id = any(${[7045]})`;
114 | const s2 = sql`select * from (${s1}) attr where attribute_id = any(${[7049, 7050]})`;
115 |
116 | // ignore cost for query stuff implemented
117 | const s1 = sql`
118 | -- ts-sql-plugin:ignore-cost
119 | select * from subscriptions.attribute
120 | `;
121 |
122 | // you can emit sql to explicit file
123 | // this will be emitted to emit-sql/AllAttribute.sql file
124 | // you may change `emit-sql` folder to another via `--emit_dir` option of cli
125 | // also `--watch` option of cli can be used to emit it in realtime
126 | const s1 = sql`
127 | /* ts-sql-plugin:emit("AllAttribute") */
128 | /* @name AllAttribute */
129 | select * from subscriptions.attribute
130 | `;
131 | ```
132 |
133 | **And there is a complete example using [ts-sql-plugin](https://github.com/xialvjun/ts-sql-plugin) and [skm_ts](https://github.com/xialvjun/skm_ts) in folder test_ts_sql_plugin.**
134 |
135 | ## Generate types from emitted sql
136 |
137 | You can use [pgtyped](https://github.com/adelsz/pgtyped) tool
138 | for generating types from your emitted sql via directive:
139 | ```
140 | /* ts-sql-plugin:emit("SomeInterface") */
141 | /* @name SomeInterface */
142 | ```
143 |
144 | For generate types in realtime, use `--watch` option of cli.
145 |
146 | ## VSCode syntax highlight extension
147 |
148 | https://marketplace.visualstudio.com/items?itemName=darky.vscode-ts-sql-plugin
149 |
--------------------------------------------------------------------------------
/cli.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import crypto from "crypto";
4 | import fs from "fs";
5 | import path from "path";
6 | import spawn from "await-spawn";
7 | import flattenDeep from "lodash.flattendeep";
8 |
9 | import ts from "typescript";
10 | import { program } from "commander";
11 | import shq from "shell-quote";
12 |
13 | import {
14 | default_mock,
15 | default_cost_pattern,
16 | default_tags,
17 | default_command,
18 | merge_defaults,
19 | get_all_ts_files,
20 | report,
21 | TsSqlPluginConfig,
22 | trim_middle_comments,
23 | } from "./lib/utils";
24 | import { make_fake_expression } from "./lib/make_fake_expression";
25 | import { directiveRegex, parseDirectives } from "./lib/directiveParser";
26 | import { addToSqlCache, existsInSqlCache } from './lib/cache';
27 |
28 | program
29 | .option("-w, --watch", `watch mode of cli`)
30 | .option("-p, --project ", "ts project path where tsconfig.json is in", "./")
31 | .option("-e, --exclude ", "regexp to exclude files", "node_modules")
32 | .option("--emit_dir ", "where sqls will be emitted")
33 | // ! --mock, --error_cost, --warn_cost, --info_cost, --cost_pattern, --tags, --command are the same as plugin options
34 | // ! do not use commander default option value, to use the options in tsconfig.json
35 | .option(
36 | "-m, --mock ",
37 | `string to mock the values in the fake sqls, you can override it with: sql.mock<'null'>(any_value) (default: "${default_mock}")`,
38 | )
39 | .option("--error_cost ", `throw error if explain cost exceeds treshold`)
40 | .option("--warn_cost ", `log warning if explain cost exceeds treshold`)
41 | .option("--info_cost ", `log info if explain cost exceeds treshold`)
42 | .option(
43 | "--cost_pattern ",
44 | `regexp to extract cost from command stdout, make sure the number is the first capturing group (default: "/${default_cost_pattern.source}/")`,
45 | // (str, pv) => new RegExp(str || pv),
46 | // default_cost_pattern.source as any as RegExp
47 | )
48 | .option(
49 | "-t, --tags ",
50 | `tags you used in you ts file (default: "${Object.entries(default_tags)
51 | .map(it => it.join("="))
52 | .join(",")}")`,
53 | (str, pv) => {
54 | return Object.fromEntries(str.split(",").map(s => s.split("=")));
55 | // return [(pv as any) as string, str]
56 | // .map((it) => Object.fromEntries(it.split(",").map((s) => s.split("="))))
57 | // .reduce((acc, cv) => ({ ...acc, ...cv }), {}) as typeof default_tags;
58 | },
59 | // (Object.entries(default_tags)
60 | // .map((it) => it.join("="))
61 | // .join(",") as any) as typeof default_tags
62 | )
63 | .option(
64 | "-c, --command ",
65 | `command to be run to explain the fake sql (default: "${default_command}")` /* default_command */,
66 | )
67 | .description(
68 | `Explain all your sqls in your code to test them. \n\nEg: ts-sql-plugin -p ./my_ts_projet/tsconfig.json -c 'psql -c'`,
69 | )
70 | .action(async () => {
71 | let cli_config: any = program.opts();
72 | if (typeof cli_config.command !== "string") {
73 | cli_config.command = undefined;
74 | }
75 | cli_config.exclude = new RegExp(cli_config.exclude);
76 |
77 | const ts_config_path = ts.findConfigFile(cli_config.project, ts.sys.fileExists, "tsconfig.json");
78 | if (!ts_config_path) {
79 | throw new Error("Could not find a valid 'tsconfig.json'.");
80 | }
81 | const { config: ts_config } = ts.parseConfigFileTextToJson(
82 | ts_config_path,
83 | await fs.promises.readFile(ts_config_path, { encoding: "utf8" }),
84 | );
85 | let plugin_config: TsSqlPluginConfig = (ts_config.compilerOptions.plugins as any[])?.find(
86 | it => it.name === "ts-sql-plugin",
87 | );
88 | plugin_config = merge_defaults(plugin_config, cli_config);
89 | const cost_pattern = new RegExp(plugin_config.cost_pattern!);
90 |
91 | const initProgram = ts.createProgram(get_all_ts_files(path.dirname(ts_config_path)), ts_config.compilerOptions);
92 | let fake_expression = make_fake_expression(initProgram.getTypeChecker(), plugin_config.tags);
93 |
94 | if (cli_config.watch) {
95 | const watchHost = ts.createWatchCompilerHost(ts_config_path, undefined, ts.sys);
96 | const watchProgram = ts.createWatchProgram(watchHost);
97 | const onChangeFile = (fileName: string) => {
98 | const file = watchProgram.getProgram().getSourceFile(fileName);
99 | if (file) {
100 | fake_expression = make_fake_expression(
101 | watchProgram.getProgram().getProgram().getTypeChecker(),
102 | plugin_config.tags,
103 | );
104 | delint(file);
105 | }
106 | };
107 | const watchFile = (sourceFile: ts.SourceFile) => {
108 | watchHost.watchFile(sourceFile.fileName, (fileName, event) => {
109 | if (event !== ts.FileWatcherEventKind.Deleted) {
110 | onChangeFile(fileName);
111 | }
112 | });
113 | };
114 | const source_files = watchProgram
115 | .getProgram()
116 | .getSourceFiles()
117 | .filter(it => !cli_config.exclude.test(it.fileName));
118 | source_files.forEach(watchFile);
119 | source_files.forEach(it => onChangeFile(it.fileName));
120 | return;
121 | }
122 |
123 | let has_error = false;
124 | let report_errors: [sourceFile: ts.SourceFile, node: ts.Node, message: string, level?: 1 | 2][] = [];
125 | console.log("-- Start init sql check and emit...");
126 | for (const file of initProgram.getSourceFiles().filter(f => !cli_config.exclude.test(f.fileName))) {
127 | await delint(file);
128 | }
129 | if (has_error) {
130 | console.error("\n\n-- Your code can not pass all sql test!!!\n");
131 | report_errors.forEach(args => report(...args));
132 | process.exit(1);
133 | }
134 | console.log("\n\n-- Init sql check and emit finished.\n");
135 |
136 | function recursiveAllChildrenNodes(node: ts.Node): ts.Node[] {
137 | return (node.getChildren().map(n => [n, ...recursiveAllChildrenNodes(n)]) as unknown) as ts.Node[];
138 | }
139 |
140 | async function delint(sourceFile: ts.SourceFile) {
141 | const treeNodes = recursiveAllChildrenNodes(sourceFile);
142 | const sqlTagNodes = flattenDeep(treeNodes).filter(
143 | (n): n is ts.TaggedTemplateExpression =>
144 | n.kind === ts.SyntaxKind.TaggedTemplateExpression &&
145 | (n as ts.TaggedTemplateExpression).tag.getText() === plugin_config.tags.sql,
146 | );
147 |
148 | await Promise.all(sqlTagNodes.map(delintNode));
149 |
150 | async function delintNode(node: ts.TaggedTemplateExpression) {
151 | let query_configs = fake_expression(node);
152 | for (const qc of query_configs) {
153 | let s: string = trim_middle_comments(qc.text).replace(/\?\?/gm, plugin_config.mock);
154 |
155 | const directives = parseDirectives(s);
156 | if (cli_config.emit_dir) {
157 | const emit_directive = directives.find(d => d.directive === "emit");
158 | if (emit_directive) {
159 | const fileName = (emit_directive.arg as string) ?? crypto.createHash("sha1").update(s).digest("hex");
160 | const filePath = `${cli_config.emit_dir}/${fileName}.sql`;
161 | try {
162 | fs.writeFileSync(filePath, s + ";");
163 | } catch (err) {
164 | console.log(`-- Emit Error occured, when emitting file "${filePath}"`);
165 | }
166 | }
167 | }
168 |
169 | console.log(`\n\n-- EXPLAIN\n${s};`);
170 | const [_command, ..._command_args] = (shq
171 | .parse(plugin_config.command)
172 | .concat("EXPLAIN " + s) as any) as string[];
173 |
174 | if (existsInSqlCache(_command, _command_args)) {
175 | continue;
176 | }
177 |
178 | const p = await spawn(_command, _command_args).catch((e: Error & { stderr: string }) => e);
179 | const stdout = p.toString();
180 | if (p instanceof Error) {
181 | has_error = true;
182 | report(sourceFile, node, p.stderr);
183 | report_errors.push([sourceFile, node, p.stderr, 2]);
184 | break;
185 | }
186 |
187 | if (
188 | (plugin_config.error_cost || plugin_config.warn_cost || plugin_config.info_cost) &&
189 | !directives.some(d => d.directive === "ignore-cost")
190 | ) {
191 | const match = stdout.match(cost_pattern);
192 | if (match) {
193 | const [_, cost_str] = match;
194 | const cost = Number(cost_str);
195 | if (cost > plugin_config.error_cost!) {
196 | has_error = true;
197 | report(sourceFile, node, `Error: explain cost is too high: ${cost}\n${s}`, 2);
198 | report_errors.push([sourceFile, node, `Error: explain cost is too high: ${cost}\n${s}`, 2]);
199 | break;
200 | } else if (cost > plugin_config.warn_cost!) {
201 | report(sourceFile, node, `Warn: explain cost is at warning: ${cost}\n${s}`, 2);
202 | } else if (cost > plugin_config.info_cost!) {
203 | report(sourceFile, node, `Info: explain cost is ok: ${cost}\n${s}`, 1);
204 | }
205 | } else {
206 | has_error = true;
207 | report(
208 | sourceFile,
209 | node,
210 | `Error: can not extract cost with cost_pattern: ${cost_pattern.source}\n${stdout}\n${s}`,
211 | 2,
212 | );
213 | report_errors.push([
214 | sourceFile,
215 | node,
216 | `Error: can not extract cost with cost_pattern: ${cost_pattern.source}\n${stdout}\n${s}`,
217 | 2,
218 | ]);
219 | break;
220 | }
221 | }
222 |
223 | addToSqlCache(_command, _command_args);
224 | }
225 | }
226 | }
227 | })
228 | .parseAsync(process.argv);
229 |
--------------------------------------------------------------------------------
/docs/autocomplete.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xialvjun/ts-sql-plugin/34c9fed4d7e0b042f52148a0d906b3d2ec277e40/docs/autocomplete.gif
--------------------------------------------------------------------------------
/docs/readme_0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xialvjun/ts-sql-plugin/34c9fed4d7e0b042f52148a0d906b3d2ec277e40/docs/readme_0.gif
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import tss from "typescript/lib/tsserverlibrary";
2 | import { makeCreate } from './lib/create';
3 |
4 | export = (mod: { typescript: typeof tss }) => {
5 | const create = makeCreate(mod);
6 | return { create };
7 | };
8 |
--------------------------------------------------------------------------------
/lib/autocomplete.ts:
--------------------------------------------------------------------------------
1 | import { TemplateContext, TemplateLanguageService } from "typescript-template-language-service-decorator";
2 | import tss from "typescript/lib/tsserverlibrary";
3 | import { Index } from "lunr";
4 |
5 | import { SchemaInfo } from "./utils";
6 |
7 | export class SqlTemplateAutocomplete implements TemplateLanguageService {
8 | constructor(private db_info_search_index: Index, private db_info: SchemaInfo) {}
9 |
10 | getCompletionEntryDetails({}, {}, name: string): tss.CompletionEntryDetails {
11 | const documentation = this.db_info_search_index.search(name).map(({ ref }) => {
12 | const db_info_item = this.db_info[ref as any];
13 | return {
14 | kind: tss.ScriptElementKind.keyword,
15 | text: `
16 | schema: ${db_info_item.schema},
17 | table: ${db_info_item.table},
18 | column: ${db_info_item.column}
19 | `.replace(/ /gm, " "),
20 | };
21 | });
22 | return {
23 | name,
24 | displayParts: [],
25 | kind: tss.ScriptElementKind.keyword,
26 | kindModifiers: "ts-sql-plugin",
27 | documentation,
28 | };
29 | }
30 |
31 | getCompletionsAtPosition(context: TemplateContext, position: tss.LineAndCharacter): tss.CompletionInfo {
32 | const entries = new Map();
33 | const query = context.text
34 | .split(/\n/g)
35 | [position.line].slice(0, position.character)
36 | .match(/[\s\.]+([\w]*)$/)?.[1];
37 | if (query) {
38 | this.db_info_search_index.search(`*${query}*`).forEach(({ ref }) => {
39 | const db_info_item = this.db_info[ref as any];
40 | if (db_info_item.schema.match(query)) {
41 | entries.set(`schema|${db_info_item.schema}`, {
42 | name: db_info_item.schema,
43 | kind: tss.ScriptElementKind.keyword,
44 | sortText: `3 - ${db_info_item.schema}`,
45 | });
46 | }
47 | if (db_info_item.table.match(query)) {
48 | entries.set(`table|${db_info_item.table}`, {
49 | name: db_info_item.table,
50 | kind: tss.ScriptElementKind.string,
51 | sortText: `2 - ${db_info_item.table}`,
52 | });
53 | }
54 | if (db_info_item.column.match(query)) {
55 | entries.set(`column|${db_info_item.column}`, {
56 | name: db_info_item.column,
57 | kind: tss.ScriptElementKind.constElement,
58 | sortText: `1 - ${db_info_item.column}`,
59 | });
60 | }
61 | });
62 | }
63 | return {
64 | isGlobalCompletion: false,
65 | isMemberCompletion: false,
66 | isNewIdentifierLocation: false,
67 | entries: Array.from(entries.values()),
68 | };
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/cache.ts:
--------------------------------------------------------------------------------
1 | import crypto from 'crypto';
2 |
3 | const sqlCache = new Set();
4 |
5 | export const addToSqlCache = (command: string, command_args: string[]) => {
6 | return sqlCache.add(
7 | crypto.createHash('sha1').update(`${command}${command_args.join()}`).digest('hex')
8 | );
9 | };
10 |
11 | export const existsInSqlCache = (command: string, command_args: string[]) => {
12 | return sqlCache.has(
13 | crypto.createHash('sha1').update(`${command}${command_args.join()}`).digest('hex')
14 | );
15 | };
16 |
--------------------------------------------------------------------------------
/lib/create.ts:
--------------------------------------------------------------------------------
1 | import child_process from "child_process";
2 |
3 | import tss from "typescript/lib/tsserverlibrary";
4 | import { decorateWithTemplateLanguageService } from "typescript-template-language-service-decorator";
5 | import shq from "shell-quote";
6 | import lunr from "lunr";
7 |
8 | import { find_all_nodes, merge_defaults } from "./utils";
9 | import { make_fake_expression } from "./make_fake_expression";
10 | import { SqlTemplateAutocomplete } from "./autocomplete";
11 | import { parseDirectives } from "./directiveParser";
12 | import { addToSqlCache, existsInSqlCache } from './cache';
13 |
14 | export function makeCreate(mod: { typescript: typeof tss }) {
15 | return function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
16 | const logger = (msg: string) => info.project.projectService.logger.info(`[ts-sql-plugin] ${msg}`);
17 |
18 | const config = merge_defaults(info.config);
19 | const cost_pattern = new RegExp(config.cost_pattern!);
20 |
21 | const proxy = new Proxy(info.languageService, {
22 | get(target, p, receiver) {
23 | if (p === "getSemanticDiagnostics") {
24 | return function getSemanticDiagnostics(fileName: string): tss.Diagnostic[] {
25 | let origin_diagnostics = target.getSemanticDiagnostics(fileName);
26 |
27 | const program = info.languageService.getProgram()!;
28 | const fake_expression = make_fake_expression(program.getTypeChecker(), config.tags);
29 |
30 | const source_file = program.getSourceFile(fileName)!;
31 | const nodes: tss.TaggedTemplateExpression[] = find_all_nodes(
32 | source_file,
33 | n =>
34 | n.kind === tss.SyntaxKind.TaggedTemplateExpression &&
35 | (n as tss.TaggedTemplateExpression).tag.getText() === config.tags.sql,
36 | ) as any;
37 |
38 | const explain_rss = nodes.map(n => {
39 | const make_diagnostic = (code: any, category: any, messageText: any) =>
40 | ({
41 | file: source_file,
42 | start: n.getStart(),
43 | length: n.getEnd() - n.getStart(),
44 | source: "ts-sql-plugin",
45 | code,
46 | category,
47 | messageText,
48 | } as tss.Diagnostic);
49 | // one sql`select * from person ${xxx ? sql.raw`aaa` : sql.raw`bbb`}` may generate two sqls, need to be explained one by one
50 | let query_configs = fake_expression(n);
51 | for (const qc of query_configs) {
52 | let s: string = qc.text.replace(/\?\?/gm, config.mock);
53 | let resp = make_diagnostic(1, tss.DiagnosticCategory.Suggestion, s);
54 |
55 | // ! Never pass unsanitized user input to child_process.execSync.
56 | // let stdout = "";
57 | // try {
58 | // stdout = child_process.execSync(`${config.command} 'EXPLAIN ${s}'`, { encoding: 'utf8' });
59 | // } catch (error) {
60 | // return make_diagnostic(1, tss.DiagnosticCategory.Error, error.stderr + "\n" + s);
61 | // }
62 |
63 | const [_command, ..._command_args] = (shq
64 | .parse(config.command)
65 | .concat("EXPLAIN " + s) as any) as string[];
66 |
67 | if (existsInSqlCache(_command, _command_args)) {
68 | return resp;
69 | }
70 |
71 | const p = child_process.spawnSync(_command, _command_args, { encoding: "utf8" });
72 | if (p.status) {
73 | return make_diagnostic(1, tss.DiagnosticCategory.Error, p.stderr + "\n" + s);
74 | }
75 |
76 | const directives = parseDirectives(s);
77 |
78 | if (
79 | [config.error_cost, config.warn_cost, config.info_cost].some(it => it != void 0) &&
80 | !directives.some(x => x.directive === "ignore-cost")
81 | ) {
82 | const match = p.stdout.match(cost_pattern);
83 | if (match) {
84 | const [_, cost_str] = match;
85 | const cost = Number(cost_str);
86 | if (cost > config.error_cost!) {
87 | return make_diagnostic(
88 | 1,
89 | tss.DiagnosticCategory.Error,
90 | `explain cost is too high: ${cost}\n${s}`,
91 | );
92 | }
93 | if (cost > config.warn_cost!) {
94 | resp = make_diagnostic(
95 | 1,
96 | tss.DiagnosticCategory.Warning,
97 | `explain cost is at warning: ${cost}\n${s}`,
98 | );
99 | }
100 | if (cost > config.info_cost!) {
101 | resp = make_diagnostic(1, tss.DiagnosticCategory.Suggestion, `explain cost is ok: ${cost}\n${s}`);
102 | }
103 | } else {
104 | return make_diagnostic(
105 | 1,
106 | tss.DiagnosticCategory.Error,
107 | `can not extract cost with cost_pattern: ${cost_pattern.source}\n${p.stdout}\n${s}`,
108 | );
109 | }
110 | }
111 |
112 | addToSqlCache(_command, _command_args);
113 | return resp;
114 | }
115 | });
116 | return [...origin_diagnostics, ...(explain_rss.filter(v => !!v) as any[])];
117 | };
118 | }
119 | return (target as any)[p];
120 | },
121 | });
122 |
123 | if (!config.schema_command) {
124 | return proxy;
125 | }
126 |
127 | const [_schema_command, ..._schema_command_args] = (shq.parse(config.schema_command) as any) as string[];
128 | const schema_info_p = child_process.spawnSync(_schema_command, _schema_command_args, { encoding: "utf8" });
129 | if (schema_info_p.status) {
130 | throw Error(schema_info_p.stderr);
131 | }
132 | const schema_info = schema_info_p.stdout
133 | .split("\n")
134 | .map(it => it.match(/\w+/g))
135 | .filter(it => it?.length === 3)
136 | .map((raw, id) => {
137 | const [schema, table, column] = raw!;
138 | return { schema, table, column, id };
139 | });
140 |
141 | return decorateWithTemplateLanguageService(
142 | mod.typescript,
143 | proxy,
144 | info.project,
145 | new SqlTemplateAutocomplete(
146 | lunr(function () {
147 | this.ref("id");
148 | this.field("schema");
149 | this.field("table");
150 | this.field("column");
151 | schema_info.forEach(schema_info_item => this.add(schema_info_item));
152 | }),
153 | schema_info,
154 | // schema_info.reduce((acc, schema_info_item) => {
155 | // acc[schema_info_item.id] = schema_info_item;
156 | // return acc;
157 | // }, {} as any),
158 | ),
159 | { tags: [config.tags.sql, config.tags.raw], enableForStringWithSubstitutions: true },
160 | );
161 | };
162 | }
163 |
--------------------------------------------------------------------------------
/lib/directiveParser.ts:
--------------------------------------------------------------------------------
1 | export interface IDirective {
2 | directive: string;
3 | arg: any;
4 | }
5 |
6 | export const directiveRegex = new RegExp(
7 | /^\s*(--|\/\*)\s*ts-sql-plugin:(?[\w\d\-]+)(?:\((?.*)\))?\s*(\*\/)?\s*$/,
8 | );
9 |
10 | const takeUntil = (source: T[], predicate: (val: T) => boolean) => {
11 | const takeUntil = source.findIndex(predicate);
12 | return source.slice(0, takeUntil);
13 | };
14 |
15 | export const parseDirectives = (query: string): IDirective[] => {
16 | return takeUntil(query.split("\n"), line => !line.match(/^\s*(?:(--|\/\*).*)?$/)).reduce((accum, line) => {
17 | const match = line.trimLeft().match(directiveRegex);
18 | if (match) {
19 | const { directive, arg } = match.groups!;
20 | return [...accum, { directive, arg: arg && JSON.parse(arg) }];
21 | } else {
22 | return accum;
23 | }
24 | }, [] as IDirective[]);
25 | };
26 |
--------------------------------------------------------------------------------
/lib/make_fake_expression.ts:
--------------------------------------------------------------------------------
1 | import ts from 'typescript'; // used as value, passed in by tsserver at runtime
2 | // import tss from 'typescript/lib/tsserverlibrary'; // used as type only
3 | import { is_array, deep_flatten } from '@xialvjun/js-utils';
4 |
5 | import sql from '../sql';
6 | import { Tags } from './utils';
7 |
8 | export const make_fake_expression = (
9 | type_checker: ts.TypeChecker,
10 | tags: Tags,
11 | ) => {
12 | const fns = {
13 | [tags.and]: sql.and,
14 | [tags.or]: sql.or,
15 | [tags.ins]: sql.ins,
16 | [tags.upd]: sql.upd,
17 | [tags.mock]: sql.mock,
18 | };
19 | const tag_regex = new RegExp(
20 | '^' + tags.sql + '$|' + tags.raw + '$|' + tags.cond + '\\(',
21 | );
22 | return fake_expression;
23 |
24 | function fake_expression_from_tagged_template(n: ts.TaggedTemplateExpression) {
25 | const fn = sql.raw;
26 | if (n.template.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
27 | return [fn(([n.template.text] as unknown) as TemplateStringsArray)];
28 | }
29 | if (n.template.kind === ts.SyntaxKind.TemplateExpression) {
30 | const texts = ([
31 | n.template.head.text,
32 | ...n.template.templateSpans.map(span => span.literal.text),
33 | ] as unknown) as TemplateStringsArray;
34 | let values: any[][] = n.template.templateSpans
35 | .map(span => fake_expression(span.expression))
36 | .map(v => (is_array(v) ? deep_flatten(v) : [v]));
37 |
38 | // * 要想编译期校验 sql, 则 sql 模板字符串内的所有有 sql.symbol 的对象都需要直接在模板字符串内定义(其实 and,ins,upd 可以不用, 只要给它们分配泛型类型就足够, 但是 raw 必须如此,
39 | // * 而且就算匹配类型, 也得寻找类型原始出处, 也容易出错, 所以干脆统一要求在模板字符串内定义)...
40 | // * 然后要做分支 raw, 则需要每个分支单独 explain 校验(不然肯定出错, 例如 asc desc 同时出现)...
41 | // * 做分支检测最好是出现分支时, 把 texts,values 复制一份, 分支各自进行下去, 进行到最终点的时候, 自行检测, 不需要统一检测所有分支
42 | // var arr = [[1],[21,22,23], [31,32], [4]];
43 | // // debugger;
44 | // var rs = arr.reduce((acc, cv) => {
45 | // return cv.map(v => {
46 | // return acc.map(ac => {
47 | // return ac.concat(v);
48 | // })
49 | // }).reduce((acc, cv) => acc.concat(cv), []);
50 | // }, [[]]);
51 | // console.table(rs);
52 | // // rs should be [[1,21,31,4],[1,22,31,4],[1,23,31,4],[1,21,32,4],[1,22,32,4],[1,23,32,4]];
53 |
54 | let all_values = values.reduce(
55 | (acc, cv) => {
56 | return cv
57 | .map(v => acc.map(ac => ac.concat(v)))
58 | .reduce((acc, cv) => acc.concat(cv), []);
59 | },
60 | [[]],
61 | );
62 | return all_values.map(_values => sql.raw(texts, ..._values));
63 | }
64 | }
65 |
66 | function fake_expression_from_tagged_value_declaration(valueDeclaration: ts.Declaration) {
67 | const childCount = valueDeclaration.getChildCount();
68 | const template = valueDeclaration.getChildAt(childCount - 1);
69 | if (ts.isTaggedTemplateExpression(template) && tag_regex.test(template.tag.getText())) {
70 | return fake_expression_from_tagged_template(template);
71 | }
72 | }
73 |
74 | function fake_expression_from_function_value_declaration(valueDeclaration: ts.Declaration) {
75 | const fnBody = (
76 | (valueDeclaration).body ||
77 | (valueDeclaration).initializer && (valueDeclaration).initializer.body);
78 | const returnStatement = (fnBody && fnBody.statements || (>[])).find(s => ts.isReturnStatement(s));
79 | if (returnStatement) {
80 | const template = returnStatement.getChildren().find(c => ts.isTaggedTemplateExpression(c)) as ts.TaggedTemplateExpression;
81 | if (template && tag_regex.test(template.tag.getText())) {
82 | return fake_expression_from_tagged_template(template);
83 | }
84 | }
85 | }
86 |
87 | // ! fake raw``,and(),ins(),upd(),?: and other expression. sql`` is just a special kind of raw``.
88 | function fake_expression(n: ts.Expression): any {
89 | if (ts.isIdentifier(n)) {
90 | const symbol = type_checker.getSymbolAtLocation(n);
91 | if (symbol && symbol.valueDeclaration) {
92 | const fromDirectVariable = fake_expression_from_tagged_value_declaration(symbol.valueDeclaration);
93 | if (fromDirectVariable) {
94 | return fromDirectVariable;
95 | }
96 | }
97 | if (symbol && symbol.declarations && symbol.declarations.length && (ts).isAliasSymbolDeclaration(symbol.declarations[0])) {
98 | const aliasedSymbol = type_checker.getAliasedSymbol(symbol);
99 | if (aliasedSymbol.valueDeclaration) {
100 | return fake_expression_from_tagged_value_declaration(aliasedSymbol.valueDeclaration);
101 | }
102 | }
103 | }
104 | if (ts.isCallExpression(n)) {
105 | const fn = fns[(n.expression.getLastToken() || n.expression).getText()];
106 | if (!!fn) {
107 | if (fn == sql.mock) {
108 | if (n.typeArguments?.length !== 1) {
109 | return sql.raw`You must assign typeArgument to sql.mock`;
110 | }
111 | const t = type_checker.getTypeFromTypeNode(n.typeArguments[0]);
112 | const ts: ts.StringLiteralType[] = [];
113 | let has_error_type = false;
114 | const get_types = (t: ts.Type) => t.isStringLiteral() ? ts.push(t) : t.isUnion() ? t.types.forEach(get_types) : (has_error_type=true);
115 | get_types(t);
116 | if (has_error_type) {
117 | return sql.raw`The typeArgument of sql.mock must be String type`;
118 | }
119 | return ts.map(t => sql.raw([t.value] as any));
120 | }
121 | const t = type_checker.getTypeAtLocation(n.arguments[0]);
122 | let fake: any = null;
123 | if (fn == sql.and || fn == sql.upd || fn == sql.ins) {
124 | const ut = t.getNumberIndexType() as ts.UnionType;
125 | if (fn == sql.ins && !!ut) {
126 | if (!!ut.types) {
127 | fake = ut.types.map(t => object_type_to_fake(t));
128 | } else {
129 | fake = object_type_to_fake(ut);
130 | }
131 | } else {
132 | fake = object_type_to_fake(t);
133 | }
134 | }
135 | if (fn == sql.or) {
136 | const ut = t.getNumberIndexType() as ts.UnionType;
137 | if (!!ut.types) {
138 | fake = ut.types.map(t => object_type_to_fake(t));
139 | } else {
140 | fake = [object_type_to_fake(ut)];
141 | }
142 | }
143 | return (fn as any)(fake);
144 | }
145 | const symbol = type_checker.getSymbolAtLocation(n.expression);
146 | if (symbol && symbol.valueDeclaration) {
147 | const resp = fake_expression_from_function_value_declaration(symbol.valueDeclaration);
148 | if (resp) {
149 | return resp;
150 | }
151 | }
152 | if (symbol && symbol.declarations && symbol.declarations.length && (ts).isAliasSymbolDeclaration(symbol.declarations[0])) {
153 | const aliasedSymbol = type_checker.getAliasedSymbol(symbol);
154 | if (aliasedSymbol.valueDeclaration) {
155 | const resp = fake_expression_from_function_value_declaration(aliasedSymbol.valueDeclaration);
156 | if (resp) {
157 | return resp;
158 | }
159 | }
160 | }
161 | }
162 | if (ts.isTaggedTemplateExpression(n)) {
163 | // 因为又 sql.cond(boolean)`` 所以不能直接 n.tag.getText() === tags.xxx
164 | if (tag_regex.test(n.tag.getText())) {
165 | return fake_expression_from_tagged_template(n);
166 | }
167 | }
168 | if (ts.isConditionalExpression(n)) {
169 | return [fake_expression(n.whenTrue), fake_expression(n.whenFalse)];
170 | }
171 | return null;
172 | }
173 | };
174 |
175 | // function isTypeReference(type: ts.Type): type is ts.TypeReference {
176 | // return !!(
177 | // type.getFlags() & ts.TypeFlags.Object &&
178 | // (type as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference
179 | // );
180 | // }
181 |
182 | // function isArrayType(type: ts.Type): boolean {
183 | // return isTypeReference(type) && (
184 | // type.target.symbol.name === "Array" ||
185 | // type.target.symbol.name === "ReadonlyArray"
186 | // );
187 | // }
188 |
189 | const object_type_to_fake = (t: ts.Type) => {
190 | return t
191 | .getProperties()
192 | .reduce((acc, cv) => Object.assign(acc, { [cv.getName()]: null }), {});
193 | };
194 |
--------------------------------------------------------------------------------
/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import path from "path";
3 |
4 | import ts from "typescript";
5 | import { quote } from "shell-quote";
6 | import { merge } from "@xialvjun/js-utils";
7 |
8 | export const find_all_nodes = (sourceFile: ts.SourceFile, cond: (n: ts.Node) => boolean) => {
9 | const result: ts.Node[] = [];
10 | function find(node: ts.Node) {
11 | if (cond(node)) {
12 | result.push(node);
13 | return;
14 | } else {
15 | ts.forEachChild(node, find);
16 | }
17 | }
18 | find(sourceFile);
19 | return result;
20 | };
21 |
22 | export const get_all_ts_files = (dirpath: string) => {
23 | let ts_files: string[] = [];
24 | const paths = fs.readdirSync(dirpath).map(it => path.join(dirpath, it));
25 | const path_stats = paths.map(it => [it, fs.statSync(it)] as const);
26 | const exts = [".ts", ".tsx"];
27 | const ts_folders = path_stats.filter(
28 | ([p, s]) =>
29 | (s.isDirectory() && path.basename(p) !== "node_modules") || (s.isFile() && exts.indexOf(path.extname(p)) > -1),
30 | );
31 | ts_folders.forEach(([p, s]) => {
32 | if (s.isFile()) {
33 | ts_files.push(p);
34 | }
35 | });
36 | ts_folders.forEach(([p, s]) => {
37 | if (s.isDirectory()) {
38 | ts_files = ts_files.concat(get_all_ts_files(p));
39 | }
40 | });
41 | return ts_files;
42 | };
43 |
44 | // ! level 不用 3, console 也不用 error, 不然做 输出管道 就很麻烦
45 | export function report(sourceFile: ts.SourceFile, node: ts.Node, message: string, level: 1 | 2 = 1) {
46 | const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
47 | let str = `${sourceFile.fileName} (${line + 1},${character + 1}):\n${message}`
48 | .split("\n")
49 | .filter(v => v.trim())
50 | .map(it => "-- " + it)
51 | .join("\n");
52 | console[(["", "info", "warn", "error"] as const)[level]](str);
53 | }
54 |
55 | export interface Tags {
56 | // template string
57 | sql: string;
58 | raw: string;
59 | cond: string;
60 | // call expression
61 | and: string;
62 | or: string;
63 | ins: string;
64 | upd: string;
65 | mock: string;
66 | }
67 |
68 | export interface TsSqlPluginConfig {
69 | mock: string;
70 | error_cost?: number;
71 | warn_cost?: number;
72 | info_cost?: number;
73 | cost_pattern: string | null;
74 | tags: Tags;
75 | command: string;
76 | schema_command: string | null;
77 | }
78 |
79 | export const default_mock = "0";
80 | export const default_cost_pattern = /\(cost=\d+\.?\d*\.\.(\d+\.?\d*)/;
81 | export const default_tags: Tags = {
82 | sql: "sql",
83 | raw: "raw",
84 | cond: "cond",
85 | and: "and",
86 | or: "or",
87 | ins: "ins",
88 | upd: "upd",
89 | mock: "mock",
90 | };
91 | export const default_command = `psql -c`;
92 |
93 | export const merge_defaults = (...configs: TsSqlPluginConfig[]) => {
94 | const config: TsSqlPluginConfig = merge(
95 | {
96 | mock: default_mock,
97 | cost_pattern: default_cost_pattern.source,
98 | command: default_command,
99 | schema_command: "pg",
100 | tags: { ...default_tags },
101 | },
102 | ...configs,
103 | );
104 | config.cost_pattern = config.cost_pattern || default_cost_pattern.source;
105 | if (config.schema_command === "pg") {
106 | config.schema_command = `${config.command} ${quote([
107 | `copy (select table_schema, table_name, column_name from information_schema.columns WHERE table_schema=CURRENT_SCHEMA()) to stdout delimiter ','`,
108 | ])}`;
109 | }
110 | if (config.schema_command === "mysql") {
111 | config.schema_command = `${config.command} ${quote([
112 | `SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()`,
113 | ])}`;
114 | }
115 | return config;
116 | };
117 |
118 | export type SchemaInfo = {
119 | schema: string;
120 | table: string;
121 | column: string;
122 | id: number;
123 | }[];
124 |
125 | export const trim_middle_comments = (q: string) => {
126 | let isHeadComment = true;
127 | return q
128 | .trim()
129 | .split("\n")
130 | .filter(l =>
131 | l.trim().match(/^\-\-/) || l.trim().match(/^\/\*.*\*\/$/)
132 | ? isHeadComment
133 | ? true
134 | : false
135 | : ((isHeadComment = false), true),
136 | )
137 | .join("\n");
138 | };
139 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ts-sql-plugin",
3 | "version": "0.10.1",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "ts-sql-plugin",
9 | "version": "0.10.1",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@xialvjun/js-utils": "^0.3.7",
13 | "await-spawn": "4.0.2",
14 | "commander": "^5.0.0",
15 | "lodash.flattendeep": "4.4.0",
16 | "lunr": "^2.3.8",
17 | "shell-quote": "^1.7.2",
18 | "tslib": "^2.0.0",
19 | "typescript-template-language-service-decorator": "^2.2.0"
20 | },
21 | "bin": {
22 | "ts-sql-plugin": "cli.js"
23 | },
24 | "devDependencies": {
25 | "@types/chai": "^4.2.11",
26 | "@types/lodash.flattendeep": "4.4.6",
27 | "@types/lunr": "^2.3.3",
28 | "@types/mocha": "^7.0.2",
29 | "@types/node": "^12.12.41",
30 | "@types/shell-quote": "^1.7.0",
31 | "chai": "^4.2.0",
32 | "mocha": "^10.2.0",
33 | "ts-node": "^8.10.2",
34 | "typescript": "^4.0.2"
35 | },
36 | "peerDependencies": {
37 | "typescript": "^4.0.2"
38 | }
39 | },
40 | "node_modules/@types/chai": {
41 | "version": "4.2.11",
42 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz",
43 | "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==",
44 | "dev": true
45 | },
46 | "node_modules/@types/lodash": {
47 | "version": "4.14.168",
48 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz",
49 | "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==",
50 | "dev": true
51 | },
52 | "node_modules/@types/lodash.flattendeep": {
53 | "version": "4.4.6",
54 | "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.6.tgz",
55 | "integrity": "sha512-uLm2MaRVlqJSGsMK0RZpP5T3KqReq+9WbYDHCUhBhp98v56hMG/Yht52bsoTSui9xz2mUvQ9NfG3LrNGDL92Ng==",
56 | "dev": true,
57 | "dependencies": {
58 | "@types/lodash": "*"
59 | }
60 | },
61 | "node_modules/@types/lunr": {
62 | "version": "2.3.3",
63 | "resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.3.tgz",
64 | "integrity": "sha512-09sXZZVsB3Ib41U0fC+O1O+4UOZT1bl/e+/QubPxpqDWHNEchvx/DEb1KJMOwq6K3MTNzZFoNSzVdR++o1DVnw==",
65 | "dev": true
66 | },
67 | "node_modules/@types/mocha": {
68 | "version": "7.0.2",
69 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
70 | "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
71 | "dev": true
72 | },
73 | "node_modules/@types/node": {
74 | "version": "12.12.50",
75 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz",
76 | "integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==",
77 | "dev": true
78 | },
79 | "node_modules/@types/shell-quote": {
80 | "version": "1.7.0",
81 | "resolved": "https://registry.npmjs.org/@types/shell-quote/-/shell-quote-1.7.0.tgz",
82 | "integrity": "sha512-0CJaSSayMigMKu/Egx1eVcFjgGYkP6T4dyPRs462BFrMB/OK2FAJFV/24+6R4cGIXw6ZQpZK8XEd2UCVKfkZRw==",
83 | "dev": true
84 | },
85 | "node_modules/@xialvjun/js-utils": {
86 | "version": "0.3.7",
87 | "resolved": "https://registry.npmjs.org/@xialvjun/js-utils/-/js-utils-0.3.7.tgz",
88 | "integrity": "sha512-IUkqFT5x8m0PJOlv08Vm802EsrZDtEoZVKYk8q4NDfeUMhCU7TRhHKrETygEFenCefVPyVq11SKGYO4oDPCuUA=="
89 | },
90 | "node_modules/ansi-colors": {
91 | "version": "4.1.1",
92 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
93 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
94 | "dev": true,
95 | "engines": {
96 | "node": ">=6"
97 | }
98 | },
99 | "node_modules/ansi-regex": {
100 | "version": "5.0.1",
101 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
102 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
103 | "dev": true,
104 | "engines": {
105 | "node": ">=8"
106 | }
107 | },
108 | "node_modules/ansi-styles": {
109 | "version": "4.3.0",
110 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
111 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
112 | "dev": true,
113 | "dependencies": {
114 | "color-convert": "^2.0.1"
115 | },
116 | "engines": {
117 | "node": ">=8"
118 | },
119 | "funding": {
120 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
121 | }
122 | },
123 | "node_modules/anymatch": {
124 | "version": "3.1.3",
125 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
126 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
127 | "dev": true,
128 | "dependencies": {
129 | "normalize-path": "^3.0.0",
130 | "picomatch": "^2.0.4"
131 | },
132 | "engines": {
133 | "node": ">= 8"
134 | }
135 | },
136 | "node_modules/arg": {
137 | "version": "4.1.3",
138 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
139 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
140 | "dev": true
141 | },
142 | "node_modules/argparse": {
143 | "version": "2.0.1",
144 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
145 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
146 | "dev": true
147 | },
148 | "node_modules/assertion-error": {
149 | "version": "1.1.0",
150 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
151 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
152 | "dev": true,
153 | "engines": {
154 | "node": "*"
155 | }
156 | },
157 | "node_modules/await-spawn": {
158 | "version": "4.0.2",
159 | "resolved": "https://registry.npmjs.org/await-spawn/-/await-spawn-4.0.2.tgz",
160 | "integrity": "sha512-GdADmeLJiMvGKJD3xWBcX40DMn07JNH1sqJYgYJZH7NTGJ3B1qDjKBKzxhhyR1hjIcnUGFUmE/+4D1HcHAJBAA==",
161 | "license": "MIT",
162 | "dependencies": {
163 | "bl": "^4.0.3"
164 | },
165 | "engines": {
166 | "node": ">=10"
167 | }
168 | },
169 | "node_modules/balanced-match": {
170 | "version": "1.0.2",
171 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
172 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
173 | "dev": true
174 | },
175 | "node_modules/base64-js": {
176 | "version": "1.5.1",
177 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
178 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
179 | "funding": [
180 | {
181 | "type": "github",
182 | "url": "https://github.com/sponsors/feross"
183 | },
184 | {
185 | "type": "patreon",
186 | "url": "https://www.patreon.com/feross"
187 | },
188 | {
189 | "type": "consulting",
190 | "url": "https://feross.org/support"
191 | }
192 | ]
193 | },
194 | "node_modules/binary-extensions": {
195 | "version": "2.2.0",
196 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
197 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
198 | "dev": true,
199 | "engines": {
200 | "node": ">=8"
201 | }
202 | },
203 | "node_modules/bl": {
204 | "version": "4.1.0",
205 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
206 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
207 | "dependencies": {
208 | "buffer": "^5.5.0",
209 | "inherits": "^2.0.4",
210 | "readable-stream": "^3.4.0"
211 | }
212 | },
213 | "node_modules/brace-expansion": {
214 | "version": "2.0.1",
215 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
216 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
217 | "dev": true,
218 | "dependencies": {
219 | "balanced-match": "^1.0.0"
220 | }
221 | },
222 | "node_modules/braces": {
223 | "version": "3.0.3",
224 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
225 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
226 | "dev": true,
227 | "dependencies": {
228 | "fill-range": "^7.1.1"
229 | },
230 | "engines": {
231 | "node": ">=8"
232 | }
233 | },
234 | "node_modules/browser-stdout": {
235 | "version": "1.3.1",
236 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
237 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
238 | "dev": true
239 | },
240 | "node_modules/buffer": {
241 | "version": "5.7.1",
242 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
243 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
244 | "funding": [
245 | {
246 | "type": "github",
247 | "url": "https://github.com/sponsors/feross"
248 | },
249 | {
250 | "type": "patreon",
251 | "url": "https://www.patreon.com/feross"
252 | },
253 | {
254 | "type": "consulting",
255 | "url": "https://feross.org/support"
256 | }
257 | ],
258 | "dependencies": {
259 | "base64-js": "^1.3.1",
260 | "ieee754": "^1.1.13"
261 | }
262 | },
263 | "node_modules/buffer-from": {
264 | "version": "1.1.1",
265 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
266 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
267 | "dev": true
268 | },
269 | "node_modules/camelcase": {
270 | "version": "6.3.0",
271 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
272 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
273 | "dev": true,
274 | "engines": {
275 | "node": ">=10"
276 | },
277 | "funding": {
278 | "url": "https://github.com/sponsors/sindresorhus"
279 | }
280 | },
281 | "node_modules/chai": {
282 | "version": "4.2.0",
283 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
284 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
285 | "dev": true,
286 | "dependencies": {
287 | "assertion-error": "^1.1.0",
288 | "check-error": "^1.0.2",
289 | "deep-eql": "^3.0.1",
290 | "get-func-name": "^2.0.0",
291 | "pathval": "^1.1.0",
292 | "type-detect": "^4.0.5"
293 | },
294 | "engines": {
295 | "node": ">=4"
296 | }
297 | },
298 | "node_modules/chalk": {
299 | "version": "4.1.2",
300 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
301 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
302 | "dev": true,
303 | "dependencies": {
304 | "ansi-styles": "^4.1.0",
305 | "supports-color": "^7.1.0"
306 | },
307 | "engines": {
308 | "node": ">=10"
309 | },
310 | "funding": {
311 | "url": "https://github.com/chalk/chalk?sponsor=1"
312 | }
313 | },
314 | "node_modules/chalk/node_modules/supports-color": {
315 | "version": "7.2.0",
316 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
317 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
318 | "dev": true,
319 | "dependencies": {
320 | "has-flag": "^4.0.0"
321 | },
322 | "engines": {
323 | "node": ">=8"
324 | }
325 | },
326 | "node_modules/check-error": {
327 | "version": "1.0.2",
328 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
329 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
330 | "dev": true,
331 | "engines": {
332 | "node": "*"
333 | }
334 | },
335 | "node_modules/chokidar": {
336 | "version": "3.5.3",
337 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
338 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
339 | "dev": true,
340 | "funding": [
341 | {
342 | "type": "individual",
343 | "url": "https://paulmillr.com/funding/"
344 | }
345 | ],
346 | "dependencies": {
347 | "anymatch": "~3.1.2",
348 | "braces": "~3.0.2",
349 | "glob-parent": "~5.1.2",
350 | "is-binary-path": "~2.1.0",
351 | "is-glob": "~4.0.1",
352 | "normalize-path": "~3.0.0",
353 | "readdirp": "~3.6.0"
354 | },
355 | "engines": {
356 | "node": ">= 8.10.0"
357 | },
358 | "optionalDependencies": {
359 | "fsevents": "~2.3.2"
360 | }
361 | },
362 | "node_modules/cliui": {
363 | "version": "7.0.4",
364 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
365 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
366 | "dev": true,
367 | "dependencies": {
368 | "string-width": "^4.2.0",
369 | "strip-ansi": "^6.0.0",
370 | "wrap-ansi": "^7.0.0"
371 | }
372 | },
373 | "node_modules/color-convert": {
374 | "version": "2.0.1",
375 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
376 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
377 | "dev": true,
378 | "dependencies": {
379 | "color-name": "~1.1.4"
380 | },
381 | "engines": {
382 | "node": ">=7.0.0"
383 | }
384 | },
385 | "node_modules/color-name": {
386 | "version": "1.1.4",
387 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
388 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
389 | "dev": true
390 | },
391 | "node_modules/commander": {
392 | "version": "5.1.0",
393 | "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
394 | "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
395 | "engines": {
396 | "node": ">= 6"
397 | }
398 | },
399 | "node_modules/concat-map": {
400 | "version": "0.0.1",
401 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
402 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
403 | "dev": true
404 | },
405 | "node_modules/debug": {
406 | "version": "4.3.4",
407 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
408 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
409 | "dev": true,
410 | "dependencies": {
411 | "ms": "2.1.2"
412 | },
413 | "engines": {
414 | "node": ">=6.0"
415 | },
416 | "peerDependenciesMeta": {
417 | "supports-color": {
418 | "optional": true
419 | }
420 | }
421 | },
422 | "node_modules/debug/node_modules/ms": {
423 | "version": "2.1.2",
424 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
425 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
426 | "dev": true
427 | },
428 | "node_modules/decamelize": {
429 | "version": "4.0.0",
430 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
431 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
432 | "dev": true,
433 | "engines": {
434 | "node": ">=10"
435 | },
436 | "funding": {
437 | "url": "https://github.com/sponsors/sindresorhus"
438 | }
439 | },
440 | "node_modules/deep-eql": {
441 | "version": "3.0.1",
442 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
443 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
444 | "dev": true,
445 | "dependencies": {
446 | "type-detect": "^4.0.0"
447 | },
448 | "engines": {
449 | "node": ">=0.12"
450 | }
451 | },
452 | "node_modules/diff": {
453 | "version": "5.0.0",
454 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
455 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
456 | "dev": true,
457 | "engines": {
458 | "node": ">=0.3.1"
459 | }
460 | },
461 | "node_modules/emoji-regex": {
462 | "version": "8.0.0",
463 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
464 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
465 | "dev": true
466 | },
467 | "node_modules/escalade": {
468 | "version": "3.1.1",
469 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
470 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
471 | "dev": true,
472 | "engines": {
473 | "node": ">=6"
474 | }
475 | },
476 | "node_modules/escape-string-regexp": {
477 | "version": "4.0.0",
478 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
479 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
480 | "dev": true,
481 | "engines": {
482 | "node": ">=10"
483 | },
484 | "funding": {
485 | "url": "https://github.com/sponsors/sindresorhus"
486 | }
487 | },
488 | "node_modules/fill-range": {
489 | "version": "7.1.1",
490 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
491 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
492 | "dev": true,
493 | "dependencies": {
494 | "to-regex-range": "^5.0.1"
495 | },
496 | "engines": {
497 | "node": ">=8"
498 | }
499 | },
500 | "node_modules/find-up": {
501 | "version": "5.0.0",
502 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
503 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
504 | "dev": true,
505 | "dependencies": {
506 | "locate-path": "^6.0.0",
507 | "path-exists": "^4.0.0"
508 | },
509 | "engines": {
510 | "node": ">=10"
511 | },
512 | "funding": {
513 | "url": "https://github.com/sponsors/sindresorhus"
514 | }
515 | },
516 | "node_modules/flat": {
517 | "version": "5.0.2",
518 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
519 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
520 | "dev": true,
521 | "bin": {
522 | "flat": "cli.js"
523 | }
524 | },
525 | "node_modules/fs.realpath": {
526 | "version": "1.0.0",
527 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
528 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
529 | "dev": true
530 | },
531 | "node_modules/fsevents": {
532 | "version": "2.3.2",
533 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
534 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
535 | "dev": true,
536 | "hasInstallScript": true,
537 | "optional": true,
538 | "os": [
539 | "darwin"
540 | ],
541 | "engines": {
542 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
543 | }
544 | },
545 | "node_modules/get-caller-file": {
546 | "version": "2.0.5",
547 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
548 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
549 | "dev": true,
550 | "engines": {
551 | "node": "6.* || 8.* || >= 10.*"
552 | }
553 | },
554 | "node_modules/get-func-name": {
555 | "version": "2.0.0",
556 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
557 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
558 | "dev": true,
559 | "engines": {
560 | "node": "*"
561 | }
562 | },
563 | "node_modules/glob": {
564 | "version": "7.2.0",
565 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
566 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
567 | "dev": true,
568 | "dependencies": {
569 | "fs.realpath": "^1.0.0",
570 | "inflight": "^1.0.4",
571 | "inherits": "2",
572 | "minimatch": "^3.0.4",
573 | "once": "^1.3.0",
574 | "path-is-absolute": "^1.0.0"
575 | },
576 | "engines": {
577 | "node": "*"
578 | },
579 | "funding": {
580 | "url": "https://github.com/sponsors/isaacs"
581 | }
582 | },
583 | "node_modules/glob-parent": {
584 | "version": "5.1.2",
585 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
586 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
587 | "dev": true,
588 | "dependencies": {
589 | "is-glob": "^4.0.1"
590 | },
591 | "engines": {
592 | "node": ">= 6"
593 | }
594 | },
595 | "node_modules/glob/node_modules/brace-expansion": {
596 | "version": "1.1.11",
597 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
598 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
599 | "dev": true,
600 | "dependencies": {
601 | "balanced-match": "^1.0.0",
602 | "concat-map": "0.0.1"
603 | }
604 | },
605 | "node_modules/glob/node_modules/minimatch": {
606 | "version": "3.1.2",
607 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
608 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
609 | "dev": true,
610 | "dependencies": {
611 | "brace-expansion": "^1.1.7"
612 | },
613 | "engines": {
614 | "node": "*"
615 | }
616 | },
617 | "node_modules/has-flag": {
618 | "version": "4.0.0",
619 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
620 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
621 | "dev": true,
622 | "engines": {
623 | "node": ">=8"
624 | }
625 | },
626 | "node_modules/he": {
627 | "version": "1.2.0",
628 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
629 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
630 | "dev": true,
631 | "bin": {
632 | "he": "bin/he"
633 | }
634 | },
635 | "node_modules/ieee754": {
636 | "version": "1.2.1",
637 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
638 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
639 | "funding": [
640 | {
641 | "type": "github",
642 | "url": "https://github.com/sponsors/feross"
643 | },
644 | {
645 | "type": "patreon",
646 | "url": "https://www.patreon.com/feross"
647 | },
648 | {
649 | "type": "consulting",
650 | "url": "https://feross.org/support"
651 | }
652 | ]
653 | },
654 | "node_modules/inflight": {
655 | "version": "1.0.6",
656 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
657 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
658 | "dev": true,
659 | "dependencies": {
660 | "once": "^1.3.0",
661 | "wrappy": "1"
662 | }
663 | },
664 | "node_modules/inherits": {
665 | "version": "2.0.4",
666 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
667 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
668 | },
669 | "node_modules/is-binary-path": {
670 | "version": "2.1.0",
671 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
672 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
673 | "dev": true,
674 | "dependencies": {
675 | "binary-extensions": "^2.0.0"
676 | },
677 | "engines": {
678 | "node": ">=8"
679 | }
680 | },
681 | "node_modules/is-extglob": {
682 | "version": "2.1.1",
683 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
684 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
685 | "dev": true,
686 | "engines": {
687 | "node": ">=0.10.0"
688 | }
689 | },
690 | "node_modules/is-fullwidth-code-point": {
691 | "version": "3.0.0",
692 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
693 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
694 | "dev": true,
695 | "engines": {
696 | "node": ">=8"
697 | }
698 | },
699 | "node_modules/is-glob": {
700 | "version": "4.0.3",
701 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
702 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
703 | "dev": true,
704 | "dependencies": {
705 | "is-extglob": "^2.1.1"
706 | },
707 | "engines": {
708 | "node": ">=0.10.0"
709 | }
710 | },
711 | "node_modules/is-number": {
712 | "version": "7.0.0",
713 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
714 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
715 | "dev": true,
716 | "engines": {
717 | "node": ">=0.12.0"
718 | }
719 | },
720 | "node_modules/is-plain-obj": {
721 | "version": "2.1.0",
722 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
723 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
724 | "dev": true,
725 | "engines": {
726 | "node": ">=8"
727 | }
728 | },
729 | "node_modules/is-unicode-supported": {
730 | "version": "0.1.0",
731 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
732 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
733 | "dev": true,
734 | "engines": {
735 | "node": ">=10"
736 | },
737 | "funding": {
738 | "url": "https://github.com/sponsors/sindresorhus"
739 | }
740 | },
741 | "node_modules/js-yaml": {
742 | "version": "4.1.0",
743 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
744 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
745 | "dev": true,
746 | "dependencies": {
747 | "argparse": "^2.0.1"
748 | },
749 | "bin": {
750 | "js-yaml": "bin/js-yaml.js"
751 | }
752 | },
753 | "node_modules/locate-path": {
754 | "version": "6.0.0",
755 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
756 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
757 | "dev": true,
758 | "dependencies": {
759 | "p-locate": "^5.0.0"
760 | },
761 | "engines": {
762 | "node": ">=10"
763 | },
764 | "funding": {
765 | "url": "https://github.com/sponsors/sindresorhus"
766 | }
767 | },
768 | "node_modules/lodash.flattendeep": {
769 | "version": "4.4.0",
770 | "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
771 | "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI="
772 | },
773 | "node_modules/log-symbols": {
774 | "version": "4.1.0",
775 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
776 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
777 | "dev": true,
778 | "dependencies": {
779 | "chalk": "^4.1.0",
780 | "is-unicode-supported": "^0.1.0"
781 | },
782 | "engines": {
783 | "node": ">=10"
784 | },
785 | "funding": {
786 | "url": "https://github.com/sponsors/sindresorhus"
787 | }
788 | },
789 | "node_modules/lunr": {
790 | "version": "2.3.8",
791 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz",
792 | "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg=="
793 | },
794 | "node_modules/make-error": {
795 | "version": "1.3.6",
796 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
797 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
798 | "dev": true
799 | },
800 | "node_modules/minimatch": {
801 | "version": "5.0.1",
802 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
803 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
804 | "dev": true,
805 | "dependencies": {
806 | "brace-expansion": "^2.0.1"
807 | },
808 | "engines": {
809 | "node": ">=10"
810 | }
811 | },
812 | "node_modules/mocha": {
813 | "version": "10.2.0",
814 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
815 | "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
816 | "dev": true,
817 | "dependencies": {
818 | "ansi-colors": "4.1.1",
819 | "browser-stdout": "1.3.1",
820 | "chokidar": "3.5.3",
821 | "debug": "4.3.4",
822 | "diff": "5.0.0",
823 | "escape-string-regexp": "4.0.0",
824 | "find-up": "5.0.0",
825 | "glob": "7.2.0",
826 | "he": "1.2.0",
827 | "js-yaml": "4.1.0",
828 | "log-symbols": "4.1.0",
829 | "minimatch": "5.0.1",
830 | "ms": "2.1.3",
831 | "nanoid": "3.3.3",
832 | "serialize-javascript": "6.0.0",
833 | "strip-json-comments": "3.1.1",
834 | "supports-color": "8.1.1",
835 | "workerpool": "6.2.1",
836 | "yargs": "16.2.0",
837 | "yargs-parser": "20.2.4",
838 | "yargs-unparser": "2.0.0"
839 | },
840 | "bin": {
841 | "_mocha": "bin/_mocha",
842 | "mocha": "bin/mocha.js"
843 | },
844 | "engines": {
845 | "node": ">= 14.0.0"
846 | },
847 | "funding": {
848 | "type": "opencollective",
849 | "url": "https://opencollective.com/mochajs"
850 | }
851 | },
852 | "node_modules/ms": {
853 | "version": "2.1.3",
854 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
855 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
856 | "dev": true
857 | },
858 | "node_modules/nanoid": {
859 | "version": "3.3.3",
860 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
861 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
862 | "dev": true,
863 | "bin": {
864 | "nanoid": "bin/nanoid.cjs"
865 | },
866 | "engines": {
867 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
868 | }
869 | },
870 | "node_modules/normalize-path": {
871 | "version": "3.0.0",
872 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
873 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
874 | "dev": true,
875 | "engines": {
876 | "node": ">=0.10.0"
877 | }
878 | },
879 | "node_modules/once": {
880 | "version": "1.4.0",
881 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
882 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
883 | "dev": true,
884 | "dependencies": {
885 | "wrappy": "1"
886 | }
887 | },
888 | "node_modules/p-limit": {
889 | "version": "3.1.0",
890 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
891 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
892 | "dev": true,
893 | "dependencies": {
894 | "yocto-queue": "^0.1.0"
895 | },
896 | "engines": {
897 | "node": ">=10"
898 | },
899 | "funding": {
900 | "url": "https://github.com/sponsors/sindresorhus"
901 | }
902 | },
903 | "node_modules/p-locate": {
904 | "version": "5.0.0",
905 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
906 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
907 | "dev": true,
908 | "dependencies": {
909 | "p-limit": "^3.0.2"
910 | },
911 | "engines": {
912 | "node": ">=10"
913 | },
914 | "funding": {
915 | "url": "https://github.com/sponsors/sindresorhus"
916 | }
917 | },
918 | "node_modules/path-exists": {
919 | "version": "4.0.0",
920 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
921 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
922 | "dev": true,
923 | "engines": {
924 | "node": ">=8"
925 | }
926 | },
927 | "node_modules/path-is-absolute": {
928 | "version": "1.0.1",
929 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
930 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
931 | "dev": true,
932 | "engines": {
933 | "node": ">=0.10.0"
934 | }
935 | },
936 | "node_modules/pathval": {
937 | "version": "1.1.1",
938 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
939 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
940 | "dev": true,
941 | "engines": {
942 | "node": "*"
943 | }
944 | },
945 | "node_modules/picomatch": {
946 | "version": "2.3.1",
947 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
948 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
949 | "dev": true,
950 | "engines": {
951 | "node": ">=8.6"
952 | },
953 | "funding": {
954 | "url": "https://github.com/sponsors/jonschlinkert"
955 | }
956 | },
957 | "node_modules/randombytes": {
958 | "version": "2.1.0",
959 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
960 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
961 | "dev": true,
962 | "dependencies": {
963 | "safe-buffer": "^5.1.0"
964 | }
965 | },
966 | "node_modules/readable-stream": {
967 | "version": "3.6.0",
968 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
969 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
970 | "dependencies": {
971 | "inherits": "^2.0.3",
972 | "string_decoder": "^1.1.1",
973 | "util-deprecate": "^1.0.1"
974 | },
975 | "engines": {
976 | "node": ">= 6"
977 | }
978 | },
979 | "node_modules/readdirp": {
980 | "version": "3.6.0",
981 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
982 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
983 | "dev": true,
984 | "dependencies": {
985 | "picomatch": "^2.2.1"
986 | },
987 | "engines": {
988 | "node": ">=8.10.0"
989 | }
990 | },
991 | "node_modules/require-directory": {
992 | "version": "2.1.1",
993 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
994 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
995 | "dev": true,
996 | "engines": {
997 | "node": ">=0.10.0"
998 | }
999 | },
1000 | "node_modules/safe-buffer": {
1001 | "version": "5.2.1",
1002 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1003 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1004 | "funding": [
1005 | {
1006 | "type": "github",
1007 | "url": "https://github.com/sponsors/feross"
1008 | },
1009 | {
1010 | "type": "patreon",
1011 | "url": "https://www.patreon.com/feross"
1012 | },
1013 | {
1014 | "type": "consulting",
1015 | "url": "https://feross.org/support"
1016 | }
1017 | ]
1018 | },
1019 | "node_modules/serialize-javascript": {
1020 | "version": "6.0.0",
1021 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
1022 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
1023 | "dev": true,
1024 | "dependencies": {
1025 | "randombytes": "^2.1.0"
1026 | }
1027 | },
1028 | "node_modules/shell-quote": {
1029 | "version": "1.7.3",
1030 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
1031 | "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="
1032 | },
1033 | "node_modules/source-map": {
1034 | "version": "0.6.1",
1035 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1036 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1037 | "dev": true,
1038 | "engines": {
1039 | "node": ">=0.10.0"
1040 | }
1041 | },
1042 | "node_modules/source-map-support": {
1043 | "version": "0.5.19",
1044 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
1045 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
1046 | "dev": true,
1047 | "dependencies": {
1048 | "buffer-from": "^1.0.0",
1049 | "source-map": "^0.6.0"
1050 | }
1051 | },
1052 | "node_modules/string_decoder": {
1053 | "version": "1.3.0",
1054 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
1055 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
1056 | "dependencies": {
1057 | "safe-buffer": "~5.2.0"
1058 | }
1059 | },
1060 | "node_modules/string-width": {
1061 | "version": "4.2.3",
1062 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1063 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1064 | "dev": true,
1065 | "dependencies": {
1066 | "emoji-regex": "^8.0.0",
1067 | "is-fullwidth-code-point": "^3.0.0",
1068 | "strip-ansi": "^6.0.1"
1069 | },
1070 | "engines": {
1071 | "node": ">=8"
1072 | }
1073 | },
1074 | "node_modules/strip-ansi": {
1075 | "version": "6.0.1",
1076 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1077 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1078 | "dev": true,
1079 | "dependencies": {
1080 | "ansi-regex": "^5.0.1"
1081 | },
1082 | "engines": {
1083 | "node": ">=8"
1084 | }
1085 | },
1086 | "node_modules/strip-json-comments": {
1087 | "version": "3.1.1",
1088 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
1089 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
1090 | "dev": true,
1091 | "engines": {
1092 | "node": ">=8"
1093 | },
1094 | "funding": {
1095 | "url": "https://github.com/sponsors/sindresorhus"
1096 | }
1097 | },
1098 | "node_modules/supports-color": {
1099 | "version": "8.1.1",
1100 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
1101 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
1102 | "dev": true,
1103 | "dependencies": {
1104 | "has-flag": "^4.0.0"
1105 | },
1106 | "engines": {
1107 | "node": ">=10"
1108 | },
1109 | "funding": {
1110 | "url": "https://github.com/chalk/supports-color?sponsor=1"
1111 | }
1112 | },
1113 | "node_modules/to-regex-range": {
1114 | "version": "5.0.1",
1115 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1116 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1117 | "dev": true,
1118 | "dependencies": {
1119 | "is-number": "^7.0.0"
1120 | },
1121 | "engines": {
1122 | "node": ">=8.0"
1123 | }
1124 | },
1125 | "node_modules/ts-node": {
1126 | "version": "8.10.2",
1127 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
1128 | "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==",
1129 | "dev": true,
1130 | "dependencies": {
1131 | "arg": "^4.1.0",
1132 | "diff": "^4.0.1",
1133 | "make-error": "^1.1.1",
1134 | "source-map-support": "^0.5.17",
1135 | "yn": "3.1.1"
1136 | },
1137 | "bin": {
1138 | "ts-node": "dist/bin.js",
1139 | "ts-node-script": "dist/bin-script.js",
1140 | "ts-node-transpile-only": "dist/bin-transpile.js",
1141 | "ts-script": "dist/bin-script-deprecated.js"
1142 | },
1143 | "engines": {
1144 | "node": ">=6.0.0"
1145 | }
1146 | },
1147 | "node_modules/ts-node/node_modules/diff": {
1148 | "version": "4.0.2",
1149 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
1150 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
1151 | "dev": true,
1152 | "engines": {
1153 | "node": ">=0.3.1"
1154 | }
1155 | },
1156 | "node_modules/tslib": {
1157 | "version": "2.0.0",
1158 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz",
1159 | "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g=="
1160 | },
1161 | "node_modules/type-detect": {
1162 | "version": "4.0.8",
1163 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
1164 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
1165 | "dev": true,
1166 | "engines": {
1167 | "node": ">=4"
1168 | }
1169 | },
1170 | "node_modules/typescript": {
1171 | "version": "4.0.2",
1172 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
1173 | "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
1174 | "dev": true,
1175 | "bin": {
1176 | "tsc": "bin/tsc",
1177 | "tsserver": "bin/tsserver"
1178 | },
1179 | "engines": {
1180 | "node": ">=4.2.0"
1181 | }
1182 | },
1183 | "node_modules/typescript-template-language-service-decorator": {
1184 | "version": "2.2.0",
1185 | "resolved": "https://registry.npmjs.org/typescript-template-language-service-decorator/-/typescript-template-language-service-decorator-2.2.0.tgz",
1186 | "integrity": "sha512-xiolqt1i7e22rpqMaprPgSFVgU64u3b9n6EJlAaUYE61jumipKAdI1+O5khPlWslpTUj80YzjUKjJ2jxT0D74w=="
1187 | },
1188 | "node_modules/util-deprecate": {
1189 | "version": "1.0.2",
1190 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1191 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
1192 | },
1193 | "node_modules/workerpool": {
1194 | "version": "6.2.1",
1195 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
1196 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
1197 | "dev": true
1198 | },
1199 | "node_modules/wrap-ansi": {
1200 | "version": "7.0.0",
1201 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
1202 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
1203 | "dev": true,
1204 | "dependencies": {
1205 | "ansi-styles": "^4.0.0",
1206 | "string-width": "^4.1.0",
1207 | "strip-ansi": "^6.0.0"
1208 | },
1209 | "engines": {
1210 | "node": ">=10"
1211 | },
1212 | "funding": {
1213 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
1214 | }
1215 | },
1216 | "node_modules/wrappy": {
1217 | "version": "1.0.2",
1218 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1219 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1220 | "dev": true
1221 | },
1222 | "node_modules/y18n": {
1223 | "version": "5.0.8",
1224 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1225 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1226 | "dev": true,
1227 | "engines": {
1228 | "node": ">=10"
1229 | }
1230 | },
1231 | "node_modules/yargs": {
1232 | "version": "16.2.0",
1233 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
1234 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
1235 | "dev": true,
1236 | "dependencies": {
1237 | "cliui": "^7.0.2",
1238 | "escalade": "^3.1.1",
1239 | "get-caller-file": "^2.0.5",
1240 | "require-directory": "^2.1.1",
1241 | "string-width": "^4.2.0",
1242 | "y18n": "^5.0.5",
1243 | "yargs-parser": "^20.2.2"
1244 | },
1245 | "engines": {
1246 | "node": ">=10"
1247 | }
1248 | },
1249 | "node_modules/yargs-parser": {
1250 | "version": "20.2.4",
1251 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
1252 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
1253 | "dev": true,
1254 | "engines": {
1255 | "node": ">=10"
1256 | }
1257 | },
1258 | "node_modules/yargs-unparser": {
1259 | "version": "2.0.0",
1260 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
1261 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
1262 | "dev": true,
1263 | "dependencies": {
1264 | "camelcase": "^6.0.0",
1265 | "decamelize": "^4.0.0",
1266 | "flat": "^5.0.2",
1267 | "is-plain-obj": "^2.1.0"
1268 | },
1269 | "engines": {
1270 | "node": ">=10"
1271 | }
1272 | },
1273 | "node_modules/yn": {
1274 | "version": "3.1.1",
1275 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
1276 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
1277 | "dev": true,
1278 | "engines": {
1279 | "node": ">=6"
1280 | }
1281 | },
1282 | "node_modules/yocto-queue": {
1283 | "version": "0.1.0",
1284 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
1285 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
1286 | "dev": true,
1287 | "engines": {
1288 | "node": ">=10"
1289 | },
1290 | "funding": {
1291 | "url": "https://github.com/sponsors/sindresorhus"
1292 | }
1293 | }
1294 | },
1295 | "dependencies": {
1296 | "@types/chai": {
1297 | "version": "4.2.11",
1298 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz",
1299 | "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==",
1300 | "dev": true
1301 | },
1302 | "@types/lodash": {
1303 | "version": "4.14.168",
1304 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz",
1305 | "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==",
1306 | "dev": true
1307 | },
1308 | "@types/lodash.flattendeep": {
1309 | "version": "4.4.6",
1310 | "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.6.tgz",
1311 | "integrity": "sha512-uLm2MaRVlqJSGsMK0RZpP5T3KqReq+9WbYDHCUhBhp98v56hMG/Yht52bsoTSui9xz2mUvQ9NfG3LrNGDL92Ng==",
1312 | "dev": true,
1313 | "requires": {
1314 | "@types/lodash": "*"
1315 | }
1316 | },
1317 | "@types/lunr": {
1318 | "version": "2.3.3",
1319 | "resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.3.tgz",
1320 | "integrity": "sha512-09sXZZVsB3Ib41U0fC+O1O+4UOZT1bl/e+/QubPxpqDWHNEchvx/DEb1KJMOwq6K3MTNzZFoNSzVdR++o1DVnw==",
1321 | "dev": true
1322 | },
1323 | "@types/mocha": {
1324 | "version": "7.0.2",
1325 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
1326 | "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
1327 | "dev": true
1328 | },
1329 | "@types/node": {
1330 | "version": "12.12.50",
1331 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz",
1332 | "integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==",
1333 | "dev": true
1334 | },
1335 | "@types/shell-quote": {
1336 | "version": "1.7.0",
1337 | "resolved": "https://registry.npmjs.org/@types/shell-quote/-/shell-quote-1.7.0.tgz",
1338 | "integrity": "sha512-0CJaSSayMigMKu/Egx1eVcFjgGYkP6T4dyPRs462BFrMB/OK2FAJFV/24+6R4cGIXw6ZQpZK8XEd2UCVKfkZRw==",
1339 | "dev": true
1340 | },
1341 | "@xialvjun/js-utils": {
1342 | "version": "0.3.7",
1343 | "resolved": "https://registry.npmjs.org/@xialvjun/js-utils/-/js-utils-0.3.7.tgz",
1344 | "integrity": "sha512-IUkqFT5x8m0PJOlv08Vm802EsrZDtEoZVKYk8q4NDfeUMhCU7TRhHKrETygEFenCefVPyVq11SKGYO4oDPCuUA=="
1345 | },
1346 | "ansi-colors": {
1347 | "version": "4.1.1",
1348 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
1349 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
1350 | "dev": true
1351 | },
1352 | "ansi-regex": {
1353 | "version": "5.0.1",
1354 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
1355 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
1356 | "dev": true
1357 | },
1358 | "ansi-styles": {
1359 | "version": "4.3.0",
1360 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
1361 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
1362 | "dev": true,
1363 | "requires": {
1364 | "color-convert": "^2.0.1"
1365 | }
1366 | },
1367 | "anymatch": {
1368 | "version": "3.1.3",
1369 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
1370 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
1371 | "dev": true,
1372 | "requires": {
1373 | "normalize-path": "^3.0.0",
1374 | "picomatch": "^2.0.4"
1375 | }
1376 | },
1377 | "arg": {
1378 | "version": "4.1.3",
1379 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
1380 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
1381 | "dev": true
1382 | },
1383 | "argparse": {
1384 | "version": "2.0.1",
1385 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
1386 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
1387 | "dev": true
1388 | },
1389 | "assertion-error": {
1390 | "version": "1.1.0",
1391 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
1392 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
1393 | "dev": true
1394 | },
1395 | "await-spawn": {
1396 | "version": "4.0.2",
1397 | "resolved": "https://registry.npmjs.org/await-spawn/-/await-spawn-4.0.2.tgz",
1398 | "integrity": "sha512-GdADmeLJiMvGKJD3xWBcX40DMn07JNH1sqJYgYJZH7NTGJ3B1qDjKBKzxhhyR1hjIcnUGFUmE/+4D1HcHAJBAA==",
1399 | "requires": {
1400 | "bl": "^4.0.3"
1401 | }
1402 | },
1403 | "balanced-match": {
1404 | "version": "1.0.2",
1405 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1406 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1407 | "dev": true
1408 | },
1409 | "base64-js": {
1410 | "version": "1.5.1",
1411 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
1412 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
1413 | },
1414 | "binary-extensions": {
1415 | "version": "2.2.0",
1416 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
1417 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
1418 | "dev": true
1419 | },
1420 | "bl": {
1421 | "version": "4.1.0",
1422 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
1423 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
1424 | "requires": {
1425 | "buffer": "^5.5.0",
1426 | "inherits": "^2.0.4",
1427 | "readable-stream": "^3.4.0"
1428 | }
1429 | },
1430 | "brace-expansion": {
1431 | "version": "2.0.1",
1432 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
1433 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
1434 | "dev": true,
1435 | "requires": {
1436 | "balanced-match": "^1.0.0"
1437 | }
1438 | },
1439 | "braces": {
1440 | "version": "3.0.3",
1441 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
1442 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
1443 | "dev": true,
1444 | "requires": {
1445 | "fill-range": "^7.1.1"
1446 | }
1447 | },
1448 | "browser-stdout": {
1449 | "version": "1.3.1",
1450 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
1451 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
1452 | "dev": true
1453 | },
1454 | "buffer": {
1455 | "version": "5.7.1",
1456 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
1457 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
1458 | "requires": {
1459 | "base64-js": "^1.3.1",
1460 | "ieee754": "^1.1.13"
1461 | }
1462 | },
1463 | "buffer-from": {
1464 | "version": "1.1.1",
1465 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
1466 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
1467 | "dev": true
1468 | },
1469 | "camelcase": {
1470 | "version": "6.3.0",
1471 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
1472 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
1473 | "dev": true
1474 | },
1475 | "chai": {
1476 | "version": "4.2.0",
1477 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
1478 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
1479 | "dev": true,
1480 | "requires": {
1481 | "assertion-error": "^1.1.0",
1482 | "check-error": "^1.0.2",
1483 | "deep-eql": "^3.0.1",
1484 | "get-func-name": "^2.0.0",
1485 | "pathval": "^1.1.0",
1486 | "type-detect": "^4.0.5"
1487 | }
1488 | },
1489 | "chalk": {
1490 | "version": "4.1.2",
1491 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
1492 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
1493 | "dev": true,
1494 | "requires": {
1495 | "ansi-styles": "^4.1.0",
1496 | "supports-color": "^7.1.0"
1497 | },
1498 | "dependencies": {
1499 | "supports-color": {
1500 | "version": "7.2.0",
1501 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1502 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1503 | "dev": true,
1504 | "requires": {
1505 | "has-flag": "^4.0.0"
1506 | }
1507 | }
1508 | }
1509 | },
1510 | "check-error": {
1511 | "version": "1.0.2",
1512 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
1513 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
1514 | "dev": true
1515 | },
1516 | "chokidar": {
1517 | "version": "3.5.3",
1518 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
1519 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
1520 | "dev": true,
1521 | "requires": {
1522 | "anymatch": "~3.1.2",
1523 | "braces": "~3.0.2",
1524 | "fsevents": "~2.3.2",
1525 | "glob-parent": "~5.1.2",
1526 | "is-binary-path": "~2.1.0",
1527 | "is-glob": "~4.0.1",
1528 | "normalize-path": "~3.0.0",
1529 | "readdirp": "~3.6.0"
1530 | }
1531 | },
1532 | "cliui": {
1533 | "version": "7.0.4",
1534 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
1535 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
1536 | "dev": true,
1537 | "requires": {
1538 | "string-width": "^4.2.0",
1539 | "strip-ansi": "^6.0.0",
1540 | "wrap-ansi": "^7.0.0"
1541 | }
1542 | },
1543 | "color-convert": {
1544 | "version": "2.0.1",
1545 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1546 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1547 | "dev": true,
1548 | "requires": {
1549 | "color-name": "~1.1.4"
1550 | }
1551 | },
1552 | "color-name": {
1553 | "version": "1.1.4",
1554 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1555 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1556 | "dev": true
1557 | },
1558 | "commander": {
1559 | "version": "5.1.0",
1560 | "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
1561 | "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="
1562 | },
1563 | "concat-map": {
1564 | "version": "0.0.1",
1565 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
1566 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
1567 | "dev": true
1568 | },
1569 | "debug": {
1570 | "version": "4.3.4",
1571 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
1572 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
1573 | "dev": true,
1574 | "requires": {
1575 | "ms": "2.1.2"
1576 | },
1577 | "dependencies": {
1578 | "ms": {
1579 | "version": "2.1.2",
1580 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1581 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
1582 | "dev": true
1583 | }
1584 | }
1585 | },
1586 | "decamelize": {
1587 | "version": "4.0.0",
1588 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
1589 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
1590 | "dev": true
1591 | },
1592 | "deep-eql": {
1593 | "version": "3.0.1",
1594 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
1595 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
1596 | "dev": true,
1597 | "requires": {
1598 | "type-detect": "^4.0.0"
1599 | }
1600 | },
1601 | "diff": {
1602 | "version": "5.0.0",
1603 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
1604 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
1605 | "dev": true
1606 | },
1607 | "emoji-regex": {
1608 | "version": "8.0.0",
1609 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1610 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1611 | "dev": true
1612 | },
1613 | "escalade": {
1614 | "version": "3.1.1",
1615 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
1616 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
1617 | "dev": true
1618 | },
1619 | "escape-string-regexp": {
1620 | "version": "4.0.0",
1621 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
1622 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
1623 | "dev": true
1624 | },
1625 | "fill-range": {
1626 | "version": "7.1.1",
1627 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
1628 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
1629 | "dev": true,
1630 | "requires": {
1631 | "to-regex-range": "^5.0.1"
1632 | }
1633 | },
1634 | "find-up": {
1635 | "version": "5.0.0",
1636 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
1637 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
1638 | "dev": true,
1639 | "requires": {
1640 | "locate-path": "^6.0.0",
1641 | "path-exists": "^4.0.0"
1642 | }
1643 | },
1644 | "flat": {
1645 | "version": "5.0.2",
1646 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
1647 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
1648 | "dev": true
1649 | },
1650 | "fs.realpath": {
1651 | "version": "1.0.0",
1652 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
1653 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
1654 | "dev": true
1655 | },
1656 | "fsevents": {
1657 | "version": "2.3.2",
1658 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
1659 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
1660 | "dev": true,
1661 | "optional": true
1662 | },
1663 | "get-caller-file": {
1664 | "version": "2.0.5",
1665 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
1666 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
1667 | "dev": true
1668 | },
1669 | "get-func-name": {
1670 | "version": "2.0.0",
1671 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
1672 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
1673 | "dev": true
1674 | },
1675 | "glob": {
1676 | "version": "7.2.0",
1677 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
1678 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
1679 | "dev": true,
1680 | "requires": {
1681 | "fs.realpath": "^1.0.0",
1682 | "inflight": "^1.0.4",
1683 | "inherits": "2",
1684 | "minimatch": "^3.0.4",
1685 | "once": "^1.3.0",
1686 | "path-is-absolute": "^1.0.0"
1687 | },
1688 | "dependencies": {
1689 | "brace-expansion": {
1690 | "version": "1.1.11",
1691 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
1692 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
1693 | "dev": true,
1694 | "requires": {
1695 | "balanced-match": "^1.0.0",
1696 | "concat-map": "0.0.1"
1697 | }
1698 | },
1699 | "minimatch": {
1700 | "version": "3.1.2",
1701 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1702 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1703 | "dev": true,
1704 | "requires": {
1705 | "brace-expansion": "^1.1.7"
1706 | }
1707 | }
1708 | }
1709 | },
1710 | "glob-parent": {
1711 | "version": "5.1.2",
1712 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1713 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1714 | "dev": true,
1715 | "requires": {
1716 | "is-glob": "^4.0.1"
1717 | }
1718 | },
1719 | "has-flag": {
1720 | "version": "4.0.0",
1721 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1722 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1723 | "dev": true
1724 | },
1725 | "he": {
1726 | "version": "1.2.0",
1727 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
1728 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
1729 | "dev": true
1730 | },
1731 | "ieee754": {
1732 | "version": "1.2.1",
1733 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
1734 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
1735 | },
1736 | "inflight": {
1737 | "version": "1.0.6",
1738 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1739 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
1740 | "dev": true,
1741 | "requires": {
1742 | "once": "^1.3.0",
1743 | "wrappy": "1"
1744 | }
1745 | },
1746 | "inherits": {
1747 | "version": "2.0.4",
1748 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1749 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
1750 | },
1751 | "is-binary-path": {
1752 | "version": "2.1.0",
1753 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
1754 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1755 | "dev": true,
1756 | "requires": {
1757 | "binary-extensions": "^2.0.0"
1758 | }
1759 | },
1760 | "is-extglob": {
1761 | "version": "2.1.1",
1762 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1763 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1764 | "dev": true
1765 | },
1766 | "is-fullwidth-code-point": {
1767 | "version": "3.0.0",
1768 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1769 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1770 | "dev": true
1771 | },
1772 | "is-glob": {
1773 | "version": "4.0.3",
1774 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
1775 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1776 | "dev": true,
1777 | "requires": {
1778 | "is-extglob": "^2.1.1"
1779 | }
1780 | },
1781 | "is-number": {
1782 | "version": "7.0.0",
1783 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1784 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1785 | "dev": true
1786 | },
1787 | "is-plain-obj": {
1788 | "version": "2.1.0",
1789 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
1790 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
1791 | "dev": true
1792 | },
1793 | "is-unicode-supported": {
1794 | "version": "0.1.0",
1795 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
1796 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
1797 | "dev": true
1798 | },
1799 | "js-yaml": {
1800 | "version": "4.1.0",
1801 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
1802 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
1803 | "dev": true,
1804 | "requires": {
1805 | "argparse": "^2.0.1"
1806 | }
1807 | },
1808 | "locate-path": {
1809 | "version": "6.0.0",
1810 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
1811 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
1812 | "dev": true,
1813 | "requires": {
1814 | "p-locate": "^5.0.0"
1815 | }
1816 | },
1817 | "lodash.flattendeep": {
1818 | "version": "4.4.0",
1819 | "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
1820 | "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI="
1821 | },
1822 | "log-symbols": {
1823 | "version": "4.1.0",
1824 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
1825 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
1826 | "dev": true,
1827 | "requires": {
1828 | "chalk": "^4.1.0",
1829 | "is-unicode-supported": "^0.1.0"
1830 | }
1831 | },
1832 | "lunr": {
1833 | "version": "2.3.8",
1834 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz",
1835 | "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg=="
1836 | },
1837 | "make-error": {
1838 | "version": "1.3.6",
1839 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
1840 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
1841 | "dev": true
1842 | },
1843 | "minimatch": {
1844 | "version": "5.0.1",
1845 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
1846 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
1847 | "dev": true,
1848 | "requires": {
1849 | "brace-expansion": "^2.0.1"
1850 | }
1851 | },
1852 | "mocha": {
1853 | "version": "10.2.0",
1854 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
1855 | "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
1856 | "dev": true,
1857 | "requires": {
1858 | "ansi-colors": "4.1.1",
1859 | "browser-stdout": "1.3.1",
1860 | "chokidar": "3.5.3",
1861 | "debug": "4.3.4",
1862 | "diff": "5.0.0",
1863 | "escape-string-regexp": "4.0.0",
1864 | "find-up": "5.0.0",
1865 | "glob": "7.2.0",
1866 | "he": "1.2.0",
1867 | "js-yaml": "4.1.0",
1868 | "log-symbols": "4.1.0",
1869 | "minimatch": "5.0.1",
1870 | "ms": "2.1.3",
1871 | "nanoid": "3.3.3",
1872 | "serialize-javascript": "6.0.0",
1873 | "strip-json-comments": "3.1.1",
1874 | "supports-color": "8.1.1",
1875 | "workerpool": "6.2.1",
1876 | "yargs": "16.2.0",
1877 | "yargs-parser": "20.2.4",
1878 | "yargs-unparser": "2.0.0"
1879 | }
1880 | },
1881 | "ms": {
1882 | "version": "2.1.3",
1883 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1884 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1885 | "dev": true
1886 | },
1887 | "nanoid": {
1888 | "version": "3.3.3",
1889 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
1890 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
1891 | "dev": true
1892 | },
1893 | "normalize-path": {
1894 | "version": "3.0.0",
1895 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1896 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1897 | "dev": true
1898 | },
1899 | "once": {
1900 | "version": "1.4.0",
1901 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1902 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1903 | "dev": true,
1904 | "requires": {
1905 | "wrappy": "1"
1906 | }
1907 | },
1908 | "p-limit": {
1909 | "version": "3.1.0",
1910 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
1911 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
1912 | "dev": true,
1913 | "requires": {
1914 | "yocto-queue": "^0.1.0"
1915 | }
1916 | },
1917 | "p-locate": {
1918 | "version": "5.0.0",
1919 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
1920 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
1921 | "dev": true,
1922 | "requires": {
1923 | "p-limit": "^3.0.2"
1924 | }
1925 | },
1926 | "path-exists": {
1927 | "version": "4.0.0",
1928 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1929 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1930 | "dev": true
1931 | },
1932 | "path-is-absolute": {
1933 | "version": "1.0.1",
1934 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1935 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
1936 | "dev": true
1937 | },
1938 | "pathval": {
1939 | "version": "1.1.1",
1940 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
1941 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
1942 | "dev": true
1943 | },
1944 | "picomatch": {
1945 | "version": "2.3.1",
1946 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1947 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1948 | "dev": true
1949 | },
1950 | "randombytes": {
1951 | "version": "2.1.0",
1952 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1953 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1954 | "dev": true,
1955 | "requires": {
1956 | "safe-buffer": "^5.1.0"
1957 | }
1958 | },
1959 | "readable-stream": {
1960 | "version": "3.6.0",
1961 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
1962 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
1963 | "requires": {
1964 | "inherits": "^2.0.3",
1965 | "string_decoder": "^1.1.1",
1966 | "util-deprecate": "^1.0.1"
1967 | }
1968 | },
1969 | "readdirp": {
1970 | "version": "3.6.0",
1971 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1972 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1973 | "dev": true,
1974 | "requires": {
1975 | "picomatch": "^2.2.1"
1976 | }
1977 | },
1978 | "require-directory": {
1979 | "version": "2.1.1",
1980 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1981 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
1982 | "dev": true
1983 | },
1984 | "safe-buffer": {
1985 | "version": "5.2.1",
1986 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1987 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1988 | },
1989 | "serialize-javascript": {
1990 | "version": "6.0.0",
1991 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
1992 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
1993 | "dev": true,
1994 | "requires": {
1995 | "randombytes": "^2.1.0"
1996 | }
1997 | },
1998 | "shell-quote": {
1999 | "version": "1.7.3",
2000 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
2001 | "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="
2002 | },
2003 | "source-map": {
2004 | "version": "0.6.1",
2005 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
2006 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
2007 | "dev": true
2008 | },
2009 | "source-map-support": {
2010 | "version": "0.5.19",
2011 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
2012 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
2013 | "dev": true,
2014 | "requires": {
2015 | "buffer-from": "^1.0.0",
2016 | "source-map": "^0.6.0"
2017 | }
2018 | },
2019 | "string_decoder": {
2020 | "version": "1.3.0",
2021 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
2022 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
2023 | "requires": {
2024 | "safe-buffer": "~5.2.0"
2025 | }
2026 | },
2027 | "string-width": {
2028 | "version": "4.2.3",
2029 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
2030 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
2031 | "dev": true,
2032 | "requires": {
2033 | "emoji-regex": "^8.0.0",
2034 | "is-fullwidth-code-point": "^3.0.0",
2035 | "strip-ansi": "^6.0.1"
2036 | }
2037 | },
2038 | "strip-ansi": {
2039 | "version": "6.0.1",
2040 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2041 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2042 | "dev": true,
2043 | "requires": {
2044 | "ansi-regex": "^5.0.1"
2045 | }
2046 | },
2047 | "strip-json-comments": {
2048 | "version": "3.1.1",
2049 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
2050 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
2051 | "dev": true
2052 | },
2053 | "supports-color": {
2054 | "version": "8.1.1",
2055 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
2056 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
2057 | "dev": true,
2058 | "requires": {
2059 | "has-flag": "^4.0.0"
2060 | }
2061 | },
2062 | "to-regex-range": {
2063 | "version": "5.0.1",
2064 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
2065 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
2066 | "dev": true,
2067 | "requires": {
2068 | "is-number": "^7.0.0"
2069 | }
2070 | },
2071 | "ts-node": {
2072 | "version": "8.10.2",
2073 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
2074 | "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==",
2075 | "dev": true,
2076 | "requires": {
2077 | "arg": "^4.1.0",
2078 | "diff": "^4.0.1",
2079 | "make-error": "^1.1.1",
2080 | "source-map-support": "^0.5.17",
2081 | "yn": "3.1.1"
2082 | },
2083 | "dependencies": {
2084 | "diff": {
2085 | "version": "4.0.2",
2086 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
2087 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
2088 | "dev": true
2089 | }
2090 | }
2091 | },
2092 | "tslib": {
2093 | "version": "2.0.0",
2094 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz",
2095 | "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g=="
2096 | },
2097 | "type-detect": {
2098 | "version": "4.0.8",
2099 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
2100 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
2101 | "dev": true
2102 | },
2103 | "typescript": {
2104 | "version": "4.0.2",
2105 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
2106 | "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
2107 | "dev": true
2108 | },
2109 | "typescript-template-language-service-decorator": {
2110 | "version": "2.2.0",
2111 | "resolved": "https://registry.npmjs.org/typescript-template-language-service-decorator/-/typescript-template-language-service-decorator-2.2.0.tgz",
2112 | "integrity": "sha512-xiolqt1i7e22rpqMaprPgSFVgU64u3b9n6EJlAaUYE61jumipKAdI1+O5khPlWslpTUj80YzjUKjJ2jxT0D74w=="
2113 | },
2114 | "util-deprecate": {
2115 | "version": "1.0.2",
2116 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2117 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
2118 | },
2119 | "workerpool": {
2120 | "version": "6.2.1",
2121 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
2122 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
2123 | "dev": true
2124 | },
2125 | "wrap-ansi": {
2126 | "version": "7.0.0",
2127 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
2128 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
2129 | "dev": true,
2130 | "requires": {
2131 | "ansi-styles": "^4.0.0",
2132 | "string-width": "^4.1.0",
2133 | "strip-ansi": "^6.0.0"
2134 | }
2135 | },
2136 | "wrappy": {
2137 | "version": "1.0.2",
2138 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2139 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
2140 | "dev": true
2141 | },
2142 | "y18n": {
2143 | "version": "5.0.8",
2144 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
2145 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
2146 | "dev": true
2147 | },
2148 | "yargs": {
2149 | "version": "16.2.0",
2150 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
2151 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
2152 | "dev": true,
2153 | "requires": {
2154 | "cliui": "^7.0.2",
2155 | "escalade": "^3.1.1",
2156 | "get-caller-file": "^2.0.5",
2157 | "require-directory": "^2.1.1",
2158 | "string-width": "^4.2.0",
2159 | "y18n": "^5.0.5",
2160 | "yargs-parser": "^20.2.2"
2161 | }
2162 | },
2163 | "yargs-parser": {
2164 | "version": "20.2.4",
2165 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
2166 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
2167 | "dev": true
2168 | },
2169 | "yargs-unparser": {
2170 | "version": "2.0.0",
2171 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
2172 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
2173 | "dev": true,
2174 | "requires": {
2175 | "camelcase": "^6.0.0",
2176 | "decamelize": "^4.0.0",
2177 | "flat": "^5.0.2",
2178 | "is-plain-obj": "^2.1.0"
2179 | }
2180 | },
2181 | "yn": {
2182 | "version": "3.1.1",
2183 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
2184 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
2185 | "dev": true
2186 | },
2187 | "yocto-queue": {
2188 | "version": "0.1.0",
2189 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
2190 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
2191 | "dev": true
2192 | }
2193 | }
2194 | }
2195 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ts-sql-plugin",
3 | "version": "0.10.1",
4 | "description": "TypeScript Language Service Plugin for SQL with a tagged template strings SQL builder.",
5 | "keywords": [
6 | "typescript",
7 | "language service",
8 | "sql"
9 | ],
10 | "main": "index.js",
11 | "bin": "cli.js",
12 | "scripts": {
13 | "build": "tsc -p .",
14 | "watch": "tsc --watch -p .",
15 | "test": "mocha -r ts-node/register test/**/*.ts"
16 | },
17 | "author": "xialvjun@live.com",
18 | "license": "MIT",
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/xialvjun/ts-sql-plugin.git"
22 | },
23 | "devDependencies": {
24 | "@types/chai": "^4.2.11",
25 | "@types/lodash.flattendeep": "4.4.6",
26 | "@types/lunr": "^2.3.3",
27 | "@types/mocha": "^7.0.2",
28 | "@types/node": "^12.12.41",
29 | "@types/shell-quote": "^1.7.0",
30 | "chai": "^4.2.0",
31 | "mocha": "^10.2.0",
32 | "ts-node": "^8.10.2",
33 | "typescript": "^4.0.2"
34 | },
35 | "peerDependencies": {
36 | "typescript": "^4.0.2"
37 | },
38 | "dependencies": {
39 | "@xialvjun/js-utils": "^0.3.7",
40 | "await-spawn": "4.0.2",
41 | "commander": "^5.0.0",
42 | "lodash.flattendeep": "4.4.0",
43 | "lunr": "^2.3.8",
44 | "shell-quote": "^1.7.2",
45 | "tslib": "^2.0.0",
46 | "typescript-template-language-service-decorator": "^2.2.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/sql.ts:
--------------------------------------------------------------------------------
1 | const parseValue = (v: any) => {
2 | return !!v && v[symbol]
3 | ? { text: v.text, values: v.values}
4 | : { text: '??', values: [v] };
5 | }
6 |
7 | const raw = (texts: TemplateStringsArray | string[], ...vs: any[]) => {
8 | let text = texts[0] || '';
9 | let values: any[] = [];
10 | let parseResult = null;
11 | vs.forEach((v, idx) => {
12 | parseResult = parseValue(v);
13 | text += parseResult.text;
14 | values.push(...parseResult.values)
15 | text += texts[idx + 1] || "";
16 | });
17 | return { [symbol]: true, text, values };
18 | };
19 |
20 | export const sql = (texts: TemplateStringsArray, ...vs: any[]) => raw(texts, ...vs);
21 |
22 | export default sql;
23 |
24 | const symbol = (sql.symbol = Symbol("sql"));
25 |
26 | sql.raw = raw;
27 |
28 | sql.cond = (condition: boolean) => (condition ? raw : (..._: any[]) => raw``);
29 |
30 | // const to_and = {m: undefined, n: undefined};
31 | // no first and
32 | // sql`select * from a where ${sql.and(to_and)}`
33 | // with first and
34 | // sql`select * from a where (1=1 ${sql.and(to_and)}) or (${sql.and(another_to_and)})`
35 | // sql`select * from a where 1=1 and ${sql.and(to_and)}`
36 | // 东西加多了是硬伤, 加少了可以有 sql.raw, 所以尽量少加
37 | sql.and = (obj: object) => {
38 | let kvs = Object.entries(obj)
39 | .filter(([k, v]) => v !== undefined)
40 | .sort(([ka, va], [kb, vb]) => (ka < kb ? -1 : ka > kb ? 1 : 0));
41 | let values: any[] = [];
42 | if (kvs.length === 0) {
43 | return { [symbol]: true, text: "", values };
44 | }
45 | let text = kvs
46 | .map(([k, v]) => {
47 | values.push(v);
48 | return validate_identifier(k) + " ??";
49 | })
50 | .join(" AND ");
51 | return { [symbol]: true, text, values };
52 | };
53 |
54 | sql.or = (objs: T) => {
55 | return objs
56 | .map(obj => sql.and(obj))
57 | .reduce(
58 | (acc, cv, idx) => {
59 | acc.text += `${idx === 0 ? "" : " OR"} (${cv.text})`;
60 | acc.values = acc.values.concat(cv.values);
61 | return acc;
62 | },
63 | { [symbol]: true, text: "", values: [] },
64 | );
65 | };
66 |
67 | sql.ins = (obj_or_objs: object | object[]) => {
68 | let objs: any[] = [].concat(obj_or_objs as any);
69 | let keys = Object.keys(Object.assign({}, ...objs)).sort();
70 | let values: any[] = [];
71 | let parseResult = null;
72 | let text = `(${keys.map(k => validate_identifier(k).split(" ")[0]).join(", ")}) VALUES ${objs
73 | .map(
74 | obj =>
75 | `(${keys
76 | .map(k => {
77 | parseResult = parseValue(obj[k])
78 | values.push(...parseResult.values);
79 | return parseResult.text;
80 | })
81 | .join(", ")})`,
82 | )
83 | .join(", ")}`;
84 | return { [symbol]: true, text, values };
85 | };
86 |
87 | sql.upd = (obj: object) => {
88 | let kvs = Object.entries(obj)
89 | .filter(([k, v]) => v !== undefined)
90 | .sort(([ka, va], [kb, vb]) => (ka < kb ? -1 : ka > kb ? 1 : 0));
91 | let values: any[] = [];
92 | let parseResult = null
93 | let text = kvs
94 | .map(([k, v]) => {
95 | parseResult = parseValue(v);
96 | values.push(...parseResult.values);
97 | return validate_identifier(k) + `${parseResult.text}`;
98 | })
99 | .join(", ");
100 | return { [symbol]: true, text, values };
101 | };
102 |
103 | sql.mock = (value: any) => value;
104 |
105 | function validate_identifier(identifier: string) {
106 | // we can believe a functionnal sql (ignore it's good or bad) has to include more than one space, so forbid it
107 | const match_space = identifier.match(/\s/g);
108 | if (!match_space) {
109 | return identifier + ' =';
110 | }
111 | if (match_space.length === 1) {
112 | return identifier;
113 | }
114 | throw Error("ts-sql-plugin sql param object key can not have more than one space");
115 | }
116 |
117 | // ? 有想过把所有数据都放在类型系统上, 这样 sql.raw`` 得到的结果就可以作为变量到处传递了, 不需要限制死在 sql`` 内部使用, 与运行时等同...但问题是 TemplateStringsArray 把字符串模板的 const 字符串信息丢失了, 这里只能 typescript 上游去解决, 这样在类型上根本无法得到 raw 里面的字符串, 至于从变量传递作用域上, 那结果就是完全不确定的
118 | // interface AAA {
119 | // __texts: TSA;
120 | // __values: VS;
121 | // }
122 |
123 | // function abc(texts: TSA, ...vs: VS): AAA {
124 | // return {__texts: texts, __values: vs}
125 | // }
126 |
127 | // var a = abc`select * from ${123} and good ${new Date()} ${window}`;
128 | // // var a: AAA<['select * from ', ' and good ', ' ', ''], [number, Date, Window]>
129 |
130 | // enum ExpressionKind {
131 | // RAW,
132 | // SQL,
133 | // AND,
134 | // INS,
135 | // UPD,
136 | // };
137 |
138 | // interface Expression {
139 | // __kind__: ExpressionKind;
140 | // text: string;
141 | // values: any[];
142 | // }
143 |
144 | // interface RawExpression extends Expression {
145 | // __kind__: ExpressionKind.RAW;
146 | // }
147 |
148 | // interface SqlExpression extends Expression {
149 | // __kind__: ExpressionKind.SQL;
150 | // }
151 |
152 | // interface AndExpression extends Expression {
153 | // __kind__: ExpressionKind.AND;
154 | // }
155 |
156 | // interface InsExpression extends Expression {
157 | // __kind__: ExpressionKind.INS;
158 | // }
159 |
160 | // interface UpdExpression extends Expression {
161 | // __kind__: ExpressionKind.UPD;
162 | // }
163 |
164 | // // raw: raw
165 | // // and: and
166 | // // ins: ins
167 | // // upd: upd
168 |
--------------------------------------------------------------------------------
/test/cache.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import { addToSqlCache, existsInSqlCache } from "../lib/cache";
3 |
4 | describe("Cache", () => {
5 | it("cache", () => {
6 | const set = addToSqlCache("command", ["a", "b"]);
7 | expect(set.size).equal(1);
8 |
9 | const exists = existsInSqlCache("command", ["a", "b"])
10 | expect(exists).equal(true);
11 |
12 | const exists2 = existsInSqlCache("command", ["a", "b", "c"])
13 | expect(exists2).equal(false);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/test/directives.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import { parseDirectives } from "../lib/directiveParser";
3 |
4 | describe("parseDirectives ", () => {
5 | it("should return [] when theres no directives specified", function () {
6 | expect(parseDirectives("select * from *")).to.have.lengthOf(0);
7 | expect(parseDirectives("-- helloworld")).to.have.lengthOf(0);
8 | expect(parseDirectives("-- ts-sql-plugin: \n select")).to.have.lengthOf(
9 | 0
10 | );
11 | });
12 |
13 | it("should parse single line directives", function () {
14 | const result = parseDirectives(`
15 | -- ts-sql-plugin:ignore-cost
16 | select * from *
17 | `);
18 | expect(result).to.have.lengthOf(1, "it should find one directive");
19 | expect(result[0].directive).to.eq("ignore-cost");
20 | expect(result[0].arg).to.be.undefined;
21 | });
22 |
23 | it("should parse single line with json argument", function () {
24 | const result = parseDirectives(`
25 | -- ts-sql-plugin:emit("../emitdir/filename")
26 | select * from *
27 | `);
28 | expect(result).to.have.lengthOf(1, "it should find one directive");
29 | expect(result[0].directive).to.eq("emit");
30 | expect(result[0].arg).to.eq("../emitdir/filename");
31 | });
32 |
33 | it("should parse multiple lines with directive", function () {
34 | const result = parseDirectives(`
35 | -- ts-sql-plugin:emit("../emitdir/filename")
36 | -- ts-sql-plugin:ignore-cost
37 | select * from *
38 | `);
39 | expect(result).to.have.lengthOf(2, "it should find two directives");
40 | expect(result[0]).to.deep.eq({
41 | directive: "emit",
42 | arg: "../emitdir/filename",
43 | });
44 | expect(result[1]).to.deep.eq({ directive: "ignore-cost", arg: undefined });
45 | });
46 |
47 | it("should extract only first directives", function () {
48 | const result = parseDirectives(`
49 | -- ts-sql-plugin:emit("../emitdir/filename")
50 | -- ts-sql-plugin:ignore-cost
51 | select * from (
52 | -- ts-sql-plugin:ignore-cost
53 | select * from *
54 | ) x
55 | `);
56 | expect(result).to.have.lengthOf(2, "it should find two directives");
57 | expect(result[0]).to.deep.eq({
58 | directive: "emit",
59 | arg: "../emitdir/filename",
60 | });
61 | expect(result[1]).to.deep.eq({ directive: "ignore-cost", arg: undefined });
62 | });
63 |
64 | it("test /**/ comments", function () {
65 | const result = parseDirectives(`
66 | /* ts-sql-plugin:emit("../emitdir/filename") */
67 | /* ts-sql-plugin:ignore-cost */
68 | select * from (
69 | /* ts-sql-plugin:ignore-cost */
70 | select * from *
71 | ) x
72 | `);
73 | expect(result).to.have.lengthOf(2, "it should find two directives");
74 | expect(result[0]).to.deep.eq({
75 | directive: "emit",
76 | arg: "../emitdir/filename",
77 | });
78 | expect(result[1]).to.deep.eq({ directive: "ignore-cost", arg: undefined });
79 | });
80 |
81 | });
82 |
--------------------------------------------------------------------------------
/test/utils.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import { trim_middle_comments } from "../lib/utils";
3 |
4 | describe("Utils", () => {
5 | describe("trim_middle_comments", () => {
6 | it("SQL without comments as is", () => {
7 | const sql = `
8 | select * from users
9 | where id = 1`;
10 | expect(trim_middle_comments(sql)).equal(sql.trim());
11 | });
12 |
13 | it("comments on head should be preserved", () => {
14 | const sql = `
15 |
16 | -- stay here
17 | /* ts-sql-plugin:ignore-cost */
18 | select * from users
19 | where id = 1`;
20 | expect(trim_middle_comments(sql)).equal(sql.trim());
21 | });
22 |
23 | it("drop comments from middle side", () => {
24 | const sql = `
25 | -- stay here
26 | /* ts-sql-plugin:ignore-cost */
27 | select * from (
28 | -- remove from here
29 | /* @name Users */
30 | /* ts-sql-plugin:ignore-cost */
31 | select * from users
32 | ) x
33 | where id = 1`;
34 | expect(trim_middle_comments(sql)).equal(
35 | `
36 | -- stay here
37 | /* ts-sql-plugin:ignore-cost */
38 | select * from (
39 | select * from users
40 | ) x
41 | where id = 1`.trim(),
42 | );
43 | });
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "ES2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
8 | "module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
9 | "lib": ["ES2020"] /* Specify library files to be included in the compilation. */,
10 | // "allowJs": true, /* Allow javascript files to be compiled. */
11 | // "checkJs": true, /* Report errors in .js files. */
12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
15 | "sourceMap": true /* Generates corresponding '.map' file. */,
16 | // "outFile": "./", /* Concatenate and emit output to single file. */
17 | // "outDir": "./", /* Redirect output structure to the directory. */
18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19 | // "composite": true, /* Enable project compilation */
20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
21 | // "removeComments": true, /* Do not emit comments to output. */
22 | // "noEmit": true, /* Do not emit outputs. */
23 | "importHelpers": true /* Import emit helpers from 'tslib'. */,
24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26 |
27 | /* Strict Type-Checking Options */
28 | "strict": true /* Enable all strict type-checking options. */,
29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
30 | // "strictNullChecks": true, /* Enable strict null checks. */
31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
36 |
37 | /* Additional Checks */
38 | // "noUnusedLocals": true, /* Report errors on unused locals. */
39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
42 |
43 | /* Module Resolution Options */
44 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
47 | // "rootDirs": ["./"], /* List of root folders whose combined content represents the structure of the project at runtime. */
48 | // "typeRoots": [], /* List of folders to include type definitions from. */
49 | // "types": [], /* Type declaration files to be included in compilation. */
50 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
51 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
52 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
53 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
54 |
55 | /* Source Map Options */
56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
60 |
61 | /* Experimental Options */
62 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
63 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
64 |
65 | /* Advanced Options */
66 | "skipLibCheck": true /* Skip type checking of declaration files. */,
67 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
68 | },
69 | // "files": ["."],
70 | // "include": ["./**/*"],
71 | "exclude": [".cache/", ".vscode/", "node_modules/", "dist/", "./gitignore.d/"]
72 | }
73 |
--------------------------------------------------------------------------------
/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module "await-spawn" {
2 | export default function (cmd: string, args: string[], opts?: object): Promise;
3 | }
4 |
--------------------------------------------------------------------------------