From 9dcda9489160aa029505e308f3b69bccc6bdb1ab Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 3 Jul 2022 21:09:54 +0200 Subject: [PATCH 01/50] Add yaml loader for webpack This will allow to directly load YAML files in Typescript (like JSON) so we can pre-load the gxformat2 schema documents without reading from disk at runtime. --- package-lock.json | 110 ++++++++++++++++++++++++++++++++++++++- package.json | 3 +- shared.webpack.config.js | 4 ++ 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c8c5b8..4cf92ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,8 @@ "ts-loader": "^9.2.9", "typescript": "^4.6.3", "webpack": "^5.72.0", - "webpack-cli": "^4.9.2" + "webpack-cli": "^4.9.2", + "yaml-loader": "^0.8.0" }, "engines": { "vscode": "^1.66.0" @@ -2088,6 +2089,15 @@ "node": ">=0.6" } }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", @@ -2667,6 +2677,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/enhanced-resolve": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", @@ -4166,6 +4185,12 @@ "node": ">=8" } }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, "node_modules/jest": { "version": "28.0.3", "resolved": "https://registry.npmjs.org/jest/-/jest-28.0.3.tgz", @@ -5293,6 +5318,20 @@ "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7231,6 +7270,29 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", + "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.0.tgz", + "integrity": "sha512-LjeKnTzVBKWiQBeE2L9ssl6WprqaUIxCSNs5tle8PaDydgu3wVFXTbMfsvF2MSErpy9TDVa092n4q6adYwJaWg==", + "dev": true, + "dependencies": { + "javascript-stringify": "^2.0.1", + "loader-utils": "^2.0.0", + "yaml": "^2.0.0" + }, + "engines": { + "node": ">= 12.13" + } + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -8886,6 +8948,12 @@ "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", "dev": true }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, "binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", @@ -9313,6 +9381,12 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "enhanced-resolve": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", @@ -10400,6 +10474,12 @@ "istanbul-lib-report": "^3.0.0" } }, + "javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, "jest": { "version": "28.0.3", "resolved": "https://registry.npmjs.org/jest/-/jest-28.0.3.tgz", @@ -11269,6 +11349,17 @@ "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "dev": true }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -12653,6 +12744,23 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", + "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==", + "dev": true + }, + "yaml-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.0.tgz", + "integrity": "sha512-LjeKnTzVBKWiQBeE2L9ssl6WprqaUIxCSNs5tle8PaDydgu3wVFXTbMfsvF2MSErpy9TDVa092n4q6adYwJaWg==", + "dev": true, + "requires": { + "javascript-stringify": "^2.0.1", + "loader-utils": "^2.0.0", + "yaml": "^2.0.0" + } + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index 577e1dc..334eb15 100644 --- a/package.json +++ b/package.json @@ -244,7 +244,8 @@ "ts-loader": "^9.2.9", "typescript": "^4.6.3", "webpack": "^5.72.0", - "webpack-cli": "^4.9.2" + "webpack-cli": "^4.9.2", + "yaml-loader": "^0.8.0" }, "__metadata": { "id": "2306ad21-fa2c-46f9-bba8-a22e32c7cb9a", diff --git a/shared.webpack.config.js b/shared.webpack.config.js index 3ccd869..7d3f767 100644 --- a/shared.webpack.config.js +++ b/shared.webpack.config.js @@ -41,6 +41,10 @@ module.exports = function withDefaults(/**@type WebpackConfig*/ extConfig) { }, ], }, + { + test: /\.ya?ml$/, + use: "yaml-loader", + }, ], }, externals: { From 385e0978e261aafaccca28b292a798ec4340ca90 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 3 Jul 2022 21:12:17 +0200 Subject: [PATCH 02/50] Add gxformat2 v19_09 schema --- server/gx-workflow-ls-format2/package.json | 3 +- .../src/schema/v19_09.ts | 16 + server/gx-workflow-ls-format2/src/types.d.ts | 4 + server/package-lock.json | 3 +- .../schemas/gxformat2/common/common.yaml | 93 +++++ .../common/metaschema/metaschema_base.yaml | 169 ++++++++ .../schemas/gxformat2/v19_09/process.yaml | 101 +++++ .../schemas/gxformat2/v19_09/workflows.yaml | 390 ++++++++++++++++++ 8 files changed, 775 insertions(+), 4 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/schema/v19_09.ts create mode 100644 server/gx-workflow-ls-format2/src/types.d.ts create mode 100644 workflow-languages/schemas/gxformat2/common/common.yaml create mode 100644 workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml create mode 100644 workflow-languages/schemas/gxformat2/v19_09/process.yaml create mode 100644 workflow-languages/schemas/gxformat2/v19_09/workflows.yaml diff --git a/server/gx-workflow-ls-format2/package.json b/server/gx-workflow-ls-format2/package.json index 9db4126..159abd9 100644 --- a/server/gx-workflow-ls-format2/package.json +++ b/server/gx-workflow-ls-format2/package.json @@ -7,11 +7,10 @@ "dependencies": { "@gxwf/server-common": "*", "@gxwf/yaml-language-service": "*", + "vscode-languageserver": "^7.0.0", "vscode-languageserver-textdocument": "^1.0.4", "vscode-languageserver-types": "^3.16.0", - "vscode-languageserver": "^7.0.0", "vscode-uri": "^3.0.3" }, - "devDependencies": {}, "scripts": {} } diff --git a/server/gx-workflow-ls-format2/src/schema/v19_09.ts b/server/gx-workflow-ls-format2/src/schema/v19_09.ts new file mode 100644 index 0000000..75fe1eb --- /dev/null +++ b/server/gx-workflow-ls-format2/src/schema/v19_09.ts @@ -0,0 +1,16 @@ +import schema_v19_09_workflows from "../../../../workflow-languages/schemas/gxformat2/v19_09/workflows.yaml"; +import schema_common_metaschema_base from "../../../../workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml"; +import schema_v19_09_process from "../../../../workflow-languages/schemas/gxformat2/v19_09/process.yaml"; +import schema_common from "../../../../workflow-languages/schemas/gxformat2/common/common.yaml"; + +/** + * All gxformat2 version 19_09 schema documents. + * + * These documents are raw yaml documents loaded by webpack. + * */ +export const SCHEMA_DOCS_v19_09 = [ + schema_common_metaschema_base, + schema_v19_09_process, + schema_common, + schema_v19_09_workflows, +]; diff --git a/server/gx-workflow-ls-format2/src/types.d.ts b/server/gx-workflow-ls-format2/src/types.d.ts new file mode 100644 index 0000000..6383136 --- /dev/null +++ b/server/gx-workflow-ls-format2/src/types.d.ts @@ -0,0 +1,4 @@ +declare module "*.yaml" { + const data: any; + export default data; +} diff --git a/server/package-lock.json b/server/package-lock.json index 0be7312..61fd9f6 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -24,8 +24,7 @@ "vscode-languageserver-textdocument": "^1.0.4", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.3" - }, - "devDependencies": {} + } }, "gx-workflow-ls-native": { "version": "0.1.0", diff --git a/workflow-languages/schemas/gxformat2/common/common.yaml b/workflow-languages/schemas/gxformat2/common/common.yaml new file mode 100644 index 0000000..808dd0f --- /dev/null +++ b/workflow-languages/schemas/gxformat2/common/common.yaml @@ -0,0 +1,93 @@ +saladVersion: v1.1 +$base: "https://galaxyproject.org/gxformat2/gxformat2common#" + +$graph: + - name: HasUUID + type: record + abstract: true + fields: + - name: uuid + type: string? + doc: | + UUID uniquely representing this element. + + - name: HasStepErrors + type: record + abstract: true + fields: + - name: errors + type: string? + doc: | + During Galaxy export there may be some problem validating the tool state, tool used, etc.. + that will be indicated by this field. The Galaxy user should be warned of these problems before + the workflow can be used in Galaxy. + + This field should not be used in human written Galaxy workflow files. + + A typical problem is the referenced tool is not installed, this can be fixed by installed the tool + and re-saving the workflow and then re-exporting it. + + - name: HasStepPosition + type: record + abstract: true + fields: + - name: position + type: StepPosition? + + - name: StepPosition + type: record + doc: This field specifies the location of the step's node when rendered in the workflow editor. + fields: + - name: top + type: + - float + - int + default: 0.0 + doc: | + Relative vertical position of the step's node when rendered in the workflow editor. + - name: left + type: + - float + - int + default: 0.0 + doc: | + Relative horizontal position of the step's node when rendered in the workflow editor. + + - name: ReferencesTool + type: record + abstract: true + fields: + - name: tool_id + type: string? + doc: | + The tool ID used to run this step of the workflow (e.g. 'cat1' or 'toolshed.g2.bx.psu.edu/repos/nml/collapse_collections/collapse_dataset/4.0'). + - name: tool_shed_repository + type: ToolShedRepository? + doc: | + The Galaxy Tool Shed repository that should be installed in order to use this tool. + - name: tool_version + type: string? + doc: | + The tool version corresponding used to run this step of the workflow. For tool shed installed tools, the ID generally uniquely specifies a version + and this field is optional. + + - name: ToolShedRepository + type: record + fields: + - name: changeset_revision + type: string + doc: | + The revision of the tool shed repository this tool can be found in. + - name: name + type: string + jsonldPredicate: "@id" # will this bite me? + doc: | + The name of the tool shed repository this tool can be found in. + - name: owner + type: string + doc: | + The owner of the tool shed repository this tool can be found in. + - name: tool_shed + type: string + doc: | + The URI of the tool shed containing the repository this tool can be found in - typically this should be toolshed.g2.bx.psu.edu. diff --git a/workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml b/workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml new file mode 100644 index 0000000..cc4fab4 --- /dev/null +++ b/workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml @@ -0,0 +1,169 @@ +$base: "https://w3id.org/cwl/salad#" + +$namespaces: + sld: "https://w3id.org/cwl/salad#" + dct: "http://purl.org/dc/terms/" + rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + rdfs: "http://www.w3.org/2000/01/rdf-schema#" + xsd: "http://www.w3.org/2001/XMLSchema#" + +$graph: + - name: "Schema" + type: documentation + doc: | + # Schema + + - name: Documented + type: record + abstract: true + docParent: "#Schema" + fields: + - name: doc + type: + - string? + - string[]? + doc: "A documentation string for this object, or an array of strings which should be concatenated." + jsonldPredicate: "rdfs:comment" + + - name: PrimitiveType + type: enum + symbols: + - "sld:null" + - "xsd:boolean" + - "xsd:int" + - "xsd:long" + - "xsd:float" + - "xsd:double" + - "xsd:string" + doc: + - | + Salad data types are based on Avro schema declarations. Refer to the + [Avro schema declaration documentation](https://avro.apache.org/docs/current/spec.html#schemas) for + detailed information. + - "null: no value" + - "boolean: a binary value" + - "int: 32-bit signed integer" + - "long: 64-bit signed integer" + - "float: single precision (32-bit) IEEE 754 floating-point number" + - "double: double precision (64-bit) IEEE 754 floating-point number" + - "string: Unicode character sequence" + + - name: Any + type: enum + symbols: ["#Any"] + docAfter: "#PrimitiveType" + doc: | + The **Any** type validates for any non-null value. + + - name: RecordField + type: record + extends: Documented + doc: A field of a record. + fields: + - name: name + type: string + jsonldPredicate: "@id" + doc: | + The name of the field + + - name: type + type: + - PrimitiveType + - RecordSchema + - EnumSchema + - ArraySchema + - string + - type: array + items: + - PrimitiveType + - RecordSchema + - EnumSchema + - ArraySchema + - string + jsonldPredicate: + _id: sld:type + _type: "@vocab" + typeDSL: true + refScope: 2 + doc: | + The field type + + - name: RecordSchema + type: record + fields: + type: + doc: "Must be `record`" + type: + type: enum + symbols: + - "sld:record" + jsonldPredicate: + _id: "sld:type" + _type: "@vocab" + typeDSL: true + refScope: 2 + fields: + type: RecordField[]? + jsonldPredicate: + _id: sld:fields + mapSubject: name + mapPredicate: type + doc: "Defines the fields of the record." + + - name: EnumSchema + type: record + doc: | + Define an enumerated type. + fields: + type: + doc: "Must be `enum`" + type: + type: enum + symbols: + - "sld:enum" + jsonldPredicate: + _id: "sld:type" + _type: "@vocab" + typeDSL: true + refScope: 2 + symbols: + type: string[] + jsonldPredicate: + _id: "sld:symbols" + _type: "@id" + identity: true + doc: "Defines the set of valid symbols." + + - name: ArraySchema + type: record + fields: + type: + doc: "Must be `array`" + type: + type: enum + symbols: + - "sld:array" + jsonldPredicate: + _id: "sld:type" + _type: "@vocab" + typeDSL: true + refScope: 2 + items: + type: + - PrimitiveType + - RecordSchema + - EnumSchema + - ArraySchema + - string + - type: array + items: + - PrimitiveType + - RecordSchema + - EnumSchema + - ArraySchema + - string + jsonldPredicate: + _id: "sld:items" + _type: "@vocab" + refScope: 2 + doc: "Defines the type of the array elements." diff --git a/workflow-languages/schemas/gxformat2/v19_09/process.yaml b/workflow-languages/schemas/gxformat2/v19_09/process.yaml new file mode 100644 index 0000000..ffa5073 --- /dev/null +++ b/workflow-languages/schemas/gxformat2/v19_09/process.yaml @@ -0,0 +1,101 @@ +# Subset of CWL's process, can't use process as is because of types not implemented. +saladVersion: v1.1 +$base: "https://w3id.org/cwl/cwl#" + +$namespaces: + cwl: "https://w3id.org/cwl/cwl#" + sld: "https://w3id.org/cwl/salad#" + rdfs: "http://www.w3.org/2000/01/rdf-schema#" + +$graph: + - name: Labeled + type: record + abstract: true + fields: + - name: label + type: + - "null" + - string + jsonldPredicate: "rdfs:label" + doc: "A short, human-readable label of this object." + + - name: Identified + type: record + abstract: true + fields: + - name: id + type: string? + jsonldPredicate: "@id" + doc: "The unique identifier for this object." + + - name: Parameter + type: record + extends: [Labeled, sld:Documented, Identified] # Replaced FieldBase with Labeled. + abstract: true + doc: | + Define an input or output parameter to a process. + + - name: InputParameter + type: record + abstract: true + extends: [Parameter] # , InputFormat, LoadContents] + fields: + - name: default + type: Any? + jsonldPredicate: + _id: sld:default + noLinkCheck: true + doc: | + The default value to use for this parameter if the parameter is missing + from the input object, or if the value of the parameter in the input + object is `null`. Default values are applied before evaluating expressions + (e.g. dependent `valueFrom` fields). + + - name: OutputParameter + type: record + extends: [Parameter] + abstract: true + + - type: record + name: Process + extends: [Identified, Labeled, sld:Documented] + abstract: true + doc: | + + The base executable type in CWL is the `Process` object defined by the + document. Note that the `Process` object is abstract and cannot be + directly executed. + + fields: + - name: inputs + type: + type: array + items: InputParameter + jsonldPredicate: + _id: "cwl:inputs" + mapSubject: id + mapPredicate: type + doc: | + Defines the input parameters of the process. The process is ready to + run when all required input parameters are associated with concrete + values. Input parameters include a schema for each parameter which is + used to validate the input object. It may also be used to build a user + interface for constructing the input object. + + When accepting an input object, all input parameters must have a value. + If an input parameter is missing from the input object, it must be + assigned a value of `null` (or the value of `default` for that + parameter, if provided) for the purposes of validation and evaluation + of expressions. + + - name: outputs + type: + type: array + items: OutputParameter + jsonldPredicate: + _id: "cwl:outputs" + mapSubject: id + mapPredicate: type + doc: | + Defines the parameters representing the output of the process. May be + used to generate and/or validate the output object. diff --git a/workflow-languages/schemas/gxformat2/v19_09/workflows.yaml b/workflow-languages/schemas/gxformat2/v19_09/workflows.yaml new file mode 100644 index 0000000..7f50924 --- /dev/null +++ b/workflow-languages/schemas/gxformat2/v19_09/workflows.yaml @@ -0,0 +1,390 @@ +saladVersion: v1.1 +$base: "https://galaxyproject.org/gxformat2/v19_09#" + +$namespaces: + gxformat2: "https://galaxyproject.org/gxformat2/v19_09#" + gxformat2common: "https://galaxyproject.org/gxformat2/gxformat2common#" + cwl: "https://w3id.org/cwl/cwl#" + sld: "https://w3id.org/cwl/salad#" + rdfs: "http://www.w3.org/2000/01/rdf-schema#" + +$graph: + - name: "WorkflowDoc" + type: documentation + doc: + - | + # Galaxy Workflow Format 2 Description + + The traditional Galaxy workflow description (.ga) is not meant to be concise and is neither readily human readable or human writable. + Format 2 addresses all three of these limitations while also converging (where it makes sense without sacrificing these other goals) + with the workflow description with that used by the Common Workflow Language. + + This standard is in active development and a moving target in many ways, but we will try to keep what is ingestible by Galaxy + backward-compatible going forward. + + - $import: "../common/metaschema/metaschema_base.yml" + - $import: "./Process.yml" # trimmed down version of cwl's Process.yml + - $import: "../common/common.yml" + + - name: GalaxyType + type: enum + extends: sld:PrimitiveType + symbols: + - integer + - text + - File + - data + - collection + doc: + - "Extends primitive types with the native Galaxy concepts such datasets and collections." + - "integer: an alias for int type - matches syntax used by Galaxy tools" + - "text: an alias for string type - matches syntax used by Galaxy tools" + - "File: an alias for data - there are subtle differences between a plain file, the CWL concept of 'File', and the Galaxy concept of a dataset - this may have subtly difference semantics in the future" + - "data: a Galaxy dataset" + - "collection: a Galaxy dataset collection" + + - name: WorkflowStepType + type: enum + symbols: + - tool + - subworkflow + - pause + doc: + - | + Module types used by Galaxy steps. Galaxy's native format allows additional types such as data_input, data_input_collection, and parameter_type + but these should be represented as ``inputs`` in Format2. + - "tool: Run a tool." + - "subworkflow: Run a subworkflow." + - "pause: Pause computation on this branch of workflow until user allows it to continue." + + - name: WorkflowInputParameter + type: record + extends: + - cwl:InputParameter + - gxformat2common:HasStepPosition + docParent: "#GalaxyWorkflow" + fields: + - name: type + type: + - GalaxyType + - string + - "null" + default: data + jsonldPredicate: + "_id": "sld:type" + "_type": "@vocab" + refScope: 2 + typeDSL: True + doc: | + Specify valid types of data that may be assigned to this parameter. + - name: optional + type: + - boolean + - "null" + default: false + doc: | + If set to true, `WorkflowInputParameter` is not required to submit the workflow. + - name: format + doc: | + Specify datatype extension for valid input datasets. + type: + - "null" + - type: array + items: string + - name: collection_type + doc: | + Collection type (defaults to `list` if `type` is `collection`). Nested + collection types are separated with colons, e.g. `list:list:paired`. + type: + - "null" + - string + + - name: WorkflowOutputParameter + type: record + extends: cwl:OutputParameter + docParent: "#GalaxyWorkflow" + doc: | + Describe an output parameter of a workflow. The parameter must be + connected to one parameter defined in the workflow that + will provide the value of the output parameter. It is legal to + connect a WorkflowInputParameter to a WorkflowOutputParameter. + fields: + - name: outputSource + doc: | + Specifies workflow parameter that supply the value of to + the output parameter. + # Steps don't reference outputs in gxformat2 (yet anyway). + # Can we just link the step if before the / + #jsonldPredicate: + # "_id": "gxformat2:outputSource" + # "_type": "@id" + # refScope: 0 + type: + - string? + - name: type + type: GalaxyType? + default: data + jsonldPredicate: + "_id": "sld:type" + "_type": "@vocab" + refScope: 2 + typeDSL: True + doc: | + Specify valid types of data that may be assigned to this parameter. + + - name: WorkflowStep + type: record + extends: + - cwl:Identified + - cwl:Labeled + - sld:Documented + - gxformat2common:HasStepPosition + - gxformat2common:ReferencesTool + - gxformat2common:HasStepErrors + - gxformat2common:HasUUID + docParent: "#GalaxyWorkflow" + doc: | + This represents a non-input step a Galaxy Workflow. + + # A note about `state` and `tool_state` fields. + + Only one or the other should be specified. These are two ways to represent the "state" + of a tool at this workflow step. Both are essentially maps from parameter names to + parameter values. + + `tool_state` is much more low-level and expects a flat dictionary with each value a JSON + dump. Nested tool structures such as conditionals and repeats should have all their values + in the JSON dumped string. In general `tool_state` may be present in workflows exported from + Galaxy but shouldn't be written by humans. + + `state` can contained a typed map. Repeat values can be represented as YAML arrays. An alternative + to representing `state` this way is defining inputs with default values. + fields: + - name: in + type: WorkflowStepInput[]? + jsonldPredicate: + _id: "gxformat2:in" + mapSubject: id + mapPredicate: source + doc: | + Defines the input parameters of the workflow step. The process is ready to + run when all required input parameters are associated with concrete + values. Input parameters include a schema for each parameter which is + used to validate the input object. It may also be used build a user + interface for constructing the input object. + - name: out + type: + - type: array + items: [string, WorkflowStepOutput] + - "null" + jsonldPredicate: + _id: "gxformat2:out" + mapSubject: id + mapPredicate: source + doc: | + Defines the parameters representing the output of the process. May be + used to generate and/or validate the output object. + + This can also be called 'outputs' for legacy reasons - but the resulting + workflow document is not a valid instance of this schema. + - name: state + type: Any? + doc: | + Structured tool state. + jsonldPredicate: + _id: "gxformat2:state" + noLinkCheck: true + - name: tool_state + type: Any? + jsonldPredicate: + _id: "gxformat2:tool_state" + noLinkCheck: true + doc: | + Unstructured tool state. + - name: type + type: WorkflowStepType? + jsonldPredicate: + "_id": "sld:type" + "_type": "@vocab" + refScope: 2 + typeDSL: True + default: tool + doc: | + Workflow step module's type (defaults to 'tool'). + - name: run + type: + - "null" + - GalaxyWorkflow + jsonldPredicate: + _id: "cwl:run" + _type: "@id" + subscope: run + doc: | + Specifies a subworkflow to run. + - name: runtime_inputs + type: + - "null" + - type: array + items: string + #- name: when + # type: + # - "null" + # - string # TODO: cwl defines an enum for this, not sure how that works + # jsonldPredicate: + # _id: "gxformat2:when" + # noLinkCheck: true + # doc: | + # If defined, only run the step when the expression evaluates to + # `true`. If `false` the step is skipped. A skipped step + # produces a `null` on each output. + + # Expression should be an ecma5.1 expression. + + - name: Sink + type: record + abstract: true + fields: + - name: source + doc: | + Specifies one or more workflow parameters that will provide input to + the underlying step parameter. + jsonldPredicate: + "_id": "cwl:source" + "_type": "@id" + refScope: 2 + type: + - string? + - string[]? + + - type: record + name: WorkflowStepInput + extends: [cwl:Identified, Sink, cwl:Labeled] + docParent: "#WorkflowStep" + doc: | + TODO: + + fields: + - name: default + type: ["null", Any] + doc: | + The default value for this parameter to use if either there is no + `source` field, or the value produced by the `source` is `null`. The + default must be applied prior to scattering or evaluating `valueFrom`. + jsonldPredicate: + _id: "sld:default" + noLinkCheck: true + + - type: record + name: Report + doc: | + Definition of an invocation report for this workflow. Currently the only + field is 'markdown'. + fields: + - name: markdown + type: string + doc: | + Galaxy flavored Markdown to define an invocation report. + + - type: record + name: WorkflowStepOutput + docParent: "#WorkflowStep" + extends: cwl:Identified + doc: | + Associate an output parameter of the underlying process with a workflow + parameter. The workflow parameter (given in the `id` field) be may be used + as a `source` to connect with input parameters of other workflow steps, or + with an output parameter of the process. + + A unique identifier for this workflow output parameter. This is + the identifier to use in the `source` field of `WorkflowStepInput` + to connect the output value to downstream parameters. + fields: + rename: + type: string? + hide: + type: boolean? + delete_intermediate_datasets: + type: boolean? + change_datatype: + type: string? + set_columns: + type: + - "null" + - type: array + items: string + add_tags: + type: + - "null" + - type: array + items: string + remove_tags: + type: + - "null" + - type: array + items: string + + - name: GalaxyWorkflow + type: record + extends: + - cwl:Process + - gxformat2common:HasUUID + specialize: + - specializeFrom: cwl:InputParameter + specializeTo: WorkflowInputParameter + - specializeFrom: cwl:OutputParameter + specializeTo: WorkflowOutputParameter + documentRoot: true + doc: | + A Galaxy workflow description. This record corresponds to the description of a workflow that should be executable + on a Galaxy server that includes the contained tool definitions. + + The workflows API or the user interface of Galaxy instances that are of version 19.09 or newer should be able to + import a document defining this record. + + ## A note about `label` field. + + This is the name of the workflow in the Galaxy user interface. This is the mechanism that + users will primarily identify the workflow using. Legacy support - this may also be called 'name' and Galaxy will + consume the workflow document fine and treat this attribute correctly - however in order to validate against this + workflow definition schema the attribute should be called `label`. + fields: + # I can't find a way to override the documentation of label, even though I contextual. + # - name: label + # type: + # - "null" + # - string + # jsonldPredicate: "rdfs:label" + # doc: {$include: ../common/workflow_label_description.txt} + # # Legacy support - this may also be called 'name' and Galaxy will consume the workflow fine and treat this + # # attribute correctly - however in order to validate against this schema the attribute should be called label. + - name: "class" + jsonldPredicate: + "_id": "@type" + "_type": "@vocab" + type: string + - name: steps + doc: { $include: ../common/steps_description.txt } + type: + - type: array + items: "#WorkflowStep" + jsonldPredicate: + mapSubject: id + - name: report + doc: Workflow invocation report template. + type: Report? + - name: tags + type: + - type: array + items: string + - "null" + doc: | + Tags for the workflow. + - name: creator + type: Any? + doc: Can be a schema.org Person (https://schema.org/Person) or Organization (https://schema.org/Organization) entity + - name: license + type: string? + doc: Must be a valid license listed at https://spdx.org/licenses/ + - name: release + type: string? + doc: If listed should correspond to the release of the workflow in its source reposiory. From e52ea6fe644a193cc27c315c40484bf6e77818ea Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 18 Jul 2022 21:43:05 +0200 Subject: [PATCH 03/50] Add `getPathFromNode` to NodeManager --- .../server-common/src/ast/nodeManager.ts | 19 ++++++++++++++++++- .../packages/server-common/src/ast/types.ts | 9 +++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/server/packages/server-common/src/ast/nodeManager.ts b/server/packages/server-common/src/ast/nodeManager.ts index ecd3726..939962b 100644 --- a/server/packages/server-common/src/ast/nodeManager.ts +++ b/server/packages/server-common/src/ast/nodeManager.ts @@ -1,5 +1,5 @@ import { Position, Range, TextDocument } from "../languageTypes"; -import { ParsedDocument, ASTNode, ObjectASTNode } from "./types"; +import { ParsedDocument, ASTNode, ObjectASTNode, NodePath } from "./types"; import { findNodeAtOffset, getPropertyNodeFromPath } from "./utils"; export class ASTNodeManager { @@ -75,6 +75,23 @@ export class ASTNodeManager { return getPropertyNodeFromPath(root, path); } + public getPathFromNode(node: ASTNode): NodePath { + if (!node.parent || !node.parent.children) { + return []; + } + const path = this.getPathFromNode(node.parent); + if (node.parent.type === "property") { + const key = node.parent.children[0].value as string; + path.push(key); + } else if (node.parent.type === "array") { + const index = node.parent.children.indexOf(node); + if (index !== -1) { + path.push(index); + } + } + return path; + } + public getStepNodes(): ObjectASTNode[] { const root = this.root; if (!root) { diff --git a/server/packages/server-common/src/ast/types.ts b/server/packages/server-common/src/ast/types.ts index 5af7b5a..06ba51c 100644 --- a/server/packages/server-common/src/ast/types.ts +++ b/server/packages/server-common/src/ast/types.ts @@ -25,3 +25,12 @@ export { export interface ParsedDocument { root?: ASTNode; } + +/** + * A NodePath segment. Either a string representing an object property name + * or a number (starting at 0) for array indices. + */ +export type Segment = string | number; + +/** Represents the full path to a node. */ +export type NodePath = Segment[]; From 82dd4a812b26b031a41a5bc1bba7544ca493e0ca Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 18 Jul 2022 21:59:26 +0200 Subject: [PATCH 04/50] Add `getNodeFromOffset` to YamlDocument --- .../yaml-language-service/src/parser/yamlDocument.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server/packages/yaml-language-service/src/parser/yamlDocument.ts b/server/packages/yaml-language-service/src/parser/yamlDocument.ts index faa8310..c0aba22 100644 --- a/server/packages/yaml-language-service/src/parser/yamlDocument.ts +++ b/server/packages/yaml-language-service/src/parser/yamlDocument.ts @@ -3,7 +3,7 @@ import { TextDocument } from "vscode-languageserver-textdocument"; import { Diagnostic, DiagnosticSeverity, Position } from "vscode-languageserver-types"; import { Document, Node, visit, YAMLError, YAMLWarning } from "yaml"; import { TextBuffer } from "../utils/textBuffer"; -import { ASTNode } from "./astTypes"; +import { ASTNode, ObjectASTNodeImpl } from "./astTypes"; const FULL_LINE_ERROR = true; const YAML_SOURCE = "YAML"; @@ -92,6 +92,16 @@ export class YAMLDocument implements ParsedDocument { return this.collectLineComments(); } + /** + * Gets the syntax node at this document offset. + * @param offset The offset in the text document + * @returns The syntax node that lies at the given offset + */ + public getNodeFromOffset(offset: number): ASTNode | null { + const rootNode = this.root as ObjectASTNodeImpl; + return rootNode?.getNodeFromOffsetEndInclusive(offset); + } + /** Collects all syntax errors and warnings found on this document. */ private getSyntaxDiagnostics(): Diagnostic[] { const syntaxErrors = this.subDocuments.flatMap((subDoc) => From be95abefd4b5ecfdcad5e533d65604e2376b7d6e Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:07:32 +0200 Subject: [PATCH 05/50] WIP: explore schema parsing (experimental) --- .../src/schema/definitions.ts | 257 ++++++++++++++++++ .../src/schema/schemaLoader.ts | 243 +++++++++++++++++ .../src/schema/{v19_09.ts => versions.ts} | 13 +- 3 files changed, 507 insertions(+), 6 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/schema/definitions.ts create mode 100644 server/gx-workflow-ls-format2/src/schema/schemaLoader.ts rename server/gx-workflow-ls-format2/src/schema/{v19_09.ts => versions.ts} (61%) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts new file mode 100644 index 0000000..28d93d8 --- /dev/null +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -0,0 +1,257 @@ +import { NodePath } from "@gxwf/server-common/src/ast/types"; + +export interface SchemaDocument { + $base: string; + $namespaces?: object; + $graph: SchemaEntryBase[]; +} + +export interface SchemaEntryBase { + name: string; + type: string | string[] | unknown; + documentRoot?: boolean; +} + +export interface DocumentedSchemaEntry extends SchemaEntryBase { + doc?: string; +} + +export interface SchemaField extends DocumentedSchemaEntry { + default?: unknown; +} + +export interface SchemaRecord extends DocumentedSchemaEntry { + fields: SchemaField[]; + extends?: string[]; +} + +export interface SchemaEnum extends DocumentedSchemaEntry { + symbols: string[]; +} + +interface SchemaType { + type: string; +} + +interface SchemaEnumType extends SchemaType { + symbols: string[]; +} + +interface SchemaArrayType extends SchemaType { + items: string; +} + +export function isSchemaEntryBase(object: unknown): object is SchemaEntryBase { + return object instanceof Object && "type" in object; +} + +export function isSchemaRecord(object: unknown): object is SchemaRecord { + return object instanceof Object && "fields" in object; +} + +export function isSchemaEnumType(object: unknown): object is SchemaEnumType { + return object instanceof Object && "symbols" in object; +} + +export function isSchemaArrayType(object: unknown): object is SchemaArrayType { + return object instanceof Object && "items" in object; +} + +export function isArrayFieldType(object: unknown): object is ArrayFieldType { + return object instanceof Object && "itemTypeName" in object; +} + +export type SchemaEntry = SchemaEnum | SchemaRecord; + +interface FieldType { + isOptional: boolean; +} + +interface BasicFieldType extends FieldType { + typeName: string; +} + +interface ArrayFieldType extends FieldType { + itemTypeName: string; +} + +interface EnumFieldType extends FieldType { + symbols: string[]; +} + +function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { + if (typeof typeEntry === "string") { + let baseType: string = typeEntry; + const isOptional = baseType.endsWith("?"); + if (isOptional) { + baseType = baseType.slice(0, baseType.length - 1); + } + const isArray = baseType.endsWith("[]"); + if (isArray) { + baseType = baseType.slice(0, baseType.length - 2); + const arrayType: ArrayFieldType = { + isOptional, + itemTypeName: baseType, + }; + return arrayType; + } + const basicType: BasicFieldType = { + isOptional, + typeName: baseType, + }; + return basicType; + } + + if (typeof typeEntry === "object") { + if (isSchemaArrayType(typeEntry)) { + const arrayType: ArrayFieldType = { + isOptional: false, + itemTypeName: (typeEntry as SchemaArrayType).items, + }; + return arrayType; + } + if (isSchemaEnumType(typeEntry)) { + const enumType: EnumFieldType = { + isOptional: false, + symbols: (typeEntry as SchemaEnumType).symbols, + }; + return enumType; + } + console.debug(`Field type unknown: ${JSON.stringify(typeEntry)}`); + return undefined; + } +} + +interface SchemaNode { + name: string; + children: SchemaNode[]; + documentation: string | undefined; + supportsArray: boolean; +} + +export class Field implements SchemaNode { + private _allowedTypes: FieldType[] = []; + private readonly _schemaField: SchemaField; + constructor(schemaField: SchemaField) { + this._schemaField = schemaField; + if (schemaField.type instanceof Array) { + schemaField.type.forEach((typeEntry) => { + const fieldType = fieldTypeFactory(typeEntry); + if (fieldType) { + this._allowedTypes.push(fieldType); + } + }); + } else { + const fieldType = fieldTypeFactory(schemaField.type); + if (fieldType) { + this._allowedTypes.push(fieldType); + } + } + } + + public get name(): string { + return this._schemaField.name; + } + + public get documentation(): string | undefined { + return this._schemaField.doc; + } + + public get typesAllowed(): FieldType[] { + return this._allowedTypes; + } + + public get children(): SchemaNode[] { + return []; + } + + public get supportsArray(): boolean { + return this._allowedTypes.some((t) => isArrayFieldType(t)); + } + + public getArrayItemTypeName(): string | undefined { + const arrayType = this._allowedTypes.find((t) => isArrayFieldType(t)) as ArrayFieldType; + return arrayType?.itemTypeName; + } +} + +class SchemaRecordNode implements SchemaNode { + public static readonly ROOT_NAME: string = "_root_"; + + private readonly _schemaRecord: SchemaRecord; + private readonly _fields: Map; + + constructor(schemaRecord: SchemaRecord) { + this._schemaRecord = schemaRecord; + this._fields = new Map(); + schemaRecord.fields.forEach((field) => { + this._fields.set(field.name, new Field(field)); + }); + } + + public get name(): string { + return this._schemaRecord.name; + } + + public get fields(): Field[] { + return Array.from(this._fields.values()); + } + + public get documentation(): string | undefined { + return this._schemaRecord.doc; + } + + public get children(): SchemaNode[] { + return this.fields; + } + + public get supportsArray(): boolean { + return false; + } +} + +export class ResolvedSchema { + public readonly root?: SchemaNode; + constructor(public readonly typeMap: Map, rootRecord?: SchemaRecord) { + this.root = rootRecord ? new SchemaRecordNode(rootRecord) : undefined; + } + + public resolveSchemaContext(path: NodePath): SchemaNode | undefined { + let currentSchemaNode = this.root; + const toWalk = path.slice().reverse(); + let next = toWalk.pop(); + while (next) { + console.debug(`EXPLORING: ${next}`); + if (typeof next === "string") { + const child = currentSchemaNode?.children.find((c) => c.name === next); + if (child) { + console.debug(` FIELD FOUND: ${child.name}`); + currentSchemaNode = child; + } else { + console.debug(` FIELD NOT FOUND: ${next}`); + if (currentSchemaNode?.supportsArray) { + const fieldSchemaNode = currentSchemaNode as Field; + let arrayItemTypeName = fieldSchemaNode.getArrayItemTypeName(); + if (arrayItemTypeName) { + // For some reason types may start with # + if (arrayItemTypeName.startsWith("#")) { + arrayItemTypeName = arrayItemTypeName.slice(1); + } + const arrayType = this.typeMap.get(arrayItemTypeName); + if (isSchemaRecord(arrayType)) { + currentSchemaNode = new SchemaRecordNode(arrayType as SchemaRecord); + } else { + console.debug(`TYPE NOT PROCESSED: ${JSON.stringify(arrayType)}`); + } + } + } + } + } else { + console.debug("NOT A STRING"); + } + + next = toWalk.pop(); + } + return currentSchemaNode; + } +} diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts new file mode 100644 index 0000000..4252a2c --- /dev/null +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -0,0 +1,243 @@ +import { + SchemaRecord, + SchemaEntry, + SchemaDocument, + SchemaEntryBase, + SchemaEnum, + SchemaField, + isSchemaEntryBase, + isSchemaRecord, + Field, + ResolvedSchema, +} from "./definitions"; +import { SCHEMA_DOCS_v19_09_MAP } from "./versions"; + +export class GalaxyWorkflowFormat2SchemaLoader { + private _root?: SchemaRecord; + private _typeMap = new Map(); + private _documentTypeMap = new Map>(); + private _namespaces = new Map(); + public readonly resolvedSchema: ResolvedSchema; + + private _unknownTypes: string[] = []; + private _extendedTypes: Set = new Set(); + constructor() { + this.loadSchema_v19_09(); + this.resolvedSchema = this.resolveSchema(); + + if (this._unknownTypes) { + console.debug(`UNKNOWN Types: ${this._unknownTypes.length}`); + this._unknownTypes.forEach((t) => { + console.debug(` ${t}`); + }); + } + + if (this._extendedTypes) { + console.debug(`EXTENDED Types (Unresolved): ${this._extendedTypes.size}`); + this._extendedTypes.forEach((type) => { + if (!this._typeMap.has(type)) { + console.debug(` ${type} ${this._typeMap.has(type) ? "[found]" : ""}`); + } + }); + } + } + + private loadSchema_v19_09(): void { + SCHEMA_DOCS_v19_09_MAP.forEach((schemaDoc) => { + const types = this.loadSchemaDocument(schemaDoc); + types.forEach((v, k) => { + this._typeMap.set(k, v); + }); + }); + } + + private loadSchemaDocument(schemaDoc: SchemaDocument): Map { + console.debug(`Loading schema doc: ${schemaDoc.$base}`); + this.registerDocumentNamespaces(schemaDoc); + const documentEntries = new Map(); + schemaDoc.$graph.forEach((entry: SchemaEntryBase) => { + let loadedEntry: SchemaEntry | undefined; + if (entry.type == "enum") { + loadedEntry = this.loadEnum(entry as SchemaEnum); + } else if (entry.type == "record") { + const recordEntry = this.loadRecord(entry as SchemaRecord); + if (entry.documentRoot) { + this._root = recordEntry; + } + loadedEntry = recordEntry; + } else { + this._unknownTypes.push(entry.type as string); + } + if (loadedEntry) { + documentEntries.set(entry.name, loadedEntry); + } + }); + this._documentTypeMap.set(schemaDoc.$base, documentEntries); + return documentEntries; + } + + private registerDocumentNamespaces(schemaDoc: SchemaDocument): void { + if (schemaDoc.$namespaces) { + Object.entries(schemaDoc.$namespaces).forEach(([k, v]) => { + this._namespaces.set(k, v); + }); + } + } + + private loadEnum(entry: SchemaEnum): SchemaEnum { + console.debug(`Enum: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""}`); + const enumEntry: SchemaEnum = { + name: entry.name, + type: entry.type, + doc: entry.doc, + symbols: entry.symbols, + }; + + return enumEntry; + } + + private loadRecord(entry: SchemaRecord): SchemaRecord { + console.debug( + `Record: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""} ${"extends" in entry ? "[extends]" : ""}` + ); + const fields = this.readEntryFields(entry); + + const recordEntry: SchemaRecord = { + name: entry.name, + type: entry.type, + doc: entry.doc, + fields: fields, + extends: entry.extends ? (entry.extends instanceof Array ? [...entry.extends] : [entry.extends]) : [], + }; + + if (recordEntry.extends) { + if (recordEntry.extends instanceof Array) { + recordEntry.extends.forEach((type) => { + this._extendedTypes.add(type); + }); + } else { + this._extendedTypes.add(recordEntry.extends); + } + } + + return recordEntry; + } + + private readEntryFields(entry: SchemaRecord): SchemaField[] { + const fields: SchemaField[] = []; + if (entry.fields instanceof Array) { + entry.fields.forEach((field) => { + fields.push(this.loadField(field)); + }); + } else { + // Is an Object + if (entry.fields) { + Object.entries(entry.fields).forEach(([key, value]) => { + console.debug(`Object Field: ${key} ${value}`); + if (isSchemaEntryBase(value)) { + fields.push({ name: key, type: value.type }); + } + }); + } else { + console.debug("------- NO FIELDS"); + } + } + if (fields) { + fields.forEach((field) => { + console.debug(` ${field.name}: ${field.type}`); + }); + } + return fields; + } + + private loadField(field: SchemaField): SchemaField { + let fieldType = field.type; + + if (fieldType instanceof String) { + fieldType = this.resolveTypeName(fieldType as string); + } else if (fieldType instanceof Array) { + //TODO Fix + fieldType = fieldType.at(0) ?? ""; + } else { + console.debug(` --Field type NOT string: ${fieldType} -> ${typeof fieldType}`); + } + return { name: field.name, type: fieldType, default: field.default, doc: field.doc }; + } + + private resolveTypeName(rawTypeName: string): string { + const tokens = rawTypeName.split(":"); + if (tokens.length > 1) { + const namespace = tokens.at(0); + const type = tokens.at(1); + if (namespace && type) { + const docBase = this._namespaces.get(namespace); + if (docBase) { + const schemaTypes = this._documentTypeMap.get(docBase); + if (schemaTypes?.has(type)) { + rawTypeName = type; + } else { + console.debug(`Type ${type} not found in namespace ${namespace}.`); + } + } else { + console.debug(`Namespace ${namespace} not found.`); + } + } + } + return rawTypeName; + } + + private resolveTypeToSchemaEntry(rawTypeName: string): SchemaEntry { + const typeName = this.resolveTypeName(rawTypeName); + if (this._typeMap.has(typeName)) { + return this._typeMap.get(typeName) as SchemaEntry; + } + throw new Error(`Unresolvable type ${rawTypeName}`); + } + + private resolveSchema(): ResolvedSchema { + this.expandRecords(); + this.resolveFields(); + return new ResolvedSchema(this._typeMap, this._root); + } + + private resolveFields(): void { + this._typeMap.forEach((value: SchemaEntry) => { + if (isSchemaRecord(value)) { + value.fields.forEach((field) => { + new Field(field); + }); + } + }); + } + + /** Expands all records with the fields defined in the extended types.*/ + private expandRecords(): void { + this._typeMap.forEach((value: SchemaEntry) => { + if (isSchemaRecord(value)) { + this.expandRecord(value); + } + }); + } + + private expandRecord(record: SchemaRecord): SchemaRecord { + if (!record.extends) { + return record; + } + const extensionFields = this.collectExtensionFields(record, []); + record.fields.push(...extensionFields); + record.extends = []; + return record; + } + + private collectExtensionFields(record: SchemaRecord, extensionFields: SchemaField[]): SchemaField[] { + record.extends?.forEach((typeToExtend) => { + console.debug(`RESOLVE ${typeToExtend}`); + const resolved = this.resolveTypeToSchemaEntry(typeToExtend); + if (isSchemaRecord(resolved)) { + extensionFields.push(...resolved.fields); + return this.collectExtensionFields(resolved, extensionFields); + } + }); + return extensionFields; + } +} diff --git a/server/gx-workflow-ls-format2/src/schema/v19_09.ts b/server/gx-workflow-ls-format2/src/schema/versions.ts similarity index 61% rename from server/gx-workflow-ls-format2/src/schema/v19_09.ts rename to server/gx-workflow-ls-format2/src/schema/versions.ts index 75fe1eb..db86e21 100644 --- a/server/gx-workflow-ls-format2/src/schema/v19_09.ts +++ b/server/gx-workflow-ls-format2/src/schema/versions.ts @@ -2,15 +2,16 @@ import schema_v19_09_workflows from "../../../../workflow-languages/schemas/gxfo import schema_common_metaschema_base from "../../../../workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml"; import schema_v19_09_process from "../../../../workflow-languages/schemas/gxformat2/v19_09/process.yaml"; import schema_common from "../../../../workflow-languages/schemas/gxformat2/common/common.yaml"; +import { SchemaDocument } from "./definitions"; /** * All gxformat2 version 19_09 schema documents. * * These documents are raw yaml documents loaded by webpack. * */ -export const SCHEMA_DOCS_v19_09 = [ - schema_common_metaschema_base, - schema_v19_09_process, - schema_common, - schema_v19_09_workflows, -]; +export const SCHEMA_DOCS_v19_09_MAP = new Map([ + [schema_common_metaschema_base.$base, schema_common_metaschema_base], + [schema_v19_09_process.$base, schema_v19_09_process], + [schema_common.$base, schema_common], + [schema_v19_09_workflows.$base, schema_v19_09_workflows], +]); From 84f27a04b956cd69265a8f69e050088c5e411d8c Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:11:50 +0200 Subject: [PATCH 06/50] Add hover service for gxformat2 schema --- .../src/languageService.ts | 10 ++- .../src/services/hoverService.ts | 67 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/services/hoverService.ts diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index 9c36b7c..32fa2e1 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -12,6 +12,8 @@ import { } from "@gxwf/server-common/src/languageTypes"; import { LanguageService, getLanguageService } from "@gxwf/yaml-language-service/src/yamlLanguageService"; import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; +import { GalaxyWorkflowFormat2SchemaLoader } from "./schema/schemaLoader"; +import { GxFormat2HoverService } from "./services/hoverService"; /** * A wrapper around the YAML Language Service to support language features @@ -19,9 +21,13 @@ import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; */ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { private _yamlLanguageService: LanguageService; + private _schemaLoader: GalaxyWorkflowFormat2SchemaLoader; + private _hoverService: GxFormat2HoverService; constructor() { super(); + this._schemaLoader = new GalaxyWorkflowFormat2SchemaLoader(); this._yamlLanguageService = getLanguageService(); + this._hoverService = new GxFormat2HoverService(this._schemaLoader.resolvedSchema); } public override parseWorkflowDocument(document: TextDocument): WorkflowDocument { @@ -33,8 +39,8 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { return this._yamlLanguageService.doFormat(document, options); } - public override async doHover(workflowDocument: WorkflowDocument, position: Position): Promise { - return null; + public override doHover(workflowDocument: WorkflowDocument, position: Position): Promise { + return this._hoverService.doHover(workflowDocument.textDocument, position, workflowDocument.nodeManager); } public override async doComplete( diff --git a/server/gx-workflow-ls-format2/src/services/hoverService.ts b/server/gx-workflow-ls-format2/src/services/hoverService.ts new file mode 100644 index 0000000..569eb4a --- /dev/null +++ b/server/gx-workflow-ls-format2/src/services/hoverService.ts @@ -0,0 +1,67 @@ +import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; +import { NodePath } from "@gxwf/server-common/src/ast/types"; +import { Hover, MarkupContent, MarkupKind, Position, Range, TextDocument } from "@gxwf/server-common/src/languageTypes"; +import { ResolvedSchema } from "../schema/definitions"; + +export class GxFormat2HoverService { + constructor(protected readonly resolvedSchema: ResolvedSchema) {} + + //Based on https://github.com/microsoft/vscode-json-languageservice/blob/12275e448a91973777c94a2e5d92c961f281231a/src/services/jsonHover.ts#L23 + public async doHover( + textDocument: TextDocument, + position: Position, + nodeManager: ASTNodeManager + ): Promise { + const offset = textDocument.offsetAt(position); + let node = nodeManager.getNodeFromOffset(offset); + if ( + !node || + ((node.type === "object" || node.type === "array") && + offset > node.offset + 1 && + offset < node.offset + node.length - 1) + ) { + return Promise.resolve(null); + } + const hoverRangeNode = node; + + // use the property description when hovering over an object key + if (node.type === "string") { + const parent = node.parent; + if (parent && parent.type === "property" && parent.keyNode === node) { + node = parent.valueNode; + if (!node) { + return Promise.resolve(null); + } + } + } + + const hoverRange = Range.create( + textDocument.positionAt(hoverRangeNode.offset), + textDocument.positionAt(hoverRangeNode.offset + hoverRangeNode.length) + ); + + const location = nodeManager.getPathFromNode(hoverRangeNode); + const nodeDoc = this.getDocFromNodePath(location); + const contents = "**Debug Test**\n\n" + nodeDoc; + const hover = this.createHover(contents, hoverRange); + return Promise.resolve(hover); + } + + private getDocFromNodePath(path: NodePath): string { + const schemaNode = this.resolvedSchema.resolveSchemaContext(path); + if (!schemaNode) return "Node not found"; + return schemaNode.documentation || "Doc not found"; + } + + private createHover(contents: string, hoverRange: Range): Hover { + const markupContent: MarkupContent = { + kind: MarkupKind.Markdown, + value: contents, + }; + const result: Hover = { + contents: markupContent, + range: hoverRange, + }; + return result; + } +} From 242d521404f988d3709779d2bb5fe7702ab8a069 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:14:37 +0200 Subject: [PATCH 07/50] Fix hover provider content rendering When using MarkupContent --- .../server-common/src/providers/hover/hoverProvider.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/packages/server-common/src/providers/hover/hoverProvider.ts b/server/packages/server-common/src/providers/hover/hoverProvider.ts index e3aca38..094b924 100644 --- a/server/packages/server-common/src/providers/hover/hoverProvider.ts +++ b/server/packages/server-common/src/providers/hover/hoverProvider.ts @@ -28,7 +28,11 @@ export class HoverProvider extends Provider { return null; } const contentSections: string[] = [ - this.hoverHasEmptyContent(hover) ? `No documentation available` : `${hover.contents}`, + this.hoverHasEmptyContent(hover) + ? `No documentation available` + : MarkupContent.is(hover.contents) + ? hover.contents.value + : `${hover.contents}`, ]; this.contributors.forEach((contentContributor) => { const contributedContent = contentContributor.onHoverContent(workflowDocument, params.position); From 6c7a365187b9ced57ae9c4baca349543b1259053 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Wed, 20 Jul 2022 18:11:57 +0200 Subject: [PATCH 08/50] WIP: continue exploring schema parsing --- .../src/schema/definitions.ts | 131 +++++++++++------- .../src/schema/schemaLoader.ts | 74 +++++----- 2 files changed, 119 insertions(+), 86 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 28d93d8..471d192 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -58,10 +58,14 @@ export function isSchemaArrayType(object: unknown): object is SchemaArrayType { } export function isArrayFieldType(object: unknown): object is ArrayFieldType { - return object instanceof Object && "itemTypeName" in object; + return object instanceof Object && "itemType" in object; } -export type SchemaEntry = SchemaEnum | SchemaRecord; +export function isBasicFieldType(object: unknown): object is BasicFieldType { + return object instanceof Object && "typeName" in object; +} + +export type SchemaEntry = SchemaEnum | SchemaRecord | SchemaField; interface FieldType { isOptional: boolean; @@ -72,7 +76,7 @@ interface BasicFieldType extends FieldType { } interface ArrayFieldType extends FieldType { - itemTypeName: string; + itemType: FieldType; } interface EnumFieldType extends FieldType { @@ -91,24 +95,21 @@ function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { baseType = baseType.slice(0, baseType.length - 2); const arrayType: ArrayFieldType = { isOptional, - itemTypeName: baseType, + itemType: buildBasicFieldType(isOptional, baseType), }; return arrayType; } - const basicType: BasicFieldType = { - isOptional, - typeName: baseType, - }; - return basicType; - } - - if (typeof typeEntry === "object") { + return buildBasicFieldType(isOptional, baseType); + } else if (typeof typeEntry === "object") { if (isSchemaArrayType(typeEntry)) { - const arrayType: ArrayFieldType = { - isOptional: false, - itemTypeName: (typeEntry as SchemaArrayType).items, - }; - return arrayType; + const itemType = fieldTypeFactory((typeEntry as SchemaArrayType).items); + if (itemType) { + const arrayType: ArrayFieldType = { + isOptional: false, + itemType: itemType, + }; + return arrayType; + } } if (isSchemaEnumType(typeEntry)) { const enumType: EnumFieldType = { @@ -117,8 +118,17 @@ function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { }; return enumType; } - console.debug(`Field type unknown: ${JSON.stringify(typeEntry)}`); + console.debug(`Object Field type UNKNOWN: ${JSON.stringify(typeEntry)}`); return undefined; + } else { + console.debug(`Field type NOT PROCESSED: ${JSON.stringify(typeEntry)}`); + } + + function buildBasicFieldType(isOptional: boolean, baseType: string): BasicFieldType { + return { + isOptional, + typeName: baseType.replace("#", ""), + }; } } @@ -129,7 +139,7 @@ interface SchemaNode { supportsArray: boolean; } -export class Field implements SchemaNode { +export class FieldSchemaNode implements SchemaNode { private _allowedTypes: FieldType[] = []; private readonly _schemaField: SchemaField; constructor(schemaField: SchemaField) { @@ -171,21 +181,25 @@ export class Field implements SchemaNode { public getArrayItemTypeName(): string | undefined { const arrayType = this._allowedTypes.find((t) => isArrayFieldType(t)) as ArrayFieldType; - return arrayType?.itemTypeName; + if (isBasicFieldType(arrayType?.itemType)) { + return arrayType?.itemType.typeName; + } + console.debug("getArrayItemTypeName -> Type name not found"); + return undefined; } } -class SchemaRecordNode implements SchemaNode { +class RecordSchemaNode implements SchemaNode { public static readonly ROOT_NAME: string = "_root_"; private readonly _schemaRecord: SchemaRecord; - private readonly _fields: Map; + private readonly _fields: Map; constructor(schemaRecord: SchemaRecord) { this._schemaRecord = schemaRecord; - this._fields = new Map(); + this._fields = new Map(); schemaRecord.fields.forEach((field) => { - this._fields.set(field.name, new Field(field)); + this._fields.set(field.name, new FieldSchemaNode(field)); }); } @@ -193,7 +207,7 @@ class SchemaRecordNode implements SchemaNode { return this._schemaRecord.name; } - public get fields(): Field[] { + public get fields(): FieldSchemaNode[] { return Array.from(this._fields.values()); } @@ -212,42 +226,55 @@ class SchemaRecordNode implements SchemaNode { export class ResolvedSchema { public readonly root?: SchemaNode; - constructor(public readonly typeMap: Map, rootRecord?: SchemaRecord) { - this.root = rootRecord ? new SchemaRecordNode(rootRecord) : undefined; + constructor( + public readonly typeMap: Map, + public readonly fieldMap: Map, + rootRecord?: SchemaRecord + ) { + this.root = rootRecord ? new RecordSchemaNode(rootRecord) : undefined; } public resolveSchemaContext(path: NodePath): SchemaNode | undefined { - let currentSchemaNode = this.root; - const toWalk = path.slice().reverse(); + const currentSchemaNode = this.root; + const toWalk = path.slice(); //.reverse(); let next = toWalk.pop(); while (next) { - console.debug(`EXPLORING: ${next}`); if (typeof next === "string") { - const child = currentSchemaNode?.children.find((c) => c.name === next); - if (child) { - console.debug(` FIELD FOUND: ${child.name}`); - currentSchemaNode = child; - } else { - console.debug(` FIELD NOT FOUND: ${next}`); - if (currentSchemaNode?.supportsArray) { - const fieldSchemaNode = currentSchemaNode as Field; - let arrayItemTypeName = fieldSchemaNode.getArrayItemTypeName(); - if (arrayItemTypeName) { - // For some reason types may start with # - if (arrayItemTypeName.startsWith("#")) { - arrayItemTypeName = arrayItemTypeName.slice(1); - } - const arrayType = this.typeMap.get(arrayItemTypeName); - if (isSchemaRecord(arrayType)) { - currentSchemaNode = new SchemaRecordNode(arrayType as SchemaRecord); - } else { - console.debug(`TYPE NOT PROCESSED: ${JSON.stringify(arrayType)}`); - } - } + if (this.typeMap.has(next)) { + const record = this.typeMap.get(next); + if (isSchemaRecord(record)) { + return new RecordSchemaNode(record); + } + } + if (this.fieldMap.has(next)) { + const field = this.fieldMap.get(next); + if (field) { + return new FieldSchemaNode(field); } } + console.debug(`TYPE NOT FOUND, processing parent of... ${JSON.stringify(next)}`); + + // const child = currentSchemaNode?.children.find((c) => c.name === next); + // if (child) { + // // console.debug(` FIELD FOUND: ${child.name}`); + // currentSchemaNode = child; + // } else { + // // console.debug(` FIELD NOT FOUND: ${next}`); + // if (currentSchemaNode?.supportsArray) { + // const fieldSchemaNode = currentSchemaNode as Field; + // let arrayItemTypeName = fieldSchemaNode.getArrayItemTypeName(); + // if (arrayItemTypeName) { + // const arrayType = this.typeMap.get(arrayItemTypeName); + // if (isSchemaRecord(arrayType)) { + // currentSchemaNode = new SchemaRecordNode(arrayType as SchemaRecord); + // } else { + // console.debug(`TYPE NOT PROCESSED: ${JSON.stringify(arrayType)}`); + // } + // } + // } + // } } else { - console.debug("NOT A STRING"); + console.debug("NOT A STRING (SKIPPING)", next); } next = toWalk.pop(); diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index 4252a2c..1095724 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -7,7 +7,7 @@ import { SchemaField, isSchemaEntryBase, isSchemaRecord, - Field, + FieldSchemaNode, ResolvedSchema, } from "./definitions"; import { SCHEMA_DOCS_v19_09_MAP } from "./versions"; @@ -15,6 +15,7 @@ import { SCHEMA_DOCS_v19_09_MAP } from "./versions"; export class GalaxyWorkflowFormat2SchemaLoader { private _root?: SchemaRecord; private _typeMap = new Map(); + private _fieldsMap = new Map(); private _documentTypeMap = new Map>(); private _namespaces = new Map(); public readonly resolvedSchema: ResolvedSchema; @@ -25,21 +26,21 @@ export class GalaxyWorkflowFormat2SchemaLoader { this.loadSchema_v19_09(); this.resolvedSchema = this.resolveSchema(); - if (this._unknownTypes) { - console.debug(`UNKNOWN Types: ${this._unknownTypes.length}`); - this._unknownTypes.forEach((t) => { - console.debug(` ${t}`); - }); - } - - if (this._extendedTypes) { - console.debug(`EXTENDED Types (Unresolved): ${this._extendedTypes.size}`); - this._extendedTypes.forEach((type) => { - if (!this._typeMap.has(type)) { - console.debug(` ${type} ${this._typeMap.has(type) ? "[found]" : ""}`); - } - }); - } + // if (this._unknownTypes) { + // console.debug(`UNKNOWN Types: ${this._unknownTypes.length}`); + // this._unknownTypes.forEach((t) => { + // console.debug(` ${t}`); + // }); + // } + + // if (this._extendedTypes) { + // console.debug(`EXTENDED Types (Unresolved): ${this._extendedTypes.size}`); + // this._extendedTypes.forEach((type) => { + // if (!this._typeMap.has(type)) { + // console.debug(` ${type} ${this._typeMap.has(type) ? "[found]" : ""}`); + // } + // }); + // } } private loadSchema_v19_09(): void { @@ -47,6 +48,14 @@ export class GalaxyWorkflowFormat2SchemaLoader { const types = this.loadSchemaDocument(schemaDoc); types.forEach((v, k) => { this._typeMap.set(k, v); + if (isSchemaRecord(v)) { + v.fields.forEach((field) => { + if (this._fieldsMap.has(field.name)) { + console.debug("****** DUPLICATED FIELD", field.name); + } + this._fieldsMap.set(field.name, field); + }); + } }); }); } @@ -85,7 +94,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { } private loadEnum(entry: SchemaEnum): SchemaEnum { - console.debug(`Enum: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""}`); + // console.debug(`Enum: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""}`); const enumEntry: SchemaEnum = { name: entry.name, type: entry.type, @@ -97,9 +106,9 @@ export class GalaxyWorkflowFormat2SchemaLoader { } private loadRecord(entry: SchemaRecord): SchemaRecord { - console.debug( - `Record: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""} ${"extends" in entry ? "[extends]" : ""}` - ); + // console.debug( + // `Record: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""} ${"extends" in entry ? "[extends]" : ""}` + // ); const fields = this.readEntryFields(entry); const recordEntry: SchemaRecord = { @@ -133,7 +142,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { // Is an Object if (entry.fields) { Object.entries(entry.fields).forEach(([key, value]) => { - console.debug(`Object Field: ${key} ${value}`); + // console.debug(`Object Field: ${key} ${value}`); if (isSchemaEntryBase(value)) { fields.push({ name: key, type: value.type }); } @@ -142,24 +151,21 @@ export class GalaxyWorkflowFormat2SchemaLoader { console.debug("------- NO FIELDS"); } } - if (fields) { - fields.forEach((field) => { - console.debug(` ${field.name}: ${field.type}`); - }); - } + // if (fields) { + // fields.forEach((field) => { + // console.debug(` ${field.name}: ${field.type}`); + // }); + // } return fields; } private loadField(field: SchemaField): SchemaField { let fieldType = field.type; - if (fieldType instanceof String) { + if (typeof fieldType === "string") { fieldType = this.resolveTypeName(fieldType as string); - } else if (fieldType instanceof Array) { - //TODO Fix - fieldType = fieldType.at(0) ?? ""; } else { - console.debug(` --Field type NOT string: ${fieldType} -> ${typeof fieldType}`); + console.debug(` --Field type NOT string: ${JSON.stringify(fieldType)} -> ${typeof fieldType}`); } return { name: field.name, type: fieldType, default: field.default, doc: field.doc }; } @@ -197,14 +203,14 @@ export class GalaxyWorkflowFormat2SchemaLoader { private resolveSchema(): ResolvedSchema { this.expandRecords(); this.resolveFields(); - return new ResolvedSchema(this._typeMap, this._root); + return new ResolvedSchema(this._typeMap, this._fieldsMap, this._root); } private resolveFields(): void { this._typeMap.forEach((value: SchemaEntry) => { if (isSchemaRecord(value)) { value.fields.forEach((field) => { - new Field(field); + new FieldSchemaNode(field); }); } }); @@ -231,7 +237,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { private collectExtensionFields(record: SchemaRecord, extensionFields: SchemaField[]): SchemaField[] { record.extends?.forEach((typeToExtend) => { - console.debug(`RESOLVE ${typeToExtend}`); + // console.debug(`RESOLVE ${typeToExtend}`); const resolved = this.resolveTypeToSchemaEntry(typeToExtend); if (isSchemaRecord(resolved)) { extensionFields.push(...resolved.fields); From f7351947eacc8cfe16c587d5935ce99bbc2c6680 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Thu, 21 Jul 2022 17:17:03 +0200 Subject: [PATCH 09/50] Add more sample workflows for testing --- test-data/yaml/validation/test_wf_03.gxwf.yml | 19 ++++++++++ test-data/yaml/validation/test_wf_04.gxwf.yml | 35 +++++++++++++++++++ test-data/yaml/validation/test_wf_05.gxwf.yml | 25 +++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 test-data/yaml/validation/test_wf_03.gxwf.yml create mode 100644 test-data/yaml/validation/test_wf_04.gxwf.yml create mode 100644 test-data/yaml/validation/test_wf_05.gxwf.yml diff --git a/test-data/yaml/validation/test_wf_03.gxwf.yml b/test-data/yaml/validation/test_wf_03.gxwf.yml new file mode 100644 index 0000000..ba0c552 --- /dev/null +++ b/test-data/yaml/validation/test_wf_03.gxwf.yml @@ -0,0 +1,19 @@ +class: GalaxyWorkflow +inputs: + - label: input1 +steps: + - tool_id: cat1 + label: first_cat + state: + input1: + $link: input1 + - label: embed1 + run: + "@import": embed_test_1_tool.gxtool.yml + - tool_id: cat1 + state: + input1: + $link: first_cat/out_file1 + queries: + - input2: + $link: embed1/output1 diff --git a/test-data/yaml/validation/test_wf_04.gxwf.yml b/test-data/yaml/validation/test_wf_04.gxwf.yml new file mode 100644 index 0000000..6bd8696 --- /dev/null +++ b/test-data/yaml/validation/test_wf_04.gxwf.yml @@ -0,0 +1,35 @@ +class: GalaxyWorkflow +inputs: + outer_input: data +outputs: + outer_output: + outputSource: second_cat/out_file1 +steps: + first_cat: + tool_id: cat1 + in: + input1: outer_input + nested_workflow: + run: + class: GalaxyWorkflow + inputs: + - id: inner_input + outputs: + - outputSource: 1/out_file1 + steps: + random: + tool_id: random_lines1 + state: + num_lines: 1 + input: + $link: inner_input + seed_source: + seed_source_selector: set_seed + seed: asdf + in: + inner_input: first_cat/out_file1 + second_cat: + tool_id: cat1 + in: + input1: nested_workflow/1:out_file1 + queries_0|input2: nested_workflow/1:out_file1 diff --git a/test-data/yaml/validation/test_wf_05.gxwf.yml b/test-data/yaml/validation/test_wf_05.gxwf.yml new file mode 100644 index 0000000..973b6b6 --- /dev/null +++ b/test-data/yaml/validation/test_wf_05.gxwf.yml @@ -0,0 +1,25 @@ +class: GalaxyWorkflow +steps: + - type: input + label: input1 + - tool_id: cat1 + label: first_cat + state: + input1: + $link: 0 + - label: embed1 + run: + class: GalaxyTool + command: echo 'hello world 2' > $output1 + outputs: + output1: + format: txt + - tool_id: cat1 + state: + input1: + $link: first_cat/out_file1 + queries: + - input2: + $link: embed1/output1 +test_data: + input1: hello world From 379c63c924c203be53afc506a4e0d2b82bb7eb5a Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Thu, 21 Jul 2022 18:38:24 +0200 Subject: [PATCH 10/50] Add load support for yaml in jest tests I had to downgrade to jest 27 because of incompatibility issues with `jest-transform-yaml` --- jest.config.js | 11 +- package-lock.json | 4479 ++++++++++++++++++++++---------------- package.json | 5 +- server/jest.config.js | 11 +- server/tsconfig.json | 5 +- shared.webpack.config.js | 6 + tsconfig.json | 5 +- 7 files changed, 2644 insertions(+), 1878 deletions(-) diff --git a/jest.config.js b/jest.config.js index fe961f8..f2a4f70 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,10 @@ // For a detailed explanation regarding each configuration property, visit: // https://jestjs.io/docs/en/configuration.html +/* eslint-disable @typescript-eslint/no-var-requires */ +const { pathsToModuleNameMapper } = require("ts-jest"); +const { compilerOptions } = require("./tsconfig"); + module.exports = { preset: "ts-jest", globals: { @@ -12,5 +16,10 @@ module.exports = { testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/unit/*.test.ts"], // An array of file extensions your modules use - moduleFileExtensions: ["ts", "tsx", "js"], + moduleFileExtensions: ["ts", "tsx", "js", "yaml"], + transform: { + // ... other transforms ... + "\\.yaml$": "jest-transform-yaml", + }, + moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: "/" }), }; diff --git a/package-lock.json b/package-lock.json index 4cf92ae..2fcf64f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,14 +22,15 @@ "eslint": "^8.14.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.0.0", - "jest": "^28.0.3", + "jest": "^27.5.1", + "jest-transform-yaml": "^1.0.0", "merge-options": "^3.0.4", "mocha": "^9.2.2", "path-browserify": "^1.0.1", "prettier": "2.6.2", "process": "^0.11.10", "rimraf": "^3.0.2", - "ts-jest": "^28.0.1", + "ts-jest": "^27.1.5", "ts-loader": "^9.2.9", "typescript": "^4.6.3", "webpack": "^5.72.0", @@ -223,9 +224,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -532,12 +533,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.10.tgz", - "integrity": "sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -776,60 +777,59 @@ } }, "node_modules/@jest/console": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.0.2.tgz", - "integrity": "sha512-tiRpnMeeyQuuzgL5UNSeiqMwF8UOWPbAE5rzcu/1zyq4oPG2Ox6xm4YCOruwbp10F8odWc+XwVxTyGzMSLMqxA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^28.0.2", - "jest-util": "^28.0.2", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/core": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.0.3.tgz", - "integrity": "sha512-cCQW06vEZ+5r50SB06pOnSWsOBs7F+lswPYnKKfBz1ncLlj1sMqmvjgam8q40KhlZ8Ut4eNAL2Hvfx4BKIO2FA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "dependencies": { - "@jest/console": "^28.0.2", - "@jest/reporters": "^28.0.3", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "ci-info": "^3.2.0", + "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.0.2", - "jest-config": "^28.0.3", - "jest-haste-map": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-resolve-dependencies": "^28.0.3", - "jest-runner": "^28.0.3", - "jest-runtime": "^28.0.3", - "jest-snapshot": "^28.0.3", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", - "jest-watcher": "^28.0.2", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", "micromatch": "^4.0.4", - "pretty-format": "^28.0.2", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -840,151 +840,159 @@ } } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "node_modules/@jest/core/node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/@jest/environment": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.0.2.tgz", - "integrity": "sha512-IvI7dEfqVEffDYlw9FQfVBt6kXt/OI38V7QUIur0ulOQgzpKYJDVvLzj4B1TVmHWTGW5tcnJdlZ3hqzV6/I9Qg==", + "node_modules/@jest/core/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "@jest/fake-timers": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", "@types/node": "*", - "jest-mock": "^28.0.2" + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/@jest/expect": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.0.3.tgz", - "integrity": "sha512-VEzZr85bqNomgayQkR7hWG5HnbZYWYWagQriZsixhLmOzU6PCpMP61aeVhkCoRrg7ri5f7JDpeTPzDAajIwFHw==", + "node_modules/@jest/core/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true, - "dependencies": { - "expect": "^28.0.2", - "jest-snapshot": "^28.0.3" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/expect-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.0.2.tgz", - "integrity": "sha512-YryfH2zN5c7M8eLtn9oTBRj1sfD+X4cHNXJnTejqCveOS33wADEZUxJ7de5++lRvByNpRpfAnc8zTK7yrUJqgA==", + "node_modules/@jest/core/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "dependencies": { - "jest-get-type": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/@jest/expect-utils/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.0.2.tgz", - "integrity": "sha512-R75yUv+WeybPa4ZVhX9C+8XN0TKjUoceUX+/QEaDVQGxZZOK50eD74cs7iMDTtpodh00d8iLlc9197vgF6oZjA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", - "@sinonjs/fake-timers": "^9.1.1", + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^28.0.2", - "jest-mock": "^28.0.2", - "jest-util": "^28.0.2" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/globals": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.0.3.tgz", - "integrity": "sha512-q/zXYI6CKtTSIt1WuTHBYizJhH7K8h+xG5PE3C0oawLlPIvUMDYmpj0JX0XsJwPRLCsz/fYXHZVG46AaEhSPmw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "dependencies": { - "@jest/environment": "^28.0.2", - "@jest/expect": "^28.0.3", - "@jest/types": "^28.0.2" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/reporters": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.0.3.tgz", - "integrity": "sha512-xrbIc7J/xwo+D7AY3enAR9ZWYCmJ8XIkstTukTGpKDph0gLl/TJje9jl3dssvE4KJzYqMKiSrnE5Nt68I4fTEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.0.2", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", - "@jridgewell/trace-mapping": "^0.3.7", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.3", + "glob": "^7.1.2", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-util": "^28.0.2", - "jest-worker": "^28.0.2", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", + "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.0" + "v8-to-istanbul": "^8.1.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -995,132 +1003,172 @@ } } }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.0.2.tgz", - "integrity": "sha512-pijNxfjxT0tGAx+8+OzZ+eayVPCwy/rsZFhebmC0F4YnXu1EHPEPxg7utL3m5uX3EaFH1/jwDxGa1EbjJCST2g==", + "node_modules/@jest/reporters/node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/@jest/reporters/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/@jest/schemas": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", - "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "node_modules/@jest/reporters/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.23.3" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "node_modules/@jest/source-map": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", - "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.7", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/test-result": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.0.2.tgz", - "integrity": "sha512-4EUqgjq9VzyUiVTvZfI9IRJD6t3NYBNP4f+Eq8Zr93+hkJ0RrGU4OBTw8tfNzidKX+bmuYzn8FxqpxOPIGGCMA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "dependencies": { - "@jest/console": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/test-sequencer": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.0.2.tgz", - "integrity": "sha512-zhnZ8ydkZQTPL7YucB86eOlD79zPy5EGSUKiR2Iv93RVEDU6OEP33kwDBg70ywOcxeJGDRhyo09q7TafNCBiIg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "dependencies": { - "@jest/test-result": "^28.0.2", + "@jest/test-result": "^27.5.1", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", - "slash": "^3.0.0" + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/transform": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.0.3.tgz", - "integrity": "sha512-+Y0ikI7SwoW/YbK8t9oKwC70h4X2Gd0OVuz5tctRvSV/EDQU00AAkoqevXgPSSFimUmp/sp7Yl8s/1bExDqOIg==", + "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^28.0.2", - "@jridgewell/trace-mapping": "^0.3.7", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.0.2", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/@jest/test-sequencer/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/types": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.0.2.tgz", - "integrity": "sha512-hi3jUdm9iht7I2yrV5C4s3ucCJHUP8Eh3W6rQ1s4n/Qw9rQgsda4eqCt+r3BKRi7klVmZfQlMx1nGlzNMP2d8A==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^17.0.8", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jridgewell/gen-mapping": { @@ -1154,6 +1202,30 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", @@ -1161,9 +1233,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.10.tgz", - "integrity": "sha512-Q0YbBd6OTsXm8Y21+YUSDXupHnodNC2M4O18jtd3iwJ3+vMZNdKGols0a9G6JOK0dcJ3IdUUHoh908ZI6qhk8Q==", + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1205,12 +1277,6 @@ "node": ">= 8" } }, - "node_modules/@sinclair/typebox": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", - "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", - "dev": true - }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -1221,9 +1287,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" @@ -1339,9 +1405,9 @@ } }, "node_modules/@types/jest": { - "version": "27.5.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.0.tgz", - "integrity": "sha512-9RBFx7r4k+msyj/arpfaa0WOOEcaAZNmN+j80KFbFCoSqCJGHTz7YMAMGQW9Xmqm5w6l5c25vbSjMwlikJi5+g==", + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", "dev": true, "dependencies": { "jest-matcher-utils": "^27.0.0", @@ -1367,9 +1433,9 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", - "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", + "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, "node_modules/@types/stack-utils": { @@ -1391,9 +1457,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1804,6 +1870,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -1816,6 +1888,28 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/acorn-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", @@ -1834,6 +1928,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -1971,6 +2074,12 @@ "util": "^0.12.0" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -1983,27 +2092,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-jest": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.0.3.tgz", - "integrity": "sha512-S0ADyYdcrt5fp9YldRYWCUHdk1BKt9AkvBkLWBoNAEV9NoWZPIj5+MYhPcGgTS65mfv3a+Ymf2UqgWoAVd41cA==", - "dev": true, - "dependencies": { - "@jest/transform": "^28.0.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -2020,21 +2108,6 @@ "node": ">=8" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", - "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -2058,22 +2131,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/babel-preset-jest": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", - "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^28.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2148,6 +2205,12 @@ "node": ">=8" } }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -2403,7 +2466,7 @@ "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "engines": { "iojs": ">= 1.0.0", @@ -2440,6 +2503,18 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2518,6 +2593,44 @@ "node": ">= 8" } }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/date-fns": { "version": "2.28.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", @@ -2560,10 +2673,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "node_modules/deep-is": { @@ -2593,6 +2712,15 @@ "node": ">= 0.4" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2644,10 +2772,31 @@ "node": ">=6.0.0" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "dependencies": { "readable-stream": "^2.0.2" @@ -2660,12 +2809,12 @@ "dev": true }, "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", "dev": true, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -2804,6 +2953,88 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", @@ -3106,109 +3337,27 @@ "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/expect": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.0.2.tgz", - "integrity": "sha512-X0qIuI/zKv98k34tM+uGeOgAC73lhs4vROF9MkPk94C1zujtwv4Cla8SxhWn0G1OwvG9gLLL7RjFBkwGVaZ83w==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^28.0.2", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-util": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/expect/node_modules/diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/jest-diff": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.0.2.tgz", - "integrity": "sha512-33Rnf821Y54OAloav0PGNWHlbtEorXpjwchnToyyWbec10X74FOW7hGfvrXLGz7xOe2dz0uo9JVFAHHj/2B5pg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/jest-matcher-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.0.2.tgz", - "integrity": "sha512-SxtTiI2qLJHFtOz/bySStCnwCvISAuxQ/grS+74dfTy5AuJw3Sgj9TVUvskcnImTfpzLoMCDJseRaeRrVYbAOA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/expect/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3359,6 +3508,20 @@ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "dev": true }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3629,6 +3792,18 @@ "he": "bin/he" } }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -3671,6 +3846,18 @@ "node": ">=10.17.0" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -3782,7 +3969,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "node_modules/is-bigint": { @@ -3991,6 +4178,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4065,6 +4258,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -4173,9 +4372,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -4192,20 +4391,20 @@ "dev": true }, "node_modules/jest": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.0.3.tgz", - "integrity": "sha512-uS+T5J3w5xyzd1KSJCGKhCo8WTJXbNl86f5SW11wgssbandJOVLRKKUxmhdFfmKxhPeksl1hHZ0HaA8VBzp7xA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "dependencies": { - "@jest/core": "^28.0.3", + "@jest/core": "^27.5.1", "import-local": "^3.0.2", - "jest-cli": "^28.0.3" + "jest-cli": "^27.5.1" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -4217,153 +4416,73 @@ } }, "node_modules/jest-changed-files": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", - "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "dependencies": { + "@jest/types": "^27.5.1", "execa": "^5.0.0", "throat": "^6.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-circus": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.0.3.tgz", - "integrity": "sha512-HJ3rUCm3A3faSy7KVH5MFCncqJLtrjEFkTPn9UIcs4Kq77+TXqHsOaI+/k73aHe6DJQigLUXq9rCYj3MYFlbIw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "dependencies": { - "@jest/environment": "^28.0.2", - "@jest/expect": "^28.0.3", - "@jest/test-result": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^28.0.2", - "jest-matcher-utils": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-runtime": "^28.0.3", - "jest-snapshot": "^28.0.3", - "jest-util": "^28.0.2", - "pretty-format": "^28.0.2", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-diff": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.0.2.tgz", - "integrity": "sha512-33Rnf821Y54OAloav0PGNWHlbtEorXpjwchnToyyWbec10X74FOW7hGfvrXLGz7xOe2dz0uo9JVFAHHj/2B5pg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-matcher-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.0.2.tgz", - "integrity": "sha512-SxtTiI2qLJHFtOz/bySStCnwCvISAuxQ/grS+74dfTy5AuJw3Sgj9TVUvskcnImTfpzLoMCDJseRaeRrVYbAOA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-circus/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/jest-cli": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.0.3.tgz", - "integrity": "sha512-NCPTEONCnhYGo1qzPP4OOcGF04YasM5GZSwQLI1HtEluxa3ct4U65IbZs6DSRt8XN1Rq0jhXwv02m5lHB28Uyg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "dependencies": { - "@jest/core": "^28.0.3", - "@jest/test-result": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^28.0.3", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "prompts": "^2.0.1", - "yargs": "^17.3.1" + "yargs": "^16.2.0" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -4374,340 +4493,303 @@ } } }, - "node_modules/jest-cli/node_modules/yargs": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", - "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/jest-cli/node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/jest-config": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.0.3.tgz", - "integrity": "sha512-3gWOEHwGpNhyYOk9vnUMv94x15QcdjACm7A3lERaluwnyD6d1WZWe9RFCShgIXVOHzRfG1hWxsI2U0gKKSGgDQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.0.2", - "@jest/types": "^28.0.2", - "babel-jest": "^28.0.3", + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.3", + "glob": "^7.1.1", "graceful-fs": "^4.2.9", - "jest-circus": "^28.0.3", - "jest-environment-node": "^28.0.2", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-runner": "^28.0.3", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^28.0.2", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { - "@types/node": "*", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, "ts-node": { "optional": true } } }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-config/node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "node_modules/jest-config/node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/jest-config/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-diff": { + "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-docblock": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", - "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", + "node_modules/jest-config/node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/jest-each": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.0.2.tgz", - "integrity": "sha512-/W5Wc0b+ipR36kDaLngdVEJ/5UYPOITK7rW0djTlCCQdMuWpCFJweMW4TzAoJ6GiRrljPL8FwiyOSoSHKrda2w==", + "node_modules/jest-config/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.0.2", - "pretty-format": "^28.0.2" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-each/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "node_modules/jest-config/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "node_modules/jest-config/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/jest-each/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-environment-node": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.0.2.tgz", - "integrity": "sha512-o9u5UHZ+NCuIoa44KEF0Behhsz/p1wMm0WumsZfWR1k4IVoWSt3aN0BavSC5dd26VxSGQvkrCnJxxOzhhUEG3Q==", + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "dependencies": { - "@jest/environment": "^28.0.2", - "@jest/fake-timers": "^28.0.2", - "@jest/types": "^28.0.2", - "@types/node": "*", - "jest-mock": "^28.0.2", - "jest-util": "^28.0.2" + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-get-type": { + "node_modules/jest-docblock": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-haste-map": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.0.2.tgz", - "integrity": "sha512-EokdL7l5uk4TqWGawwrIt8w3tZNcbeiRxmKGEURf42pl+/rWJy3sCJlon5HBhJXZTW978jk6600BLQOI7i25Ig==", + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.0.2", - "jest-worker": "^28.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.7" + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.0.2.tgz", - "integrity": "sha512-pijNxfjxT0tGAx+8+OzZ+eayVPCwy/rsZFhebmC0F4YnXu1EHPEPxg7utL3m5uX3EaFH1/jwDxGa1EbjJCST2g==", + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", "dev": true, "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-leak-detector": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.0.2.tgz", - "integrity": "sha512-UGaSPYtxKXl/YKacq6juRAKmMp1z2os8NaU8PSC+xvNikmu3wF6QFrXrihMM4hXeMr9HuNotBrQZHmzDY8KIBQ==", + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-leak-detector/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-leak-detector/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/jest-matcher-utils": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", @@ -4724,69 +4806,36 @@ } }, "node_modules/jest-message-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.0.2.tgz", - "integrity": "sha512-knK7XyojvwYh1XiF2wmVdskgM/uN11KsjcEWWHfnMZNEdwXCrqB4sCBO94F4cfiAwCS8WFV6CDixDwPlMh/wdA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.0.2", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/jest-mock": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.0.2.tgz", - "integrity": "sha512-vfnJ4zXRB0i24jOTGtQJyl26JKsgBKtqRlCnsrORZbG06FToSSn33h2x/bmE8XxqxkLWdZBRo+/65l8Vi3nD+g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/node": "*" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-pnp-resolver": { @@ -4806,274 +4855,434 @@ } } }, - "node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, "node_modules/jest-resolve": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.0.3.tgz", - "integrity": "sha512-lfgjd9JhEjpjIN3HLUfdysdK+A7ePQoYmd7WL9DUEWqdnngb1rF56eee6iDXJxl/3eSolpP43VD7VrhjL3NsoQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "dependencies": { + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", + "jest-haste-map": "^27.5.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.0.3.tgz", - "integrity": "sha512-lCgHMm0/5p0qHemrOzm7kI6JDei28xJwIf7XOEcv1HeAVHnsON8B8jO/woqlU+/GcOXb58ymieYqhk3zjGWnvQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, "dependencies": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.0.3" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-runner": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.0.3.tgz", - "integrity": "sha512-4OsHMjBLtYUWCENucAQ4Za0jGfEbOFi/Fusv6dzUuaweqx8apb4+5p2LR2yvgF4StFulmxyC238tGLftfu+zBA==", + "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "@jest/console": "^28.0.2", - "@jest/environment": "^28.0.2", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-docblock": "^28.0.2", - "jest-environment-node": "^28.0.2", - "jest-haste-map": "^28.0.2", - "jest-leak-detector": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-runtime": "^28.0.3", - "jest-util": "^28.0.2", - "jest-watcher": "^28.0.2", - "jest-worker": "^28.0.2", - "source-map-support": "0.5.13", - "throat": "^6.0.1" + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-resolve/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-runner/node_modules/jest-worker": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.0.2.tgz", - "integrity": "sha512-pijNxfjxT0tGAx+8+OzZ+eayVPCwy/rsZFhebmC0F4YnXu1EHPEPxg7utL3m5uX3EaFH1/jwDxGa1EbjJCST2g==", + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "node_modules/jest-runner/node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jest-runner/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-runner/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "node_modules/jest-runtime": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.0.3.tgz", - "integrity": "sha512-7FtPUmvbZEHLOdjsF6dyHg5Pe4E0DU+f3Vvv8BPzVR7mQA6nFR4clQYLAPyJGnsUvN8WRWn+b5a5SVwnj1WaGg==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.0.2", - "@jest/fake-timers": "^28.0.2", - "@jest/globals": "^28.0.3", - "@jest/source-map": "^28.0.2", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-mock": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-snapshot": "^28.0.3", - "jest-util": "^28.0.2", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.0.3.tgz", - "integrity": "sha512-nVzAAIlAbrMuvVUrS1YxmAeo1TfSsDDU+K5wv/Ow56MBp+L+Y71ksAbwRp3kGCgZAz4oOXcAMPAwtT9Yh1hlQQ==", + "node_modules/jest-runtime/node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "expect": "^28.0.2", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.0.2", - "jest-matcher-utils": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-util": "^28.0.2", - "natural-compare": "^1.4.0", - "pretty-format": "^28.0.2", - "semver": "^7.3.5" + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-runtime/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-snapshot/node_modules/diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "node_modules/jest-runtime/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.0.2.tgz", - "integrity": "sha512-33Rnf821Y54OAloav0PGNWHlbtEorXpjwchnToyyWbec10X74FOW7hGfvrXLGz7xOe2dz0uo9JVFAHHj/2B5pg==", + "node_modules/jest-runtime/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.0.2.tgz", - "integrity": "sha512-SxtTiI2qLJHFtOz/bySStCnwCvISAuxQ/grS+74dfTy5AuJw3Sgj9TVUvskcnImTfpzLoMCDJseRaeRrVYbAOA==", + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-snapshot/node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/jest-transform-yaml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jest-transform-yaml/-/jest-transform-yaml-1.0.0.tgz", + "integrity": "sha512-W2vVRXLCF2sCc6p0/hwRx0PgimmXqImLlRzXxtZAQZTjcUvzydWgg5dQ+Xc2FpvkXj0k0vmin4dPsylVOWuE2Q==", + "dev": true, + "dependencies": { + "js-yaml": "4.1.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^12.0.0 || ^14.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/jest-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.0.2.tgz", - "integrity": "sha512-EVdpIRCC8lzqhp9A0u0aAKlsFIzufK6xKxNK7awsnebTdOP4hpyQW5o6Ox2qPl8gbeUKYF+POLyItaND53kpGA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -5081,85 +5290,42 @@ "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-validate": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.0.2.tgz", - "integrity": "sha512-nr0UOvCTtxP0YPdsk01Gk7e7c0xIiEe2nncAe3pj0wBfUvAykTVrMrdeASlAJnlEQCBuwN/GF4hKoCzbkGNCNw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "dependencies": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", + "jest-get-type": "^27.5.1", "leven": "^3.1.0", - "pretty-format": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "pretty-format": "^27.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, "node_modules/jest-watcher": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.0.2.tgz", - "integrity": "sha512-uIVJLpQ/5VTGQWBiBatHsi7jrCqHjHl0e0dFHMWzwuIfUbdW/muk0DtSr0fteY2T7QTFylv+7a5Rm8sBKrE12Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, "dependencies": { - "@jest/test-result": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.0.2", + "jest-util": "^27.5.1", "string-length": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-worker": { @@ -5209,6 +5375,52 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5641,7 +5853,7 @@ "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node_modules/node-releases": { @@ -5671,6 +5883,12 @@ "node": ">=8" } }, + "node_modules/nwsapi": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz", + "integrity": "sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==", + "dev": true + }, "node_modules/object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -5833,6 +6051,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -6062,6 +6286,12 @@ "node": ">= 6" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -6308,6 +6538,24 @@ } ] }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -6623,6 +6871,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -6649,13 +6903,14 @@ } }, "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -6663,14 +6918,6 @@ }, "engines": { "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } } }, "node_modules/terser-webpack-plugin": { @@ -6713,15 +6960,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -6775,6 +7013,32 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", @@ -6794,32 +7058,32 @@ } }, "node_modules/ts-jest": { - "version": "28.0.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.1.tgz", - "integrity": "sha512-PbkbitaT/9ZYAqqzk3UYTvCq080Seo46T3m/AdwcZ0D8WH2uBhG6PvA8oOAWsZIknzPQU66fYobvFCL8IqIhmg==", + "version": "27.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", + "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", + "jest-util": "^27.0.0", "json5": "2.x", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "^20.x" + "yargs-parser": "20.x" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", - "babel-jest": "^28.0.0", - "jest": "^28.0.0", - "typescript": ">=4.3" + "babel-jest": ">=27.0.0 <28", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" }, "peerDependenciesMeta": { "@babel/core": { @@ -6909,6 +7173,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", @@ -6937,6 +7210,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", @@ -6991,19 +7273,49 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", - "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.7", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" }, "engines": { "node": ">=10.12.0" } }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -7026,6 +7338,15 @@ "node": ">=10.13.0" } }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, "node_modules/webpack": { "version": "5.72.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", @@ -7147,6 +7468,35 @@ "node": ">=10.13.0" } }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7242,19 +7592,39 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -7490,9 +7860,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", "dev": true }, "@babel/helper-simple-access": { @@ -7720,12 +8090,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.10.tgz", - "integrity": "sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/template": { @@ -7911,277 +8281,327 @@ "dev": true }, "@jest/console": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.0.2.tgz", - "integrity": "sha512-tiRpnMeeyQuuzgL5UNSeiqMwF8UOWPbAE5rzcu/1zyq4oPG2Ox6xm4YCOruwbp10F8odWc+XwVxTyGzMSLMqxA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "requires": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^28.0.2", - "jest-util": "^28.0.2", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" } }, "@jest/core": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.0.3.tgz", - "integrity": "sha512-cCQW06vEZ+5r50SB06pOnSWsOBs7F+lswPYnKKfBz1ncLlj1sMqmvjgam8q40KhlZ8Ut4eNAL2Hvfx4BKIO2FA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "requires": { - "@jest/console": "^28.0.2", - "@jest/reporters": "^28.0.3", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "ci-info": "^3.2.0", + "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.0.2", - "jest-config": "^28.0.3", - "jest-haste-map": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-resolve-dependencies": "^28.0.3", - "jest-runner": "^28.0.3", - "jest-runtime": "^28.0.3", - "jest-snapshot": "^28.0.3", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", - "jest-watcher": "^28.0.2", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", "micromatch": "^4.0.4", - "pretty-format": "^28.0.2", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" } }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } } } }, "@jest/environment": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.0.2.tgz", - "integrity": "sha512-IvI7dEfqVEffDYlw9FQfVBt6kXt/OI38V7QUIur0ulOQgzpKYJDVvLzj4B1TVmHWTGW5tcnJdlZ3hqzV6/I9Qg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, "requires": { - "@jest/fake-timers": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^28.0.2" - } - }, - "@jest/expect": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.0.3.tgz", - "integrity": "sha512-VEzZr85bqNomgayQkR7hWG5HnbZYWYWagQriZsixhLmOzU6PCpMP61aeVhkCoRrg7ri5f7JDpeTPzDAajIwFHw==", - "dev": true, - "requires": { - "expect": "^28.0.2", - "jest-snapshot": "^28.0.3" - } - }, - "@jest/expect-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.0.2.tgz", - "integrity": "sha512-YryfH2zN5c7M8eLtn9oTBRj1sfD+X4cHNXJnTejqCveOS33wADEZUxJ7de5++lRvByNpRpfAnc8zTK7yrUJqgA==", - "dev": true, - "requires": { - "jest-get-type": "^28.0.2" - }, - "dependencies": { - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - } + "jest-mock": "^27.5.1" } }, "@jest/fake-timers": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.0.2.tgz", - "integrity": "sha512-R75yUv+WeybPa4ZVhX9C+8XN0TKjUoceUX+/QEaDVQGxZZOK50eD74cs7iMDTtpodh00d8iLlc9197vgF6oZjA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "requires": { - "@jest/types": "^28.0.2", - "@sinonjs/fake-timers": "^9.1.1", + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^28.0.2", - "jest-mock": "^28.0.2", - "jest-util": "^28.0.2" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "@jest/globals": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.0.3.tgz", - "integrity": "sha512-q/zXYI6CKtTSIt1WuTHBYizJhH7K8h+xG5PE3C0oawLlPIvUMDYmpj0JX0XsJwPRLCsz/fYXHZVG46AaEhSPmw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "requires": { - "@jest/environment": "^28.0.2", - "@jest/expect": "^28.0.3", - "@jest/types": "^28.0.2" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" } }, "@jest/reporters": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.0.3.tgz", - "integrity": "sha512-xrbIc7J/xwo+D7AY3enAR9ZWYCmJ8XIkstTukTGpKDph0gLl/TJje9jl3dssvE4KJzYqMKiSrnE5Nt68I4fTEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.0.2", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", - "@jridgewell/trace-mapping": "^0.3.7", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.3", + "glob": "^7.1.2", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-util": "^28.0.2", - "jest-worker": "^28.0.2", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", + "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.0" + "v8-to-istanbul": "^8.1.0" }, "dependencies": { - "jest-worker": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.0.2.tgz", - "integrity": "sha512-pijNxfjxT0tGAx+8+OzZ+eayVPCwy/rsZFhebmC0F4YnXu1EHPEPxg7utL3m5uX3EaFH1/jwDxGa1EbjJCST2g==", + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" } }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } } } }, - "@jest/schemas": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", - "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.23.3" - } - }, "@jest/source-map": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", - "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.7", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" } }, "@jest/test-result": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.0.2.tgz", - "integrity": "sha512-4EUqgjq9VzyUiVTvZfI9IRJD6t3NYBNP4f+Eq8Zr93+hkJ0RrGU4OBTw8tfNzidKX+bmuYzn8FxqpxOPIGGCMA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "requires": { - "@jest/console": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.0.2.tgz", - "integrity": "sha512-zhnZ8ydkZQTPL7YucB86eOlD79zPy5EGSUKiR2Iv93RVEDU6OEP33kwDBg70ywOcxeJGDRhyo09q7TafNCBiIg==", - "dev": true, - "requires": { - "@jest/test-result": "^28.0.2", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.0.3.tgz", - "integrity": "sha512-+Y0ikI7SwoW/YbK8t9oKwC70h4X2Gd0OVuz5tctRvSV/EDQU00AAkoqevXgPSSFimUmp/sp7Yl8s/1bExDqOIg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^28.0.2", - "@jridgewell/trace-mapping": "^0.3.7", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", + "@jest/test-result": "^27.5.1", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.0.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "dependencies": { + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + } } }, "@jest/types": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.0.2.tgz", - "integrity": "sha512-hi3jUdm9iht7I2yrV5C4s3ucCJHUP8Eh3W6rQ1s4n/Qw9rQgsda4eqCt+r3BKRi7klVmZfQlMx1nGlzNMP2d8A==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^17.0.8", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" } }, @@ -8207,6 +8627,29 @@ "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", @@ -8214,9 +8657,9 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.10.tgz", - "integrity": "sha512-Q0YbBd6OTsXm8Y21+YUSDXupHnodNC2M4O18jtd3iwJ3+vMZNdKGols0a9G6JOK0dcJ3IdUUHoh908ZI6qhk8Q==", + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", @@ -8249,12 +8692,6 @@ "fastq": "^1.6.0" } }, - "@sinclair/typebox": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", - "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", - "dev": true - }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -8265,9 +8702,9 @@ } }, "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -8380,9 +8817,9 @@ } }, "@types/jest": { - "version": "27.5.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.0.tgz", - "integrity": "sha512-9RBFx7r4k+msyj/arpfaa0WOOEcaAZNmN+j80KFbFCoSqCJGHTz7YMAMGQW9Xmqm5w6l5c25vbSjMwlikJi5+g==", + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", "dev": true, "requires": { "jest-matcher-utils": "^27.0.0", @@ -8408,9 +8845,9 @@ "dev": true }, "@types/prettier": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", - "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", + "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, "@types/stack-utils": { @@ -8432,9 +8869,9 @@ "dev": true }, "@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -8740,12 +9177,36 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } + } + }, "acorn-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", @@ -8760,6 +9221,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -8860,27 +9327,18 @@ "util": "^0.12.0" } }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true }, - "babel-jest": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.0.3.tgz", - "integrity": "sha512-S0ADyYdcrt5fp9YldRYWCUHdk1BKt9AkvBkLWBoNAEV9NoWZPIj5+MYhPcGgTS65mfv3a+Ymf2UqgWoAVd41cA==", - "dev": true, - "requires": { - "@jest/transform": "^28.0.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, "babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -8894,18 +9352,6 @@ "test-exclude": "^6.0.0" } }, - "babel-plugin-jest-hoist": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", - "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, "babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -8926,16 +9372,6 @@ "@babel/plugin-syntax-top-level-await": "^7.8.3" } }, - "babel-preset-jest": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", - "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^28.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -8995,6 +9431,12 @@ "fill-range": "^7.0.1" } }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -9173,7 +9615,7 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "collect-v8-coverage": { @@ -9203,6 +9645,15 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -9270,6 +9721,40 @@ "which": "^2.0.1" } }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, "date-fns": { "version": "2.28.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", @@ -9291,10 +9776,16 @@ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "deep-is": { @@ -9318,6 +9809,12 @@ "object-keys": "^1.0.12" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -9354,6 +9851,23 @@ "esutils": "^2.0.2" } }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -9370,9 +9884,9 @@ "dev": true }, "emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", "dev": true }, "emoji-regex": { @@ -9475,6 +9989,66 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, "eslint": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", @@ -9688,82 +10262,19 @@ "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, "expect": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.0.2.tgz", - "integrity": "sha512-X0qIuI/zKv98k34tM+uGeOgAC73lhs4vROF9MkPk94C1zujtwv4Cla8SxhWn0G1OwvG9gLLL7RjFBkwGVaZ83w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, "requires": { - "@jest/expect-utils": "^28.0.2", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-util": "^28.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true - }, - "jest-diff": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.0.2.tgz", - "integrity": "sha512-33Rnf821Y54OAloav0PGNWHlbtEorXpjwchnToyyWbec10X74FOW7hGfvrXLGz7xOe2dz0uo9JVFAHHj/2B5pg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - } - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "jest-matcher-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.0.2.tgz", - "integrity": "sha512-SxtTiI2qLJHFtOz/bySStCnwCvISAuxQ/grS+74dfTy5AuJw3Sgj9TVUvskcnImTfpzLoMCDJseRaeRrVYbAOA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - } - }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - } + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" } }, "fast-deep-equal": { @@ -9894,6 +10405,17 @@ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "dev": true }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -10087,6 +10609,15 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -10120,6 +10651,15 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -10198,7 +10738,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-bigint": { @@ -10335,6 +10875,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -10382,6 +10928,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -10465,9 +11017,9 @@ } }, "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -10481,217 +11033,205 @@ "dev": true }, "jest": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.0.3.tgz", - "integrity": "sha512-uS+T5J3w5xyzd1KSJCGKhCo8WTJXbNl86f5SW11wgssbandJOVLRKKUxmhdFfmKxhPeksl1hHZ0HaA8VBzp7xA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "requires": { - "@jest/core": "^28.0.3", + "@jest/core": "^27.5.1", "import-local": "^3.0.2", - "jest-cli": "^28.0.3" + "jest-cli": "^27.5.1" } }, "jest-changed-files": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", - "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "requires": { + "@jest/types": "^27.5.1", "execa": "^5.0.0", "throat": "^6.0.1" } }, "jest-circus": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.0.3.tgz", - "integrity": "sha512-HJ3rUCm3A3faSy7KVH5MFCncqJLtrjEFkTPn9UIcs4Kq77+TXqHsOaI+/k73aHe6DJQigLUXq9rCYj3MYFlbIw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "requires": { - "@jest/environment": "^28.0.2", - "@jest/expect": "^28.0.3", - "@jest/test-result": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^28.0.2", - "jest-matcher-utils": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-runtime": "^28.0.3", - "jest-snapshot": "^28.0.3", - "jest-util": "^28.0.2", - "pretty-format": "^28.0.2", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true - }, - "jest-diff": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.0.2.tgz", - "integrity": "sha512-33Rnf821Y54OAloav0PGNWHlbtEorXpjwchnToyyWbec10X74FOW7hGfvrXLGz7xOe2dz0uo9JVFAHHj/2B5pg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - } - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "jest-matcher-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.0.2.tgz", - "integrity": "sha512-SxtTiI2qLJHFtOz/bySStCnwCvISAuxQ/grS+74dfTy5AuJw3Sgj9TVUvskcnImTfpzLoMCDJseRaeRrVYbAOA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - } - }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - } } }, "jest-cli": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.0.3.tgz", - "integrity": "sha512-NCPTEONCnhYGo1qzPP4OOcGF04YasM5GZSwQLI1HtEluxa3ct4U65IbZs6DSRt8XN1Rq0jhXwv02m5lHB28Uyg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "requires": { - "@jest/core": "^28.0.3", - "@jest/test-result": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^28.0.3", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "dependencies": { - "yargs": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", - "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", - "dev": true - } + "yargs": "^16.2.0" } }, "jest-config": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.0.3.tgz", - "integrity": "sha512-3gWOEHwGpNhyYOk9vnUMv94x15QcdjACm7A3lERaluwnyD6d1WZWe9RFCShgIXVOHzRfG1hWxsI2U0gKKSGgDQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.0.2", - "@jest/types": "^28.0.2", - "babel-jest": "^28.0.3", + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.3", + "glob": "^7.1.1", "graceful-fs": "^4.2.9", - "jest-circus": "^28.0.3", - "jest-environment-node": "^28.0.2", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-runner": "^28.0.3", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^28.0.2", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "requires": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" } }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } } } }, @@ -10708,71 +11248,54 @@ } }, "jest-docblock": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", - "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.0.2.tgz", - "integrity": "sha512-/W5Wc0b+ipR36kDaLngdVEJ/5UYPOITK7rW0djTlCCQdMuWpCFJweMW4TzAoJ6GiRrljPL8FwiyOSoSHKrda2w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, "requires": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.0.2", - "pretty-format": "^28.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - } + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.0.2.tgz", - "integrity": "sha512-o9u5UHZ+NCuIoa44KEF0Behhsz/p1wMm0WumsZfWR1k4IVoWSt3aN0BavSC5dd26VxSGQvkrCnJxxOzhhUEG3Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "requires": { - "@jest/environment": "^28.0.2", - "@jest/fake-timers": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^28.0.2", - "jest-util": "^28.0.2" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "jest-get-type": { @@ -10781,88 +11304,39 @@ "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true }, - "jest-haste-map": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.0.2.tgz", - "integrity": "sha512-EokdL7l5uk4TqWGawwrIt8w3tZNcbeiRxmKGEURf42pl+/rWJy3sCJlon5HBhJXZTW978jk6600BLQOI7i25Ig==", + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, "requires": { - "@jest/types": "^28.0.2", - "@types/graceful-fs": "^4.1.3", + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.0.2", - "jest-worker": "^28.0.2", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "dependencies": { - "jest-worker": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.0.2.tgz", - "integrity": "sha512-pijNxfjxT0tGAx+8+OzZ+eayVPCwy/rsZFhebmC0F4YnXu1EHPEPxg7utL3m5uX3EaFH1/jwDxGa1EbjJCST2g==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" } }, "jest-leak-detector": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.0.2.tgz", - "integrity": "sha512-UGaSPYtxKXl/YKacq6juRAKmMp1z2os8NaU8PSC+xvNikmu3wF6QFrXrihMM4hXeMr9HuNotBrQZHmzDY8KIBQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, "requires": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - } + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-matcher-utils": { @@ -10878,55 +11352,29 @@ } }, "jest-message-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.0.2.tgz", - "integrity": "sha512-knK7XyojvwYh1XiF2wmVdskgM/uN11KsjcEWWHfnMZNEdwXCrqB4sCBO94F4cfiAwCS8WFV6CDixDwPlMh/wdA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.0.2", + "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - } } }, "jest-mock": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.0.2.tgz", - "integrity": "sha512-vfnJ4zXRB0i24jOTGtQJyl26JKsgBKtqRlCnsrORZbG06FToSSn33h2x/bmE8XxqxkLWdZBRo+/65l8Vi3nD+g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "requires": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/node": "*" } }, @@ -10937,230 +11385,379 @@ "dev": true, "requires": {} }, - "jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "dev": true - }, "jest-resolve": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.0.3.tgz", - "integrity": "sha512-lfgjd9JhEjpjIN3HLUfdysdK+A7ePQoYmd7WL9DUEWqdnngb1rF56eee6iDXJxl/3eSolpP43VD7VrhjL3NsoQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "requires": { + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", + "jest-haste-map": "^27.5.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.0.2", - "jest-validate": "^28.0.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" + }, + "dependencies": { + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + } } }, "jest-resolve-dependencies": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.0.3.tgz", - "integrity": "sha512-lCgHMm0/5p0qHemrOzm7kI6JDei28xJwIf7XOEcv1HeAVHnsON8B8jO/woqlU+/GcOXb58ymieYqhk3zjGWnvQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, "requires": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.0.3" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "dependencies": { + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + } } }, "jest-runner": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.0.3.tgz", - "integrity": "sha512-4OsHMjBLtYUWCENucAQ4Za0jGfEbOFi/Fusv6dzUuaweqx8apb4+5p2LR2yvgF4StFulmxyC238tGLftfu+zBA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "requires": { - "@jest/console": "^28.0.2", - "@jest/environment": "^28.0.2", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.10.2", + "emittery": "^0.8.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^28.0.2", - "jest-environment-node": "^28.0.2", - "jest-haste-map": "^28.0.2", - "jest-leak-detector": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-runtime": "^28.0.3", - "jest-util": "^28.0.2", - "jest-watcher": "^28.0.2", - "jest-worker": "^28.0.2", - "source-map-support": "0.5.13", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", "throat": "^6.0.1" }, "dependencies": { - "jest-worker": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.0.2.tgz", - "integrity": "sha512-pijNxfjxT0tGAx+8+OzZ+eayVPCwy/rsZFhebmC0F4YnXu1EHPEPxg7utL3m5uX3EaFH1/jwDxGa1EbjJCST2g==", + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" } }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" } }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } } } }, "jest-runtime": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.0.3.tgz", - "integrity": "sha512-7FtPUmvbZEHLOdjsF6dyHg5Pe4E0DU+f3Vvv8BPzVR7mQA6nFR4clQYLAPyJGnsUvN8WRWn+b5a5SVwnj1WaGg==", - "dev": true, - "requires": { - "@jest/environment": "^28.0.2", - "@jest/fake-timers": "^28.0.2", - "@jest/globals": "^28.0.3", - "@jest/source-map": "^28.0.2", - "@jest/test-result": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-mock": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.0.3", - "jest-snapshot": "^28.0.3", - "jest-util": "^28.0.2", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0", "strip-bom": "^4.0.0" + }, + "dependencies": { + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } + } + }, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" } }, "jest-snapshot": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.0.3.tgz", - "integrity": "sha512-nVzAAIlAbrMuvVUrS1YxmAeo1TfSsDDU+K5wv/Ow56MBp+L+Y71ksAbwRp3kGCgZAz4oOXcAMPAwtT9Yh1hlQQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, "requires": { - "@babel/core": "^7.11.6", + "@babel/core": "^7.7.2", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.0.2", - "@jest/transform": "^28.0.3", - "@jest/types": "^28.0.2", - "@types/babel__traverse": "^7.0.6", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^28.0.2", + "expect": "^27.5.1", "graceful-fs": "^4.2.9", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.0.2", - "jest-matcher-utils": "^28.0.2", - "jest-message-util": "^28.0.2", - "jest-util": "^28.0.2", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^28.0.2", - "semver": "^7.3.5" + "pretty-format": "^27.5.1", + "semver": "^7.3.2" }, "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true - }, - "jest-diff": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.0.2.tgz", - "integrity": "sha512-33Rnf821Y54OAloav0PGNWHlbtEorXpjwchnToyyWbec10X74FOW7hGfvrXLGz7xOe2dz0uo9JVFAHHj/2B5pg==", + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" } }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "jest-matcher-utils": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.0.2.tgz", - "integrity": "sha512-SxtTiI2qLJHFtOz/bySStCnwCvISAuxQ/grS+74dfTy5AuJw3Sgj9TVUvskcnImTfpzLoMCDJseRaeRrVYbAOA==", + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { - "chalk": "^4.0.0", - "jest-diff": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.0.2" + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" } }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true } } }, + "jest-transform-yaml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jest-transform-yaml/-/jest-transform-yaml-1.0.0.tgz", + "integrity": "sha512-W2vVRXLCF2sCc6p0/hwRx0PgimmXqImLlRzXxtZAQZTjcUvzydWgg5dQ+Xc2FpvkXj0k0vmin4dPsylVOWuE2Q==", + "dev": true, + "requires": { + "js-yaml": "4.1.0" + } + }, "jest-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.0.2.tgz", - "integrity": "sha512-EVdpIRCC8lzqhp9A0u0aAKlsFIzufK6xKxNK7awsnebTdOP4hpyQW5o6Ox2qPl8gbeUKYF+POLyItaND53kpGA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "requires": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -11169,64 +11766,31 @@ } }, "jest-validate": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.0.2.tgz", - "integrity": "sha512-nr0UOvCTtxP0YPdsk01Gk7e7c0xIiEe2nncAe3pj0wBfUvAykTVrMrdeASlAJnlEQCBuwN/GF4hKoCzbkGNCNw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "requires": { - "@jest/types": "^28.0.2", + "@jest/types": "^27.5.1", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", + "jest-get-type": "^27.5.1", "leven": "^3.1.0", - "pretty-format": "^28.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "pretty-format": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.0.2.tgz", - "integrity": "sha512-UmGZ1IERwS3yY35LDMTaBUYI1w4udZDdJGGT/DqQeKG9ZLDn7/K2Jf/JtYSRiHCCKMHvUA+zsEGSmHdpaVp1yw==", - "dev": true, - "requires": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - } + "pretty-format": "^27.5.1" } }, "jest-watcher": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.0.2.tgz", - "integrity": "sha512-uIVJLpQ/5VTGQWBiBatHsi7jrCqHjHl0e0dFHMWzwuIfUbdW/muk0DtSr0fteY2T7QTFylv+7a5Rm8sBKrE12Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, "requires": { - "@jest/test-result": "^28.0.2", - "@jest/types": "^28.0.2", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.0.2", + "jest-util": "^27.5.1", "string-length": "^4.0.1" } }, @@ -11267,6 +11831,41 @@ "argparse": "^2.0.1" } }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -11599,7 +12198,7 @@ "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node-releases": { @@ -11623,6 +12222,12 @@ "path-key": "^3.0.0" } }, + "nwsapi": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz", + "integrity": "sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==", + "dev": true + }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -11734,6 +12339,12 @@ "lines-and-columns": "^1.1.6" } }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -11898,6 +12509,12 @@ "sisteransi": "^1.0.5" } }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -12057,6 +12674,21 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -12300,6 +12932,12 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -12317,13 +12955,14 @@ } }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { @@ -12332,12 +12971,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true } } }, @@ -12398,6 +13031,26 @@ "is-number": "^7.0.0" } }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, "traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", @@ -12411,19 +13064,19 @@ "dev": true }, "ts-jest": { - "version": "28.0.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.1.tgz", - "integrity": "sha512-PbkbitaT/9ZYAqqzk3UYTvCq080Seo46T3m/AdwcZ0D8WH2uBhG6PvA8oOAWsZIknzPQU66fYobvFCL8IqIhmg==", + "version": "27.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", + "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", "dev": true, "requires": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", + "jest-util": "^27.0.0", "json5": "2.x", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "^20.x" + "yargs-parser": "20.x" } }, "ts-loader": { @@ -12474,6 +13127,15 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", @@ -12492,6 +13154,12 @@ "which-boxed-primitive": "^1.0.2" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", @@ -12546,14 +13214,40 @@ "dev": true }, "v8-to-istanbul": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", - "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.7", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + } + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" } }, "walker": { @@ -12575,6 +13269,12 @@ "graceful-fs": "^4.1.2" } }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, "webpack": { "version": "5.72.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", @@ -12651,6 +13351,32 @@ "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -12722,15 +13448,24 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } + "requires": {} + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true }, "y18n": { "version": "5.0.8", diff --git a/package.json b/package.json index 334eb15..89e81af 100644 --- a/package.json +++ b/package.json @@ -233,14 +233,15 @@ "eslint": "^8.14.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.0.0", - "jest": "^28.0.3", + "jest": "^27.5.1", + "jest-transform-yaml": "^1.0.0", "merge-options": "^3.0.4", "mocha": "^9.2.2", "path-browserify": "^1.0.1", "prettier": "2.6.2", "process": "^0.11.10", "rimraf": "^3.0.2", - "ts-jest": "^28.0.1", + "ts-jest": "^27.1.5", "ts-loader": "^9.2.9", "typescript": "^4.6.3", "webpack": "^5.72.0", diff --git a/server/jest.config.js b/server/jest.config.js index 9d817ae..98d29bd 100644 --- a/server/jest.config.js +++ b/server/jest.config.js @@ -1,6 +1,10 @@ // For a detailed explanation regarding each configuration property, visit: // https://jestjs.io/docs/en/configuration.html +/* eslint-disable @typescript-eslint/no-var-requires */ +const { pathsToModuleNameMapper } = require("ts-jest"); +const { compilerOptions } = require("./tsconfig"); + module.exports = { preset: "ts-jest", globals: { @@ -12,5 +16,10 @@ module.exports = { testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/unit/*.test.ts"], // An array of file extensions your modules use - moduleFileExtensions: ["ts", "tsx", "js"], + moduleFileExtensions: ["ts", "tsx", "js", "yaml"], + transform: { + // ... other transforms ... + "\\.yaml$": "jest-transform-yaml", + }, + moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: "/" }), }; diff --git a/server/tsconfig.json b/server/tsconfig.json index aa03c3f..5200861 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -8,7 +8,10 @@ "esModuleInterop": true, "sourceMap": true, "strict": true, - "composite": true + "composite": true, + "paths": { + "@schemas/*": ["../workflow-languages/schemas/*"] + } }, "files": [], "include": [], diff --git a/shared.webpack.config.js b/shared.webpack.config.js index 7d3f767..8bff832 100644 --- a/shared.webpack.config.js +++ b/shared.webpack.config.js @@ -24,6 +24,9 @@ module.exports = function withDefaults(/**@type WebpackConfig*/ extConfig) { fallback: { path: require.resolve("path-browserify"), }, + alias: { + "@schemas": path.resolve(__dirname, "./workflow-languages/schemas/"), + }, }, module: { rules: [ @@ -36,6 +39,9 @@ module.exports = function withDefaults(/**@type WebpackConfig*/ extConfig) { options: { compilerOptions: { sourceMap: true, + paths: { + "@schemas": [path.resolve(__dirname, "./workflow-languages/schemas/")], + }, }, }, }, diff --git a/tsconfig.json b/tsconfig.json index 209a682..b373707 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,10 @@ "esModuleInterop": true, "sourceMap": true, "strict": true, - "composite": true + "composite": true, + "paths": { + "@schemas/*": ["./workflow-languages/schemas/*"] + } }, "files": [], "include": [], From 3a2ea2ffbf82ae05704724d18b9bb542847f2234 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 22 Jul 2022 15:52:55 +0200 Subject: [PATCH 11/50] Fix jest config for debugging --- client/jest.config.js | 5 ++++- jest.config.js | 4 ++-- server/jest.config.js | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/client/jest.config.js b/client/jest.config.js index 9d817ae..070fb0c 100644 --- a/client/jest.config.js +++ b/client/jest.config.js @@ -1,11 +1,14 @@ // For a detailed explanation regarding each configuration property, visit: // https://jestjs.io/docs/en/configuration.html +/* eslint-disable @typescript-eslint/no-var-requires */ +const { compilerOptions } = require("./tsconfig.json"); + module.exports = { preset: "ts-jest", globals: { "ts-jest": { - tsconfig: "../tsconfig.json", + tsconfig: compilerOptions, }, }, // The glob patterns Jest uses to detect test files diff --git a/jest.config.js b/jest.config.js index f2a4f70..7383a9b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -3,13 +3,13 @@ /* eslint-disable @typescript-eslint/no-var-requires */ const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig"); +const { compilerOptions } = require("./tsconfig.json"); module.exports = { preset: "ts-jest", globals: { "ts-jest": { - tsconfig: "tsconfig.json", + tsconfig: compilerOptions, }, }, // The glob patterns Jest uses to detect test files diff --git a/server/jest.config.js b/server/jest.config.js index 98d29bd..7383a9b 100644 --- a/server/jest.config.js +++ b/server/jest.config.js @@ -3,13 +3,13 @@ /* eslint-disable @typescript-eslint/no-var-requires */ const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig"); +const { compilerOptions } = require("./tsconfig.json"); module.exports = { preset: "ts-jest", globals: { "ts-jest": { - tsconfig: "../tsconfig.json", + tsconfig: compilerOptions, }, }, // The glob patterns Jest uses to detect test files From afc7e73e18c70f983bd4c61dc318bf76037d9b58 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 22 Jul 2022 17:33:27 +0200 Subject: [PATCH 12/50] Add experimental SchemaNodeResolver --- .../src/languageService.ts | 2 +- .../src/schema/definitions.ts | 78 +++--------- .../src/schema/schemaLoader.ts | 117 +++++++++--------- .../src/schema/schemaNodeResolver.ts | 35 ++++++ .../src/schema/versions.ts | 12 +- 5 files changed, 119 insertions(+), 125 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index 32fa2e1..3c54c2c 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -27,7 +27,7 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { super(); this._schemaLoader = new GalaxyWorkflowFormat2SchemaLoader(); this._yamlLanguageService = getLanguageService(); - this._hoverService = new GxFormat2HoverService(this._schemaLoader.resolvedSchema); + this._hoverService = new GxFormat2HoverService(this._schemaLoader.nodeResolver); } public override parseWorkflowDocument(document: TextDocument): WorkflowDocument { diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 471d192..43a2c0c 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -1,5 +1,3 @@ -import { NodePath } from "@gxwf/server-common/src/ast/types"; - export interface SchemaDocument { $base: string; $namespaces?: object; @@ -132,11 +130,12 @@ function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { } } -interface SchemaNode { +export interface SchemaNode { name: string; children: SchemaNode[]; documentation: string | undefined; supportsArray: boolean; + typeRef: string; } export class FieldSchemaNode implements SchemaNode { @@ -179,6 +178,14 @@ export class FieldSchemaNode implements SchemaNode { return this._allowedTypes.some((t) => isArrayFieldType(t)); } + public get typeRef(): string { + if (this.supportsArray) { + return this.getArrayItemTypeName() || "undefined"; + } + const mainType = this.typesAllowed.at(0); + return isBasicFieldType(mainType) ? mainType.typeName : "not basic or undef"; + } + public getArrayItemTypeName(): string | undefined { const arrayType = this._allowedTypes.find((t) => isArrayFieldType(t)) as ArrayFieldType; if (isBasicFieldType(arrayType?.itemType)) { @@ -189,7 +196,7 @@ export class FieldSchemaNode implements SchemaNode { } } -class RecordSchemaNode implements SchemaNode { +export class RecordSchemaNode implements SchemaNode { public static readonly ROOT_NAME: string = "_root_"; private readonly _schemaRecord: SchemaRecord; @@ -222,63 +229,14 @@ class RecordSchemaNode implements SchemaNode { public get supportsArray(): boolean { return false; } -} -export class ResolvedSchema { - public readonly root?: SchemaNode; - constructor( - public readonly typeMap: Map, - public readonly fieldMap: Map, - rootRecord?: SchemaRecord - ) { - this.root = rootRecord ? new RecordSchemaNode(rootRecord) : undefined; + public get typeRef(): string { + return this._schemaRecord.name; } +} - public resolveSchemaContext(path: NodePath): SchemaNode | undefined { - const currentSchemaNode = this.root; - const toWalk = path.slice(); //.reverse(); - let next = toWalk.pop(); - while (next) { - if (typeof next === "string") { - if (this.typeMap.has(next)) { - const record = this.typeMap.get(next); - if (isSchemaRecord(record)) { - return new RecordSchemaNode(record); - } - } - if (this.fieldMap.has(next)) { - const field = this.fieldMap.get(next); - if (field) { - return new FieldSchemaNode(field); - } - } - console.debug(`TYPE NOT FOUND, processing parent of... ${JSON.stringify(next)}`); - - // const child = currentSchemaNode?.children.find((c) => c.name === next); - // if (child) { - // // console.debug(` FIELD FOUND: ${child.name}`); - // currentSchemaNode = child; - // } else { - // // console.debug(` FIELD NOT FOUND: ${next}`); - // if (currentSchemaNode?.supportsArray) { - // const fieldSchemaNode = currentSchemaNode as Field; - // let arrayItemTypeName = fieldSchemaNode.getArrayItemTypeName(); - // if (arrayItemTypeName) { - // const arrayType = this.typeMap.get(arrayItemTypeName); - // if (isSchemaRecord(arrayType)) { - // currentSchemaNode = new SchemaRecordNode(arrayType as SchemaRecord); - // } else { - // console.debug(`TYPE NOT PROCESSED: ${JSON.stringify(arrayType)}`); - // } - // } - // } - // } - } else { - console.debug("NOT A STRING (SKIPPING)", next); - } - - next = toWalk.pop(); - } - return currentSchemaNode; - } +export interface SchemaDefinitions { + types: Map; + records: Map; + fields: Map; } diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index 1095724..2fda83f 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -1,67 +1,75 @@ import { - SchemaRecord, - SchemaEntry, + isSchemaEntryBase, + isSchemaRecord, + SchemaDefinitions, SchemaDocument, + SchemaEntry, SchemaEntryBase, SchemaEnum, SchemaField, - isSchemaEntryBase, - isSchemaRecord, - FieldSchemaNode, - ResolvedSchema, + SchemaRecord, } from "./definitions"; +import { SchemaNodeResolver } from "./schemaNodeResolver"; import { SCHEMA_DOCS_v19_09_MAP } from "./versions"; export class GalaxyWorkflowFormat2SchemaLoader { - private _root?: SchemaRecord; - private _typeMap = new Map(); - private _fieldsMap = new Map(); + public readonly definitions: SchemaDefinitions; private _documentTypeMap = new Map>(); private _namespaces = new Map(); - public readonly resolvedSchema: ResolvedSchema; + public readonly nodeResolver: SchemaNodeResolver; private _unknownTypes: string[] = []; private _extendedTypes: Set = new Set(); - constructor() { - this.loadSchema_v19_09(); - this.resolvedSchema = this.resolveSchema(); - - // if (this._unknownTypes) { - // console.debug(`UNKNOWN Types: ${this._unknownTypes.length}`); - // this._unknownTypes.forEach((t) => { - // console.debug(` ${t}`); - // }); - // } + private _root?: SchemaRecord; + constructor(private readonly enableDebugTrace: boolean = false) { + this.definitions = this.loadSchemaDefinitions_v19_09(); + this.nodeResolver = this.createNodeResolver(); + + if (this.enableDebugTrace) { + if (this._unknownTypes) { + console.debug(`UNKNOWN Types: ${this._unknownTypes.length}`); + this._unknownTypes.forEach((t) => { + console.debug(` ${t}`); + }); + } - // if (this._extendedTypes) { - // console.debug(`EXTENDED Types (Unresolved): ${this._extendedTypes.size}`); - // this._extendedTypes.forEach((type) => { - // if (!this._typeMap.has(type)) { - // console.debug(` ${type} ${this._typeMap.has(type) ? "[found]" : ""}`); - // } - // }); - // } + if (this._extendedTypes) { + console.debug(`EXTENDED Types (Unresolved): ${this._extendedTypes.size}`); + this._extendedTypes.forEach((type) => { + if (!this.definitions.types.has(type)) { + console.debug(` ${type} ${this.definitions.types.has(type) ? "[found]" : ""}`); + } + }); + } + } } - private loadSchema_v19_09(): void { + private loadSchemaDefinitions_v19_09(): SchemaDefinitions { + const definitions: SchemaDefinitions = { + types: new Map(), + records: new Map(), + fields: new Map(), + }; SCHEMA_DOCS_v19_09_MAP.forEach((schemaDoc) => { const types = this.loadSchemaDocument(schemaDoc); types.forEach((v, k) => { - this._typeMap.set(k, v); + definitions.types.set(k, v); if (isSchemaRecord(v)) { + definitions.records.set(k, v); v.fields.forEach((field) => { - if (this._fieldsMap.has(field.name)) { - console.debug("****** DUPLICATED FIELD", field.name); + if (definitions.fields.has(field.name)) { + if (this.enableDebugTrace) console.debug("****** DUPLICATED FIELD", field.name); } - this._fieldsMap.set(field.name, field); + definitions.fields.set(field.name, field); }); } }); }); + return definitions; } private loadSchemaDocument(schemaDoc: SchemaDocument): Map { - console.debug(`Loading schema doc: ${schemaDoc.$base}`); + if (this.enableDebugTrace) console.debug(`Loading schema doc: ${schemaDoc.$base}`); this.registerDocumentNamespaces(schemaDoc); const documentEntries = new Map(); schemaDoc.$graph.forEach((entry: SchemaEntryBase) => { @@ -94,7 +102,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { } private loadEnum(entry: SchemaEnum): SchemaEnum { - // console.debug(`Enum: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""}`); + if (this.enableDebugTrace) console.debug(`Enum: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""}`); const enumEntry: SchemaEnum = { name: entry.name, type: entry.type, @@ -106,9 +114,10 @@ export class GalaxyWorkflowFormat2SchemaLoader { } private loadRecord(entry: SchemaRecord): SchemaRecord { - // console.debug( - // `Record: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""} ${"extends" in entry ? "[extends]" : ""}` - // ); + if (this.enableDebugTrace) + console.debug( + `Record: ${entry.name} ${"abstract" in entry ? "[abstract]" : ""} ${"extends" in entry ? "[extends]" : ""}` + ); const fields = this.readEntryFields(entry); const recordEntry: SchemaRecord = { @@ -142,13 +151,12 @@ export class GalaxyWorkflowFormat2SchemaLoader { // Is an Object if (entry.fields) { Object.entries(entry.fields).forEach(([key, value]) => { - // console.debug(`Object Field: ${key} ${value}`); if (isSchemaEntryBase(value)) { fields.push({ name: key, type: value.type }); } }); } else { - console.debug("------- NO FIELDS"); + if (this.enableDebugTrace) console.debug("------- NO FIELDS"); } } // if (fields) { @@ -165,7 +173,8 @@ export class GalaxyWorkflowFormat2SchemaLoader { if (typeof fieldType === "string") { fieldType = this.resolveTypeName(fieldType as string); } else { - console.debug(` --Field type NOT string: ${JSON.stringify(fieldType)} -> ${typeof fieldType}`); + if (this.enableDebugTrace) + console.debug(` --Field type NOT string: ${JSON.stringify(fieldType)} -> ${typeof fieldType}`); } return { name: field.name, type: fieldType, default: field.default, doc: field.doc }; } @@ -182,10 +191,10 @@ export class GalaxyWorkflowFormat2SchemaLoader { if (schemaTypes?.has(type)) { rawTypeName = type; } else { - console.debug(`Type ${type} not found in namespace ${namespace}.`); + if (this.enableDebugTrace) console.debug(`Type ${type} not found in namespace ${namespace}.`); } } else { - console.debug(`Namespace ${namespace} not found.`); + if (this.enableDebugTrace) console.debug(`Namespace ${namespace} not found.`); } } } @@ -194,31 +203,20 @@ export class GalaxyWorkflowFormat2SchemaLoader { private resolveTypeToSchemaEntry(rawTypeName: string): SchemaEntry { const typeName = this.resolveTypeName(rawTypeName); - if (this._typeMap.has(typeName)) { - return this._typeMap.get(typeName) as SchemaEntry; + if (this.definitions.types.has(typeName)) { + return this.definitions.types.get(typeName) as SchemaEntry; } throw new Error(`Unresolvable type ${rawTypeName}`); } - private resolveSchema(): ResolvedSchema { + private createNodeResolver(): SchemaNodeResolver { this.expandRecords(); - this.resolveFields(); - return new ResolvedSchema(this._typeMap, this._fieldsMap, this._root); - } - - private resolveFields(): void { - this._typeMap.forEach((value: SchemaEntry) => { - if (isSchemaRecord(value)) { - value.fields.forEach((field) => { - new FieldSchemaNode(field); - }); - } - }); + return new SchemaNodeResolver(this.definitions); } /** Expands all records with the fields defined in the extended types.*/ private expandRecords(): void { - this._typeMap.forEach((value: SchemaEntry) => { + this.definitions.types.forEach((value: SchemaEntry) => { if (isSchemaRecord(value)) { this.expandRecord(value); } @@ -237,7 +235,6 @@ export class GalaxyWorkflowFormat2SchemaLoader { private collectExtensionFields(record: SchemaRecord, extensionFields: SchemaField[]): SchemaField[] { record.extends?.forEach((typeToExtend) => { - // console.debug(`RESOLVE ${typeToExtend}`); const resolved = this.resolveTypeToSchemaEntry(typeToExtend); if (isSchemaRecord(resolved)) { extensionFields.push(...resolved.fields); diff --git a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts new file mode 100644 index 0000000..0be78f6 --- /dev/null +++ b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts @@ -0,0 +1,35 @@ +import { NodePath, Segment } from "@gxwf/server-common/src/ast/types"; +import { SchemaDefinitions, SchemaNode, RecordSchemaNode, FieldSchemaNode } from "./definitions"; + +export class SchemaNodeResolver { + constructor(public readonly definitions: SchemaDefinitions) {} + + public resolveSchemaContext(path: NodePath): SchemaNode | undefined { + const toWalk = path.slice(); + const lastSegment = toWalk.pop(); + const schemaNodeFound = this.getSchemaNodeForSegment(lastSegment); + while (toWalk.length && !schemaNodeFound) { + const parentSegment = toWalk.pop(); + const parentNode = this.getSchemaNodeForSegment(parentSegment); + if (parentNode) { + return this.getSchemaNodeForSegment(parentNode.typeRef); + } + } + + return schemaNodeFound; + } + + private getSchemaNodeForSegment(pathSegment?: Segment): SchemaNode | undefined { + if (typeof pathSegment === "string") { + if (this.definitions.records.has(pathSegment)) { + const record = this.definitions.records.get(pathSegment); + if (record) return new RecordSchemaNode(record); + } + if (this.definitions.fields.has(pathSegment)) { + const field = this.definitions.fields.get(pathSegment); + if (field) return new FieldSchemaNode(field); + } + } + return undefined; + } +} diff --git a/server/gx-workflow-ls-format2/src/schema/versions.ts b/server/gx-workflow-ls-format2/src/schema/versions.ts index db86e21..ed737d6 100644 --- a/server/gx-workflow-ls-format2/src/schema/versions.ts +++ b/server/gx-workflow-ls-format2/src/schema/versions.ts @@ -1,7 +1,11 @@ -import schema_v19_09_workflows from "../../../../workflow-languages/schemas/gxformat2/v19_09/workflows.yaml"; -import schema_common_metaschema_base from "../../../../workflow-languages/schemas/gxformat2/common/metaschema/metaschema_base.yaml"; -import schema_v19_09_process from "../../../../workflow-languages/schemas/gxformat2/v19_09/process.yaml"; -import schema_common from "../../../../workflow-languages/schemas/gxformat2/common/common.yaml"; +//TODO: remove this reference when https://github.com/sumwatshade/jest-transform-yaml/pull/20 is merged and upgrade to jest 28 +// eslint-disable-next-line @typescript-eslint/triple-slash-reference +/// + +import schema_v19_09_workflows from "@schemas/gxformat2/v19_09/workflows.yaml"; +import schema_common_metaschema_base from "@schemas/gxformat2/common/metaschema/metaschema_base.yaml"; +import schema_v19_09_process from "@schemas/gxformat2/v19_09/process.yaml"; +import schema_common from "@schemas/gxformat2/common/common.yaml"; import { SchemaDocument } from "./definitions"; /** From eb15c167886956171e97ec37d2bb66e4bcf6a201 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 22 Jul 2022 17:34:29 +0200 Subject: [PATCH 13/50] Add some tests for schema handling --- .../tests/unit/schema.test.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 server/gx-workflow-ls-format2/tests/unit/schema.test.ts diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts new file mode 100644 index 0000000..08a0b95 --- /dev/null +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -0,0 +1,44 @@ +import { NodePath } from "@gxwf/server-common/src/ast/types"; +import { SchemaNodeResolver } from "../../src/schema/schemaNodeResolver"; +import { GalaxyWorkflowFormat2SchemaLoader } from "../../src/schema/schemaLoader"; + +describe("Gxformat2 Schema Handling", () => { + describe("Schema Version 19_09", () => { + let schemaLoader: GalaxyWorkflowFormat2SchemaLoader; + beforeAll(() => { + schemaLoader = new GalaxyWorkflowFormat2SchemaLoader(); + }); + describe("GalaxyWorkflowFormat2SchemaLoader", () => { + it("should load all schema record definitions", () => { + expect(schemaLoader.definitions.records.size).toBe(25); + }); + }); + + describe("SchemaNodeResolver", () => { + let nodeResolver: SchemaNodeResolver; + beforeAll(() => { + nodeResolver = new SchemaNodeResolver(schemaLoader.definitions); + }); + describe("resolveSchemaContext", () => { + it.each([ + [["class"], "class"], + [["inputs"], "inputs"], + [["inputs", 0], "InputParameter"], + [["inputs", 0, "doc"], "doc"], + [["inputs", "input1"], "InputParameter"], + [["inputs", "input1", "label"], "label"], + [["outputs"], "outputs"], + [["outputs", 1], "OutputParameter"], + [["outputs", "output1"], "OutputParameter"], + [["steps"], "steps"], + [["steps", 5], "WorkflowStep"], + [["steps", "random", "tool_id"], "tool_id"], + ])("returns expected schema node name from path", (nodePath: NodePath, expectedNodeName: string) => { + const schemaNode = nodeResolver.resolveSchemaContext(nodePath); + expect(schemaNode).toBeDefined(); + expect(schemaNode?.name).toBe(expectedNodeName); + }); + }); + }); + }); +}); From c4821431c1450a48adf806ff563ccfc2bac177c4 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 22 Jul 2022 18:54:00 +0200 Subject: [PATCH 14/50] Cleanup schema imports --- server/gx-workflow-ls-format2/src/languageService.ts | 2 +- server/gx-workflow-ls-format2/src/schema/index.ts | 5 +++++ server/gx-workflow-ls-format2/tests/unit/schema.test.ts | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/schema/index.ts diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index 3c54c2c..8bfd6ca 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -12,7 +12,7 @@ import { } from "@gxwf/server-common/src/languageTypes"; import { LanguageService, getLanguageService } from "@gxwf/yaml-language-service/src/yamlLanguageService"; import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; -import { GalaxyWorkflowFormat2SchemaLoader } from "./schema/schemaLoader"; +import { GalaxyWorkflowFormat2SchemaLoader } from "./schema"; import { GxFormat2HoverService } from "./services/hoverService"; /** diff --git a/server/gx-workflow-ls-format2/src/schema/index.ts b/server/gx-workflow-ls-format2/src/schema/index.ts new file mode 100644 index 0000000..17c3bc5 --- /dev/null +++ b/server/gx-workflow-ls-format2/src/schema/index.ts @@ -0,0 +1,5 @@ +import { GalaxyWorkflowFormat2SchemaLoader } from "./schemaLoader"; +import { SchemaNode } from "./definitions"; +import { SchemaNodeResolver } from "./schemaNodeResolver"; + +export { GalaxyWorkflowFormat2SchemaLoader, SchemaNode, SchemaNodeResolver }; diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts index 08a0b95..66f32aa 100644 --- a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -1,6 +1,5 @@ import { NodePath } from "@gxwf/server-common/src/ast/types"; -import { SchemaNodeResolver } from "../../src/schema/schemaNodeResolver"; -import { GalaxyWorkflowFormat2SchemaLoader } from "../../src/schema/schemaLoader"; +import { GalaxyWorkflowFormat2SchemaLoader, SchemaNodeResolver } from "../../src/schema"; describe("Gxformat2 Schema Handling", () => { describe("Schema Version 19_09", () => { From 0a6e12ef4bbf0297dce4acccfc17a5c8dd62c78e Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 22 Jul 2022 19:12:06 +0200 Subject: [PATCH 15/50] Refactor hoverService --- .../src/services/hoverService.ts | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/services/hoverService.ts b/server/gx-workflow-ls-format2/src/services/hoverService.ts index 569eb4a..d662adf 100644 --- a/server/gx-workflow-ls-format2/src/services/hoverService.ts +++ b/server/gx-workflow-ls-format2/src/services/hoverService.ts @@ -1,10 +1,10 @@ import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; import { NodePath } from "@gxwf/server-common/src/ast/types"; import { Hover, MarkupContent, MarkupKind, Position, Range, TextDocument } from "@gxwf/server-common/src/languageTypes"; -import { ResolvedSchema } from "../schema/definitions"; +import { SchemaNode, SchemaNodeResolver } from "../schema"; export class GxFormat2HoverService { - constructor(protected readonly resolvedSchema: ResolvedSchema) {} + constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} //Based on https://github.com/microsoft/vscode-json-languageservice/blob/12275e448a91973777c94a2e5d92c961f281231a/src/services/jsonHover.ts#L23 public async doHover( @@ -41,16 +41,23 @@ export class GxFormat2HoverService { ); const location = nodeManager.getPathFromNode(hoverRangeNode); - const nodeDoc = this.getDocFromNodePath(location); - const contents = "**Debug Test**\n\n" + nodeDoc; + const schemaNode = this.schemaNodeResolver.resolveSchemaContext(location); + const contents = this.getHoverMarkdownContentsForNode(schemaNode); const hover = this.createHover(contents, hoverRange); return Promise.resolve(hover); } - private getDocFromNodePath(path: NodePath): string { - const schemaNode = this.resolvedSchema.resolveSchemaContext(path); - if (!schemaNode) return "Node not found"; - return schemaNode.documentation || "Doc not found"; + private getHoverMarkdownContentsForNode(schemaNode?: SchemaNode): string { + const contents = []; + if (schemaNode) { + contents.push(`**${schemaNode?.name}**`); + contents.push(schemaNode?.documentation || "Doc not found"); + } else { + contents.push("Schema node not found"); + } + // DEBUG + // contents.push(...this.debugInfo(location, schemaNode)); + return contents.join("\n\n"); } private createHover(contents: string, hoverRange: Range): Hover { @@ -64,4 +71,12 @@ export class GxFormat2HoverService { }; return result; } + + private debugInfo(location: NodePath, schemaNode?: SchemaNode): string[] { + return ["---", `## ${location}`, "---", `${this.toMarkdownFencedCodeBlock(schemaNode)}`]; + } + + private toMarkdownFencedCodeBlock(object: unknown): string { + return "```json\n" + `${JSON.stringify(object, null, 2)}` + "\n```"; + } } From 7dd6c2ccc874763fde1ed717ddd41f0232b5d4f3 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 24 Jul 2022 14:30:20 +0200 Subject: [PATCH 16/50] Define root node in schema definitions --- .../src/schema/definitions.ts | 16 +++++++++++++++- .../src/schema/schemaLoader.ts | 2 +- .../src/schema/schemaNodeResolver.ts | 7 +++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 43a2c0c..1e36e42 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -136,6 +136,7 @@ export interface SchemaNode { documentation: string | undefined; supportsArray: boolean; typeRef: string; + isRoot: boolean; } export class FieldSchemaNode implements SchemaNode { @@ -174,6 +175,10 @@ export class FieldSchemaNode implements SchemaNode { return []; } + public get isRoot(): boolean { + return false; + } + public get supportsArray(): boolean { return this._allowedTypes.some((t) => isArrayFieldType(t)); } @@ -197,7 +202,12 @@ export class FieldSchemaNode implements SchemaNode { } export class RecordSchemaNode implements SchemaNode { - public static readonly ROOT_NAME: string = "_root_"; + public static readonly NULL: SchemaNode = new RecordSchemaNode({ + name: "null", + type: "null", + fields: [], + documentRoot: true, + }); private readonly _schemaRecord: SchemaRecord; private readonly _fields: Map; @@ -226,6 +236,10 @@ export class RecordSchemaNode implements SchemaNode { return this.fields; } + public get isRoot(): boolean { + return !!this._schemaRecord.documentRoot; + } + public get supportsArray(): boolean { return false; } diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index 2fda83f..1da0bd3 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -211,7 +211,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { private createNodeResolver(): SchemaNodeResolver { this.expandRecords(); - return new SchemaNodeResolver(this.definitions); + return new SchemaNodeResolver(this.definitions, this._root); } /** Expands all records with the fields defined in the extended types.*/ diff --git a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts index 0be78f6..5936b97 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts @@ -1,8 +1,11 @@ import { NodePath, Segment } from "@gxwf/server-common/src/ast/types"; -import { SchemaDefinitions, SchemaNode, RecordSchemaNode, FieldSchemaNode } from "./definitions"; +import { SchemaDefinitions, SchemaNode, RecordSchemaNode, FieldSchemaNode, SchemaRecord } from "./definitions"; export class SchemaNodeResolver { - constructor(public readonly definitions: SchemaDefinitions) {} + public readonly rootNode: SchemaNode; + constructor(public readonly definitions: SchemaDefinitions, root?: SchemaRecord) { + this.rootNode = root ? new RecordSchemaNode(root) : RecordSchemaNode.NULL; + } public resolveSchemaContext(path: NodePath): SchemaNode | undefined { const toWalk = path.slice(); From 641fe704d6649e101422f3406a658295514daa4f Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 24 Jul 2022 14:55:13 +0200 Subject: [PATCH 17/50] Refactor NodeManager.getNodeFromOffset --- .../server-common/src/ast/nodeManager.ts | 25 +++++++++++++----- .../packages/server-common/src/ast/types.ts | 1 + .../packages/server-common/src/ast/utils.ts | 26 ------------------- .../src/parser/astTypes.ts | 8 +++--- .../src/parser/yamlDocument.ts | 2 +- 5 files changed, 25 insertions(+), 37 deletions(-) diff --git a/server/packages/server-common/src/ast/nodeManager.ts b/server/packages/server-common/src/ast/nodeManager.ts index 939962b..d3d8a55 100644 --- a/server/packages/server-common/src/ast/nodeManager.ts +++ b/server/packages/server-common/src/ast/nodeManager.ts @@ -1,6 +1,6 @@ import { Position, Range, TextDocument } from "../languageTypes"; import { ParsedDocument, ASTNode, ObjectASTNode, NodePath } from "./types"; -import { findNodeAtOffset, getPropertyNodeFromPath } from "./utils"; +import { getPropertyNodeFromPath } from "./utils"; export class ASTNodeManager { constructor(private readonly textDocument: TextDocument, private readonly parsedDocument: ParsedDocument) {} @@ -9,11 +9,8 @@ export class ASTNodeManager { return this.parsedDocument.root; } - public getNodeFromOffset(offset: number, includeRightBound = false): ASTNode | undefined { - if (this.root) { - return findNodeAtOffset(this.root, offset, includeRightBound); - } - return undefined; + public getNodeFromOffset(offset: number): ASTNode | undefined { + return this.parsedDocument.getNodeFromOffset(offset); } public getNodeAtPosition(position: Position): ASTNode | undefined { @@ -69,6 +66,22 @@ export class ASTNodeManager { return parent.children[previousNodeIndex]; } + public getChildren(node: ASTNode): ASTNode[] { + return node.children ?? []; + } + + public getDeclaredPropertyNames(node: ASTNode): Set { + const declaredNodes = this.getChildren(node); + const result = new Set(); + declaredNodes.forEach((node) => { + if (node.type === "property") { + const key = node.keyNode.value; + result.add(key); + } + }); + return result; + } + public getNodeFromPath(path: string): ASTNode | null { const root = this.root; if (!root) return null; diff --git a/server/packages/server-common/src/ast/types.ts b/server/packages/server-common/src/ast/types.ts index 06ba51c..cec2efd 100644 --- a/server/packages/server-common/src/ast/types.ts +++ b/server/packages/server-common/src/ast/types.ts @@ -24,6 +24,7 @@ export { export interface ParsedDocument { root?: ASTNode; + getNodeFromOffset(offset: number): ASTNode | undefined; } /** diff --git a/server/packages/server-common/src/ast/utils.ts b/server/packages/server-common/src/ast/utils.ts index 220bc0d..790353a 100644 --- a/server/packages/server-common/src/ast/utils.ts +++ b/server/packages/server-common/src/ast/utils.ts @@ -39,29 +39,3 @@ export function getPropertyNodeFromPath(root: ASTNode, path: string): ASTNode | } return currentNode; } - -export function contains(node: ASTNode, offset: number, includeRightBound = false): boolean { - return ( - (offset >= node.offset && offset <= node.offset + node.length) || - (includeRightBound && offset === node.offset + node.length) - ); -} - -export function findNodeAtOffset(node: ASTNode, offset: number, includeRightBound: boolean): ASTNode | undefined { - if (includeRightBound === void 0) { - includeRightBound = false; - } - if (contains(node, offset, includeRightBound)) { - const children = node.children; - if (Array.isArray(children)) { - for (let i = 0; i < children.length && children[i].offset <= offset; i++) { - const item = findNodeAtOffset(children[i], offset, includeRightBound); - if (item) { - return item; - } - } - } - return node; - } - return undefined; -} diff --git a/server/packages/yaml-language-service/src/parser/astTypes.ts b/server/packages/yaml-language-service/src/parser/astTypes.ts index 7d07f0f..f7f0eaf 100644 --- a/server/packages/yaml-language-service/src/parser/astTypes.ts +++ b/server/packages/yaml-language-service/src/parser/astTypes.ts @@ -39,9 +39,9 @@ export abstract class ASTNodeImpl { this.internalNode = internalNode; } - public getNodeFromOffsetEndInclusive(offset: number): ASTNode | null { + public getNodeFromOffsetEndInclusive(offset: number): ASTNode | undefined { const collector: BaseASTNode[] = []; - const findNode = (node: BaseASTNode): BaseASTNode | null => { + const findNode = (node: BaseASTNode): BaseASTNode | undefined => { if (offset >= node.offset && offset <= node.offset + node.length) { const children = node.children; if (children && children.length) { @@ -54,7 +54,7 @@ export abstract class ASTNodeImpl { return node; } } - return null; + return undefined; }; const foundNode = findNode(this); let currMinDist = Number.MAX_VALUE; @@ -66,7 +66,7 @@ export abstract class ASTNodeImpl { currMinDist = minDist; } } - return (currMinNode || foundNode) as ASTNode | null; + return (currMinNode || foundNode) as ASTNode | undefined; } public get children(): ASTNode[] { diff --git a/server/packages/yaml-language-service/src/parser/yamlDocument.ts b/server/packages/yaml-language-service/src/parser/yamlDocument.ts index c0aba22..07677b5 100644 --- a/server/packages/yaml-language-service/src/parser/yamlDocument.ts +++ b/server/packages/yaml-language-service/src/parser/yamlDocument.ts @@ -97,7 +97,7 @@ export class YAMLDocument implements ParsedDocument { * @param offset The offset in the text document * @returns The syntax node that lies at the given offset */ - public getNodeFromOffset(offset: number): ASTNode | null { + public getNodeFromOffset(offset: number): ASTNode | undefined { const rootNode = this.root as ObjectASTNodeImpl; return rootNode?.getNodeFromOffsetEndInclusive(offset); } From ce622c2ed66b96dd960937e91ff9bfad78cde284 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 24 Jul 2022 16:13:47 +0200 Subject: [PATCH 18/50] Adapt NodeManager.getPathFromNode --- .../server-common/src/ast/nodeManager.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/server/packages/server-common/src/ast/nodeManager.ts b/server/packages/server-common/src/ast/nodeManager.ts index d3d8a55..1a9f16b 100644 --- a/server/packages/server-common/src/ast/nodeManager.ts +++ b/server/packages/server-common/src/ast/nodeManager.ts @@ -1,5 +1,5 @@ import { Position, Range, TextDocument } from "../languageTypes"; -import { ParsedDocument, ASTNode, ObjectASTNode, NodePath } from "./types"; +import { ParsedDocument, ASTNode, ObjectASTNode, NodePath, Segment } from "./types"; import { getPropertyNodeFromPath } from "./utils"; export class ASTNodeManager { @@ -89,20 +89,29 @@ export class ASTNodeManager { } public getPathFromNode(node: ASTNode): NodePath { - if (!node.parent || !node.parent.children) { - return []; + const path: NodePath = []; + let current: ASTNode | undefined = node; + while (current) { + const segment = this.getNodeSegment(current); + if (segment) { + path.push(segment); + } + current = current.parent; + } + return path.reverse(); + } + + private getNodeSegment(node: ASTNode): Segment | undefined { + if (node.type === "property") { + const name = node.keyNode.value as string; + return name; } - const path = this.getPathFromNode(node.parent); - if (node.parent.type === "property") { - const key = node.parent.children[0].value as string; - path.push(key); - } else if (node.parent.type === "array") { + if (node.parent?.type === "array") { const index = node.parent.children.indexOf(node); if (index !== -1) { - path.push(index); + return index; } } - return path; } public getStepNodes(): ObjectASTNode[] { From 34344bede4cedbc2c9a86243f3cb41d24cca7d85 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 25 Jul 2022 17:45:52 +0200 Subject: [PATCH 19/50] Fix debug hover information --- .../src/services/hoverService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/services/hoverService.ts b/server/gx-workflow-ls-format2/src/services/hoverService.ts index d662adf..11fd931 100644 --- a/server/gx-workflow-ls-format2/src/services/hoverService.ts +++ b/server/gx-workflow-ls-format2/src/services/hoverService.ts @@ -43,11 +43,13 @@ export class GxFormat2HoverService { const location = nodeManager.getPathFromNode(hoverRangeNode); const schemaNode = this.schemaNodeResolver.resolveSchemaContext(location); const contents = this.getHoverMarkdownContentsForNode(schemaNode); - const hover = this.createHover(contents, hoverRange); + // DEBUG + //contents.push(...this.debugInfo(location, schemaNode)); + const hover = this.createHover(contents.join("\n\n"), hoverRange); return Promise.resolve(hover); } - private getHoverMarkdownContentsForNode(schemaNode?: SchemaNode): string { + private getHoverMarkdownContentsForNode(schemaNode?: SchemaNode): string[] { const contents = []; if (schemaNode) { contents.push(`**${schemaNode?.name}**`); @@ -55,9 +57,7 @@ export class GxFormat2HoverService { } else { contents.push("Schema node not found"); } - // DEBUG - // contents.push(...this.debugInfo(location, schemaNode)); - return contents.join("\n\n"); + return contents; } private createHover(contents: string, hoverRange: Range): Hover { From eb3ff4e9b671fbef694a5855a5420b8aeab76454 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Thu, 28 Jul 2022 16:15:15 +0200 Subject: [PATCH 20/50] Refactor YAMLDocument `getNodeFromOffset` --- .../src/parser/charCode.ts | 436 ++++++++++++++++++ .../src/parser/yamlDocument.ts | 121 +++-- .../src/utils/textBuffer.ts | 68 ++- 3 files changed, 572 insertions(+), 53 deletions(-) create mode 100644 server/packages/yaml-language-service/src/parser/charCode.ts diff --git a/server/packages/yaml-language-service/src/parser/charCode.ts b/server/packages/yaml-language-service/src/parser/charCode.ts new file mode 100644 index 0000000..d7c8c33 --- /dev/null +++ b/server/packages/yaml-language-service/src/parser/charCode.ts @@ -0,0 +1,436 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// copied from https://github.com/Microsoft/vscode/blob/015c3afe96966df50c15a7d66be2ab0ef1dc5f49/src/vs/base/common/charCode.ts + +// Names from https://blog.codinghorror.com/ascii-pronunciation-rules-for-programmers/ + +/** + * An inlined enum containing useful character codes (to be used with String.charCodeAt). + * Please leave the const keyword such that it gets inlined when compiled to JavaScript! + */ +export const enum CharCode { + Null = 0, + /** + * The `\b` character. + */ + Backspace = 8, + /** + * The `\t` character. + */ + Tab = 9, + /** + * The `\n` character. + */ + LineFeed = 10, + /** + * The `\r` character. + */ + CarriageReturn = 13, + Space = 32, + /** + * The `!` character. + */ + ExclamationMark = 33, + /** + * The `"` character. + */ + DoubleQuote = 34, + /** + * The `#` character. + */ + Hash = 35, + /** + * The `$` character. + */ + DollarSign = 36, + /** + * The `%` character. + */ + PercentSign = 37, + /** + * The `&` character. + */ + Ampersand = 38, + /** + * The `'` character. + */ + SingleQuote = 39, + /** + * The `(` character. + */ + OpenParen = 40, + /** + * The `)` character. + */ + CloseParen = 41, + /** + * The `*` character. + */ + Asterisk = 42, + /** + * The `+` character. + */ + Plus = 43, + /** + * The `,` character. + */ + Comma = 44, + /** + * The `-` character. + */ + Dash = 45, + /** + * The `.` character. + */ + Period = 46, + /** + * The `/` character. + */ + Slash = 47, + + Digit0 = 48, + Digit1 = 49, + Digit2 = 50, + Digit3 = 51, + Digit4 = 52, + Digit5 = 53, + Digit6 = 54, + Digit7 = 55, + Digit8 = 56, + Digit9 = 57, + + /** + * The `:` character. + */ + Colon = 58, + /** + * The `;` character. + */ + Semicolon = 59, + /** + * The `<` character. + */ + LessThan = 60, + /** + * The `=` character. + */ + Equals = 61, + /** + * The `>` character. + */ + GreaterThan = 62, + /** + * The `?` character. + */ + QuestionMark = 63, + /** + * The `@` character. + */ + AtSign = 64, + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + /** + * The `[` character. + */ + OpenSquareBracket = 91, + /** + * The `\` character. + */ + Backslash = 92, + /** + * The `]` character. + */ + CloseSquareBracket = 93, + /** + * The `^` character. + */ + Caret = 94, + /** + * The `_` character. + */ + Underline = 95, + /** + * The ``(`)`` character. + */ + BackTick = 96, + + a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, + g = 103, + h = 104, + i = 105, + j = 106, + k = 107, + l = 108, + m = 109, + n = 110, + o = 111, + p = 112, + q = 113, + r = 114, + s = 115, + t = 116, + u = 117, + v = 118, + w = 119, + x = 120, + y = 121, + z = 122, + + /** + * The `{` character. + */ + OpenCurlyBrace = 123, + /** + * The `|` character. + */ + Pipe = 124, + /** + * The `}` character. + */ + CloseCurlyBrace = 125, + /** + * The `~` character. + */ + Tilde = 126, + + U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent + U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent + U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent + U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde + U_Combining_Macron = 0x0304, // U+0304 Combining Macron + U_Combining_Overline = 0x0305, // U+0305 Combining Overline + U_Combining_Breve = 0x0306, // U+0306 Combining Breve + U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above + U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis + U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above + U_Combining_Ring_Above = 0x030a, // U+030A Combining Ring Above + U_Combining_Double_Acute_Accent = 0x030b, // U+030B Combining Double Acute Accent + U_Combining_Caron = 0x030c, // U+030C Combining Caron + U_Combining_Vertical_Line_Above = 0x030d, // U+030D Combining Vertical Line Above + U_Combining_Double_Vertical_Line_Above = 0x030e, // U+030E Combining Double Vertical Line Above + U_Combining_Double_Grave_Accent = 0x030f, // U+030F Combining Double Grave Accent + U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu + U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve + U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above + U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above + U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above + U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right + U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below + U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below + U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below + U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below + U_Combining_Left_Angle_Above = 0x031a, // U+031A Combining Left Angle Above + U_Combining_Horn = 0x031b, // U+031B Combining Horn + U_Combining_Left_Half_Ring_Below = 0x031c, // U+031C Combining Left Half Ring Below + U_Combining_Up_Tack_Below = 0x031d, // U+031D Combining Up Tack Below + U_Combining_Down_Tack_Below = 0x031e, // U+031E Combining Down Tack Below + U_Combining_Plus_Sign_Below = 0x031f, // U+031F Combining Plus Sign Below + U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below + U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below + U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below + U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below + U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below + U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below + U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below + U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla + U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek + U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below + U_Combining_Bridge_Below = 0x032a, // U+032A Combining Bridge Below + U_Combining_Inverted_Double_Arch_Below = 0x032b, // U+032B Combining Inverted Double Arch Below + U_Combining_Caron_Below = 0x032c, // U+032C Combining Caron Below + U_Combining_Circumflex_Accent_Below = 0x032d, // U+032D Combining Circumflex Accent Below + U_Combining_Breve_Below = 0x032e, // U+032E Combining Breve Below + U_Combining_Inverted_Breve_Below = 0x032f, // U+032F Combining Inverted Breve Below + U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below + U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below + U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line + U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line + U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay + U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay + U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay + U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay + U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay + U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below + U_Combining_Inverted_Bridge_Below = 0x033a, // U+033A Combining Inverted Bridge Below + U_Combining_Square_Below = 0x033b, // U+033B Combining Square Below + U_Combining_Seagull_Below = 0x033c, // U+033C Combining Seagull Below + U_Combining_X_Above = 0x033d, // U+033D Combining X Above + U_Combining_Vertical_Tilde = 0x033e, // U+033E Combining Vertical Tilde + U_Combining_Double_Overline = 0x033f, // U+033F Combining Double Overline + U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark + U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark + U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni + U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis + U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos + U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni + U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above + U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below + U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below + U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below + U_Combining_Not_Tilde_Above = 0x034a, // U+034A Combining Not Tilde Above + U_Combining_Homothetic_Above = 0x034b, // U+034B Combining Homothetic Above + U_Combining_Almost_Equal_To_Above = 0x034c, // U+034C Combining Almost Equal To Above + U_Combining_Left_Right_Arrow_Below = 0x034d, // U+034D Combining Left Right Arrow Below + U_Combining_Upwards_Arrow_Below = 0x034e, // U+034E Combining Upwards Arrow Below + U_Combining_Grapheme_Joiner = 0x034f, // U+034F Combining Grapheme Joiner + U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above + U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above + U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata + U_Combining_X_Below = 0x0353, // U+0353 Combining X Below + U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below + U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below + U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below + U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above + U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right + U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below + U_Combining_Double_Ring_Below = 0x035a, // U+035A Combining Double Ring Below + U_Combining_Zigzag_Above = 0x035b, // U+035B Combining Zigzag Above + U_Combining_Double_Breve_Below = 0x035c, // U+035C Combining Double Breve Below + U_Combining_Double_Breve = 0x035d, // U+035D Combining Double Breve + U_Combining_Double_Macron = 0x035e, // U+035E Combining Double Macron + U_Combining_Double_Macron_Below = 0x035f, // U+035F Combining Double Macron Below + U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde + U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve + U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below + U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A + U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E + U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I + U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O + U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U + U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C + U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D + U_Combining_Latin_Small_Letter_H = 0x036a, // U+036A Combining Latin Small Letter H + U_Combining_Latin_Small_Letter_M = 0x036b, // U+036B Combining Latin Small Letter M + U_Combining_Latin_Small_Letter_R = 0x036c, // U+036C Combining Latin Small Letter R + U_Combining_Latin_Small_Letter_T = 0x036d, // U+036D Combining Latin Small Letter T + U_Combining_Latin_Small_Letter_V = 0x036e, // U+036E Combining Latin Small Letter V + U_Combining_Latin_Small_Letter_X = 0x036f, // U+036F Combining Latin Small Letter X + + /** + * Unicode Character 'LINE SEPARATOR' (U+2028) + * http://www.fileformat.info/info/unicode/char/2028/index.htm + */ + LINE_SEPARATOR = 0x2028, + /** + * Unicode Character 'PARAGRAPH SEPARATOR' (U+2029) + * http://www.fileformat.info/info/unicode/char/2029/index.htm + */ + PARAGRAPH_SEPARATOR = 0x2029, + /** + * Unicode Character 'NEXT LINE' (U+0085) + * http://www.fileformat.info/info/unicode/char/0085/index.htm + */ + NEXT_LINE = 0x0085, + + // http://www.fileformat.info/info/unicode/category/Sk/list.htm + U_CIRCUMFLEX = 0x005e, // U+005E CIRCUMFLEX + U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT + U_DIAERESIS = 0x00a8, // U+00A8 DIAERESIS + U_MACRON = 0x00af, // U+00AF MACRON + U_ACUTE_ACCENT = 0x00b4, // U+00B4 ACUTE ACCENT + U_CEDILLA = 0x00b8, // U+00B8 CEDILLA + U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02c2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD + U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02c3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD + U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02c4, // U+02C4 MODIFIER LETTER UP ARROWHEAD + U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02c5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD + U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02d2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING + U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02d3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING + U_MODIFIER_LETTER_UP_TACK = 0x02d4, // U+02D4 MODIFIER LETTER UP TACK + U_MODIFIER_LETTER_DOWN_TACK = 0x02d5, // U+02D5 MODIFIER LETTER DOWN TACK + U_MODIFIER_LETTER_PLUS_SIGN = 0x02d6, // U+02D6 MODIFIER LETTER PLUS SIGN + U_MODIFIER_LETTER_MINUS_SIGN = 0x02d7, // U+02D7 MODIFIER LETTER MINUS SIGN + U_BREVE = 0x02d8, // U+02D8 BREVE + U_DOT_ABOVE = 0x02d9, // U+02D9 DOT ABOVE + U_RING_ABOVE = 0x02da, // U+02DA RING ABOVE + U_OGONEK = 0x02db, // U+02DB OGONEK + U_SMALL_TILDE = 0x02dc, // U+02DC SMALL TILDE + U_DOUBLE_ACUTE_ACCENT = 0x02dd, // U+02DD DOUBLE ACUTE ACCENT + U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02de, // U+02DE MODIFIER LETTER RHOTIC HOOK + U_MODIFIER_LETTER_CROSS_ACCENT = 0x02df, // U+02DF MODIFIER LETTER CROSS ACCENT + U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02e5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR + U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02e6, // U+02E6 MODIFIER LETTER HIGH TONE BAR + U_MODIFIER_LETTER_MID_TONE_BAR = 0x02e7, // U+02E7 MODIFIER LETTER MID TONE BAR + U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02e8, // U+02E8 MODIFIER LETTER LOW TONE BAR + U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02e9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR + U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02ea, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK + U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02eb, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK + U_MODIFIER_LETTER_UNASPIRATED = 0x02ed, // U+02ED MODIFIER LETTER UNASPIRATED + U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02ef, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD + U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02f0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD + U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02f1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD + U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02f2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD + U_MODIFIER_LETTER_LOW_RING = 0x02f3, // U+02F3 MODIFIER LETTER LOW RING + U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02f4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT + U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02f5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT + U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02f6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT + U_MODIFIER_LETTER_LOW_TILDE = 0x02f7, // U+02F7 MODIFIER LETTER LOW TILDE + U_MODIFIER_LETTER_RAISED_COLON = 0x02f8, // U+02F8 MODIFIER LETTER RAISED COLON + U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02f9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE + U_MODIFIER_LETTER_END_HIGH_TONE = 0x02fa, // U+02FA MODIFIER LETTER END HIGH TONE + U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02fb, // U+02FB MODIFIER LETTER BEGIN LOW TONE + U_MODIFIER_LETTER_END_LOW_TONE = 0x02fc, // U+02FC MODIFIER LETTER END LOW TONE + U_MODIFIER_LETTER_SHELF = 0x02fd, // U+02FD MODIFIER LETTER SHELF + U_MODIFIER_LETTER_OPEN_SHELF = 0x02fe, // U+02FE MODIFIER LETTER OPEN SHELF + U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02ff, // U+02FF MODIFIER LETTER LOW LEFT ARROW + U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN + U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS + U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS + U_GREEK_KORONIS = 0x1fbd, // U+1FBD GREEK KORONIS + U_GREEK_PSILI = 0x1fbf, // U+1FBF GREEK PSILI + U_GREEK_PERISPOMENI = 0x1fc0, // U+1FC0 GREEK PERISPOMENI + U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1fc1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI + U_GREEK_PSILI_AND_VARIA = 0x1fcd, // U+1FCD GREEK PSILI AND VARIA + U_GREEK_PSILI_AND_OXIA = 0x1fce, // U+1FCE GREEK PSILI AND OXIA + U_GREEK_PSILI_AND_PERISPOMENI = 0x1fcf, // U+1FCF GREEK PSILI AND PERISPOMENI + U_GREEK_DASIA_AND_VARIA = 0x1fdd, // U+1FDD GREEK DASIA AND VARIA + U_GREEK_DASIA_AND_OXIA = 0x1fde, // U+1FDE GREEK DASIA AND OXIA + U_GREEK_DASIA_AND_PERISPOMENI = 0x1fdf, // U+1FDF GREEK DASIA AND PERISPOMENI + U_GREEK_DIALYTIKA_AND_VARIA = 0x1fed, // U+1FED GREEK DIALYTIKA AND VARIA + U_GREEK_DIALYTIKA_AND_OXIA = 0x1fee, // U+1FEE GREEK DIALYTIKA AND OXIA + U_GREEK_VARIA = 0x1fef, // U+1FEF GREEK VARIA + U_GREEK_OXIA = 0x1ffd, // U+1FFD GREEK OXIA + U_GREEK_DASIA = 0x1ffe, // U+1FFE GREEK DASIA + + U_OVERLINE = 0x203e, // Unicode Character 'OVERLINE' + + /** + * UTF-8 BOM + * Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF) + * http://www.fileformat.info/info/unicode/char/feff/index.htm + */ + UTF8_BOM = 65279, +} diff --git a/server/packages/yaml-language-service/src/parser/yamlDocument.ts b/server/packages/yaml-language-service/src/parser/yamlDocument.ts index 07677b5..af1cb2d 100644 --- a/server/packages/yaml-language-service/src/parser/yamlDocument.ts +++ b/server/packages/yaml-language-service/src/parser/yamlDocument.ts @@ -7,56 +7,12 @@ import { ASTNode, ObjectASTNodeImpl } from "./astTypes"; const FULL_LINE_ERROR = true; const YAML_SOURCE = "YAML"; +const YAML_COMMENT_SYMBOL = "#"; export class LineComment { constructor(public readonly text: string) {} } -export class YAMLSubDocument { - private _lineComments: LineComment[] | undefined; - - constructor(public readonly root: ASTNode | undefined, private readonly parsedDocument: Document) {} - - get errors(): YAMLError[] { - return this.parsedDocument.errors; - } - - get warnings(): YAMLWarning[] { - return this.parsedDocument.warnings; - } - - get lineComments(): LineComment[] { - if (!this._lineComments) { - this._lineComments = this.collectLineComments(); - } - return this._lineComments; - } - - private collectLineComments(): LineComment[] { - const lineComments = []; - if (this.parsedDocument.commentBefore) { - const comments = this.parsedDocument.commentBefore.split("\n"); - comments.forEach((comment) => lineComments.push(new LineComment(`#${comment}`))); - } - visit(this.parsedDocument, (_key, docNode) => { - const node = docNode as Node; - if (node?.commentBefore) { - const comments = node?.commentBefore.split("\n"); - comments.forEach((comment) => lineComments.push(new LineComment(`#${comment}`))); - } - - if (node?.comment) { - lineComments.push(new LineComment(`#${node.comment}`)); - } - }); - - if (this.parsedDocument.comment) { - lineComments.push(new LineComment(`#${this.parsedDocument.comment}`)); - } - return lineComments; - } -} - /** * Represents a YAML document. * YAML documents can contain multiple sub-documents separated by "---". @@ -64,6 +20,7 @@ export class YAMLSubDocument { export class YAMLDocument implements ParsedDocument { private readonly _textBuffer: TextBuffer; private _diagnostics: Diagnostic[] | undefined; + private _configuredIndentation = 2; // TODO read this value from config constructor(public readonly subDocuments: YAMLSubDocument[], public readonly textDocument: TextDocument) { this._textBuffer = new TextBuffer(textDocument); @@ -92,6 +49,12 @@ export class YAMLDocument implements ParsedDocument { return this.collectLineComments(); } + public isComment(offset: number): boolean { + const position = this._textBuffer.getPosition(offset); + const lineContent = this._textBuffer.getLineContent(position.line).trimStart(); + return lineContent.startsWith(YAML_COMMENT_SYMBOL); + } + /** * Gets the syntax node at this document offset. * @param offset The offset in the text document @@ -99,7 +62,28 @@ export class YAMLDocument implements ParsedDocument { */ public getNodeFromOffset(offset: number): ASTNode | undefined { const rootNode = this.root as ObjectASTNodeImpl; - return rootNode?.getNodeFromOffsetEndInclusive(offset); + if (!rootNode) return undefined; + if (this.isComment(offset)) return undefined; + const indentation = this._textBuffer.getLineIndentationAtOffset(offset); + let result = rootNode.getNodeFromOffsetEndInclusive(offset); + if (!result || (result === rootNode && indentation != 0)) { + result = this.findParentNodeByIndentation(offset, indentation); + } + return result; + } + + private findParentNodeByIndentation(offset: number, indentation: number): ASTNode | undefined { + if (indentation == 0) { + return this.root; + } + const parentIndentation = indentation - this._configuredIndentation; + const parentLine = this._textBuffer.getPreviousLineNumberWithIndentation(offset, parentIndentation); + const parentOffset = this._textBuffer.getOffsetAt(Position.create(parentLine, parentIndentation)); + + const rootNode = this.root as ObjectASTNodeImpl; + if (!rootNode) return undefined; + const parentNode = rootNode.getNodeFromOffsetEndInclusive(parentOffset); + return parentNode; } /** Collects all syntax errors and warnings found on this document. */ @@ -138,3 +122,48 @@ export class YAMLDocument implements ParsedDocument { return lineComments; } } + +export class YAMLSubDocument { + private _lineComments: LineComment[] | undefined; + + constructor(public readonly root: ASTNode | undefined, private readonly parsedDocument: Document) {} + + get errors(): YAMLError[] { + return this.parsedDocument.errors; + } + + get warnings(): YAMLWarning[] { + return this.parsedDocument.warnings; + } + + get lineComments(): LineComment[] { + if (!this._lineComments) { + this._lineComments = this.collectLineComments(); + } + return this._lineComments; + } + + private collectLineComments(): LineComment[] { + const lineComments = []; + if (this.parsedDocument.commentBefore) { + const comments = this.parsedDocument.commentBefore.split("\n"); + comments.forEach((comment) => lineComments.push(new LineComment(`${YAML_COMMENT_SYMBOL}${comment}`))); + } + visit(this.parsedDocument, (_key, docNode) => { + const node = docNode as Node; + if (node?.commentBefore) { + const comments = node?.commentBefore.split("\n"); + comments.forEach((comment) => lineComments.push(new LineComment(`${YAML_COMMENT_SYMBOL}${comment}`))); + } + + if (node?.comment) { + lineComments.push(new LineComment(`${YAML_COMMENT_SYMBOL}${node.comment}`)); + } + }); + + if (this.parsedDocument.comment) { + lineComments.push(new LineComment(`${YAML_COMMENT_SYMBOL}${this.parsedDocument.comment}`)); + } + return lineComments; + } +} diff --git a/server/packages/yaml-language-service/src/utils/textBuffer.ts b/server/packages/yaml-language-service/src/utils/textBuffer.ts index 5d68240..baf0ff2 100644 --- a/server/packages/yaml-language-service/src/utils/textBuffer.ts +++ b/server/packages/yaml-language-service/src/utils/textBuffer.ts @@ -5,6 +5,7 @@ import { TextDocument } from "vscode-languageserver-textdocument"; import { Position, Range } from "vscode-languageserver-types"; +import { CharCode } from "../parser/charCode"; interface FullTextDocument { getLineOffsets(): number[]; @@ -13,11 +14,11 @@ interface FullTextDocument { export class TextBuffer { constructor(private doc: TextDocument) {} - getLineCount(): number { + public getLineCount(): number { return this.doc.lineCount; } - getLineLength(lineNumber: number): number { + public getLineLength(lineNumber: number): number { const lineOffsets = (this.doc as unknown as FullTextDocument).getLineOffsets(); if (lineNumber >= lineOffsets.length) { return this.doc.getText().length; @@ -30,7 +31,7 @@ export class TextBuffer { return nextLineOffset - lineOffsets[lineNumber]; } - getLineContent(lineNumber: number): string { + public getLineContent(lineNumber: number): string { const lineOffsets = (this.doc as unknown as FullTextDocument).getLineOffsets(); if (lineNumber >= lineOffsets.length) { return this.doc.getText(); @@ -42,15 +43,68 @@ export class TextBuffer { return this.doc.getText().substring(lineOffsets[lineNumber], nextLineOffset); } - getLineCharCode(lineNumber: number, index: number): number { + public getLineCharCode(lineNumber: number, index: number): number { return this.doc.getText(Range.create(lineNumber - 1, index - 1, lineNumber - 1, index)).charCodeAt(0); } - getText(range?: Range): string { + public getText(range?: Range): string { return this.doc.getText(range); } - getPosition(offest: number): Position { - return this.doc.positionAt(offest); + public getPosition(offset: number): Position { + return this.doc.positionAt(offset); + } + + public getOffsetAt(position: Position): number { + return this.doc.offsetAt(position); + } + + public getCurrentWord(offset: number): string { + let i = offset - 1; + const text = this.getText(); + while (i >= 0 && ' \t\n\r\v":{[,]}'.indexOf(text.charAt(i)) === -1) { + i--; + } + return text.substring(i + 1, offset); + } + + public getLineIndentationAtOffset(offset: number): number { + const position = this.getPosition(offset); + const lineContent = this.getLineContent(position.line); + const indentation = this.getIndentation(lineContent, position.character); + return indentation; + } + + public getPreviousLineNumberWithIndentation(offset: number, parentIndentation: number): number { + const position = this.getPosition(offset); + const indentationSpaces = " ".repeat(parentIndentation); + let currentLine = position.line - 1; + let found = false; + + while (currentLine > 0 && !found) { + const lineContent = this.getLineContent(currentLine); + if (lineContent.startsWith(indentationSpaces)) { + found = true; + } else { + currentLine--; + } + } + return currentLine; + } + + private getIndentation(lineContent: string, lineOffset: number): number { + if (lineContent.length < lineOffset) { + return 0; + } + + for (let i = 0; i < lineOffset; i++) { + const char = lineContent.charCodeAt(i); + if (char !== CharCode.Space && char !== CharCode.Tab) { + return i; + } + } + + // assuming that current position is indentation + return lineOffset; } } From c9a5635aa57047e563c14df1507a1e478d725cc8 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:15:16 +0200 Subject: [PATCH 21/50] Add tests for `getNodeFromOffset` Includes refactoring and fixes --- .../server-common/src/ast/nodeManager.ts | 4 + .../src/parser/yamlDocument.ts | 20 +- .../src/utils/indentationGuesser.ts | 235 ++++++++++++++++++ .../src/utils/textBuffer.ts | 18 +- .../tests/unit/yamlParser.test.ts | 52 ++++ 5 files changed, 318 insertions(+), 11 deletions(-) create mode 100644 server/packages/yaml-language-service/src/utils/indentationGuesser.ts diff --git a/server/packages/server-common/src/ast/nodeManager.ts b/server/packages/server-common/src/ast/nodeManager.ts index 1a9f16b..545e970 100644 --- a/server/packages/server-common/src/ast/nodeManager.ts +++ b/server/packages/server-common/src/ast/nodeManager.ts @@ -54,6 +54,10 @@ export class ASTNodeManager { return node === lastNode; } + public isRoot(node: ASTNode): boolean { + return node.parent === undefined; + } + public getPreviousSiblingNode(node: ASTNode): ASTNode | null { const parent = node.parent; if (!parent || !parent.children) { diff --git a/server/packages/yaml-language-service/src/parser/yamlDocument.ts b/server/packages/yaml-language-service/src/parser/yamlDocument.ts index af1cb2d..591d6be 100644 --- a/server/packages/yaml-language-service/src/parser/yamlDocument.ts +++ b/server/packages/yaml-language-service/src/parser/yamlDocument.ts @@ -2,12 +2,14 @@ import { ParsedDocument } from "@gxwf/server-common/src/ast/types"; import { TextDocument } from "vscode-languageserver-textdocument"; import { Diagnostic, DiagnosticSeverity, Position } from "vscode-languageserver-types"; import { Document, Node, visit, YAMLError, YAMLWarning } from "yaml"; +import { guessIndentation } from "../utils/indentationGuesser"; import { TextBuffer } from "../utils/textBuffer"; import { ASTNode, ObjectASTNodeImpl } from "./astTypes"; const FULL_LINE_ERROR = true; const YAML_SOURCE = "YAML"; const YAML_COMMENT_SYMBOL = "#"; +const DEFAULT_INDENTATION = 2; export class LineComment { constructor(public readonly text: string) {} @@ -20,11 +22,12 @@ export class LineComment { export class YAMLDocument implements ParsedDocument { private readonly _textBuffer: TextBuffer; private _diagnostics: Diagnostic[] | undefined; - private _configuredIndentation = 2; // TODO read this value from config + private _indentation: number; constructor(public readonly subDocuments: YAMLSubDocument[], public readonly textDocument: TextDocument) { this._textBuffer = new TextBuffer(textDocument); this._diagnostics = undefined; + this._indentation = guessIndentation(this._textBuffer, DEFAULT_INDENTATION, true).tabSize; } public get root(): ASTNode | undefined { @@ -64,20 +67,21 @@ export class YAMLDocument implements ParsedDocument { const rootNode = this.root as ObjectASTNodeImpl; if (!rootNode) return undefined; if (this.isComment(offset)) return undefined; + const position = this._textBuffer.getPosition(offset); + if (position.character === 0 && !this._textBuffer.hasTextAfterPosition(position)) return rootNode; const indentation = this._textBuffer.getLineIndentationAtOffset(offset); let result = rootNode.getNodeFromOffsetEndInclusive(offset); - if (!result || (result === rootNode && indentation != 0)) { - result = this.findParentNodeByIndentation(offset, indentation); + const parent = this.findParentNodeByIndentation(offset, indentation); + if (!result || (parent && result.offset < parent.offset && result.length > parent.length)) { + result = parent; } return result; } private findParentNodeByIndentation(offset: number, indentation: number): ASTNode | undefined { - if (indentation == 0) { - return this.root; - } - const parentIndentation = indentation - this._configuredIndentation; - const parentLine = this._textBuffer.getPreviousLineNumberWithIndentation(offset, parentIndentation); + if (indentation === 0) return this.root; + const parentIndentation = Math.max(0, indentation - this._indentation); + const parentLine = this._textBuffer.findPreviousLineWithSameIndentation(offset, parentIndentation); const parentOffset = this._textBuffer.getOffsetAt(Position.create(parentLine, parentIndentation)); const rootNode = this.root as ObjectASTNodeImpl; diff --git a/server/packages/yaml-language-service/src/utils/indentationGuesser.ts b/server/packages/yaml-language-service/src/utils/indentationGuesser.ts new file mode 100644 index 0000000..06d53ea --- /dev/null +++ b/server/packages/yaml-language-service/src/utils/indentationGuesser.ts @@ -0,0 +1,235 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// Copied from: https://github.com/Microsoft/vscode/blob/main/src/vs/editor/common/model/indentationGuesser.ts + +import { CharCode } from "../parser/charCode"; +import { ITextBuffer } from "./textBuffer"; + +class SpacesDiffResult { + public spacesDiff = 0; + public looksLikeAlignment = false; +} + +/** + * Compute the diff in spaces between two line's indentation. + */ +function spacesDiff(a: string, aLength: number, b: string, bLength: number, result: SpacesDiffResult): void { + result.spacesDiff = 0; + result.looksLikeAlignment = false; + + // This can go both ways (e.g.): + // - a: "\t" + // - b: "\t " + // => This should count 1 tab and 4 spaces + + let i: number; + + for (i = 0; i < aLength && i < bLength; i++) { + const aCharCode = a.charCodeAt(i); + const bCharCode = b.charCodeAt(i); + + if (aCharCode !== bCharCode) { + break; + } + } + + let aSpacesCnt = 0, + aTabsCount = 0; + for (let j = i; j < aLength; j++) { + const aCharCode = a.charCodeAt(j); + if (aCharCode === CharCode.Space) { + aSpacesCnt++; + } else { + aTabsCount++; + } + } + + let bSpacesCnt = 0, + bTabsCount = 0; + for (let j = i; j < bLength; j++) { + const bCharCode = b.charCodeAt(j); + if (bCharCode === CharCode.Space) { + bSpacesCnt++; + } else { + bTabsCount++; + } + } + + if (aSpacesCnt > 0 && aTabsCount > 0) { + return; + } + if (bSpacesCnt > 0 && bTabsCount > 0) { + return; + } + + const tabsDiff = Math.abs(aTabsCount - bTabsCount); + const spacesDiff = Math.abs(aSpacesCnt - bSpacesCnt); + + if (tabsDiff === 0) { + // check if the indentation difference might be caused by alignment reasons + // sometime folks like to align their code, but this should not be used as a hint + result.spacesDiff = spacesDiff; + + if (spacesDiff > 0 && 0 <= bSpacesCnt - 1 && bSpacesCnt - 1 < a.length && bSpacesCnt < b.length) { + if (b.charCodeAt(bSpacesCnt) !== CharCode.Space && a.charCodeAt(bSpacesCnt - 1) === CharCode.Space) { + if (a.charCodeAt(a.length - 1) === CharCode.Comma) { + // This looks like an alignment desire: e.g. + // const a = b + c, + // d = b - c; + result.looksLikeAlignment = true; + } + } + } + return; + } + if (spacesDiff % tabsDiff === 0) { + result.spacesDiff = spacesDiff / tabsDiff; + return; + } +} + +/** + * Result for a guessIndentation + */ +export interface IGuessedIndentation { + /** + * If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent? + */ + tabSize: number; + /** + * Is indentation based on spaces? + */ + insertSpaces: boolean; +} + +export function guessIndentation( + source: ITextBuffer, + defaultTabSize: number, + defaultInsertSpaces: boolean +): IGuessedIndentation { + // Look at most at the first 10k lines + const linesCount = Math.min(source.getLineCount(), 10000); + + let linesIndentedWithTabsCount = 0; // number of lines that contain at least one tab in indentation + let linesIndentedWithSpacesCount = 0; // number of lines that contain only spaces in indentation + + let previousLineText = ""; // content of latest line that contained non-whitespace chars + let previousLineIndentation = 0; // index at which latest line contained the first non-whitespace char + + const ALLOWED_TAB_SIZE_GUESSES = [2, 4, 6, 8, 3, 5, 7]; // prefer even guesses for `tabSize`, limit to [2, 8]. + const MAX_ALLOWED_TAB_SIZE_GUESS = 8; // max(ALLOWED_TAB_SIZE_GUESSES) = 8 + + const spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0]; // `tabSize` scores + const tmp = new SpacesDiffResult(); + + for (let lineNumber = 1; lineNumber <= linesCount; lineNumber++) { + const currentLineLength = source.getLineLength(lineNumber); + const currentLineText = source.getLineContent(lineNumber); + + // if the text buffer is chunk based, so long lines are cons-string, v8 will flattern the string when we check charCode. + // checking charCode on chunks directly is cheaper. + const useCurrentLineText = currentLineLength <= 65536; + + let currentLineHasContent = false; // does `currentLineText` contain non-whitespace chars + let currentLineIndentation = 0; // index at which `currentLineText` contains the first non-whitespace char + let currentLineSpacesCount = 0; // count of spaces found in `currentLineText` indentation + let currentLineTabsCount = 0; // count of tabs found in `currentLineText` indentation + for (let j = 0, lenJ = currentLineLength; j < lenJ; j++) { + const charCode = useCurrentLineText ? currentLineText.charCodeAt(j) : source.getLineCharCode(lineNumber, j); + + if (charCode === CharCode.Tab) { + currentLineTabsCount++; + } else if (charCode === CharCode.Space) { + currentLineSpacesCount++; + } else { + // Hit non whitespace character on this line + currentLineHasContent = true; + currentLineIndentation = j; + break; + } + } + + // Ignore empty or only whitespace lines + if (!currentLineHasContent) { + continue; + } + + if (currentLineTabsCount > 0) { + linesIndentedWithTabsCount++; + } else if (currentLineSpacesCount > 1) { + linesIndentedWithSpacesCount++; + } + + spacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation, tmp); + + if (tmp.looksLikeAlignment) { + // if defaultInsertSpaces === true && the spaces count == tabSize, we may want to count it as valid indentation + // + // - item1 + // - item2 + // + // otherwise skip this line entirely + // + // const a = 1, + // b = 2; + + if (!(defaultInsertSpaces && defaultTabSize === tmp.spacesDiff)) { + continue; + } + } + + const currentSpacesDiff = tmp.spacesDiff; + if (currentSpacesDiff <= MAX_ALLOWED_TAB_SIZE_GUESS) { + spacesDiffCount[currentSpacesDiff]++; + } + + previousLineText = currentLineText; + previousLineIndentation = currentLineIndentation; + } + + let insertSpaces = defaultInsertSpaces; + if (linesIndentedWithTabsCount !== linesIndentedWithSpacesCount) { + insertSpaces = linesIndentedWithTabsCount < linesIndentedWithSpacesCount; + } + + let tabSize = defaultTabSize; + + // Guess tabSize only if inserting spaces... + if (insertSpaces) { + let tabSizeScore = insertSpaces ? 0 : 0.1 * linesCount; + + // console.log("score threshold: " + tabSizeScore); + + ALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => { + const possibleTabSizeScore = spacesDiffCount[possibleTabSize]; + if (possibleTabSizeScore > tabSizeScore) { + tabSizeScore = possibleTabSizeScore; + tabSize = possibleTabSize; + } + }); + + // Let a tabSize of 2 win even if it is not the maximum + // (only in case 4 was guessed) + if ( + tabSize === 4 && + spacesDiffCount[4] > 0 && + spacesDiffCount[2] > 0 && + spacesDiffCount[2] >= spacesDiffCount[4] / 2 + ) { + tabSize = 2; + } + } + + // console.log('--------------------------'); + // console.log('linesIndentedWithTabsCount: ' + linesIndentedWithTabsCount + ', linesIndentedWithSpacesCount: ' + linesIndentedWithSpacesCount); + // console.log('spacesDiffCount: ' + spacesDiffCount); + // console.log('tabSize: ' + tabSize + ', tabSizeScore: ' + tabSizeScore); + + return { + insertSpaces: insertSpaces, + tabSize: tabSize, + }; +} diff --git a/server/packages/yaml-language-service/src/utils/textBuffer.ts b/server/packages/yaml-language-service/src/utils/textBuffer.ts index baf0ff2..5b0f9d5 100644 --- a/server/packages/yaml-language-service/src/utils/textBuffer.ts +++ b/server/packages/yaml-language-service/src/utils/textBuffer.ts @@ -11,6 +11,13 @@ interface FullTextDocument { getLineOffsets(): number[]; } +export interface ITextBuffer { + getLineCount(): number; + getLineLength(lineNumber: number): number; + getLineCharCode(lineNumber: number, index: number): number; + getLineContent(lineNumber: number): string; +} + export class TextBuffer { constructor(private doc: TextDocument) {} @@ -68,6 +75,11 @@ export class TextBuffer { return text.substring(i + 1, offset); } + public hasTextAfterPosition(position: Position): boolean { + const lineContent = this.getLineContent(position.line); + return lineContent.charAt(position.character + 1).trim() !== ""; + } + public getLineIndentationAtOffset(offset: number): number { const position = this.getPosition(offset); const lineContent = this.getLineContent(position.line); @@ -75,15 +87,15 @@ export class TextBuffer { return indentation; } - public getPreviousLineNumberWithIndentation(offset: number, parentIndentation: number): number { + public findPreviousLineWithSameIndentation(offset: number, indentation: number): number { const position = this.getPosition(offset); - const indentationSpaces = " ".repeat(parentIndentation); + const indentationSpaces = " ".repeat(indentation); let currentLine = position.line - 1; let found = false; while (currentLine > 0 && !found) { const lineContent = this.getLineContent(currentLine); - if (lineContent.startsWith(indentationSpaces)) { + if (lineContent.startsWith(indentationSpaces) && lineContent.charCodeAt(indentation + 1) !== CharCode.Space) { found = true; } else { currentLine--; diff --git a/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts b/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts index aa2d068..af10d40 100644 --- a/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts +++ b/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts @@ -158,3 +158,55 @@ namespace: defaul`; ).toBeDefined(); }); }); + +describe("YamlDocument", () => { + it("should identify comments", () => { + const parsedDocument = parse("# a comment\ntest: test\n# a second comment"); + let isComment = parsedDocument.isComment(11); + expect(isComment).toBe(true); + isComment = parsedDocument.isComment(12); + expect(isComment).toBe(false); + isComment = parsedDocument.isComment(22); + expect(isComment).toBe(false); + isComment = parsedDocument.isComment(23); + expect(isComment).toBe(true); + }); + describe("getNodeFromOffset", () => { + const SAMPLE_DOC = ` +test: value +test02: + prop03: + test04: val + +`; + it.each([ + // [0, "_root_"], // _root_ is not a property, is an object + [1, "test"], + [12, "test"], + [13, "test02"], + [20, "test02"], + [22, "test02"], + [23, "prop03"], + [30, "prop03"], + [31, "_root_"], + [35, "test04"], + [46, "test04"], + [47, "_root_"], + [49, "test02"], + [51, "prop03"], + [53, "test04"], + ])("should return for offset %p the expected node name %p", (offset: number, expectedNodeName: string) => { + const parsedDocument = parse(SAMPLE_DOC); + const node = parsedDocument.getNodeFromOffset(offset); + expect(node).toBeDefined(); + if (expectedNodeName === "_root_") { + expect(node?.parent).toBeUndefined(); + } else { + expect(node?.parent).toBeDefined(); + } + if (node?.type === "property") { + expect(node.keyNode.value).toBe(expectedNodeName); + } + }); + }); +}); From 282f8f1c4b53ce99d19702ae288f1e5993143451 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:17:32 +0200 Subject: [PATCH 22/50] Add basic completion service Still WIP --- .../src/languageService.ts | 5 +- .../src/schema/schemaNodeResolver.ts | 1 - .../src/services/completionService.ts | 82 +++++++++++++++++++ .../tests/unit/schema.test.ts | 2 +- .../tests/unit/yamlParser.test.ts | 2 +- 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/services/completionService.ts diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index 8bfd6ca..a72f99b 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -13,6 +13,7 @@ import { import { LanguageService, getLanguageService } from "@gxwf/yaml-language-service/src/yamlLanguageService"; import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; import { GalaxyWorkflowFormat2SchemaLoader } from "./schema"; +import { GxFormat2CompletionService } from "./services/completionService"; import { GxFormat2HoverService } from "./services/hoverService"; /** @@ -23,11 +24,13 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { private _yamlLanguageService: LanguageService; private _schemaLoader: GalaxyWorkflowFormat2SchemaLoader; private _hoverService: GxFormat2HoverService; + private _completionService: GxFormat2CompletionService; constructor() { super(); this._schemaLoader = new GalaxyWorkflowFormat2SchemaLoader(); this._yamlLanguageService = getLanguageService(); this._hoverService = new GxFormat2HoverService(this._schemaLoader.nodeResolver); + this._completionService = new GxFormat2CompletionService(this._schemaLoader.nodeResolver); } public override parseWorkflowDocument(document: TextDocument): WorkflowDocument { @@ -47,7 +50,7 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { workflowDocument: WorkflowDocument, position: Position ): Promise { - return null; + return this._completionService.doComplete(workflowDocument.textDocument, position, workflowDocument.nodeManager); } protected override async doValidation(workflowDocument: WorkflowDocument): Promise { diff --git a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts index 5936b97..b20ba44 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts @@ -18,7 +18,6 @@ export class SchemaNodeResolver { return this.getSchemaNodeForSegment(parentNode.typeRef); } } - return schemaNodeFound; } diff --git a/server/gx-workflow-ls-format2/src/services/completionService.ts b/server/gx-workflow-ls-format2/src/services/completionService.ts new file mode 100644 index 0000000..912675d --- /dev/null +++ b/server/gx-workflow-ls-format2/src/services/completionService.ts @@ -0,0 +1,82 @@ +import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; +import { ASTNode } from "@gxwf/server-common/src/ast/types"; +import { + CompletionItem, + CompletionItemKind, + CompletionList, + Position, + TextDocument, +} from "@gxwf/server-common/src/languageTypes"; +import { TextBuffer } from "@gxwf/yaml-language-service/src/utils/textBuffer"; +import { SchemaNode, SchemaNodeResolver } from "../schema"; + +export class GxFormat2CompletionService { + constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} + + public doComplete( + textDocument: TextDocument, + position: Position, + nodeManager: ASTNodeManager + ): Promise { + const result: CompletionList = { + items: [], + isIncomplete: false, + }; + + const textBuffer = new TextBuffer(textDocument); + const text = textBuffer.getText(); + const offset = textBuffer.getOffsetAt(position); + const node = nodeManager.getNodeFromOffset(offset); + if (!node) { + return Promise.resolve(result); + } + if (text.charAt(offset - 1) === ":") { + return Promise.resolve(result); + } + + DEBUG_printNodeName(node); + + const existing = nodeManager.getDeclaredPropertyNames(node); + if (nodeManager.isRoot(node)) { + result.items = this.getProposedItems(this.schemaNodeResolver.rootNode, existing); + return Promise.resolve(result); + } + const nodePath = nodeManager.getPathFromNode(node); + const schemaNode = this.schemaNodeResolver.resolveSchemaContext(nodePath); + if (schemaNode) { + result.items = this.getProposedItems(schemaNode, existing); + } + return Promise.resolve(result); + } + + private getProposedItems(schemaNode: SchemaNode, exclude: Set): CompletionItem[] { + const result: CompletionItem[] = []; + schemaNode.children.forEach((child) => { + if (exclude.has(child.name)) return; + const item: CompletionItem = { + label: child.name, + documentation: child.documentation, + sortText: `_${child.name}`, + kind: CompletionItemKind.Field, + insertText: `${child.name}: `, + }; + result.push(item); + }); + return result; + } +} + +function DEBUG_printNodeName(node: ASTNode): void { + let nodeName = "_root_"; + if (node?.type === "property") { + nodeName = node.keyNode.value; + console.debug("COMPLETION NODE PROPERTY", nodeName); + } else if (node?.type === "object") { + console.debug(`COMPLETION NODE OBJECT:`); + node.properties.forEach((p) => { + console.debug(` ${p.keyNode.value}`); + }); + } else { + console.debug("UNKNOWN"); + } +} diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts index 66f32aa..3834f83 100644 --- a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -16,7 +16,7 @@ describe("Gxformat2 Schema Handling", () => { describe("SchemaNodeResolver", () => { let nodeResolver: SchemaNodeResolver; beforeAll(() => { - nodeResolver = new SchemaNodeResolver(schemaLoader.definitions); + nodeResolver = schemaLoader.nodeResolver; }); describe("resolveSchemaContext", () => { it.each([ diff --git a/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts b/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts index af10d40..ae7f800 100644 --- a/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts +++ b/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts @@ -180,7 +180,7 @@ test02: `; it.each([ - // [0, "_root_"], // _root_ is not a property, is an object + [0, "_root_"], // _root_ is not a property, is an object [1, "test"], [12, "test"], [13, "test02"], From 88f2adc384dbc8153f7883ffc7123426d057603c Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 26 Aug 2022 15:08:08 +0200 Subject: [PATCH 23/50] Add typeName to all schema field types - Handle null as optional --- .../src/schema/definitions.ts | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 1e36e42..87bc7b1 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -65,35 +65,37 @@ export function isBasicFieldType(object: unknown): object is BasicFieldType { export type SchemaEntry = SchemaEnum | SchemaRecord | SchemaField; -interface FieldType { +interface FieldTypeBase { isOptional: boolean; } -interface BasicFieldType extends FieldType { +interface BasicFieldType extends FieldTypeBase { typeName: string; } -interface ArrayFieldType extends FieldType { - itemType: FieldType; +interface ArrayFieldType extends BasicFieldType { + itemType: FieldTypeBase; } -interface EnumFieldType extends FieldType { +interface EnumFieldType extends BasicFieldType { symbols: string[]; } -function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { +function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { if (typeof typeEntry === "string") { let baseType: string = typeEntry; - const isOptional = baseType.endsWith("?"); + let isOptional = baseType.endsWith("?"); if (isOptional) { baseType = baseType.slice(0, baseType.length - 1); } + isOptional = isOptional || baseType === "null"; const isArray = baseType.endsWith("[]"); if (isArray) { baseType = baseType.slice(0, baseType.length - 2); const arrayType: ArrayFieldType = { isOptional, itemType: buildBasicFieldType(isOptional, baseType), + typeName: "array", }; return arrayType; } @@ -105,6 +107,7 @@ function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { const arrayType: ArrayFieldType = { isOptional: false, itemType: itemType, + typeName: "array", }; return arrayType; } @@ -113,6 +116,7 @@ function fieldTypeFactory(typeEntry: unknown): FieldType | undefined { const enumType: EnumFieldType = { isOptional: false, symbols: (typeEntry as SchemaEnumType).symbols, + typeName: "enum", }; return enumType; } @@ -140,8 +144,9 @@ export interface SchemaNode { } export class FieldSchemaNode implements SchemaNode { - private _allowedTypes: FieldType[] = []; + private _allowedTypes: BasicFieldType[] = []; private readonly _schemaField: SchemaField; + constructor(schemaField: SchemaField) { this._schemaField = schemaField; if (schemaField.type instanceof Array) { @@ -167,7 +172,7 @@ export class FieldSchemaNode implements SchemaNode { return this._schemaField.doc; } - public get typesAllowed(): FieldType[] { + public get typesAllowed(): BasicFieldType[] { return this._allowedTypes; } @@ -179,6 +184,14 @@ export class FieldSchemaNode implements SchemaNode { return false; } + public get isRequired(): boolean { + return !this.isOptional; + } + + public get isOptional(): boolean { + return this._allowedTypes.some((ft) => ft.isOptional); + } + public get supportsArray(): boolean { return this._allowedTypes.some((t) => isArrayFieldType(t)); } @@ -187,8 +200,8 @@ export class FieldSchemaNode implements SchemaNode { if (this.supportsArray) { return this.getArrayItemTypeName() || "undefined"; } - const mainType = this.typesAllowed.at(0); - return isBasicFieldType(mainType) ? mainType.typeName : "not basic or undef"; + const mainType = this.typesAllowed.find((t) => t.typeName !== "null"); + return isBasicFieldType(mainType) ? mainType.typeName : "unknown"; } public getArrayItemTypeName(): string | undefined { From 4ba147abdde4e8d17b3bd66d76abb32cf6cc2672 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 26 Aug 2022 15:10:01 +0200 Subject: [PATCH 24/50] Implement basic schema validation service --- .../src/schema/schemaNodeResolver.ts | 4 ++ .../src/services/schemaValidationService.ts | 70 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 server/gx-workflow-ls-format2/src/services/schemaValidationService.ts diff --git a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts index b20ba44..692c6e1 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts @@ -21,6 +21,10 @@ export class SchemaNodeResolver { return schemaNodeFound; } + public getSchemaNodeByTypeRef(typeRef: string): SchemaNode | undefined { + return this.getSchemaNodeForSegment(typeRef); + } + private getSchemaNodeForSegment(pathSegment?: Segment): SchemaNode | undefined { if (typeof pathSegment === "string") { if (this.definitions.records.has(pathSegment)) { diff --git a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts new file mode 100644 index 0000000..992f500 --- /dev/null +++ b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts @@ -0,0 +1,70 @@ +import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; +import { ASTNode } from "@gxwf/server-common/src/ast/types"; +import { Diagnostic, DiagnosticSeverity, Range, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; +import { SchemaNode, SchemaNodeResolver } from "../schema"; +import { RecordSchemaNode, FieldSchemaNode } from "../schema/definitions"; + +export class GxFormat2SchemaValidationService { + constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} + + public doValidation(workflowDocument: WorkflowDocument): Promise { + const diagnostics: Diagnostic[] = []; + if (workflowDocument.nodeManager.root) { + this.collectDiagnostics( + workflowDocument.nodeManager, + workflowDocument.nodeManager.root, + this.schemaNodeResolver.rootNode, + diagnostics + ); + } + return Promise.resolve(diagnostics); + } + + private collectDiagnostics( + nodeManager: ASTNodeManager, + node: ASTNode, + schemaNode: SchemaNode, + diagnostics: Diagnostic[] + ): void { + const range = this.getRange(nodeManager, node); + if (schemaNode instanceof RecordSchemaNode) { + if (node.type !== "object") { + diagnostics.push(Diagnostic.create(range, `${schemaNode.name} definition expected`, DiagnosticSeverity.Error)); + } else { + schemaNode.fields.forEach((schemaFieldNode) => { + const propertyNode = node.properties.find((prop) => prop.keyNode.value === schemaFieldNode.name); + const nodeFound = propertyNode !== undefined; + if (schemaFieldNode.isRequired && !nodeFound) { + diagnostics.push(Diagnostic.create(range, `${schemaFieldNode.name} is required`, DiagnosticSeverity.Error)); + } + if (nodeFound) { + const childSchemaNode = this.schemaNodeResolver.getSchemaNodeByTypeRef(schemaFieldNode.typeRef); + if (childSchemaNode && propertyNode.valueNode) { + if (schemaFieldNode.supportsArray) { + propertyNode.valueNode.children?.forEach((item) => { + if (item.type === "property" && item.valueNode) { + this.collectDiagnostics(nodeManager, item.valueNode, childSchemaNode, diagnostics); + } + }); + } else { + this.collectDiagnostics(nodeManager, propertyNode.valueNode, childSchemaNode, diagnostics); + } + } + } + }); + } + } else if (schemaNode instanceof FieldSchemaNode) { + console.log("Field Schema Node"); + } else { + console.log("Other Schema Node"); + } + } + + private getRange(nodeManager: ASTNodeManager, node: ASTNode): Range { + if (node === nodeManager.root) { + const classNode = nodeManager.getNodeFromPath("class") ?? node; + return nodeManager.getNodeRange(classNode); + } + return nodeManager.getNodeRange(node); + } +} From c4c7c6f3f6ade3889cafc96eb36eab9a41ca907d Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 26 Aug 2022 15:12:14 +0200 Subject: [PATCH 25/50] Add schema validation to workflow validation --- server/gx-workflow-ls-format2/src/languageService.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index a72f99b..7a556ff 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -15,6 +15,7 @@ import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; import { GalaxyWorkflowFormat2SchemaLoader } from "./schema"; import { GxFormat2CompletionService } from "./services/completionService"; import { GxFormat2HoverService } from "./services/hoverService"; +import { GxFormat2SchemaValidationService } from "./services/schemaValidationService"; /** * A wrapper around the YAML Language Service to support language features @@ -25,12 +26,14 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { private _schemaLoader: GalaxyWorkflowFormat2SchemaLoader; private _hoverService: GxFormat2HoverService; private _completionService: GxFormat2CompletionService; + private _validationService: GxFormat2SchemaValidationService; constructor() { super(); this._schemaLoader = new GalaxyWorkflowFormat2SchemaLoader(); this._yamlLanguageService = getLanguageService(); this._hoverService = new GxFormat2HoverService(this._schemaLoader.nodeResolver); this._completionService = new GxFormat2CompletionService(this._schemaLoader.nodeResolver); + this._validationService = new GxFormat2SchemaValidationService(this._schemaLoader.nodeResolver); } public override parseWorkflowDocument(document: TextDocument): WorkflowDocument { @@ -55,6 +58,8 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { protected override async doValidation(workflowDocument: WorkflowDocument): Promise { const format2WorkflowDocument = workflowDocument as GxFormat2WorkflowDocument; - return this._yamlLanguageService.doValidation(format2WorkflowDocument.yamlDocument); + const yamlDiagnostics = await this._yamlLanguageService.doValidation(format2WorkflowDocument.yamlDocument); + const schemaDiagnostics = await this._validationService.doValidation(workflowDocument); + return [...yamlDiagnostics, ...schemaDiagnostics]; } } From bbad6cb5c931556df8ac68f7b6dbcc0baf160b90 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sat, 27 Aug 2022 18:06:44 +0200 Subject: [PATCH 26/50] Support specialization in schema types --- .../src/schema/definitions.ts | 6 ++++++ .../src/schema/schemaLoader.ts | 14 ++++++++++++++ .../src/schema/schemaNodeResolver.ts | 1 + 3 files changed, 21 insertions(+) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 87bc7b1..d1cb559 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -17,10 +17,15 @@ export interface DocumentedSchemaEntry extends SchemaEntryBase { export interface SchemaField extends DocumentedSchemaEntry { default?: unknown; } +export interface Specialization { + specializeFrom: string; + specializeTo: string; +} export interface SchemaRecord extends DocumentedSchemaEntry { fields: SchemaField[]; extends?: string[]; + specialize?: Specialization[]; } export interface SchemaEnum extends DocumentedSchemaEntry { @@ -266,4 +271,5 @@ export interface SchemaDefinitions { types: Map; records: Map; fields: Map; + specializations: Map; } diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index 1da0bd3..29bb699 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -49,6 +49,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { types: new Map(), records: new Map(), fields: new Map(), + specializations: new Map(), }; SCHEMA_DOCS_v19_09_MAP.forEach((schemaDoc) => { const types = this.loadSchemaDocument(schemaDoc); @@ -56,6 +57,11 @@ export class GalaxyWorkflowFormat2SchemaLoader { definitions.types.set(k, v); if (isSchemaRecord(v)) { definitions.records.set(k, v); + if (v.specialize) { + v.specialize.forEach((sp) => { + definitions.specializations.set(sp.specializeFrom, sp.specializeTo); + }); + } v.fields.forEach((field) => { if (definitions.fields.has(field.name)) { if (this.enableDebugTrace) console.debug("****** DUPLICATED FIELD", field.name); @@ -126,6 +132,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { doc: entry.doc, fields: fields, extends: entry.extends ? (entry.extends instanceof Array ? [...entry.extends] : [entry.extends]) : [], + specialize: entry.specialize, }; if (recordEntry.extends) { @@ -138,6 +145,13 @@ export class GalaxyWorkflowFormat2SchemaLoader { } } + if (recordEntry.specialize) { + recordEntry.specialize.forEach((sp) => { + sp.specializeFrom = this.resolveTypeName(sp.specializeFrom); + sp.specializeTo = this.resolveTypeName(sp.specializeTo); + }); + } + return recordEntry; } diff --git a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts index 692c6e1..7c13af4 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts @@ -27,6 +27,7 @@ export class SchemaNodeResolver { private getSchemaNodeForSegment(pathSegment?: Segment): SchemaNode | undefined { if (typeof pathSegment === "string") { + pathSegment = this.definitions.specializations.get(pathSegment) || pathSegment; if (this.definitions.records.has(pathSegment)) { const record = this.definitions.records.get(pathSegment); if (record) return new RecordSchemaNode(record); From 4371f120cc40565c423f9119a84e260041cf22ab Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sat, 27 Aug 2022 18:15:09 +0200 Subject: [PATCH 27/50] Skip validation on simple matching types --- server/gx-workflow-ls-format2/src/schema/definitions.ts | 8 ++++++++ .../src/services/schemaValidationService.ts | 3 +++ 2 files changed, 11 insertions(+) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index d1cb559..1e63608 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -265,6 +265,14 @@ export class RecordSchemaNode implements SchemaNode { public get typeRef(): string { return this._schemaRecord.name; } + + public get typeField(): FieldSchemaNode | undefined { + return this.fields.find((t) => t.name === "type"); + } + + public matchesTypeField(typeName: string): boolean { + return this.typeField?.typesAllowed.find((t) => t.typeName === typeName) !== undefined; + } } export interface SchemaDefinitions { diff --git a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts index 992f500..ee5a695 100644 --- a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts @@ -29,6 +29,9 @@ export class GxFormat2SchemaValidationService { const range = this.getRange(nodeManager, node); if (schemaNode instanceof RecordSchemaNode) { if (node.type !== "object") { + if (schemaNode.matchesTypeField(node.type)) { + return; + } diagnostics.push(Diagnostic.create(range, `${schemaNode.name} definition expected`, DiagnosticSeverity.Error)); } else { schemaNode.fields.forEach((schemaFieldNode) => { From 64ff315871b04f65c4312789585bd95823dc0f94 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 28 Aug 2022 22:43:23 +0200 Subject: [PATCH 28/50] Add mapping type matching Is this the correct way of mapping nodes? --- .../src/schema/definitions.ts | 22 ++++++++++++++++++- .../src/schema/schemaLoader.ts | 9 +++++++- .../src/services/schemaValidationService.ts | 17 +++++++++++--- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 1e63608..ea6dab1 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -14,8 +14,14 @@ export interface DocumentedSchemaEntry extends SchemaEntryBase { doc?: string; } +export interface IdMapper { + mapSubject?: string; + mapPredicate?: string; +} + export interface SchemaField extends DocumentedSchemaEntry { default?: unknown; + jsonldPredicate?: IdMapper; } export interface Specialization { specializeFrom: string; @@ -148,7 +154,7 @@ export interface SchemaNode { isRoot: boolean; } -export class FieldSchemaNode implements SchemaNode { +export class FieldSchemaNode implements SchemaNode, IdMapper { private _allowedTypes: BasicFieldType[] = []; private readonly _schemaField: SchemaField; @@ -209,6 +215,14 @@ export class FieldSchemaNode implements SchemaNode { return isBasicFieldType(mainType) ? mainType.typeName : "unknown"; } + public get mapSubject(): string | undefined { + return this._schemaField.jsonldPredicate?.mapSubject; + } + + public get mapPredicate(): string | undefined { + return this._schemaField.jsonldPredicate?.mapPredicate; + } + public getArrayItemTypeName(): string | undefined { const arrayType = this._allowedTypes.find((t) => isArrayFieldType(t)) as ArrayFieldType; if (isBasicFieldType(arrayType?.itemType)) { @@ -273,6 +287,12 @@ export class RecordSchemaNode implements SchemaNode { public matchesTypeField(typeName: string): boolean { return this.typeField?.typesAllowed.find((t) => t.typeName === typeName) !== undefined; } + + public matchesMapping(typeName: string, idMapper?: IdMapper): boolean { + if (!idMapper || !idMapper.mapSubject) return false; + const mappedField = this.fields.find((f) => f.name === idMapper.mapSubject); + return mappedField?.typesAllowed.find((t) => t.typeName === typeName) !== undefined; + } } export interface SchemaDefinitions { diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index 29bb699..94c8b81 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -190,7 +190,14 @@ export class GalaxyWorkflowFormat2SchemaLoader { if (this.enableDebugTrace) console.debug(` --Field type NOT string: ${JSON.stringify(fieldType)} -> ${typeof fieldType}`); } - return { name: field.name, type: fieldType, default: field.default, doc: field.doc }; + return { + name: field.name, + type: fieldType, + default: field.default, + doc: field.doc, + jsonldPredicate: field.jsonldPredicate, + documentRoot: field.documentRoot, + }; } private resolveTypeName(rawTypeName: string): string { diff --git a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts index ee5a695..3d2a46c 100644 --- a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts @@ -2,7 +2,7 @@ import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; import { ASTNode } from "@gxwf/server-common/src/ast/types"; import { Diagnostic, DiagnosticSeverity, Range, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; import { SchemaNode, SchemaNodeResolver } from "../schema"; -import { RecordSchemaNode, FieldSchemaNode } from "../schema/definitions"; +import { RecordSchemaNode, FieldSchemaNode, IdMapper } from "../schema/definitions"; export class GxFormat2SchemaValidationService { constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} @@ -14,6 +14,7 @@ export class GxFormat2SchemaValidationService { workflowDocument.nodeManager, workflowDocument.nodeManager.root, this.schemaNodeResolver.rootNode, + null, diagnostics ); } @@ -24,6 +25,7 @@ export class GxFormat2SchemaValidationService { nodeManager: ASTNodeManager, node: ASTNode, schemaNode: SchemaNode, + parenSchemaNode: SchemaNode | null, diagnostics: Diagnostic[] ): void { const range = this.getRange(nodeManager, node); @@ -32,6 +34,9 @@ export class GxFormat2SchemaValidationService { if (schemaNode.matchesTypeField(node.type)) { return; } + if (schemaNode.matchesMapping(node.type, parenSchemaNode as IdMapper)) { + return; + } diagnostics.push(Diagnostic.create(range, `${schemaNode.name} definition expected`, DiagnosticSeverity.Error)); } else { schemaNode.fields.forEach((schemaFieldNode) => { @@ -46,11 +51,17 @@ export class GxFormat2SchemaValidationService { if (schemaFieldNode.supportsArray) { propertyNode.valueNode.children?.forEach((item) => { if (item.type === "property" && item.valueNode) { - this.collectDiagnostics(nodeManager, item.valueNode, childSchemaNode, diagnostics); + this.collectDiagnostics(nodeManager, item.valueNode, childSchemaNode, schemaFieldNode, diagnostics); } }); } else { - this.collectDiagnostics(nodeManager, propertyNode.valueNode, childSchemaNode, diagnostics); + this.collectDiagnostics( + nodeManager, + propertyNode.valueNode, + childSchemaNode, + schemaFieldNode, + diagnostics + ); } } } From 87796485ce3480ba00f056fde0bd684c6b42960a Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Wed, 31 Aug 2022 01:14:00 +0200 Subject: [PATCH 29/50] Refactor schema validation service --- .../src/services/schemaValidationService.ts | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts index 3d2a46c..62c6896 100644 --- a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts @@ -1,76 +1,89 @@ import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; -import { ASTNode } from "@gxwf/server-common/src/ast/types"; +import { ASTNode, ObjectASTNode } from "@gxwf/server-common/src/ast/types"; import { Diagnostic, DiagnosticSeverity, Range, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; import { SchemaNode, SchemaNodeResolver } from "../schema"; -import { RecordSchemaNode, FieldSchemaNode, IdMapper } from "../schema/definitions"; +import { RecordSchemaNode, IdMapper } from "../schema/definitions"; export class GxFormat2SchemaValidationService { constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} public doValidation(workflowDocument: WorkflowDocument): Promise { const diagnostics: Diagnostic[] = []; + this.collectSchemaDiagnostics(workflowDocument, diagnostics); + return Promise.resolve(diagnostics); + } + + private collectSchemaDiagnostics(workflowDocument: WorkflowDocument, diagnostics: Diagnostic[]): void { if (workflowDocument.nodeManager.root) { this.collectDiagnostics( workflowDocument.nodeManager, workflowDocument.nodeManager.root, this.schemaNodeResolver.rootNode, - null, diagnostics ); } - return Promise.resolve(diagnostics); } private collectDiagnostics( nodeManager: ASTNodeManager, node: ASTNode, schemaNode: SchemaNode, - parenSchemaNode: SchemaNode | null, - diagnostics: Diagnostic[] + diagnostics: Diagnostic[], + parenSchemaNode?: SchemaNode ): void { const range = this.getRange(nodeManager, node); if (schemaNode instanceof RecordSchemaNode) { - if (node.type !== "object") { - if (schemaNode.matchesTypeField(node.type)) { - return; - } - if (schemaNode.matchesMapping(node.type, parenSchemaNode as IdMapper)) { - return; - } - diagnostics.push(Diagnostic.create(range, `${schemaNode.name} definition expected`, DiagnosticSeverity.Error)); - } else { - schemaNode.fields.forEach((schemaFieldNode) => { - const propertyNode = node.properties.find((prop) => prop.keyNode.value === schemaFieldNode.name); - const nodeFound = propertyNode !== undefined; - if (schemaFieldNode.isRequired && !nodeFound) { - diagnostics.push(Diagnostic.create(range, `${schemaFieldNode.name} is required`, DiagnosticSeverity.Error)); - } - if (nodeFound) { - const childSchemaNode = this.schemaNodeResolver.getSchemaNodeByTypeRef(schemaFieldNode.typeRef); - if (childSchemaNode && propertyNode.valueNode) { - if (schemaFieldNode.supportsArray) { - propertyNode.valueNode.children?.forEach((item) => { - if (item.type === "property" && item.valueNode) { - this.collectDiagnostics(nodeManager, item.valueNode, childSchemaNode, schemaFieldNode, diagnostics); - } - }); - } else { - this.collectDiagnostics( - nodeManager, - propertyNode.valueNode, - childSchemaNode, - schemaFieldNode, - diagnostics - ); + switch (node.type) { + case "object": + this.validateObjectNode(nodeManager, node, schemaNode, range, diagnostics); + break; + + default: + this.validateNodeTypeDefinition(schemaNode, node, range, diagnostics, parenSchemaNode); + break; + } + } + } + + private validateObjectNode( + nodeManager: ASTNodeManager, + node: ObjectASTNode, + schemaNode: RecordSchemaNode, + range: Range, + diagnostics: Diagnostic[] + ): void { + schemaNode.fields.forEach((schemaFieldNode) => { + const propertyNode = node.properties.find((prop) => prop.keyNode.value === schemaFieldNode.name); + const nodeFound = propertyNode !== undefined; + if (schemaFieldNode.isRequired && !nodeFound) { + diagnostics.push(Diagnostic.create(range, `${schemaFieldNode.name} is required`, DiagnosticSeverity.Error)); + } + if (nodeFound) { + const childSchemaNode = this.schemaNodeResolver.getSchemaNodeByTypeRef(schemaFieldNode.typeRef); + if (childSchemaNode && propertyNode.valueNode) { + if (schemaFieldNode.supportsArray) { + propertyNode.valueNode.children?.forEach((item) => { + if (item.type === "property" && item.valueNode) { + this.collectDiagnostics(nodeManager, item.valueNode, childSchemaNode, diagnostics, schemaFieldNode); } - } + }); + } else { + this.collectDiagnostics(nodeManager, propertyNode.valueNode, childSchemaNode, diagnostics, schemaFieldNode); } - }); + } } - } else if (schemaNode instanceof FieldSchemaNode) { - console.log("Field Schema Node"); - } else { - console.log("Other Schema Node"); + }); + } + + private validateNodeTypeDefinition( + schemaNode: RecordSchemaNode, + node: ASTNode, + range: Range, + diagnostics: Diagnostic[], + parenSchemaNode?: SchemaNode + ): void { + if (!schemaNode.matchesTypeField(node.type) && !schemaNode.matchesMapping(node.type, parenSchemaNode as IdMapper)) { + diagnostics.push(Diagnostic.create(range, `${schemaNode.name} definition expected`, DiagnosticSeverity.Error)); } } From 8adf724b4900f64c9134b7b05d6f317e38f97a1a Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 2 Sep 2022 22:47:10 +0200 Subject: [PATCH 30/50] Change toString in ASTNodeImpl to display internalNode --- .../yaml-language-service/src/parser/astTypes.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/server/packages/yaml-language-service/src/parser/astTypes.ts b/server/packages/yaml-language-service/src/parser/astTypes.ts index f7f0eaf..534410c 100644 --- a/server/packages/yaml-language-service/src/parser/astTypes.ts +++ b/server/packages/yaml-language-service/src/parser/astTypes.ts @@ -74,16 +74,7 @@ export abstract class ASTNodeImpl { } public toString(): string { - return ( - "type: " + - this.type + - " (" + - this.offset + - "/" + - this.length + - ")" + - (this.parent ? " parent: {" + this.parent.toString() + "}" : "") - ); + return this.internalNode.toString(); } } From 9aac84c42af992a1403834b669b5102b86be131c Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 2 Sep 2022 23:11:33 +0200 Subject: [PATCH 31/50] Add WorkflowValidationService --- .../src/languageService.ts | 2 +- .../schemaValidationService.ts | 14 +++-- .../validation/workflowValidationService.ts | 51 +++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) rename server/gx-workflow-ls-format2/src/services/{ => validation}/schemaValidationService.ts (85%) create mode 100644 server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index 7a556ff..28b2878 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -15,7 +15,7 @@ import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; import { GalaxyWorkflowFormat2SchemaLoader } from "./schema"; import { GxFormat2CompletionService } from "./services/completionService"; import { GxFormat2HoverService } from "./services/hoverService"; -import { GxFormat2SchemaValidationService } from "./services/schemaValidationService"; +import { GxFormat2SchemaValidationService } from "./services/validation/schemaValidationService"; /** * A wrapper around the YAML Language Service to support language features diff --git a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts similarity index 85% rename from server/gx-workflow-ls-format2/src/services/schemaValidationService.ts rename to server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts index 62c6896..a0242ed 100644 --- a/server/gx-workflow-ls-format2/src/services/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts @@ -1,15 +1,21 @@ import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; import { ASTNode, ObjectASTNode } from "@gxwf/server-common/src/ast/types"; import { Diagnostic, DiagnosticSeverity, Range, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; -import { SchemaNode, SchemaNodeResolver } from "../schema"; -import { RecordSchemaNode, IdMapper } from "../schema/definitions"; +import { SchemaNode, SchemaNodeResolver } from "../../schema"; +import { RecordSchemaNode, IdMapper } from "../../schema/definitions"; +import { WorkflowValidationService } from "./workflowValidationService"; export class GxFormat2SchemaValidationService { - constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} + private workflowValidator: WorkflowValidationService; + constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) { + this.workflowValidator = new WorkflowValidationService(); + } - public doValidation(workflowDocument: WorkflowDocument): Promise { + public async doValidation(workflowDocument: WorkflowDocument): Promise { const diagnostics: Diagnostic[] = []; this.collectSchemaDiagnostics(workflowDocument, diagnostics); + const additionalDiagnostics = await this.workflowValidator.doValidation(workflowDocument); + diagnostics.push(...additionalDiagnostics); return Promise.resolve(diagnostics); } diff --git a/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts new file mode 100644 index 0000000..bb1db38 --- /dev/null +++ b/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts @@ -0,0 +1,51 @@ +import { Diagnostic, DiagnosticSeverity, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; + +export class WorkflowValidationService { + public doValidation(workflowDocument: WorkflowDocument): Promise { + const diagnostics: Diagnostic[] = [ + ...collectStepErrorDiagnostics(workflowDocument), + ...collectToolDiagnostics(workflowDocument), + ]; + return Promise.resolve(diagnostics); + } +} + +export function collectStepErrorDiagnostics(workflowDocument: WorkflowDocument): Diagnostic[] { + const diagnostics: Diagnostic[] = []; + const steps = workflowDocument.nodeManager.getStepNodes(); + steps.forEach((step) => { + const errors = step.properties.find((p) => p.keyNode.value === "errors"); + if (errors) { + const range = workflowDocument.nodeManager.getNodeRange(errors); + diagnostics.push( + Diagnostic.create( + range, + `Tool step contains error indicated during Galaxy export - ${errors}`, + DiagnosticSeverity.Warning + ) + ); + } + }); + return diagnostics; +} + +export function collectToolDiagnostics(workflowDocument: WorkflowDocument): Diagnostic[] { + const diagnostics: Diagnostic[] = []; + const steps = workflowDocument.nodeManager.getStepNodes(); + steps.forEach((step) => { + const tool_id = step.properties.find((p) => p.keyNode.value === "tool_id"); + if (tool_id) { + if (tool_id.valueNode?.value?.toString().includes("testtoolshed")) { + const range = workflowDocument.nodeManager.getNodeRange(tool_id); + diagnostics.push( + Diagnostic.create( + range, + `Step references a tool from the test tool shed, this should be replaced with a production tool`, + DiagnosticSeverity.Warning + ) + ); + } + } + }); + return diagnostics; +} From bbce6c87ba9a0843c5181968a1c45400deb18691 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sat, 3 Sep 2022 13:10:46 +0200 Subject: [PATCH 32/50] Refactor validation services --- .../src/languageService.ts | 19 ++++++++++++------ .../src/services/validation/index.ts | 4 ++++ .../validation/schemaValidationService.ts | 20 +++++++++---------- .../validation/workflowValidationService.ts | 9 +++++++-- .../server-common/src/languageTypes.ts | 8 ++++++++ 5 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 server/gx-workflow-ls-format2/src/services/validation/index.ts diff --git a/server/gx-workflow-ls-format2/src/languageService.ts b/server/gx-workflow-ls-format2/src/languageService.ts index 28b2878..bfffb2a 100644 --- a/server/gx-workflow-ls-format2/src/languageService.ts +++ b/server/gx-workflow-ls-format2/src/languageService.ts @@ -9,13 +9,14 @@ import { Hover, CompletionList, Diagnostic, + WorkflowValidator, } from "@gxwf/server-common/src/languageTypes"; import { LanguageService, getLanguageService } from "@gxwf/yaml-language-service/src/yamlLanguageService"; import { GxFormat2WorkflowDocument } from "./gxFormat2WorkflowDocument"; import { GalaxyWorkflowFormat2SchemaLoader } from "./schema"; import { GxFormat2CompletionService } from "./services/completionService"; import { GxFormat2HoverService } from "./services/hoverService"; -import { GxFormat2SchemaValidationService } from "./services/validation/schemaValidationService"; +import { GxFormat2SchemaValidationService, WorkflowValidationService } from "./services/validation"; /** * A wrapper around the YAML Language Service to support language features @@ -26,14 +27,17 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { private _schemaLoader: GalaxyWorkflowFormat2SchemaLoader; private _hoverService: GxFormat2HoverService; private _completionService: GxFormat2CompletionService; - private _validationService: GxFormat2SchemaValidationService; + private _validationServices: WorkflowValidator[]; constructor() { super(); this._schemaLoader = new GalaxyWorkflowFormat2SchemaLoader(); this._yamlLanguageService = getLanguageService(); this._hoverService = new GxFormat2HoverService(this._schemaLoader.nodeResolver); this._completionService = new GxFormat2CompletionService(this._schemaLoader.nodeResolver); - this._validationService = new GxFormat2SchemaValidationService(this._schemaLoader.nodeResolver); + this._validationServices = [ + new GxFormat2SchemaValidationService(this._schemaLoader.nodeResolver), + new WorkflowValidationService(), + ]; } public override parseWorkflowDocument(document: TextDocument): WorkflowDocument { @@ -58,8 +62,11 @@ export class GxFormat2WorkflowLanguageService extends WorkflowLanguageService { protected override async doValidation(workflowDocument: WorkflowDocument): Promise { const format2WorkflowDocument = workflowDocument as GxFormat2WorkflowDocument; - const yamlDiagnostics = await this._yamlLanguageService.doValidation(format2WorkflowDocument.yamlDocument); - const schemaDiagnostics = await this._validationService.doValidation(workflowDocument); - return [...yamlDiagnostics, ...schemaDiagnostics]; + const diagnostics = await this._yamlLanguageService.doValidation(format2WorkflowDocument.yamlDocument); + for (const validator of this._validationServices) { + const results = await validator.doValidation(workflowDocument); + diagnostics.push(...results); + } + return diagnostics; } } diff --git a/server/gx-workflow-ls-format2/src/services/validation/index.ts b/server/gx-workflow-ls-format2/src/services/validation/index.ts new file mode 100644 index 0000000..904820f --- /dev/null +++ b/server/gx-workflow-ls-format2/src/services/validation/index.ts @@ -0,0 +1,4 @@ +import { GxFormat2SchemaValidationService } from "./schemaValidationService"; +import { WorkflowValidationService } from "./workflowValidationService"; + +export { GxFormat2SchemaValidationService, WorkflowValidationService }; diff --git a/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts index a0242ed..189543e 100644 --- a/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts @@ -1,21 +1,21 @@ import { ASTNodeManager } from "@gxwf/server-common/src/ast/nodeManager"; import { ASTNode, ObjectASTNode } from "@gxwf/server-common/src/ast/types"; -import { Diagnostic, DiagnosticSeverity, Range, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; +import { + Diagnostic, + DiagnosticSeverity, + Range, + WorkflowDocument, + WorkflowValidator, +} from "@gxwf/server-common/src/languageTypes"; import { SchemaNode, SchemaNodeResolver } from "../../schema"; import { RecordSchemaNode, IdMapper } from "../../schema/definitions"; -import { WorkflowValidationService } from "./workflowValidationService"; -export class GxFormat2SchemaValidationService { - private workflowValidator: WorkflowValidationService; - constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) { - this.workflowValidator = new WorkflowValidationService(); - } +export class GxFormat2SchemaValidationService implements WorkflowValidator { + constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} - public async doValidation(workflowDocument: WorkflowDocument): Promise { + public doValidation(workflowDocument: WorkflowDocument): Promise { const diagnostics: Diagnostic[] = []; this.collectSchemaDiagnostics(workflowDocument, diagnostics); - const additionalDiagnostics = await this.workflowValidator.doValidation(workflowDocument); - diagnostics.push(...additionalDiagnostics); return Promise.resolve(diagnostics); } diff --git a/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts index bb1db38..86c7aab 100644 --- a/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts @@ -1,6 +1,11 @@ -import { Diagnostic, DiagnosticSeverity, WorkflowDocument } from "@gxwf/server-common/src/languageTypes"; +import { + Diagnostic, + DiagnosticSeverity, + WorkflowDocument, + WorkflowValidator, +} from "@gxwf/server-common/src/languageTypes"; -export class WorkflowValidationService { +export class WorkflowValidationService implements WorkflowValidator { public doValidation(workflowDocument: WorkflowDocument): Promise { const diagnostics: Diagnostic[] = [ ...collectStepErrorDiagnostics(workflowDocument), diff --git a/server/packages/server-common/src/languageTypes.ts b/server/packages/server-common/src/languageTypes.ts index 744a648..09c8fe9 100644 --- a/server/packages/server-common/src/languageTypes.ts +++ b/server/packages/server-common/src/languageTypes.ts @@ -132,6 +132,14 @@ export interface ValidationProfile { get rules(): Set; } +/** + * Interface for validating workflows and collecting diagnostics. + */ +export interface WorkflowValidator { + /** Collects diagnostics for the given workflow document. */ + doValidation(workflowDocument: WorkflowDocument): Promise; +} + /** * Abstract service defining the base functionality that a workflow language must * implement to provide assistance for workflow documents editing. From df74ec5957e64fefb80e9e76c1959e20714c5a71 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 4 Sep 2022 20:54:54 +0200 Subject: [PATCH 33/50] Refactor schema loader --- .../src/schema/definitions.ts | 5 +- .../src/schema/schemaLoader.ts | 87 +++++++++++-------- .../src/schema/schemaNodeResolver.ts | 10 +-- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index ea6dab1..d869d61 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -296,8 +296,7 @@ export class RecordSchemaNode implements SchemaNode { } export interface SchemaDefinitions { - types: Map; - records: Map; - fields: Map; + records: Map; + fields: Map; specializations: Map; } diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index 94c8b81..e83b7c5 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -1,6 +1,8 @@ import { + FieldSchemaNode, isSchemaEntryBase, isSchemaRecord, + RecordSchemaNode, SchemaDefinitions, SchemaDocument, SchemaEntry, @@ -13,16 +15,18 @@ import { SchemaNodeResolver } from "./schemaNodeResolver"; import { SCHEMA_DOCS_v19_09_MAP } from "./versions"; export class GalaxyWorkflowFormat2SchemaLoader { - public readonly definitions: SchemaDefinitions; - private _documentTypeMap = new Map>(); + private _documentEntryMap = new Map>(); + private _rawSchemaEntries = new Map(); private _namespaces = new Map(); - public readonly nodeResolver: SchemaNodeResolver; - private _unknownTypes: string[] = []; private _extendedTypes: Set = new Set(); private _root?: SchemaRecord; + public readonly definitions: SchemaDefinitions; + public readonly nodeResolver: SchemaNodeResolver; + constructor(private readonly enableDebugTrace: boolean = false) { - this.definitions = this.loadSchemaDefinitions_v19_09(); + this._rawSchemaEntries = this.loadSchemaEntriesMap_v19_09(); + this.definitions = this.loadSchemaDefinitions(this._rawSchemaEntries); this.nodeResolver = this.createNodeResolver(); if (this.enableDebugTrace) { @@ -36,40 +40,48 @@ export class GalaxyWorkflowFormat2SchemaLoader { if (this._extendedTypes) { console.debug(`EXTENDED Types (Unresolved): ${this._extendedTypes.size}`); this._extendedTypes.forEach((type) => { - if (!this.definitions.types.has(type)) { - console.debug(` ${type} ${this.definitions.types.has(type) ? "[found]" : ""}`); + if (!this._rawSchemaEntries.has(type)) { + console.debug(` ${type} ${this._rawSchemaEntries.has(type) ? "[found]" : ""}`); } }); } } } - private loadSchemaDefinitions_v19_09(): SchemaDefinitions { + private loadSchemaEntriesMap_v19_09(): Map { + const entries = new Map(); + for (const schemaDoc of SCHEMA_DOCS_v19_09_MAP.values()) { + const types = this.loadSchemaDocument(schemaDoc); + types.forEach((v, k) => { + entries.set(k, v); + }); + } + return entries; + } + + private loadSchemaDefinitions(schemaEntries: Map): SchemaDefinitions { const definitions: SchemaDefinitions = { - types: new Map(), - records: new Map(), - fields: new Map(), + records: new Map(), + fields: new Map(), specializations: new Map(), }; - SCHEMA_DOCS_v19_09_MAP.forEach((schemaDoc) => { - const types = this.loadSchemaDocument(schemaDoc); - types.forEach((v, k) => { - definitions.types.set(k, v); - if (isSchemaRecord(v)) { - definitions.records.set(k, v); - if (v.specialize) { - v.specialize.forEach((sp) => { - definitions.specializations.set(sp.specializeFrom, sp.specializeTo); - }); - } - v.fields.forEach((field) => { - if (definitions.fields.has(field.name)) { - if (this.enableDebugTrace) console.debug("****** DUPLICATED FIELD", field.name); - } - definitions.fields.set(field.name, field); + + this.expandRecords(schemaEntries.values()); + schemaEntries.forEach((v, k) => { + if (isSchemaRecord(v)) { + definitions.records.set(k, new RecordSchemaNode(v)); + if (v.specialize) { + v.specialize.forEach((sp) => { + definitions.specializations.set(sp.specializeFrom, sp.specializeTo); }); } - }); + v.fields.forEach((field) => { + if (definitions.fields.has(field.name)) { + if (this.enableDebugTrace) console.debug("****** DUPLICATED FIELD", field.name); + } + definitions.fields.set(field.name, new FieldSchemaNode(field)); + }); + } }); return definitions; } @@ -95,7 +107,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { documentEntries.set(entry.name, loadedEntry); } }); - this._documentTypeMap.set(schemaDoc.$base, documentEntries); + this._documentEntryMap.set(schemaDoc.$base, documentEntries); return documentEntries; } @@ -208,7 +220,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { if (namespace && type) { const docBase = this._namespaces.get(namespace); if (docBase) { - const schemaTypes = this._documentTypeMap.get(docBase); + const schemaTypes = this._documentEntryMap.get(docBase); if (schemaTypes?.has(type)) { rawTypeName = type; } else { @@ -224,24 +236,23 @@ export class GalaxyWorkflowFormat2SchemaLoader { private resolveTypeToSchemaEntry(rawTypeName: string): SchemaEntry { const typeName = this.resolveTypeName(rawTypeName); - if (this.definitions.types.has(typeName)) { - return this.definitions.types.get(typeName) as SchemaEntry; + if (this._rawSchemaEntries.has(typeName)) { + return this._rawSchemaEntries.get(typeName) as SchemaEntry; } throw new Error(`Unresolvable type ${rawTypeName}`); } private createNodeResolver(): SchemaNodeResolver { - this.expandRecords(); return new SchemaNodeResolver(this.definitions, this._root); } /** Expands all records with the fields defined in the extended types.*/ - private expandRecords(): void { - this.definitions.types.forEach((value: SchemaEntry) => { - if (isSchemaRecord(value)) { - this.expandRecord(value); + private expandRecords(schemaEntries: IterableIterator): void { + for (const entry of schemaEntries) { + if (isSchemaRecord(entry)) { + this.expandRecord(entry); } - }); + } } private expandRecord(record: SchemaRecord): SchemaRecord { diff --git a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts index 7c13af4..17dc3c7 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaNodeResolver.ts @@ -1,5 +1,5 @@ import { NodePath, Segment } from "@gxwf/server-common/src/ast/types"; -import { SchemaDefinitions, SchemaNode, RecordSchemaNode, FieldSchemaNode, SchemaRecord } from "./definitions"; +import { SchemaDefinitions, SchemaNode, RecordSchemaNode, SchemaRecord } from "./definitions"; export class SchemaNodeResolver { public readonly rootNode: SchemaNode; @@ -29,13 +29,9 @@ export class SchemaNodeResolver { if (typeof pathSegment === "string") { pathSegment = this.definitions.specializations.get(pathSegment) || pathSegment; if (this.definitions.records.has(pathSegment)) { - const record = this.definitions.records.get(pathSegment); - if (record) return new RecordSchemaNode(record); - } - if (this.definitions.fields.has(pathSegment)) { - const field = this.definitions.fields.get(pathSegment); - if (field) return new FieldSchemaNode(field); + return this.definitions.records.get(pathSegment); } + return this.definitions.fields.get(pathSegment); } return undefined; } From a45cc52c4981ddcce51db7405b827973964f18ef Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Sun, 4 Sep 2022 20:58:27 +0200 Subject: [PATCH 34/50] Fix unit tests after adding specialization support --- server/gx-workflow-ls-format2/tests/unit/schema.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts index 3834f83..6dcea71 100644 --- a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -22,13 +22,13 @@ describe("Gxformat2 Schema Handling", () => { it.each([ [["class"], "class"], [["inputs"], "inputs"], - [["inputs", 0], "InputParameter"], + [["inputs", 0], "WorkflowInputParameter"], [["inputs", 0, "doc"], "doc"], - [["inputs", "input1"], "InputParameter"], + [["inputs", "input1"], "WorkflowInputParameter"], [["inputs", "input1", "label"], "label"], [["outputs"], "outputs"], - [["outputs", 1], "OutputParameter"], - [["outputs", "output1"], "OutputParameter"], + [["outputs", 1], "WorkflowOutputParameter"], + [["outputs", "output1"], "WorkflowOutputParameter"], [["steps"], "steps"], [["steps", 5], "WorkflowStep"], [["steps", "random", "tool_id"], "tool_id"], From 47c8d4cdccdd2196f347cd8f7d01358a3e6cd8da Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 5 Sep 2022 10:33:14 +0200 Subject: [PATCH 35/50] Remove unused children property --- .../src/schema/definitions.ts | 10 ------- .../src/schema/index.ts | 4 +-- .../src/services/completionService.ts | 26 ++++++++++--------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index d869d61..35f91ae 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -147,7 +147,6 @@ function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { export interface SchemaNode { name: string; - children: SchemaNode[]; documentation: string | undefined; supportsArray: boolean; typeRef: string; @@ -187,10 +186,6 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { return this._allowedTypes; } - public get children(): SchemaNode[] { - return []; - } - public get isRoot(): boolean { return false; } @@ -263,11 +258,6 @@ export class RecordSchemaNode implements SchemaNode { public get documentation(): string | undefined { return this._schemaRecord.doc; } - - public get children(): SchemaNode[] { - return this.fields; - } - public get isRoot(): boolean { return !!this._schemaRecord.documentRoot; } diff --git a/server/gx-workflow-ls-format2/src/schema/index.ts b/server/gx-workflow-ls-format2/src/schema/index.ts index 17c3bc5..a4239af 100644 --- a/server/gx-workflow-ls-format2/src/schema/index.ts +++ b/server/gx-workflow-ls-format2/src/schema/index.ts @@ -1,5 +1,5 @@ import { GalaxyWorkflowFormat2SchemaLoader } from "./schemaLoader"; -import { SchemaNode } from "./definitions"; +import { RecordSchemaNode, FieldSchemaNode, SchemaNode } from "./definitions"; import { SchemaNodeResolver } from "./schemaNodeResolver"; -export { GalaxyWorkflowFormat2SchemaLoader, SchemaNode, SchemaNodeResolver }; +export { GalaxyWorkflowFormat2SchemaLoader, SchemaNodeResolver, SchemaNode, RecordSchemaNode, FieldSchemaNode }; diff --git a/server/gx-workflow-ls-format2/src/services/completionService.ts b/server/gx-workflow-ls-format2/src/services/completionService.ts index 912675d..9567a37 100644 --- a/server/gx-workflow-ls-format2/src/services/completionService.ts +++ b/server/gx-workflow-ls-format2/src/services/completionService.ts @@ -8,7 +8,7 @@ import { TextDocument, } from "@gxwf/server-common/src/languageTypes"; import { TextBuffer } from "@gxwf/yaml-language-service/src/utils/textBuffer"; -import { SchemaNode, SchemaNodeResolver } from "../schema"; +import { RecordSchemaNode, SchemaNode, SchemaNodeResolver } from "../schema"; export class GxFormat2CompletionService { constructor(protected readonly schemaNodeResolver: SchemaNodeResolver) {} @@ -51,17 +51,19 @@ export class GxFormat2CompletionService { private getProposedItems(schemaNode: SchemaNode, exclude: Set): CompletionItem[] { const result: CompletionItem[] = []; - schemaNode.children.forEach((child) => { - if (exclude.has(child.name)) return; - const item: CompletionItem = { - label: child.name, - documentation: child.documentation, - sortText: `_${child.name}`, - kind: CompletionItemKind.Field, - insertText: `${child.name}: `, - }; - result.push(item); - }); + if (schemaNode instanceof RecordSchemaNode) { + schemaNode.fields.forEach((field) => { + if (exclude.has(field.name)) return; + const item: CompletionItem = { + label: field.name, + documentation: field.documentation, + sortText: `_${field.name}`, + kind: CompletionItemKind.Field, + insertText: `${field.name}: `, + }; + result.push(item); + }); + } return result; } } From d92175ef0b9845f66f319ec3f52a9f4b9bd0692a Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 6 Sep 2022 09:20:52 +0200 Subject: [PATCH 36/50] Add support for multi type array definitions in schema --- .../src/schema/definitions.ts | 83 +++++++++++++------ .../validation/schemaValidationService.ts | 2 +- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 35f91ae..a8b5a39 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -85,14 +85,14 @@ interface BasicFieldType extends FieldTypeBase { } interface ArrayFieldType extends BasicFieldType { - itemType: FieldTypeBase; + itemType: BasicFieldType | BasicFieldType[]; } interface EnumFieldType extends BasicFieldType { symbols: string[]; } -function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { +function fieldTypeFactory(typeEntry: unknown): BasicFieldType[] | undefined { if (typeof typeEntry === "string") { let baseType: string = typeEntry; let isOptional = baseType.endsWith("?"); @@ -108,9 +108,9 @@ function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { itemType: buildBasicFieldType(isOptional, baseType), typeName: "array", }; - return arrayType; + return [arrayType]; } - return buildBasicFieldType(isOptional, baseType); + return [buildBasicFieldType(isOptional, baseType)]; } else if (typeof typeEntry === "object") { if (isSchemaArrayType(typeEntry)) { const itemType = fieldTypeFactory((typeEntry as SchemaArrayType).items); @@ -120,7 +120,7 @@ function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { itemType: itemType, typeName: "array", }; - return arrayType; + return [arrayType]; } } if (isSchemaEnumType(typeEntry)) { @@ -129,9 +129,19 @@ function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { symbols: (typeEntry as SchemaEnumType).symbols, typeName: "enum", }; - return enumType; + return [enumType]; } - console.debug(`Object Field type UNKNOWN: ${JSON.stringify(typeEntry)}`); + if (typeEntry instanceof Array) { + const types: BasicFieldType[] = []; + typeEntry.forEach((e) => { + const res = fieldTypeFactory(e); + if (res) { + types.push(...res); + } + }); + return types; + } + console.debug(`Object Field type UNKNOWN: ${JSON.stringify(typeEntry)} - ${typeof typeEntry}`); return undefined; } else { console.debug(`Field type NOT PROCESSED: ${JSON.stringify(typeEntry)}`); @@ -148,7 +158,7 @@ function fieldTypeFactory(typeEntry: unknown): BasicFieldType | undefined { export interface SchemaNode { name: string; documentation: string | undefined; - supportsArray: boolean; + canBeArray: boolean; typeRef: string; isRoot: boolean; } @@ -163,13 +173,13 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { schemaField.type.forEach((typeEntry) => { const fieldType = fieldTypeFactory(typeEntry); if (fieldType) { - this._allowedTypes.push(fieldType); + fieldType.forEach((t) => this._allowedTypes.push(t)); } }); } else { const fieldType = fieldTypeFactory(schemaField.type); if (fieldType) { - this._allowedTypes.push(fieldType); + fieldType.forEach((t) => this._allowedTypes.push(t)); } } } @@ -182,10 +192,6 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { return this._schemaField.doc; } - public get typesAllowed(): BasicFieldType[] { - return this._allowedTypes; - } - public get isRoot(): boolean { return false; } @@ -195,18 +201,40 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { } public get isOptional(): boolean { - return this._allowedTypes.some((ft) => ft.isOptional); + return this._allowedTypes.some((t) => t.isOptional); } - public get supportsArray(): boolean { - return this._allowedTypes.some((t) => isArrayFieldType(t)); + public get canBeAny(): boolean { + return this._allowedTypes.some((t) => t.typeName === "Any"); + } + + public get canBeArray(): boolean { + return this.canBeAny || this._allowedTypes.some((t) => isArrayFieldType(t)); + } + + //TODO: add canBeObject = non-basic type + + public matchesType(typeName: string): boolean { + if (this.canBeAny) return true; + for (const allowedType of this._allowedTypes) { + if (allowedType.typeName === typeName) { + return true; + } + if (isArrayFieldType(allowedType) && allowedType.itemType instanceof Array) { + const result = allowedType.itemType.find((t) => t.typeName === typeName); + if (result) return true; + } + } + return false; } public get typeRef(): string { - if (this.supportsArray) { + if (this.canBeAny) return "Any"; + if (this.canBeArray) { return this.getArrayItemTypeName() || "undefined"; } - const mainType = this.typesAllowed.find((t) => t.typeName !== "null"); + const mainType = this._allowedTypes.find((t) => t.typeName !== "null"); + //TODO: this requires more logic... we cannot assume the first non-null type to be the main return isBasicFieldType(mainType) ? mainType.typeName : "unknown"; } @@ -223,6 +251,9 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { if (isBasicFieldType(arrayType?.itemType)) { return arrayType?.itemType.typeName; } + if (arrayType?.itemType instanceof Array) { + return arrayType.itemType.map((i) => i.typeName).at(0); // TODO REMOVE AT + } console.debug("getArrayItemTypeName -> Type name not found"); return undefined; } @@ -262,7 +293,7 @@ export class RecordSchemaNode implements SchemaNode { return !!this._schemaRecord.documentRoot; } - public get supportsArray(): boolean { + public get canBeArray(): boolean { return false; } @@ -271,17 +302,21 @@ export class RecordSchemaNode implements SchemaNode { } public get typeField(): FieldSchemaNode | undefined { - return this.fields.find((t) => t.name === "type"); + return this.getFieldByName("type"); } public matchesTypeField(typeName: string): boolean { - return this.typeField?.typesAllowed.find((t) => t.typeName === typeName) !== undefined; + return this.typeField?.matchesType(typeName) || false; } public matchesMapping(typeName: string, idMapper?: IdMapper): boolean { if (!idMapper || !idMapper.mapSubject) return false; - const mappedField = this.fields.find((f) => f.name === idMapper.mapSubject); - return mappedField?.typesAllowed.find((t) => t.typeName === typeName) !== undefined; + const mappedField = this.getFieldByName(idMapper.mapSubject); + return mappedField?.matchesType(typeName) || false; + } + + public getFieldByName(name: string): FieldSchemaNode | undefined { + return this.fields.find((t) => t.name === name); } } diff --git a/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts index 189543e..ea10615 100644 --- a/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts @@ -67,7 +67,7 @@ export class GxFormat2SchemaValidationService implements WorkflowValidator { if (nodeFound) { const childSchemaNode = this.schemaNodeResolver.getSchemaNodeByTypeRef(schemaFieldNode.typeRef); if (childSchemaNode && propertyNode.valueNode) { - if (schemaFieldNode.supportsArray) { + if (schemaFieldNode.canBeArray) { propertyNode.valueNode.children?.forEach((item) => { if (item.type === "property" && item.valueNode) { this.collectDiagnostics(nodeManager, item.valueNode, childSchemaNode, diagnostics, schemaFieldNode); From 8441e31f356c01f512605a298974c476da311db5 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 6 Sep 2022 09:21:54 +0200 Subject: [PATCH 37/50] Add some unit tests for schema definitions --- .../tests/unit/schema.test.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts index 6dcea71..0a08199 100644 --- a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -39,5 +39,42 @@ describe("Gxformat2 Schema Handling", () => { }); }); }); + + describe("Definitions", () => { + it("should define GalaxyWorkflow record as expected", () => { + const record = schemaLoader.definitions.records.get("GalaxyWorkflow"); + expect(record).toBeDefined(); + expect(record?.name).toBe("GalaxyWorkflow"); + expect(record?.documentation).toBeDefined(); + expect(record?.fields.length).toBe(13); + const field = record?.getFieldByName("class"); + expect(field).toBeDefined(); + expect(field?.typeRef).toBe("string"); + }); + + it("should define WorkflowStep record as expected", () => { + const record = schemaLoader.definitions.records.get("WorkflowStep"); + expect(record).toBeDefined(); + expect(record?.name).toBe("WorkflowStep"); + expect(record?.documentation).toBeDefined(); + expect(record?.fields.length).toBe(16); + let field = record?.getFieldByName("out"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.matchesType("null")).toBe(true); + expect(field?.matchesType("string")).toBe(true); + expect(field?.matchesType("WorkflowStepOutput")).toBe(true); + expect(field?.matchesType("Any")).toBe(false); + field = record?.getFieldByName("state"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.typeRef).toBe("Any"); + expect(field?.canBeArray).toBe(true); + expect(field?.matchesType("null")).toBe(true); + expect(field?.matchesType("string")).toBe(true); + expect(field?.matchesType("anything...")).toBe(true); + }); + }); }); }); From e26f71e68f3a09fb2400a72e78a7556dc9969526 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Wed, 7 Sep 2022 10:26:20 +0200 Subject: [PATCH 38/50] Fix array with single type matching --- .../src/schema/definitions.ts | 13 ++++++++++--- .../tests/unit/schema.test.ts | 8 +++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index a8b5a39..aa8df8e 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -216,13 +216,20 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { public matchesType(typeName: string): boolean { if (this.canBeAny) return true; + if (typeName === "null" && this.isOptional) return true; for (const allowedType of this._allowedTypes) { if (allowedType.typeName === typeName) { return true; } - if (isArrayFieldType(allowedType) && allowedType.itemType instanceof Array) { - const result = allowedType.itemType.find((t) => t.typeName === typeName); - if (result) return true; + if (isArrayFieldType(allowedType)) { + if (allowedType.itemType instanceof Array) { + const result = allowedType.itemType.find((t) => t.typeName === typeName); + if (result) return true; + } else { + if (allowedType.itemType.typeName === typeName) { + return true; + } + } } } return false; diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts index 0a08199..a22cbc0 100644 --- a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -58,7 +58,13 @@ describe("Gxformat2 Schema Handling", () => { expect(record?.name).toBe("WorkflowStep"); expect(record?.documentation).toBeDefined(); expect(record?.fields.length).toBe(16); - let field = record?.getFieldByName("out"); + let field = record?.getFieldByName("in"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.matchesType("null")).toBe(true); + expect(field?.matchesType("WorkflowStepInput")).toBe(true); + field = record?.getFieldByName("out"); expect(field).toBeDefined(); expect(field?.isOptional).toBe(true); expect(field?.canBeArray).toBe(true); From 695323b0705bce75028e0a5fbe584d20f972c52d Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Wed, 21 Sep 2022 16:04:18 +0200 Subject: [PATCH 39/50] Add support for enums symbol extensions --- .../src/schema/definitions.ts | 1 + .../src/schema/schemaLoader.ts | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index aa8df8e..8b1fa05 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -36,6 +36,7 @@ export interface SchemaRecord extends DocumentedSchemaEntry { export interface SchemaEnum extends DocumentedSchemaEntry { symbols: string[]; + extends?: string; } interface SchemaType { diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index e83b7c5..bf615ba 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -1,6 +1,7 @@ import { FieldSchemaNode, isSchemaEntryBase, + isSchemaEnumType, isSchemaRecord, RecordSchemaNode, SchemaDefinitions, @@ -66,7 +67,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { specializations: new Map(), }; - this.expandRecords(schemaEntries.values()); + this.expandEntries(schemaEntries.values()); schemaEntries.forEach((v, k) => { if (isSchemaRecord(v)) { definitions.records.set(k, new RecordSchemaNode(v)); @@ -126,6 +127,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { type: entry.type, doc: entry.doc, symbols: entry.symbols, + extends: entry.extends, }; return enumEntry; @@ -246,11 +248,13 @@ export class GalaxyWorkflowFormat2SchemaLoader { return new SchemaNodeResolver(this.definitions, this._root); } - /** Expands all records with the fields defined in the extended types.*/ - private expandRecords(schemaEntries: IterableIterator): void { + /** Expands all entries with the types defined in the extended types.*/ + private expandEntries(schemaEntries: IterableIterator): void { for (const entry of schemaEntries) { if (isSchemaRecord(entry)) { this.expandRecord(entry); + } else if (isSchemaEnumType(entry)) { + this.expandEnum(entry); } } } @@ -265,6 +269,21 @@ export class GalaxyWorkflowFormat2SchemaLoader { return record; } + private expandEnum(entry: SchemaEnum): SchemaEnum { + if (!entry.extends) { + return entry; + } + const resolved = this.resolveTypeToSchemaEntry(entry.extends); + if (isSchemaEnumType(resolved)) { + resolved.symbols.forEach((s) => { + const symbol = s.indexOf(":") > 0 ? (s.split(":").at(1) as string) : s; + entry.symbols.push(symbol); + }); + } + entry.extends = undefined; + return entry; + } + private collectExtensionFields(record: SchemaRecord, extensionFields: SchemaField[]): SchemaField[] { record.extends?.forEach((typeToExtend) => { const resolved = this.resolveTypeToSchemaEntry(typeToExtend); From 1da7935cddbba53c2a6ae58871bfad91441d115b Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 3 Oct 2022 22:34:59 +0200 Subject: [PATCH 40/50] Add support for primitives and objects detection --- .../src/schema/definitions.ts | 20 ++++++++++++++++++- .../src/schema/schemaLoader.ts | 5 +++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/server/gx-workflow-ls-format2/src/schema/definitions.ts b/server/gx-workflow-ls-format2/src/schema/definitions.ts index 8b1fa05..db02d71 100644 --- a/server/gx-workflow-ls-format2/src/schema/definitions.ts +++ b/server/gx-workflow-ls-format2/src/schema/definitions.ts @@ -165,6 +165,8 @@ export interface SchemaNode { } export class FieldSchemaNode implements SchemaNode, IdMapper { + public static definitions: SchemaDefinitions; + private _allowedTypes: BasicFieldType[] = []; private readonly _schemaField: SchemaField; @@ -205,6 +207,10 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { return this._allowedTypes.some((t) => t.isOptional); } + public get default(): unknown { + return this._schemaField.default; + } + public get canBeAny(): boolean { return this._allowedTypes.some((t) => t.typeName === "Any"); } @@ -213,7 +219,9 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { return this.canBeAny || this._allowedTypes.some((t) => isArrayFieldType(t)); } - //TODO: add canBeObject = non-basic type + public get canBeObject(): boolean { + return this.canBeAny || this._allowedTypes.some((t) => this.isObjectType(t.typeName)); + } public matchesType(typeName: string): boolean { if (this.canBeAny) return true; @@ -265,9 +273,18 @@ export class FieldSchemaNode implements SchemaNode, IdMapper { console.debug("getArrayItemTypeName -> Type name not found"); return undefined; } + + private isPrimitiveType(typeName: string): boolean { + return FieldSchemaNode.definitions.primitiveTypes.has(typeName); + } + + private isObjectType(typeName: string): boolean { + return FieldSchemaNode.definitions.records.has(typeName); + } } export class RecordSchemaNode implements SchemaNode { + public static definitions: SchemaDefinitions; public static readonly NULL: SchemaNode = new RecordSchemaNode({ name: "null", type: "null", @@ -332,4 +349,5 @@ export interface SchemaDefinitions { records: Map; fields: Map; specializations: Map; + primitiveTypes: Set; } diff --git a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts index bf615ba..0b3acaa 100644 --- a/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts +++ b/server/gx-workflow-ls-format2/src/schema/schemaLoader.ts @@ -29,6 +29,8 @@ export class GalaxyWorkflowFormat2SchemaLoader { this._rawSchemaEntries = this.loadSchemaEntriesMap_v19_09(); this.definitions = this.loadSchemaDefinitions(this._rawSchemaEntries); this.nodeResolver = this.createNodeResolver(); + RecordSchemaNode.definitions = this.definitions; + FieldSchemaNode.definitions = this.definitions; if (this.enableDebugTrace) { if (this._unknownTypes) { @@ -65,6 +67,7 @@ export class GalaxyWorkflowFormat2SchemaLoader { records: new Map(), fields: new Map(), specializations: new Map(), + primitiveTypes: new Set(), }; this.expandEntries(schemaEntries.values()); @@ -82,6 +85,8 @@ export class GalaxyWorkflowFormat2SchemaLoader { } definitions.fields.set(field.name, new FieldSchemaNode(field)); }); + } else if (isSchemaEnumType(v) && v.name === "GalaxyType") { + definitions.primitiveTypes = new Set(v.symbols); } }); return definitions; From b3827042df4296b9621142abe07dd2bc5cab745a Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 3 Oct 2022 22:35:34 +0200 Subject: [PATCH 41/50] Add more tests for schema definitions --- .../tests/unit/schema.test.ts | 183 ++++++++++++++---- 1 file changed, 147 insertions(+), 36 deletions(-) diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts index a22cbc0..f8dacda 100644 --- a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts +++ b/server/gx-workflow-ls-format2/tests/unit/schema.test.ts @@ -1,5 +1,5 @@ import { NodePath } from "@gxwf/server-common/src/ast/types"; -import { GalaxyWorkflowFormat2SchemaLoader, SchemaNodeResolver } from "../../src/schema"; +import { GalaxyWorkflowFormat2SchemaLoader, RecordSchemaNode, SchemaNodeResolver } from "../../src/schema"; describe("Gxformat2 Schema Handling", () => { describe("Schema Version 19_09", () => { @@ -41,45 +41,156 @@ describe("Gxformat2 Schema Handling", () => { }); describe("Definitions", () => { - it("should define GalaxyWorkflow record as expected", () => { - const record = schemaLoader.definitions.records.get("GalaxyWorkflow"); - expect(record).toBeDefined(); - expect(record?.name).toBe("GalaxyWorkflow"); - expect(record?.documentation).toBeDefined(); - expect(record?.fields.length).toBe(13); - const field = record?.getFieldByName("class"); + function expectRecordHasOptionalStringField( + record: RecordSchemaNode, + fieldName: string, + canBeArray = false + ): void { + const field = record.getFieldByName(fieldName); expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(canBeArray); + expect(field?.canBeObject).toBe(false); expect(field?.typeRef).toBe("string"); + } + describe("GalaxyWorkflow Record", () => { + it("should have the expected field definitions", () => { + const record = schemaLoader.definitions.records.get("GalaxyWorkflow") as RecordSchemaNode; + expect(record).toBeDefined(); + expect(record.name).toBe("GalaxyWorkflow"); + expect(record.documentation).toBeDefined(); + expect(record.fields.length).toBe(13); + let field = record.getFieldByName("class"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(false); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(false); + expect(field?.typeRef).toBe("string"); + field = record.getFieldByName("steps"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(false); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(false); + expect(field?.typeRef).toBe("WorkflowStep"); + field = record.getFieldByName("report"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(true); + expect(field?.typeRef).toBe("Report"); + field = record.getFieldByName("tags"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(false); + expect(field?.typeRef).toBe("string"); + field = record.getFieldByName("creator"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(true); + expect(field?.typeRef).toBe("Any"); + field = record.getFieldByName("license"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(false); + expect(field?.typeRef).toBe("string"); + field = record.getFieldByName("release"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(false); + expect(field?.typeRef).toBe("string"); + + // HasUUID + expectRecordHasOptionalStringField(record, "uuid"); + + expectRecordHasOptionalStringField(record, "id"); + expectRecordHasOptionalStringField(record, "label"); + expectRecordHasOptionalStringField(record, "doc", true); + }); }); - it("should define WorkflowStep record as expected", () => { - const record = schemaLoader.definitions.records.get("WorkflowStep"); - expect(record).toBeDefined(); - expect(record?.name).toBe("WorkflowStep"); - expect(record?.documentation).toBeDefined(); - expect(record?.fields.length).toBe(16); - let field = record?.getFieldByName("in"); - expect(field).toBeDefined(); - expect(field?.isOptional).toBe(true); - expect(field?.canBeArray).toBe(true); - expect(field?.matchesType("null")).toBe(true); - expect(field?.matchesType("WorkflowStepInput")).toBe(true); - field = record?.getFieldByName("out"); - expect(field).toBeDefined(); - expect(field?.isOptional).toBe(true); - expect(field?.canBeArray).toBe(true); - expect(field?.matchesType("null")).toBe(true); - expect(field?.matchesType("string")).toBe(true); - expect(field?.matchesType("WorkflowStepOutput")).toBe(true); - expect(field?.matchesType("Any")).toBe(false); - field = record?.getFieldByName("state"); - expect(field).toBeDefined(); - expect(field?.isOptional).toBe(true); - expect(field?.typeRef).toBe("Any"); - expect(field?.canBeArray).toBe(true); - expect(field?.matchesType("null")).toBe(true); - expect(field?.matchesType("string")).toBe(true); - expect(field?.matchesType("anything...")).toBe(true); + describe("WorkflowStep Record", () => { + it("should have the expected field definitions", () => { + const record = schemaLoader.definitions.records.get("WorkflowStep") as RecordSchemaNode; + expect(record).toBeDefined(); + expect(record.name).toBe("WorkflowStep"); + expect(record.documentation).toBeDefined(); + expect(record.fields.length).toBe(16); + let field = record.getFieldByName("in"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(false); + expect(field?.matchesType("null")).toBe(true); + expect(field?.matchesType("WorkflowStepInput")).toBe(true); + field = record.getFieldByName("out"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(false); + expect(field?.matchesType("null")).toBe(true); + expect(field?.matchesType("string")).toBe(true); + expect(field?.matchesType("WorkflowStepOutput")).toBe(true); + expect(field?.matchesType("Any")).toBe(false); + field = record.getFieldByName("state"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.typeRef).toBe("Any"); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(true); + expect(field?.matchesType("null")).toBe(true); + expect(field?.matchesType("string")).toBe(true); + expect(field?.matchesType("anything...")).toBe(true); + field = record.getFieldByName("type"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(false); + expect(field?.default).toBe("tool"); + field = record.getFieldByName("run"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(true); + expect(field?.typeRef).toBe("GalaxyWorkflow"); + field = record.getFieldByName("runtime_inputs"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(true); + expect(field?.canBeObject).toBe(false); + expect(field?.typeRef).toBe("string"); + + expectRecordHasOptionalStringField(record, "id"); + expectRecordHasOptionalStringField(record, "label"); + expectRecordHasOptionalStringField(record, "doc", true); + + // HasStepPosition + field = record.getFieldByName("position"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(true); + expect(field?.typeRef).toBe("StepPosition"); + + // ReferencesTool + expectRecordHasOptionalStringField(record, "tool_id"); + expectRecordHasOptionalStringField(record, "tool_version"); + field = record.getFieldByName("tool_shed_repository"); + expect(field).toBeDefined(); + expect(field?.isOptional).toBe(true); + expect(field?.canBeArray).toBe(false); + expect(field?.canBeObject).toBe(true); + expect(field?.typeRef).toBe("ToolShedRepository"); + + // HasStepErrors + expectRecordHasOptionalStringField(record, "errors"); + + // HasUUID + expectRecordHasOptionalStringField(record, "uuid"); + }); }); }); }); From f3df2843c6f05ab7f2c1d00e1f8ea63c79391572 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Mon, 3 Oct 2022 23:53:45 +0200 Subject: [PATCH 42/50] Split e2e tests --- client/tests/e2e/suite/extension.e2e.ts | 74 ------------------- client/tests/e2e/suite/extension.ga.e2e.ts | 73 ++++++++++++++++++ .../e2e/suite/extension.gxformat2.e2e.ts | 45 +++++++++++ client/tests/e2e/suite/helpers.ts | 4 + .../validation/schemaValidationService.ts | 4 +- test-data/yaml/validation/test_wf_00.gxwf.yml | 5 +- 6 files changed, 126 insertions(+), 79 deletions(-) delete mode 100644 client/tests/e2e/suite/extension.e2e.ts create mode 100644 client/tests/e2e/suite/extension.ga.e2e.ts create mode 100644 client/tests/e2e/suite/extension.gxformat2.e2e.ts diff --git a/client/tests/e2e/suite/extension.e2e.ts b/client/tests/e2e/suite/extension.e2e.ts deleted file mode 100644 index ddfcd14..0000000 --- a/client/tests/e2e/suite/extension.e2e.ts +++ /dev/null @@ -1,74 +0,0 @@ -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -import * as vscode from "vscode"; -import * as path from "path"; -import * as assert from "assert"; -import { beforeEach } from "mocha"; -import { - activateAndOpenInEditor, - getDocUri, - closeAllEditors, - openDocument, - sleep, - assertDiagnostics, - updateSettings, - resetSettings, -} from "./helpers"; - -suite("Extension Test Suite", () => { - teardown(closeAllEditors); - suite("Native (JSON) Workflows", () => { - suite("Commands Tests", () => { - test("Clean workflow command removes non-essential properties", async () => { - const dirtyDocUri = getDocUri(path.join("json", "clean", "wf_01_dirty.ga")); - const cleanDocUri = getDocUri(path.join("json", "clean", "wf_01_clean.ga")); - const { document } = await activateAndOpenInEditor(dirtyDocUri); - const dirtyDoc = document.getText(); - await vscode.commands.executeCommand("galaxy-workflows.cleanWorkflow"); - await sleep(1000); // Wait for command to apply changes - const actualCleanJson = document.getText(); - assert.notEqual(dirtyDoc, actualCleanJson); - const expectedCleanDocument = await openDocument(cleanDocUri); - const expectedCleanJson = expectedCleanDocument.getText(); - assert.strictEqual(actualCleanJson, expectedCleanJson); - }); - }); - - suite("Validation Tests", () => { - beforeEach(async () => { - await resetSettings(); - }); - test("Changing validation profile shows custom diagnostics", async () => { - const docUri = getDocUri(path.join("json", "validation", "test_wf_03.ga")); - await activateAndOpenInEditor(docUri); - await sleep(1000); // Wait for diagnostics - await assertDiagnostics(docUri, []); // Expect no issues - - // Change to stricter validation profile - await updateSettings("validation.profile", "iwc"); - await sleep(2000); // Wait for diagnostics - await assertDiagnostics(docUri, [ - { - message: 'Missing property "release".', - range: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)), - severity: 0, - }, - { - message: "Missing label in workflow output.", - range: new vscode.Range(new vscode.Position(16, 16), new vscode.Position(19, 17)), - severity: 0, - }, - { - message: "Missing label in workflow output.", - range: new vscode.Range(new vscode.Position(20, 16), new vscode.Position(23, 17)), - severity: 0, - }, - ]); - - await resetSettings(); - await sleep(2000); // Wait for diagnostics - await assertDiagnostics(docUri, []); // Expect no issues - }); - }); - }); -}); diff --git a/client/tests/e2e/suite/extension.ga.e2e.ts b/client/tests/e2e/suite/extension.ga.e2e.ts new file mode 100644 index 0000000..bda2f29 --- /dev/null +++ b/client/tests/e2e/suite/extension.ga.e2e.ts @@ -0,0 +1,73 @@ +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from "vscode"; +import * as path from "path"; +import * as assert from "assert"; +import { beforeEach } from "mocha"; +import { + activateAndOpenInEditor, + getDocUri, + closeAllEditors, + openDocument, + sleep, + assertDiagnostics, + updateSettings, + resetSettings, + waitForDiagnostics, +} from "./helpers"; + +suite("Native (JSON) Workflows", () => { + teardown(closeAllEditors); + suite("Commands Tests", () => { + test("Clean workflow command removes non-essential properties", async () => { + const dirtyDocUri = getDocUri(path.join("json", "clean", "wf_01_dirty.ga")); + const cleanDocUri = getDocUri(path.join("json", "clean", "wf_01_clean.ga")); + const { document } = await activateAndOpenInEditor(dirtyDocUri); + const dirtyDoc = document.getText(); + await vscode.commands.executeCommand("galaxy-workflows.cleanWorkflow"); + await sleep(1000); // Wait for command to apply changes + const actualCleanJson = document.getText(); + assert.notEqual(dirtyDoc, actualCleanJson); + const expectedCleanDocument = await openDocument(cleanDocUri); + const expectedCleanJson = expectedCleanDocument.getText(); + assert.strictEqual(actualCleanJson, expectedCleanJson); + }); + }); + + suite("Validation Tests", () => { + beforeEach(async () => { + await resetSettings(); + }); + test("Changing validation profile shows custom diagnostics", async () => { + const docUri = getDocUri(path.join("json", "validation", "test_wf_03.ga")); + await activateAndOpenInEditor(docUri); + await waitForDiagnostics(); + await assertDiagnostics(docUri, []); // Expect no issues + + // Change to stricter validation profile + await updateSettings("validation.profile", "iwc"); + await waitForDiagnostics(); + await assertDiagnostics(docUri, [ + { + message: 'Missing property "release".', + range: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)), + severity: vscode.DiagnosticSeverity.Error, + }, + { + message: "Missing label in workflow output.", + range: new vscode.Range(new vscode.Position(16, 16), new vscode.Position(19, 17)), + severity: vscode.DiagnosticSeverity.Error, + }, + { + message: "Missing label in workflow output.", + range: new vscode.Range(new vscode.Position(20, 16), new vscode.Position(23, 17)), + severity: vscode.DiagnosticSeverity.Error, + }, + ]); + + await resetSettings(); + await waitForDiagnostics(); + await assertDiagnostics(docUri, []); // Expect no issues + }); + }); +}); diff --git a/client/tests/e2e/suite/extension.gxformat2.e2e.ts b/client/tests/e2e/suite/extension.gxformat2.e2e.ts new file mode 100644 index 0000000..949de76 --- /dev/null +++ b/client/tests/e2e/suite/extension.gxformat2.e2e.ts @@ -0,0 +1,45 @@ +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from "vscode"; +import * as path from "path"; +import * as assert from "assert"; +import { beforeEach } from "mocha"; +import { + activateAndOpenInEditor, + getDocUri, + closeAllEditors, + assertDiagnostics, + resetSettings, + waitForDiagnostics, +} from "./helpers"; + +suite("Format2 (YAML) Workflows", () => { + teardown(closeAllEditors); + suite("Validation Tests", () => { + beforeEach(async () => { + await resetSettings(); + }); + test("Missing required fields return diagnostics", async () => { + const docUri = getDocUri(path.join("yaml", "validation", "test_wf_00.gxwf.yml")); + await activateAndOpenInEditor(docUri); + await waitForDiagnostics(); + await assertDiagnostics(docUri, [ + { + message: "The 'steps' field is required.", + range: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 21)), + severity: vscode.DiagnosticSeverity.Error, + }, + { + message: "The 'inputs' field is required.", + range: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 21)), + severity: vscode.DiagnosticSeverity.Error, + }, + { + message: "The 'outputs' field is required.", + range: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 21)), + severity: vscode.DiagnosticSeverity.Error, + }, + ]); + }); + }); +}); diff --git a/client/tests/e2e/suite/helpers.ts b/client/tests/e2e/suite/helpers.ts index 319b370..825d910 100644 --- a/client/tests/e2e/suite/helpers.ts +++ b/client/tests/e2e/suite/helpers.ts @@ -49,6 +49,10 @@ export async function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } +export async function waitForDiagnostics(ms = 1000): Promise { + return sleep(ms); +} + export const getDocPath = (filePath: string): string => { return path.resolve(__dirname, path.join("..", "..", "..", "..", "test-data", filePath)); }; diff --git a/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts index ea10615..4705302 100644 --- a/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/validation/schemaValidationService.ts @@ -62,7 +62,9 @@ export class GxFormat2SchemaValidationService implements WorkflowValidator { const propertyNode = node.properties.find((prop) => prop.keyNode.value === schemaFieldNode.name); const nodeFound = propertyNode !== undefined; if (schemaFieldNode.isRequired && !nodeFound) { - diagnostics.push(Diagnostic.create(range, `${schemaFieldNode.name} is required`, DiagnosticSeverity.Error)); + diagnostics.push( + Diagnostic.create(range, `The '${schemaFieldNode.name}' field is required.`, DiagnosticSeverity.Error) + ); } if (nodeFound) { const childSchemaNode = this.schemaNodeResolver.getSchemaNodeByTypeRef(schemaFieldNode.typeRef); diff --git a/test-data/yaml/validation/test_wf_00.gxwf.yml b/test-data/yaml/validation/test_wf_00.gxwf.yml index b5e534f..3c5d77a 100644 --- a/test-data/yaml/validation/test_wf_00.gxwf.yml +++ b/test-data/yaml/validation/test_wf_00.gxwf.yml @@ -1,5 +1,2 @@ class: GalaxyWorkflow -label: Test Workflow Without Steps -inputs: {} -outputs: {} -steps: {} +label: Test workflow with missing required fields From 5eccc953900e77a733914d08366e19861d9faa78 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 4 Oct 2022 00:04:51 +0200 Subject: [PATCH 43/50] Move schema tests to integration --- .../tests/{unit => integration}/schema.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename server/gx-workflow-ls-format2/tests/{unit => integration}/schema.test.ts (100%) diff --git a/server/gx-workflow-ls-format2/tests/unit/schema.test.ts b/server/gx-workflow-ls-format2/tests/integration/schema.test.ts similarity index 100% rename from server/gx-workflow-ls-format2/tests/unit/schema.test.ts rename to server/gx-workflow-ls-format2/tests/integration/schema.test.ts From 65f7bb9ce0ea36e8003244b147f04bdd9e70c669 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 4 Oct 2022 00:05:23 +0200 Subject: [PATCH 44/50] Setup jest to detect all kinds of tests --- client/jest.config.js | 2 +- jest.config.js | 2 +- server/jest.config.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/jest.config.js b/client/jest.config.js index 070fb0c..ce536c3 100644 --- a/client/jest.config.js +++ b/client/jest.config.js @@ -12,7 +12,7 @@ module.exports = { }, }, // The glob patterns Jest uses to detect test files - testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/unit/*.test.ts"], + testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/*.test.ts"], // An array of file extensions your modules use moduleFileExtensions: ["ts", "tsx", "js"], diff --git a/jest.config.js b/jest.config.js index 7383a9b..a13e749 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,7 +13,7 @@ module.exports = { }, }, // The glob patterns Jest uses to detect test files - testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/unit/*.test.ts"], + testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/*.test.ts"], // An array of file extensions your modules use moduleFileExtensions: ["ts", "tsx", "js", "yaml"], diff --git a/server/jest.config.js b/server/jest.config.js index 7383a9b..a13e749 100644 --- a/server/jest.config.js +++ b/server/jest.config.js @@ -13,7 +13,7 @@ module.exports = { }, }, // The glob patterns Jest uses to detect test files - testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/unit/*.test.ts"], + testMatch: ["**/__tests__/*.+(ts|tsx|js)", "**/*.test.ts"], // An array of file extensions your modules use moduleFileExtensions: ["ts", "tsx", "js", "yaml"], From 544b85cdd43465b25238659be63e9daac9049088 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 4 Oct 2022 00:47:38 +0200 Subject: [PATCH 45/50] Reduce a bit e2e tests execution time --- client/tests/e2e/suite/extension.ga.e2e.ts | 7 +++---- client/tests/e2e/suite/extension.gxformat2.e2e.ts | 2 +- client/tests/e2e/suite/helpers.ts | 15 +++++++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/client/tests/e2e/suite/extension.ga.e2e.ts b/client/tests/e2e/suite/extension.ga.e2e.ts index bda2f29..9143604 100644 --- a/client/tests/e2e/suite/extension.ga.e2e.ts +++ b/client/tests/e2e/suite/extension.ga.e2e.ts @@ -25,7 +25,7 @@ suite("Native (JSON) Workflows", () => { const { document } = await activateAndOpenInEditor(dirtyDocUri); const dirtyDoc = document.getText(); await vscode.commands.executeCommand("galaxy-workflows.cleanWorkflow"); - await sleep(1000); // Wait for command to apply changes + await sleep(500); // Wait for command to apply changes const actualCleanJson = document.getText(); assert.notEqual(dirtyDoc, actualCleanJson); const expectedCleanDocument = await openDocument(cleanDocUri); @@ -41,12 +41,11 @@ suite("Native (JSON) Workflows", () => { test("Changing validation profile shows custom diagnostics", async () => { const docUri = getDocUri(path.join("json", "validation", "test_wf_03.ga")); await activateAndOpenInEditor(docUri); - await waitForDiagnostics(); await assertDiagnostics(docUri, []); // Expect no issues // Change to stricter validation profile await updateSettings("validation.profile", "iwc"); - await waitForDiagnostics(); + await waitForDiagnostics(docUri); await assertDiagnostics(docUri, [ { message: 'Missing property "release".', @@ -66,7 +65,7 @@ suite("Native (JSON) Workflows", () => { ]); await resetSettings(); - await waitForDiagnostics(); + await waitForDiagnostics(docUri); await assertDiagnostics(docUri, []); // Expect no issues }); }); diff --git a/client/tests/e2e/suite/extension.gxformat2.e2e.ts b/client/tests/e2e/suite/extension.gxformat2.e2e.ts index 949de76..09a7f08 100644 --- a/client/tests/e2e/suite/extension.gxformat2.e2e.ts +++ b/client/tests/e2e/suite/extension.gxformat2.e2e.ts @@ -22,7 +22,7 @@ suite("Format2 (YAML) Workflows", () => { test("Missing required fields return diagnostics", async () => { const docUri = getDocUri(path.join("yaml", "validation", "test_wf_00.gxwf.yml")); await activateAndOpenInEditor(docUri); - await waitForDiagnostics(); + await waitForDiagnostics(docUri); await assertDiagnostics(docUri, [ { message: "The 'steps' field is required.", diff --git a/client/tests/e2e/suite/helpers.ts b/client/tests/e2e/suite/helpers.ts index 825d910..39d742a 100644 --- a/client/tests/e2e/suite/helpers.ts +++ b/client/tests/e2e/suite/helpers.ts @@ -41,7 +41,6 @@ export async function openDocument(docUri: vscode.Uri): Promise { await activate(); const documentEditor = await openDocumentInEditor(docUri); - await sleep(2000); // Wait for server activation return documentEditor; } @@ -49,8 +48,15 @@ export async function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } -export async function waitForDiagnostics(ms = 1000): Promise { - return sleep(ms); +export async function waitForDiagnostics(docUri: vscode.Uri, timeoutInMilliseconds = 2000): Promise { + const waitMilliseconds = 100; + let waitTimeout = timeoutInMilliseconds; + let diagnostics = vscode.languages.getDiagnostics(docUri); + while (waitTimeout > 0 && !diagnostics.length) { + await sleep(waitMilliseconds); + waitTimeout -= waitMilliseconds; + diagnostics = vscode.languages.getDiagnostics(docUri); + } } export const getDocPath = (filePath: string): string => { @@ -96,5 +102,6 @@ export async function updateSettings(setting: string, value: unknown): Promise { const configuration = vscode.workspace.getConfiguration("galaxyWorkflows"); await configuration.update("cleaning.cleanableProperties", undefined, true); - return configuration.update("validation.profile", undefined, true); + await configuration.update("validation.profile", undefined, true); + return sleep(500); // Wait for settings to be applied } From 1397b7b0d8864038263794d2513c48b17cc7bb58 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:14:14 +0200 Subject: [PATCH 46/50] Fix getNodeFromOffset in some contexts This makes finding the context node at cursor a bit more accurate. --- .../packages/yaml-language-service/src/parser/yamlDocument.ts | 3 +++ .../yaml-language-service/tests/unit/yamlParser.test.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/packages/yaml-language-service/src/parser/yamlDocument.ts b/server/packages/yaml-language-service/src/parser/yamlDocument.ts index 591d6be..d587309 100644 --- a/server/packages/yaml-language-service/src/parser/yamlDocument.ts +++ b/server/packages/yaml-language-service/src/parser/yamlDocument.ts @@ -70,6 +70,9 @@ export class YAMLDocument implements ParsedDocument { const position = this._textBuffer.getPosition(offset); if (position.character === 0 && !this._textBuffer.hasTextAfterPosition(position)) return rootNode; const indentation = this._textBuffer.getLineIndentationAtOffset(offset); + const lineContent = this._textBuffer.getLineContent(position.line); + const contentAfterCursor = lineContent.slice(position.character).replace(/\s/g, ""); + if (indentation === 0 && contentAfterCursor.length === 0) return rootNode; let result = rootNode.getNodeFromOffsetEndInclusive(offset); const parent = this.findParentNodeByIndentation(offset, indentation); if (!result || (parent && result.offset < parent.offset && result.length > parent.length)) { diff --git a/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts b/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts index ae7f800..87d2776 100644 --- a/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts +++ b/server/packages/yaml-language-service/tests/unit/yamlParser.test.ts @@ -182,9 +182,9 @@ test02: it.each([ [0, "_root_"], // _root_ is not a property, is an object [1, "test"], - [12, "test"], + [12, "_root_"], [13, "test02"], - [20, "test02"], + [20, "_root_"], [22, "test02"], [23, "prop03"], [30, "prop03"], From c6c0dc58937cb304c28da2828972708209b3c240 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:16:25 +0200 Subject: [PATCH 47/50] Enhance auto-completion By filtering the available fields to auto-complete by the current word at the cursor. --- .../src/services/completionService.ts | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/services/completionService.ts b/server/gx-workflow-ls-format2/src/services/completionService.ts index 9567a37..bee39b7 100644 --- a/server/gx-workflow-ls-format2/src/services/completionService.ts +++ b/server/gx-workflow-ls-format2/src/services/completionService.ts @@ -22,7 +22,7 @@ export class GxFormat2CompletionService { items: [], isIncomplete: false, }; - + // TODO: Refactor most of this to an Context class with all the information around the cursor const textBuffer = new TextBuffer(textDocument); const text = textBuffer.getText(); const offset = textBuffer.getOffsetAt(position); @@ -34,35 +34,39 @@ export class GxFormat2CompletionService { return Promise.resolve(result); } + const currentWord = textBuffer.getCurrentWord(offset); + DEBUG_printNodeName(node); const existing = nodeManager.getDeclaredPropertyNames(node); if (nodeManager.isRoot(node)) { - result.items = this.getProposedItems(this.schemaNodeResolver.rootNode, existing); + result.items = this.getProposedItems(this.schemaNodeResolver.rootNode, currentWord, existing); return Promise.resolve(result); } const nodePath = nodeManager.getPathFromNode(node); const schemaNode = this.schemaNodeResolver.resolveSchemaContext(nodePath); if (schemaNode) { - result.items = this.getProposedItems(schemaNode, existing); + result.items = this.getProposedItems(schemaNode, currentWord, existing); } return Promise.resolve(result); } - private getProposedItems(schemaNode: SchemaNode, exclude: Set): CompletionItem[] { + private getProposedItems(schemaNode: SchemaNode, currentWord: string, exclude: Set): CompletionItem[] { const result: CompletionItem[] = []; if (schemaNode instanceof RecordSchemaNode) { - schemaNode.fields.forEach((field) => { - if (exclude.has(field.name)) return; - const item: CompletionItem = { - label: field.name, - documentation: field.documentation, - sortText: `_${field.name}`, - kind: CompletionItemKind.Field, - insertText: `${field.name}: `, - }; - result.push(item); - }); + schemaNode.fields + .filter((f) => f.name.startsWith(currentWord)) + .forEach((field) => { + if (exclude.has(field.name)) return; + const item: CompletionItem = { + label: field.name, + documentation: field.documentation, + sortText: `_${field.name}`, + kind: CompletionItemKind.Field, + insertText: `${field.name}: `, + }; + result.push(item); + }); } return result; } From ab87e963c1019716a3138edf35528eaee21ae083 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:34:42 +0200 Subject: [PATCH 48/50] Slightly increase activation wait time in e2e tests Windows machine it's a little bit slower apparently. TODO: replace sleep with an active check for activation or timeout --- client/tests/e2e/suite/extension.ga.e2e.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/client/tests/e2e/suite/extension.ga.e2e.ts b/client/tests/e2e/suite/extension.ga.e2e.ts index 9143604..8cab3cd 100644 --- a/client/tests/e2e/suite/extension.ga.e2e.ts +++ b/client/tests/e2e/suite/extension.ga.e2e.ts @@ -23,6 +23,7 @@ suite("Native (JSON) Workflows", () => { const dirtyDocUri = getDocUri(path.join("json", "clean", "wf_01_dirty.ga")); const cleanDocUri = getDocUri(path.join("json", "clean", "wf_01_clean.ga")); const { document } = await activateAndOpenInEditor(dirtyDocUri); + await sleep(500); // Wait for extension to fully activate... yes Windows CI I'm looking at you... const dirtyDoc = document.getText(); await vscode.commands.executeCommand("galaxy-workflows.cleanWorkflow"); await sleep(500); // Wait for command to apply changes From 0d49a9a0e887db38fdf79832aeffaa1b62e2d96f Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:39:43 +0200 Subject: [PATCH 49/50] Add getAllPropertyNodesByName to NodeManager --- .../server-common/src/ast/nodeManager.ts | 59 +++++++++++++++---- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/server/packages/server-common/src/ast/nodeManager.ts b/server/packages/server-common/src/ast/nodeManager.ts index 545e970..2837796 100644 --- a/server/packages/server-common/src/ast/nodeManager.ts +++ b/server/packages/server-common/src/ast/nodeManager.ts @@ -1,5 +1,5 @@ import { Position, Range, TextDocument } from "../languageTypes"; -import { ParsedDocument, ASTNode, ObjectASTNode, NodePath, Segment } from "./types"; +import { ParsedDocument, ASTNode, ObjectASTNode, NodePath, Segment, PropertyASTNode } from "./types"; import { getPropertyNodeFromPath } from "./utils"; export class ASTNodeManager { @@ -92,6 +92,20 @@ export class ASTNodeManager { return getPropertyNodeFromPath(root, path); } + public getAllPropertyNodesByName(name: string): PropertyASTNode[] { + const result: PropertyASTNode[] = []; + const root = this.root; + if (!root) return result; + + this.visit((node) => { + if (node.type === "property" && node.keyNode.value === name && node.valueNode?.type === "object") { + result.push(node); + } + return true; + }); + return result; + } + public getPathFromNode(node: ASTNode): NodePath { const path: NodePath = []; let current: ASTNode | undefined = node; @@ -118,21 +132,30 @@ export class ASTNodeManager { } } - public getStepNodes(): ObjectASTNode[] { + public getStepNodes(includeSubworkflows = false): ObjectASTNode[] { const root = this.root; if (!root) { return []; } const result: ObjectASTNode[] = []; - const stepsNode = this.getNodeFromPath("steps"); - if (stepsNode && stepsNode.type === "property" && stepsNode.valueNode && stepsNode.valueNode.type === "object") { - stepsNode.valueNode.properties.forEach((stepProperty) => { - const stepNode = stepProperty.valueNode; - if (stepNode && stepNode.type === "object") { - result.push(stepNode); - } - }); + let stepsPropertyNodes: PropertyASTNode[] = []; + if (includeSubworkflows) { + stepsPropertyNodes = this.getAllPropertyNodesByName("steps"); + } else { + const mainStepsProperty = this.getNodeFromPath("steps") as PropertyASTNode; + stepsPropertyNodes = mainStepsProperty ? [mainStepsProperty] : []; } + for (const stepsNode of stepsPropertyNodes) { + if (stepsNode && stepsNode.valueNode && stepsNode.valueNode.type === "object") { + stepsNode.valueNode.properties.forEach((stepProperty) => { + const stepNode = stepProperty.valueNode; + if (stepNode && stepNode.type === "object") { + result.push(stepNode); + } + }); + } + } + return result; } @@ -140,4 +163,20 @@ export class ASTNodeManager { const offset = this.textDocument.offsetAt(position); return Range.create(this.textDocument.positionAt(offset), this.textDocument.positionAt(offset + 1)); } + + public visit(visitor: (node: ASTNode) => boolean): void { + if (this.root) { + const doVisit = (node: ASTNode): boolean => { + let ctn = visitor(node); + const children = node.children; + if (Array.isArray(children)) { + for (let i = 0; i < children.length && ctn; i++) { + ctn = doVisit(children[i]); + } + } + return ctn; + }; + doVisit(this.root); + } + } } From 4829c805c36619832fe68ae5dc2391051812c6c1 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:40:18 +0200 Subject: [PATCH 50/50] Validate subworkflows steps too --- .../src/services/validation/workflowValidationService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts b/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts index 86c7aab..9e1f0e9 100644 --- a/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts +++ b/server/gx-workflow-ls-format2/src/services/validation/workflowValidationService.ts @@ -17,7 +17,7 @@ export class WorkflowValidationService implements WorkflowValidator { export function collectStepErrorDiagnostics(workflowDocument: WorkflowDocument): Diagnostic[] { const diagnostics: Diagnostic[] = []; - const steps = workflowDocument.nodeManager.getStepNodes(); + const steps = workflowDocument.nodeManager.getStepNodes(true); steps.forEach((step) => { const errors = step.properties.find((p) => p.keyNode.value === "errors"); if (errors) { @@ -36,7 +36,7 @@ export function collectStepErrorDiagnostics(workflowDocument: WorkflowDocument): export function collectToolDiagnostics(workflowDocument: WorkflowDocument): Diagnostic[] { const diagnostics: Diagnostic[] = []; - const steps = workflowDocument.nodeManager.getStepNodes(); + const steps = workflowDocument.nodeManager.getStepNodes(true); steps.forEach((step) => { const tool_id = step.properties.find((p) => p.keyNode.value === "tool_id"); if (tool_id) {