From 549c9508fd182984a826d8be855e23a797e8f50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Mon, 23 May 2022 18:42:58 +0200 Subject: [PATCH 01/11] feat(core): improve alias validation --- .../src/ruleset/__tests__/ruleset.test.ts | 8 +- packages/core/src/ruleset/alias.ts | 102 +++++++++++++++ .../core/src/ruleset/meta/rule.schema.json | 123 +++++++++--------- packages/core/src/ruleset/meta/shared.json | 23 +++- packages/core/src/ruleset/rule.ts | 86 +----------- packages/core/src/ruleset/utils/guards.ts | 25 +++- .../validation/__tests__/validation.test.ts | 24 +++- packages/core/src/ruleset/validation/ajv.ts | 90 +++++++++++-- .../core/src/ruleset/validation/assertions.ts | 4 +- .../core/src/ruleset/validation/errors.ts | 4 +- 10 files changed, 321 insertions(+), 168 deletions(-) create mode 100644 packages/core/src/ruleset/alias.ts diff --git a/packages/core/src/ruleset/__tests__/ruleset.test.ts b/packages/core/src/ruleset/__tests__/ruleset.test.ts index 2fdc3fccd..55792031f 100644 --- a/packages/core/src/ruleset/__tests__/ruleset.test.ts +++ b/packages/core/src/ruleset/__tests__/ruleset.test.ts @@ -1266,7 +1266,7 @@ describe('Ruleset', () => { }, }, }), - ).toThrowError(ReferenceError('Alias "PathItem-" does not exist')); + ).toThrowError('Error at #/rules/valid-path/given: Alias "PathItem-" does not exist'); }); it('given circular alias, should throw', () => { @@ -1289,7 +1289,7 @@ describe('Ruleset', () => { }, }), ).toThrowError( - ReferenceError('Alias "Test" is circular. Resolution stack: Test -> Contact -> Info -> Root -> Info'), + 'Error at #/rules/valid-path/given: Alias "Test" is circular. Resolution stack: Test -> Contact -> Info -> Root -> Info', ); }); @@ -1321,7 +1321,9 @@ describe('Ruleset', () => { }, }, }), - ).toThrowError(ReferenceError('Alias "PathItem" does not exist')); + ).toThrowError(`Error at #/rules/valid-path/given: Alias "PathItem" does not exist +Error at #/rules/valid-name-and-description/given/0: Alias "Name" does not exist +Error at #/rules/valid-name-and-description/given/1: Alias "Description" does not exist`); }); describe('scoped aliases', () => { diff --git a/packages/core/src/ruleset/alias.ts b/packages/core/src/ruleset/alias.ts new file mode 100644 index 000000000..81ef8e232 --- /dev/null +++ b/packages/core/src/ruleset/alias.ts @@ -0,0 +1,102 @@ +import { isScopedAliasDefinition, isSimpleAliasDefinition } from './utils/guards'; +import type { RulesetScopedAliasDefinition } from './types'; + +const ALIAS = /^#([A-Za-z0-9_-]+)/; + +const CACHE = new (class { + // maybe try to cache array-ish given? + #store = new WeakMap, Map>(); + + add(ruleset: Record, expression: string, resolvedExpressions: string[]): void { + let existing = this.#store.get(ruleset); + if (!existing) { + existing = new Map(); + this.#store.set(ruleset, existing); + } + + existing.set(expression, resolvedExpressions); + } +})(); + +export function resolveAliasForFormats( + { targets }: RulesetScopedAliasDefinition, + formats: Set | null, +): string[] | null { + if (formats === null || formats.size === 0) { + return null; + } + + // we start from the end to be consistent with overrides etc. - we generally tend to pick the "last" value. + for (let i = targets.length - 1; i >= 0; i--) { + const target = targets[i]; + for (const format of target.formats) { + if (formats.has(format)) { + return target.given; + } + } + } + + return null; +} + +export function resolveAlias( + aliases: Record | null, + expression: string, + formats: Set | null, +): string[] { + return _resolveAlias(aliases, expression, formats, new Set()); +} + +function _resolveAlias( + aliases: Record | null, + expression: string, + formats: Set | null, + stack: Set, +): string[] { + const resolvedExpressions: string[] = []; + + if (expression.startsWith('#')) { + const alias = ALIAS.exec(expression)?.[1]; + + if (alias === void 0 || alias === null) { + throw new ReferenceError(`Alias must match /^#([A-Za-z0-9_-]+)/`); + } + + if (stack.has(alias)) { + const _stack = [...stack, alias]; + throw new ReferenceError(`Alias "${_stack[0]}" is circular. Resolution stack: ${_stack.join(' -> ')}`); + } + + stack.add(alias); + + if (aliases === null || !(alias in aliases)) { + throw new ReferenceError(`Alias "${alias}" does not exist`); + } + + const aliasValue = aliases[alias]; + let actualAliasValue: string[] | null; + if (isSimpleAliasDefinition(aliasValue)) { + actualAliasValue = aliasValue; + } else if (isScopedAliasDefinition(aliasValue)) { + actualAliasValue = resolveAliasForFormats(aliasValue, formats); + } else { + actualAliasValue = null; + } + + if (actualAliasValue !== null) { + resolvedExpressions.push( + ...actualAliasValue.flatMap(item => + _resolveAlias(aliases, item + expression.slice(alias.length + 1), formats, new Set([...stack])), + ), + ); + } + } else { + resolvedExpressions.push(expression); + } + + if (aliases !== null) { + CACHE.add(aliases, expression, resolvedExpressions); + } + + return resolvedExpressions; +} diff --git a/packages/core/src/ruleset/meta/rule.schema.json b/packages/core/src/ruleset/meta/rule.schema.json index 4372cacff..7973663ec 100644 --- a/packages/core/src/ruleset/meta/rule.schema.json +++ b/packages/core/src/ruleset/meta/rule.schema.json @@ -21,72 +21,77 @@ "$ref": "shared#severity" } }, - "oneOf": [ - { - "properties": { - "description": { - "type": "string" - }, - "documentationUrl": { - "type": "string", - "format": "url", - "errorMessage": "must be a valid URL" - }, - "recommended": { - "type": "boolean" - }, - "given": { - "$ref": "shared#given" - }, - "resolved": { - "type": "boolean" - }, - "severity": { - "$ref": "#/$defs/Severity" - }, - "message": { + "if": { + "type": "object" + }, + "then": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "documentationUrl": { + "type": "string", + "format": "url", + "errorMessage": "must be a valid URL" + }, + "recommended": { + "type": "boolean" + }, + "given": { + "$ref": "shared#given" + }, + "resolved": { + "type": "boolean" + }, + "severity": { + "$ref": "#/$defs/Severity" + }, + "message": { + "type": "string" + }, + "tags": { + "items": { "type": "string" }, - "tags": { - "items": { - "type": "string" + "type": "array" + }, + "formats": { + "$ref": "shared#formats" + }, + "then": { + "anyOf": [ + { + "$ref": "#/$defs/Then" }, - "type": "array" - }, - "formats": { - "$ref": "shared#formats" - }, - "then": { - "anyOf": [ - { + { + "items": { "$ref": "#/$defs/Then" }, - { - "items": { - "$ref": "#/$defs/Then" - }, - "type": "array" - } - ] - }, - "type": { - "enum": ["style", "validation"], - "type": "string", - "errorMessage": "allowed types are \"style\" and \"validation\"" - } + "type": "array" + } + ] }, - "required": ["given", "then"], - "type": "object", - "additionalProperties": false, - "errorMessage": { - "required": "the rule must have at least \"given\" and \"then\" properties" + "type": { + "enum": ["style", "validation"], + "type": "string", + "errorMessage": "allowed types are \"style\" and \"validation\"" } }, - { - "$ref": "shared#/$defs/HumanReadableSeverity" - }, - { - "type": "boolean" + "required": ["given", "then"], + "additionalProperties": false, + "errorMessage": { + "required": "the rule must have at least \"given\" and \"then\" properties" } - ] + }, + "else": { + "oneOf": [ + { + "$ref": "shared#/$defs/HumanReadableSeverity" + }, + { + "type": "boolean" + } + ] + } } diff --git a/packages/core/src/ruleset/meta/shared.json b/packages/core/src/ruleset/meta/shared.json index e46e507cf..1a013f69f 100644 --- a/packages/core/src/ruleset/meta/shared.json +++ b/packages/core/src/ruleset/meta/shared.json @@ -50,9 +50,26 @@ }, "PathExpression": { "$id": "path-expression", - "type": "string", - "pattern": "^[$#]", - "errorMessage": "must be a valid JSON Path expression or a reference to the existing Alias optionally paired with a JSON Path expression subset" + "if": { + "type": "string" + }, + "then": { + "type": "string", + "if": { + "pattern": "^#" + }, + "then": { + "spectral-runtime": "alias" + }, + "else": { + "pattern": "^\\$", + "errorMessage": "must be a valid JSON Path expression or a reference to the existing Alias optionally paired with a JSON Path expression subset" + } + }, + "else": { + "not": {}, + "errorMessage": "must be a valid JSON Path expression or a reference to the existing Alias optionally paired with a JSON Path expression subset" + } } } } diff --git a/packages/core/src/ruleset/rule.ts b/packages/core/src/ruleset/rule.ts index d7a73608a..3cc581337 100644 --- a/packages/core/src/ruleset/rule.ts +++ b/packages/core/src/ruleset/rule.ts @@ -7,19 +7,10 @@ import { printValue } from '@stoplight/spectral-runtime'; import { DEFAULT_SEVERITY_LEVEL, getDiagnosticSeverity } from './utils/severity'; import { Ruleset } from './ruleset'; import { Format } from './format'; -import type { - HumanReadableDiagnosticSeverity, - IRuleThen, - RuleDefinition, - RulesetAliasesDefinition, - RulesetScopedAliasDefinition, - Stringifable, -} from './types'; +import type { HumanReadableDiagnosticSeverity, IRuleThen, RuleDefinition, Stringifable } from './types'; import { minimatch } from './utils/minimatch'; import { Formats } from './formats'; -import { isSimpleAliasDefinition } from './utils/guards'; - -const ALIAS = /^#([A-Za-z0-9_-]+)/; +import { resolveAlias } from './alias'; export interface IRule { description: string | null; @@ -142,84 +133,15 @@ export class Rule implements IRule { const actualGiven = Array.isArray(given) ? given : [given]; this.#given = this.owner.hasComplexAliases ? actualGiven - : actualGiven.flatMap(expr => Rule.#resolveAlias(this.owner.aliases, expr, null, new Set())).filter(isString); + : actualGiven.flatMap(expr => resolveAlias(this.owner.aliases, expr, null)).filter(isString); } public getGivenForFormats(formats: Set | null): string[] { return this.owner.hasComplexAliases - ? this.#given.flatMap(expr => Rule.#resolveAlias(this.owner.aliases, expr, formats, new Set())) + ? this.#given.flatMap(expr => resolveAlias(this.owner.aliases, expr, formats)) : this.#given; } - static #resolveAlias( - aliases: RulesetAliasesDefinition | null, - expr: string, - formats: Set | null, - stack: Set, - ): string[] { - const resolvedExpressions: string[] = []; - - if (expr.startsWith('#')) { - const alias = ALIAS.exec(expr)?.[1]; - - if (alias === void 0 || alias === null) { - throw new ReferenceError(`"${this.name}" rule references an invalid alias`); - } - - if (stack.has(alias)) { - const _stack = [...stack, alias]; - throw new ReferenceError(`Alias "${_stack[0]}" is circular. Resolution stack: ${_stack.join(' -> ')}`); - } - - stack.add(alias); - - if (aliases === null || !(alias in aliases)) { - throw new ReferenceError(`Alias "${alias}" does not exist`); - } - - const aliasValue = aliases[alias]; - let actualAliasValue: string[] | null; - if (isSimpleAliasDefinition(aliasValue)) { - actualAliasValue = aliasValue; - } else { - actualAliasValue = Rule.#resolveAliasForFormats(aliasValue, formats); - } - - if (actualAliasValue !== null) { - resolvedExpressions.push( - ...actualAliasValue.flatMap(item => - Rule.#resolveAlias(aliases, item + expr.slice(alias.length + 1), formats, new Set([...stack])), - ), - ); - } - } else { - resolvedExpressions.push(expr); - } - - return resolvedExpressions; - } - - static #resolveAliasForFormats( - { targets }: RulesetScopedAliasDefinition, - formats: Set | null, - ): string[] | null { - if (formats === null || formats.size === 0) { - return null; - } - - // we start from the end to be consistent with overrides etc. - we generally tend to pick the "last" value. - for (let i = targets.length - 1; i >= 0; i--) { - const target = targets[i]; - for (const format of target.formats) { - if (formats.has(format)) { - return target.given; - } - } - } - - return null; - } - public matchesFormat(formats: Set | null): boolean { if (this.formats === null) { return true; diff --git a/packages/core/src/ruleset/utils/guards.ts b/packages/core/src/ruleset/utils/guards.ts index 8bc05279f..45646adf2 100644 --- a/packages/core/src/ruleset/utils/guards.ts +++ b/packages/core/src/ruleset/utils/guards.ts @@ -1,7 +1,22 @@ -import { RulesetScopedAliasDefinition } from '../types'; +import { isPlainObject } from '@stoplight/json'; +import { isString } from 'lodash'; +import type { RulesetScopedAliasDefinition } from '../types'; -export function isSimpleAliasDefinition( - alias: string | string[] | RulesetScopedAliasDefinition, -): alias is string | string[] { - return typeof alias === 'string' || Array.isArray(alias); +export function isSimpleAliasDefinition(alias: unknown): alias is string[] { + return Array.isArray(alias); +} + +export function isValidAliasTarget( + target: Record, +): target is RulesetScopedAliasDefinition['targets'][number] { + const formats = target.formats; + if (!Array.isArray(formats) && !(formats instanceof Set)) { + return false; + } + + return Array.isArray(target.given) && target.given.every(isString); +} + +export function isScopedAliasDefinition(alias: unknown): alias is RulesetScopedAliasDefinition { + return isPlainObject(alias) && Array.isArray(alias.targets) && alias.targets.every(isValidAliasTarget); } diff --git a/packages/core/src/ruleset/validation/__tests__/validation.test.ts b/packages/core/src/ruleset/validation/__tests__/validation.test.ts index 81e7715c5..b699f2526 100644 --- a/packages/core/src/ruleset/validation/__tests__/validation.test.ts +++ b/packages/core/src/ruleset/validation/__tests__/validation.test.ts @@ -338,11 +338,12 @@ Error at #/rules/rule/formats/1: must be a valid format`, }, ); - it.each(['#Info', '#i', '#Info.contact', '#Info[*]'])('recognizes %s as a valid value of an alias', value => { + it.each(['#Info', '#Info.contact', '#Info[*]'])('recognizes %s as a valid value of an alias', value => { expect( assertValidRuleset.bind(null, { rules: {}, aliases: { + Info: ['$'], alias: [value], }, }), @@ -450,11 +451,26 @@ Error at #/rules/rule/formats/1: must be a valid format`, }, ); - it.each(['#Info', '#i', '#Info.contact', '#Info[*]'])('recognizes %s as a valid value of an alias', value => { + it.each(['#Info', '#Info.contact', '#Info[*]'])('recognizes %s as a valid value of an alias', value => { expect( assertValidRuleset.bind(null, { - rules: {}, + rules: { + a: { + given: '#alias', + then: { + function: truthy, + }, + }, + }, aliases: { + Info: { + targets: [ + { + formats: [formatA], + given: ['$'], + }, + ], + }, alias: { targets: [ { @@ -551,7 +567,7 @@ Error at #/aliases/SchemaObject/targets/1/formats/1: must be a valid format`, targets: [ { formats: [formatA], - given: ['#.definitions[*]'], + given: ['$.definitions[*]'], }, { formats: [formatA, formatB], diff --git a/packages/core/src/ruleset/validation/ajv.ts b/packages/core/src/ruleset/validation/ajv.ts index 88fecdadc..22d412d10 100644 --- a/packages/core/src/ruleset/validation/ajv.ts +++ b/packages/core/src/ruleset/validation/ajv.ts @@ -1,13 +1,17 @@ +import { isPlainObject } from '@stoplight/json'; import Ajv, { _, ValidateFunction } from 'ajv'; +import names from 'ajv/dist/compile/names'; import addFormats from 'ajv-formats'; import addErrors from 'ajv-errors'; +import { isError, get } from 'lodash'; import * as ruleSchema from '../meta/rule.schema.json'; import * as shared from '../meta/shared.json'; import * as rulesetSchema from '../meta/ruleset.schema.json'; import * as jsExtensions from '../meta/js-extensions.json'; import * as jsonExtensions from '../meta/json-extensions.json'; - -const message = _`'spectral-message'`; +import { resolveAlias } from '../alias'; +import type { RulesetFunction, RulesetFunctionWithValidator } from '../../types'; +import { Formats } from '../formats'; const validators: { [key in 'js' | 'json']: null | ValidateFunction } = { js: null, @@ -26,6 +30,7 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { strictRequired: false, keywords: ['$anchor'], schemas: [ruleSchema, shared], + passContext: true, }); addFormats(ajv); addErrors(ajv); @@ -33,8 +38,8 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { keyword: 'spectral-runtime', schemaType: 'string', error: { - message(ctx) { - return _`${ctx.data}[Symbol.for(${message})]`; + message(cxt) { + return _`${cxt.params?.message ? cxt.params.message : ''}`; }, }, code(cxt) { @@ -44,12 +49,29 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { case 'format': cxt.fail(_`typeof ${data} !== "function"`); break; - case 'ruleset-function': - cxt.pass(_`typeof ${data}.function === "function"`); - cxt.pass( - _`(() => { try { ${data}.function.validator && ${data}.function.validator('functionOptions' in ${data} ? ${data} : null); } catch (e) { ${data}[${message}] = e.message } })()`, + case 'ruleset-function': { + cxt.gen.if(_`typeof ${data}.function !== "function"`); + cxt.error(false, { message: 'function is not defined' }); + cxt.gen.endIf(); + const fn = cxt.gen.const( + 'spectralFunction', + _`this.validateFunction(${data}.function, ${data}.functionOptions)`, + ); + cxt.gen.if(_`${fn} !== void 0`); + cxt.error(false, { message: fn }); + cxt.gen.endIf(); + break; + } + case 'alias': { + const alias = cxt.gen.const( + 'spectralAlias', + _`this.validateAlias(${names.rootData}, ${data}, ${names.instancePath})`, ); + cxt.gen.if(_`${alias} !== void 0`); + cxt.error(false, { message: alias }); + cxt.gen.endIf(); break; + } } }, }); @@ -61,6 +83,56 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { } const validator = ajv.compile(rulesetSchema); - validators[format] = validator; + validators[format] = new Proxy(validator, { + apply(target, thisArg, args: unknown[]): unknown { + return Reflect.apply(target, { validateAlias, validateFunction }, args); + }, + }); return validator; } + +function getOverrides(overrides: unknown, key: string): Record | null { + if (!Array.isArray(overrides)) return null; + + const index = Number(key); + if (Number.isNaN(index)) return null; + if (index < 0 && index >= overrides.length) return null; + + const actualOverrides: unknown = overrides[index]; + // @ts-ignore + return isPlainObject(actualOverrides) ? actualOverrides.aliases : null; +} + +export function validateAlias( + ruleset: { aliases?: Record; overrides?: Record }, + alias: string, + path: string, +): string | void { + try { + const parsedPath = path.slice(1).split('/'); + const formats: unknown = get(ruleset, [...parsedPath.slice(0, parsedPath.indexOf('rules') + 2), 'formats']); + + const aliases = + parsedPath[0] === 'overrides' + ? { + ...ruleset.aliases, + ...getOverrides(ruleset.overrides, parsedPath[1]), + } + : ruleset.aliases; + + resolveAlias(aliases ?? null, alias, Array.isArray(formats) ? new Formats(formats) : null); + } catch (ex) { + return isError(ex) ? ex.message : 'invalid alias'; + } +} + +export function validateFunction(fn: RulesetFunction | RulesetFunctionWithValidator, opts: unknown): string | void { + if (!('validator' in fn)) return; + + try { + const validator: RulesetFunctionWithValidator['validator'] = fn.validator.bind(fn); + validator(opts); + } catch (ex) { + return isError(ex) ? ex.message : 'invalid options'; + } +} diff --git a/packages/core/src/ruleset/validation/assertions.ts b/packages/core/src/ruleset/validation/assertions.ts index f8702feb9..42a5e2548 100644 --- a/packages/core/src/ruleset/validation/assertions.ts +++ b/packages/core/src/ruleset/validation/assertions.ts @@ -1,5 +1,5 @@ import { isPlainObject } from '@stoplight/json'; -import { createValidator } from './ajv'; +import { createValidator, validateAlias, validateFunction } from './ajv'; import { RulesetAjvValidationError, RulesetValidationError } from './errors'; import type { FileRuleDefinition, RuleDefinition, RulesetDefinition } from '../types'; @@ -17,7 +17,7 @@ export function assertValidRuleset( const validate = createValidator(format); - if (!validate(ruleset)) { + if (!validate.call({ validateAlias, validateFunction }, ruleset)) { throw new RulesetAjvValidationError(ruleset, validate.errors ?? []); } } diff --git a/packages/core/src/ruleset/validation/errors.ts b/packages/core/src/ruleset/validation/errors.ts index 3f3d120ef..32c7ed7fd 100644 --- a/packages/core/src/ruleset/validation/errors.ts +++ b/packages/core/src/ruleset/validation/errors.ts @@ -27,7 +27,9 @@ export class RulesetAjvValidationError extends RulesetValidationError { l: for (let i = 0; i < sortedErrors.length; i++) { const error = sortedErrors[i]; - const prevError = i === 0 ? null : sortedErrors[i - 1]; + const prevError = filteredErrors.length === 0 ? null : filteredErrors[filteredErrors.length - 1]; + + if (error.keyword === 'if') continue; if (GENERIC_INSTANCE_PATH.test(error.instancePath)) { let x = 1; From cebca90b4383298cf3226b4493ebba282492b813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Fri, 27 May 2022 19:19:11 +0200 Subject: [PATCH 02/11] chore(core): ignore overrides for now --- packages/core/src/ruleset/validation/ajv.ts | 27 +++---------------- .../core/src/ruleset/validation/assertions.ts | 4 +-- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/packages/core/src/ruleset/validation/ajv.ts b/packages/core/src/ruleset/validation/ajv.ts index 22d412d10..e8d4fae5c 100644 --- a/packages/core/src/ruleset/validation/ajv.ts +++ b/packages/core/src/ruleset/validation/ajv.ts @@ -1,4 +1,3 @@ -import { isPlainObject } from '@stoplight/json'; import Ajv, { _, ValidateFunction } from 'ajv'; import names from 'ajv/dist/compile/names'; import addFormats from 'ajv-formats'; @@ -91,18 +90,6 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { return validator; } -function getOverrides(overrides: unknown, key: string): Record | null { - if (!Array.isArray(overrides)) return null; - - const index = Number(key); - if (Number.isNaN(index)) return null; - if (index < 0 && index >= overrides.length) return null; - - const actualOverrides: unknown = overrides[index]; - // @ts-ignore - return isPlainObject(actualOverrides) ? actualOverrides.aliases : null; -} - export function validateAlias( ruleset: { aliases?: Record; overrides?: Record }, alias: string, @@ -110,17 +97,11 @@ export function validateAlias( ): string | void { try { const parsedPath = path.slice(1).split('/'); - const formats: unknown = get(ruleset, [...parsedPath.slice(0, parsedPath.indexOf('rules') + 2), 'formats']); - - const aliases = - parsedPath[0] === 'overrides' - ? { - ...ruleset.aliases, - ...getOverrides(ruleset.overrides, parsedPath[1]), - } - : ruleset.aliases; + // skip overrides for now + if (parsedPath[0] === 'overrides') return; - resolveAlias(aliases ?? null, alias, Array.isArray(formats) ? new Formats(formats) : null); + const formats: unknown = get(ruleset, [...parsedPath.slice(0, parsedPath.indexOf('rules') + 2), 'formats']); + resolveAlias(ruleset.aliases ?? null, alias, Array.isArray(formats) ? new Formats(formats) : null); } catch (ex) { return isError(ex) ? ex.message : 'invalid alias'; } diff --git a/packages/core/src/ruleset/validation/assertions.ts b/packages/core/src/ruleset/validation/assertions.ts index 42a5e2548..f8702feb9 100644 --- a/packages/core/src/ruleset/validation/assertions.ts +++ b/packages/core/src/ruleset/validation/assertions.ts @@ -1,5 +1,5 @@ import { isPlainObject } from '@stoplight/json'; -import { createValidator, validateAlias, validateFunction } from './ajv'; +import { createValidator } from './ajv'; import { RulesetAjvValidationError, RulesetValidationError } from './errors'; import type { FileRuleDefinition, RuleDefinition, RulesetDefinition } from '../types'; @@ -17,7 +17,7 @@ export function assertValidRuleset( const validate = createValidator(format); - if (!validate.call({ validateAlias, validateFunction }, ruleset)) { + if (!validate(ruleset)) { throw new RulesetAjvValidationError(ruleset, validate.errors ?? []); } } From e086d74cf07ab313f3f03f360543b6b21a5c0668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Mon, 30 May 2022 13:19:22 +0200 Subject: [PATCH 03/11] feat(core): validate aliases in overrides --- docs/guides/4-custom-rulesets.md | 44 ++++++++++++++++++- docs/reference/error-handling.md | 1 + .../__fixtures__/overrides/aliases/scope.ts | 3 ++ packages/core/src/ruleset/validation/ajv.ts | 39 +++------------- .../ruleset/validation/validators/alias.ts | 38 ++++++++++++++++ .../ruleset/validation/validators/function.ts | 13 ++++++ 6 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 packages/core/src/ruleset/validation/validators/alias.ts create mode 100644 packages/core/src/ruleset/validation/validators/function.ts diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 0bb994b77..8de044cc2 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -327,7 +327,7 @@ For now the JSON, YAML, and JS, are all being maintained, and there are no curre Targeting certain parts of an OpenAPI spec is powerful but it can become cumbersome to write and repeat complex JSONPath expressions across various rules. Define aliases for commonly used JSONPath expressions on a global level which can then be reused across the ruleset. -Aliases can be defined in an array of key-value pairs at the root level of the ruleset. +Aliases can be defined in an array of key-value pairs at the root level of the ruleset, or alternatively, within an override. It's similar to `given`, with the notable difference being the possibility to distinguish between different formats. **Example** @@ -396,6 +396,48 @@ aliases: Rulesets can then reference aliases in the [given](#given) keyword, either in full: `"given": "#Paths"`, or use it as a prefix for further JSONPath syntax, like dot notation: `"given": "#ParameterObject.name"`. +Bear in mind that an alias has to be explicitly defined in either at the top-level or inside an override. +This is to avoid ambiguity. + +```yaml +aliases: + Stoplight: + - "$..stoplight" +overrides: + - files: + - "*.yaml" + rules: + value-matches-stoplight: + message: Value must contain Stoplight + given: "#Stoplight" # valid because declared at the root + severity: error + then: + field: description + function: pattern + functionOptions: + match: Stoplight + - files: + - "**/*.json" + aliases: + Value: + - "$..value" + rules: + truthy-stoplight-property: + message: Value must contain Stoplight + given: "#Value" # valid because declared within the override block + severity: error + then: + function: truthy + - files: + - legacy/**/*.json + rules: + falsy-value: + given: "#Value" # invalid because undeclared both at the top-level and the override. Note that this could be technically resolvable for some JSON documents, because the previous override block has the alias, but to spare some headaches, we demand an alias to be explicitly defined. + severity: error + then: + function: falsy +``` + > This will be followed by our core rulesets providing a common set of aliases for OpenAPI and AsyncAPI so that our users don't have to do the work at all. If you have ideas about what kind of aliases could be useful leave your thoughts [here](https://roadmap.stoplight.io). ## Overrides diff --git a/docs/reference/error-handling.md b/docs/reference/error-handling.md index d21d93c3b..094f8e740 100644 --- a/docs/reference/error-handling.md +++ b/docs/reference/error-handling.md @@ -10,6 +10,7 @@ - a rule in the ruleset: - had an invalid `given`, i.e. the JSON Path expression is not valid from syntax's standpoint - the ruleset contains `except` entries and the input is passed through stdin +- a JSON Path alias cannot be resolved ### Runtime diff --git a/packages/core/src/ruleset/__tests__/__fixtures__/overrides/aliases/scope.ts b/packages/core/src/ruleset/__tests__/__fixtures__/overrides/aliases/scope.ts index c0ffad10e..c36b6a9fc 100644 --- a/packages/core/src/ruleset/__tests__/__fixtures__/overrides/aliases/scope.ts +++ b/packages/core/src/ruleset/__tests__/__fixtures__/overrides/aliases/scope.ts @@ -44,6 +44,9 @@ const ruleset: RulesetDefinition = { }, { files: ['legacy/**/*.json'], + aliases: { + Value: ['$..value'], + }, rules: { 'falsy-value': { given: '#Value', diff --git a/packages/core/src/ruleset/validation/ajv.ts b/packages/core/src/ruleset/validation/ajv.ts index e8d4fae5c..fb2171db6 100644 --- a/packages/core/src/ruleset/validation/ajv.ts +++ b/packages/core/src/ruleset/validation/ajv.ts @@ -2,15 +2,13 @@ import Ajv, { _, ValidateFunction } from 'ajv'; import names from 'ajv/dist/compile/names'; import addFormats from 'ajv-formats'; import addErrors from 'ajv-errors'; -import { isError, get } from 'lodash'; import * as ruleSchema from '../meta/rule.schema.json'; import * as shared from '../meta/shared.json'; import * as rulesetSchema from '../meta/ruleset.schema.json'; import * as jsExtensions from '../meta/js-extensions.json'; import * as jsonExtensions from '../meta/json-extensions.json'; -import { resolveAlias } from '../alias'; -import type { RulesetFunction, RulesetFunctionWithValidator } from '../../types'; -import { Formats } from '../formats'; +import { validateAlias } from './validators/alias'; +import { validateFunction } from './validators/function'; const validators: { [key in 'js' | 'json']: null | ValidateFunction } = { js: null, @@ -81,39 +79,12 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { ajv.addSchema(jsonExtensions); } - const validator = ajv.compile(rulesetSchema); - validators[format] = new Proxy(validator, { + const validator = new Proxy(ajv.compile(rulesetSchema), { apply(target, thisArg, args: unknown[]): unknown { return Reflect.apply(target, { validateAlias, validateFunction }, args); }, }); - return validator; -} - -export function validateAlias( - ruleset: { aliases?: Record; overrides?: Record }, - alias: string, - path: string, -): string | void { - try { - const parsedPath = path.slice(1).split('/'); - // skip overrides for now - if (parsedPath[0] === 'overrides') return; - const formats: unknown = get(ruleset, [...parsedPath.slice(0, parsedPath.indexOf('rules') + 2), 'formats']); - resolveAlias(ruleset.aliases ?? null, alias, Array.isArray(formats) ? new Formats(formats) : null); - } catch (ex) { - return isError(ex) ? ex.message : 'invalid alias'; - } -} - -export function validateFunction(fn: RulesetFunction | RulesetFunctionWithValidator, opts: unknown): string | void { - if (!('validator' in fn)) return; - - try { - const validator: RulesetFunctionWithValidator['validator'] = fn.validator.bind(fn); - validator(opts); - } catch (ex) { - return isError(ex) ? ex.message : 'invalid options'; - } + validators[format] = validator; + return validator; } diff --git a/packages/core/src/ruleset/validation/validators/alias.ts b/packages/core/src/ruleset/validation/validators/alias.ts new file mode 100644 index 000000000..b683afac0 --- /dev/null +++ b/packages/core/src/ruleset/validation/validators/alias.ts @@ -0,0 +1,38 @@ +import { isPlainObject } from '@stoplight/json'; +import { get, isError } from 'lodash'; +import { resolveAlias } from '../../alias'; +import { Formats } from '../../formats'; + +function getOverrides(overrides: unknown, key: string): Record | null { + if (!Array.isArray(overrides)) return null; + + const index = Number(key); + if (Number.isNaN(index)) return null; + if (index < 0 && index >= overrides.length) return null; + + const actualOverrides: unknown = overrides[index]; + return isPlainObject(actualOverrides) && isPlainObject(actualOverrides.aliases) ? actualOverrides.aliases : null; +} + +export function validateAlias( + ruleset: { aliases?: Record; overrides?: Record }, + alias: string, + path: string, +): string | void { + try { + const parsedPath = path.slice(1).split('/'); + const formats: unknown = get(ruleset, [...parsedPath.slice(0, parsedPath.indexOf('rules') + 2), 'formats']); + + const aliases = + parsedPath[0] === 'overrides' + ? { + ...ruleset.aliases, + ...getOverrides(ruleset.overrides, parsedPath[1]), + } + : ruleset.aliases; + + resolveAlias(aliases ?? null, alias, Array.isArray(formats) ? new Formats(formats) : null); + } catch (ex) { + return isError(ex) ? ex.message : 'invalid alias'; + } +} diff --git a/packages/core/src/ruleset/validation/validators/function.ts b/packages/core/src/ruleset/validation/validators/function.ts new file mode 100644 index 000000000..bf3e9e69b --- /dev/null +++ b/packages/core/src/ruleset/validation/validators/function.ts @@ -0,0 +1,13 @@ +import { isError } from 'lodash'; +import type { RulesetFunction, RulesetFunctionWithValidator } from '../../../types'; + +export function validateFunction(fn: RulesetFunction | RulesetFunctionWithValidator, opts: unknown): string | void { + if (!('validator' in fn)) return; + + try { + const validator: RulesetFunctionWithValidator['validator'] = fn.validator.bind(fn); + validator(opts); + } catch (ex) { + return isError(ex) ? ex.message : 'invalid options'; + } +} From e546d4f48eeda7a39745cb189edf284ddc9b04a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Mon, 30 May 2022 13:21:03 +0200 Subject: [PATCH 04/11] chore(core): eslint warning --- packages/core/src/ruleset/validation/ajv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/ruleset/validation/ajv.ts b/packages/core/src/ruleset/validation/ajv.ts index fb2171db6..55d6af9d5 100644 --- a/packages/core/src/ruleset/validation/ajv.ts +++ b/packages/core/src/ruleset/validation/ajv.ts @@ -36,7 +36,7 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { schemaType: 'string', error: { message(cxt) { - return _`${cxt.params?.message ? cxt.params.message : ''}`; + return _`${cxt.params?.message !== void 0 ? cxt.params.message : ''}`; }, }, code(cxt) { From 38d9c123bd88b870720a2d7c4b6079e4d8780351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Mon, 30 May 2022 13:25:46 +0200 Subject: [PATCH 05/11] chore(core): no cache --- packages/core/src/ruleset/alias.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/core/src/ruleset/alias.ts b/packages/core/src/ruleset/alias.ts index 81ef8e232..b70de064a 100644 --- a/packages/core/src/ruleset/alias.ts +++ b/packages/core/src/ruleset/alias.ts @@ -3,21 +3,6 @@ import type { RulesetScopedAliasDefinition } from './types'; const ALIAS = /^#([A-Za-z0-9_-]+)/; -const CACHE = new (class { - // maybe try to cache array-ish given? - #store = new WeakMap, Map>(); - - add(ruleset: Record, expression: string, resolvedExpressions: string[]): void { - let existing = this.#store.get(ruleset); - if (!existing) { - existing = new Map(); - this.#store.set(ruleset, existing); - } - - existing.set(expression, resolvedExpressions); - } -})(); - export function resolveAliasForFormats( { targets }: RulesetScopedAliasDefinition, formats: Set | null, @@ -94,9 +79,5 @@ function _resolveAlias( resolvedExpressions.push(expression); } - if (aliases !== null) { - CACHE.add(aliases, expression, resolvedExpressions); - } - return resolvedExpressions; } From f8c5487b8dafa3fba79c0f316b0566631ef10a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Thu, 18 Aug 2022 23:09:46 +0200 Subject: [PATCH 06/11] test(core): validate error paths --- .../src/ruleset/__tests__/ruleset.test.ts | 8 +------ .../validation/__tests__/validation.test.ts | 22 +++++++++++++------ test-utils/matchers.ts | 17 ++++++++++++-- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/core/src/ruleset/__tests__/ruleset.test.ts b/packages/core/src/ruleset/__tests__/ruleset.test.ts index 7df53fbba..96546ce04 100644 --- a/packages/core/src/ruleset/__tests__/ruleset.test.ts +++ b/packages/core/src/ruleset/__tests__/ruleset.test.ts @@ -1336,17 +1336,11 @@ describe('Ruleset', () => { ).toThrowAggregateError( new AggregateError([ new RulesetValidationError('Alias "PathItem" does not exist', ['rules', 'valid-path', 'given']), - new RulesetValidationError('Alias "Name" does not exist', [ - 'rules', - 'valid-name-and-description', - 'given', - '0', - ]), + new RulesetValidationError('Alias "Name" does not exist', ['rules', 'valid-name-and-description', 'given']), new RulesetValidationError(`Alias "Description" does not exist`, [ 'rules', 'valid-name-and-description', 'given', - '1', ]), ]), ); diff --git a/packages/core/src/ruleset/validation/__tests__/validation.test.ts b/packages/core/src/ruleset/validation/__tests__/validation.test.ts index 0a68343ca..a729f2f68 100644 --- a/packages/core/src/ruleset/validation/__tests__/validation.test.ts +++ b/packages/core/src/ruleset/validation/__tests__/validation.test.ts @@ -41,13 +41,18 @@ describe('JS Ruleset Validation', () => { expect(assertValidRuleset.bind(null, invalidRuleset)).toThrowAggregateError( new AggregateError([ new RulesetValidationError('the rule must have at least "given" and "then" properties', [ - '/rules/no-given-no-then', + 'rules', + 'no-given-no-then', ]), new RulesetValidationError('allowed types are "style" and "validation"', [ - '#/rules/rule-with-invalid-enum/type', + 'rules', + 'rule-with-invalid-enum', + 'type', ]), new RulesetValidationError('the value has to be one of: 0, 1, 2, 3 or "error", "warn", "info", "hint", "off"', [ - '#/rules/rule-with-invalid-enum/severity', + 'rules', + 'rule-with-invalid-enum', + 'severity', ]), ]), ); @@ -428,7 +433,7 @@ describe('JS Ruleset Validation', () => { [ new RulesetValidationError( 'must be a valid JSON Path expression or a reference to the existing Alias optionally paired with a JSON Path expression subset', - ['aliases', 'PathItem'], + ['aliases', 'PathItem', '0'], ), ], ], @@ -437,7 +442,7 @@ describe('JS Ruleset Validation', () => { [ new RulesetValidationError( 'must be a valid JSON Path expression or a reference to the existing Alias optionally paired with a JSON Path expression subset', - ['aliases', 'PathItem'], + ['aliases', 'PathItem', '0'], ), ], ], @@ -447,7 +452,7 @@ describe('JS Ruleset Validation', () => { [ new RulesetValidationError( 'must be a valid JSON Path expression or a reference to the existing Alias optionally paired with a JSON Path expression subset', - ['aliases', 'PathItem'], + ['aliases', 'PathItem', '0'], ), ], ], @@ -473,7 +478,10 @@ describe('JS Ruleset Validation', () => { }), ).toThrowAggregateError( new AggregateError([ - new RulesetValidationError('targets must be present and have at least a single alias definition', []), + new RulesetValidationError('targets must be present and have at least a single alias definition', [ + 'aliases', + 'alias', + ]), ]), ); }); diff --git a/test-utils/matchers.ts b/test-utils/matchers.ts index ca1376f09..b51cd3869 100644 --- a/test-utils/matchers.ts +++ b/test-utils/matchers.ts @@ -9,6 +9,18 @@ declare global { } } +function toPlainObject(ex: unknown): Record { + if (ex instanceof Error) { + return { + ...ex, + message: ex.message, + name: ex.name, + }; + } + + return Object(ex); +} + expect.extend({ toThrowAggregateError(received, expected) { let error: unknown; @@ -23,11 +35,12 @@ expect.extend({ error = received; } - expect(error).toBeInstanceOf(Error); + expect(error).toEqual(expected); expect((error as AggregateError).errors).toEqual(expected.errors); + expect((error as AggregateError).errors.map(toPlainObject)).toEqual(expected.errors.map(toPlainObject)); return { - message: () => 'All errors matched!', + message: (): string => 'All errors matched!', pass: true, }; }, From e7b5afe5488be22ebf15013a2b7832d05103f6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Thu, 18 Aug 2022 23:35:01 +0200 Subject: [PATCH 07/11] fix(core): default fn options to null --- packages/core/src/ruleset/function.ts | 2 +- packages/core/src/ruleset/validation/ajv.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/ruleset/function.ts b/packages/core/src/ruleset/function.ts index ac462d282..2a680ab29 100644 --- a/packages/core/src/ruleset/function.ts +++ b/packages/core/src/ruleset/function.ts @@ -91,7 +91,7 @@ type Schema = ( export type SchemaDefinition = Schema | boolean; -const DEFAULT_OPTIONS_VALIDATOR = (o: unknown): boolean => o === void 0 || o === null; +const DEFAULT_OPTIONS_VALIDATOR = (o: unknown): boolean => o === null; export function createRulesetFunction( { diff --git a/packages/core/src/ruleset/validation/ajv.ts b/packages/core/src/ruleset/validation/ajv.ts index d36900bff..ca2ce2c72 100644 --- a/packages/core/src/ruleset/validation/ajv.ts +++ b/packages/core/src/ruleset/validation/ajv.ts @@ -52,7 +52,7 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { case 'ruleset-function': { const fn = cxt.gen.const( 'spectralFunction', - _`this.validateFunction(${data}.function, ${data}.functionOptions, ${names.instancePath})`, + _`this.validateFunction(${data}.function, ${data}.functionOptions ?? null, ${names.instancePath})`, ); cxt.gen.if(_`${fn} !== void 0`); cxt.error(false, { errors: fn }); From d1424bf84267b15d20126fde5f9091234e21bd2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Thu, 18 Aug 2022 23:39:08 +0200 Subject: [PATCH 08/11] chore(core): ah, Node 12 --- packages/core/src/ruleset/validation/ajv.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/ruleset/validation/ajv.ts b/packages/core/src/ruleset/validation/ajv.ts index ca2ce2c72..0686aee26 100644 --- a/packages/core/src/ruleset/validation/ajv.ts +++ b/packages/core/src/ruleset/validation/ajv.ts @@ -39,7 +39,7 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { return _`${cxt.params?.message !== void 0 ? cxt.params.message : ''}`; }, params(cxt) { - return _`{ errors: ${cxt.params?.errors !== void 0 && cxt.params.errors} ?? [] }`; + return _`{ errors: ${cxt.params?.errors !== void 0 && cxt.params.errors} || [] }`; }, }, code(cxt) { @@ -52,7 +52,7 @@ export function createValidator(format: 'js' | 'json'): ValidateFunction { case 'ruleset-function': { const fn = cxt.gen.const( 'spectralFunction', - _`this.validateFunction(${data}.function, ${data}.functionOptions ?? null, ${names.instancePath})`, + _`this.validateFunction(${data}.function, ${data}.functionOptions === void 0 ? null : ${data}.functionOptions, ${names.instancePath})`, ); cxt.gen.if(_`${fn} !== void 0`); cxt.error(false, { errors: fn }); From 53ad8650255911c095c0b80baad532603b9e399c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Tue, 23 Aug 2022 14:16:08 +0200 Subject: [PATCH 09/11] chore(test-utils): cast error to object for proper assertion --- commitlint.config.js | 8 +++++++- test-utils/matchers.ts | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/commitlint.config.js b/commitlint.config.js index 9262c69b4..114b6c78f 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -2,7 +2,13 @@ const fs = require('fs'); const path = require('path'); -const scopes = ['repo', 'test-harness', 'deps-dev', ...fs.readdirSync(path.join(__dirname, './packages'))]; +const scopes = [ + 'repo', + 'test-harness', + 'test-utils', + 'deps-dev', + ...fs.readdirSync(path.join(__dirname, './packages')), +]; module.exports = { extends: ['@commitlint/config-conventional'], diff --git a/test-utils/matchers.ts b/test-utils/matchers.ts index ca1376f09..b51cd3869 100644 --- a/test-utils/matchers.ts +++ b/test-utils/matchers.ts @@ -9,6 +9,18 @@ declare global { } } +function toPlainObject(ex: unknown): Record { + if (ex instanceof Error) { + return { + ...ex, + message: ex.message, + name: ex.name, + }; + } + + return Object(ex); +} + expect.extend({ toThrowAggregateError(received, expected) { let error: unknown; @@ -23,11 +35,12 @@ expect.extend({ error = received; } - expect(error).toBeInstanceOf(Error); + expect(error).toEqual(expected); expect((error as AggregateError).errors).toEqual(expected.errors); + expect((error as AggregateError).errors.map(toPlainObject)).toEqual(expected.errors.map(toPlainObject)); return { - message: () => 'All errors matched!', + message: (): string => 'All errors matched!', pass: true, }; }, From 3476a1388823317f16a3de445425ee1d07985bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Tue, 23 Aug 2022 14:22:08 +0200 Subject: [PATCH 10/11] chore(deps-dev): bump ESLint and related packages --- .eslintrc | 1 + package.json | 12 +- packages/core/src/ruleset/function.ts | 2 +- packages/core/src/types/function.ts | 7 +- yarn.lock | 549 +++++++++++++------------- 5 files changed, 279 insertions(+), 292 deletions(-) diff --git a/.eslintrc b/.eslintrc index 95efccda1..bb989174a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -46,6 +46,7 @@ "@typescript-eslint/strict-boolean-expressions": "warn", "@typescript-eslint/no-throw-literal": "error", "@typescript-eslint/ban-types": "warn", + "@typescript-eslint/no-unsafe-argument": "warn", "import/no-extraneous-dependencies": ["error", { "devDependencies": ["**/*.{test,spec}.ts", "**/__tests__/__helpers__/*.ts"] }] } diff --git a/package.json b/package.json index c522d36fe..b15efc315 100644 --- a/package.json +++ b/package.json @@ -80,12 +80,12 @@ "@types/node-fetch": "^2.5.12", "@types/node-powershell": "^3.1.1", "@types/text-table": "^0.2.2", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "eslint": "^7.32.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-prettier": "^4.0.0", + "@typescript-eslint/eslint-plugin": "^5.34.0", + "@typescript-eslint/parser": "^5.34.0", + "eslint": "^8.22.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.2.1", "expect": "^27.5.1", "fast-glob": "^3.2.7", "fetch-mock": "^9.11.0", diff --git a/packages/core/src/ruleset/function.ts b/packages/core/src/ruleset/function.ts index 2a680ab29..14a91de5a 100644 --- a/packages/core/src/ruleset/function.ts +++ b/packages/core/src/ruleset/function.ts @@ -93,7 +93,7 @@ export type SchemaDefinition = Schema | boolean; const DEFAULT_OPTIONS_VALIDATOR = (o: unknown): boolean => o === null; -export function createRulesetFunction( +export function createRulesetFunction( { input, errorOnInvalidInput = false, diff --git a/packages/core/src/types/function.ts b/packages/core/src/types/function.ts index b4e2aae50..55fffc495 100644 --- a/packages/core/src/types/function.ts +++ b/packages/core/src/types/function.ts @@ -4,7 +4,7 @@ import type { IRule } from '../ruleset/rule'; import type { IDocument } from '../document'; import type { JSONSchema7 } from 'json-schema'; -export type RulesetFunction = ( +export type RulesetFunction = ( input: I, options: O, context: RulesetFunctionContext, @@ -19,10 +19,7 @@ export type RulesetFunctionContext = { export type IFunction = RulesetFunction; -export type RulesetFunctionWithValidator = RulesetFunction< - I, - O -> & { +export type RulesetFunctionWithValidator = RulesetFunction & { validator(options: unknown): asserts options is O; readonly schemas: Readonly<{ input: Readonly | null; diff --git a/yarn.lock b/yarn.lock index d7b2c6a71..dc25e2201 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,15 +34,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:7.12.11": - version: 7.12.11 - resolution: "@babel/code-frame@npm:7.12.11" - dependencies: - "@babel/highlight": ^7.10.4 - checksum: 3963eff3ebfb0e091c7e6f99596ef4b258683e4ba8a134e4e95f77afe85be5c931e184fff6435fb4885d12eba04a5e25532f7fbc292ca13b48e7da943474e2f3 - languageName: node - linkType: hard - "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.18.6": version: 7.18.6 resolution: "@babel/code-frame@npm:7.18.6" @@ -336,7 +327,7 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.18.6": +"@babel/highlight@npm:^7.18.6": version: 7.18.6 resolution: "@babel/highlight@npm:7.18.6" dependencies: @@ -1420,20 +1411,20 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^0.4.3": - version: 0.4.3 - resolution: "@eslint/eslintrc@npm:0.4.3" +"@eslint/eslintrc@npm:^1.3.0": + version: 1.3.0 + resolution: "@eslint/eslintrc@npm:1.3.0" dependencies: ajv: ^6.12.4 - debug: ^4.1.1 - espree: ^7.3.0 - globals: ^13.9.0 - ignore: ^4.0.6 + debug: ^4.3.2 + espree: ^9.3.2 + globals: ^13.15.0 + ignore: ^5.2.0 import-fresh: ^3.2.1 - js-yaml: ^3.13.1 - minimatch: ^3.0.4 + js-yaml: ^4.1.0 + minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: 03a7704150b868c318aab6a94d87a33d30dc2ec579d27374575014f06237ba1370ae11178db772f985ef680d469dc237e7b16a1c5d8edaaeb8c3733e7a95a6d3 + checksum: a1e734ad31a8b5328dce9f479f185fd4fc83dd7f06c538e1fa457fd8226b89602a55cc6458cd52b29573b01cdfaf42331be8cfc1fec732570086b591f4ed6515 languageName: node linkType: hard @@ -1444,21 +1435,28 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.5.0": - version: 0.5.0 - resolution: "@humanwhocodes/config-array@npm:0.5.0" +"@humanwhocodes/config-array@npm:^0.10.4": + version: 0.10.4 + resolution: "@humanwhocodes/config-array@npm:0.10.4" dependencies: - "@humanwhocodes/object-schema": ^1.2.0 + "@humanwhocodes/object-schema": ^1.2.1 debug: ^4.1.1 minimatch: ^3.0.4 - checksum: 44ee6a9f05d93dd9d5935a006b17572328ba9caff8002442f601736cbda79c580cc0f5a49ce9eb88fbacc5c3a6b62098357c2e95326cd17bb9f1a6c61d6e95e7 + checksum: d480e5d57e6d787565b6cff78e27c3d1b380692d4ffb0ada7d7f5957a56c9032f034da05a3e443065dbd0671ebf4d859036ced34e96b325bbc1badbae3c05300 languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.0": - version: 1.2.0 - resolution: "@humanwhocodes/object-schema@npm:1.2.0" - checksum: 40b75480376de8104d65f7c44a7dd76d30fb57823ca8ba3a3239b2b568323be894d93440578a72fd8e5e2cc3df3577ce0d2f0fe308b990dd51cf35392bf3c9a2 +"@humanwhocodes/gitignore-to-minimatch@npm:^1.0.2": + version: 1.0.2 + resolution: "@humanwhocodes/gitignore-to-minimatch@npm:1.0.2" + checksum: aba5c40c9e3770ed73a558b0bfb53323842abfc2ce58c91d7e8b1073995598e6374456d38767be24ab6176915f0a8d8b23eaae5c85e2b488c0dccca6d795e2ad + languageName: node + linkType: hard + +"@humanwhocodes/object-schema@npm:^1.2.1": + version: 1.2.1 + resolution: "@humanwhocodes/object-schema@npm:1.2.1" + checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 languageName: node linkType: hard @@ -3114,7 +3112,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.7": +"@types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.7, @types/json-schema@npm:^7.0.9": version: 7.0.11 resolution: "@types/json-schema@npm:7.0.11" checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d @@ -3282,103 +3280,120 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/eslint-plugin@npm:4.33.0" +"@typescript-eslint/eslint-plugin@npm:^5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.34.0" dependencies: - "@typescript-eslint/experimental-utils": 4.33.0 - "@typescript-eslint/scope-manager": 4.33.0 - debug: ^4.3.1 + "@typescript-eslint/scope-manager": 5.34.0 + "@typescript-eslint/type-utils": 5.34.0 + "@typescript-eslint/utils": 5.34.0 + debug: ^4.3.4 functional-red-black-tree: ^1.0.1 - ignore: ^5.1.8 - regexpp: ^3.1.0 - semver: ^7.3.5 + ignore: ^5.2.0 + regexpp: ^3.2.0 + semver: ^7.3.7 tsutils: ^3.21.0 peerDependencies: - "@typescript-eslint/parser": ^4.0.0 - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + "@typescript-eslint/parser": ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: d74855d0a5ffe0b2f362ec02fcd9301d39a53fb4155b9bd0cb15a0a31d065143129ebf98df9d86af4b6f74de1d423a4c0d8c0095520844068117453afda5bc4f + checksum: c984549931ffd20a3fb612bfd01e244484d36031198a6343ed6b27a0a0cf7bf271b382ac26f88d3d63a15fe61af6ab6a3a3870b9538897c4c09034b20ea87140 languageName: node linkType: hard -"@typescript-eslint/experimental-utils@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/experimental-utils@npm:4.33.0" +"@typescript-eslint/parser@npm:^5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/parser@npm:5.34.0" dependencies: - "@types/json-schema": ^7.0.7 - "@typescript-eslint/scope-manager": 4.33.0 - "@typescript-eslint/types": 4.33.0 - "@typescript-eslint/typescript-estree": 4.33.0 - eslint-scope: ^5.1.1 - eslint-utils: ^3.0.0 + "@typescript-eslint/scope-manager": 5.34.0 + "@typescript-eslint/types": 5.34.0 + "@typescript-eslint/typescript-estree": 5.34.0 + debug: ^4.3.4 peerDependencies: - eslint: "*" - checksum: f859800ada0884f92db6856f24efcb1d073ac9883ddc2b1aa9339f392215487895bed8447ebce3741e8141bb32e545244abef62b73193ba9a8a0527c523aabae + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: eacbfe1495998b7a00b1254631f410874d001a59163daac877265cace428eb608acc0320a2801d950dcd8900f63aa1e056507e022def9ac312f7eabe87a1e4a9 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/parser@npm:4.33.0" +"@typescript-eslint/scope-manager@npm:5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/scope-manager@npm:5.34.0" dependencies: - "@typescript-eslint/scope-manager": 4.33.0 - "@typescript-eslint/types": 4.33.0 - "@typescript-eslint/typescript-estree": 4.33.0 - debug: ^4.3.1 - peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 102457eae1acd516211098fea081c8a2ed728522bbda7f5a557b6ef23d88970514f9a0f6285d53fca134d3d4d7d17822b5d5e12438d5918df4d1f89cc9e67d57 + "@typescript-eslint/types": 5.34.0 + "@typescript-eslint/visitor-keys": 5.34.0 + checksum: 039893fa1b8d349427c642a24932dba7932be823f860ce191691d999cd77ac99c3cc743ecd9dd68ad58ba987626e77c1ec458dad9534623e136766b9f9c5c9bf languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/scope-manager@npm:4.33.0" +"@typescript-eslint/type-utils@npm:5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/type-utils@npm:5.34.0" dependencies: - "@typescript-eslint/types": 4.33.0 - "@typescript-eslint/visitor-keys": 4.33.0 - checksum: 9a25fb7ba7c725ea7227a24d315b0f6aacbad002e2549a049edf723c1d3615c22f5c301f0d7d615b377f2cdf2f3519d97e79af0c459de6ef8d2aaf0906dff13e + "@typescript-eslint/utils": 5.34.0 + debug: ^4.3.4 + tsutils: ^3.21.0 + peerDependencies: + eslint: "*" + peerDependenciesMeta: + typescript: + optional: true + checksum: d26c4c14e24ff18f3f542afae85e95e88895de23ba0f3ac6f98286464473ca1b93325e60c8ae24fee0e24a450ea65682250791fca8ec193e081f661b4a17d225 languageName: node linkType: hard -"@typescript-eslint/types@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/types@npm:4.33.0" - checksum: 3baae1ca35872421b4eb60f5d3f3f32dc1d513f2ae0a67dee28c7d159fd7a43ed0d11a8a5a0f0c2d38507ffa036fc7c511cb0f18a5e8ac524b3ebde77390ec53 +"@typescript-eslint/types@npm:5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/types@npm:5.34.0" + checksum: 74ad0302ebac160d1b8178ff07183868018a9b558137c638140b24589ba71dbeccfcedf57156f4d6b7443b139e186ede24a01cba66132f0bda6f891d515878fb languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/typescript-estree@npm:4.33.0" +"@typescript-eslint/typescript-estree@npm:5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.34.0" dependencies: - "@typescript-eslint/types": 4.33.0 - "@typescript-eslint/visitor-keys": 4.33.0 - debug: ^4.3.1 - globby: ^11.0.3 - is-glob: ^4.0.1 - semver: ^7.3.5 + "@typescript-eslint/types": 5.34.0 + "@typescript-eslint/visitor-keys": 5.34.0 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.3.7 tsutils: ^3.21.0 peerDependenciesMeta: typescript: optional: true - checksum: 2566984390c76bd95f43240057215c068c69769e406e27aba41e9f21fd300074d6772e4983fa58fe61e80eb5550af1548d2e31e80550d92ba1d051bb00fe6f5c + checksum: 2b9dac41d6dc544a2f61384ef8ed6559a15bdc19d9e49257829441dd166dd0ca395f4f6b42c97fbb2f006b1a6e7c8907c149add7644267b638ec7f1c0d01de30 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:4.33.0": - version: 4.33.0 - resolution: "@typescript-eslint/visitor-keys@npm:4.33.0" +"@typescript-eslint/utils@npm:5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/utils@npm:5.34.0" dependencies: - "@typescript-eslint/types": 4.33.0 - eslint-visitor-keys: ^2.0.0 - checksum: 59953e474ad4610c1aa23b2b1a964445e2c6201521da6367752f37939d854352bbfced5c04ea539274065e012b1337ba3ffa49c2647a240a4e87155378ba9873 + "@types/json-schema": ^7.0.9 + "@typescript-eslint/scope-manager": 5.34.0 + "@typescript-eslint/types": 5.34.0 + "@typescript-eslint/typescript-estree": 5.34.0 + eslint-scope: ^5.1.1 + eslint-utils: ^3.0.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 6b05bb2bf5c492dec19ae8ee29550ede1c76cc46c5aa03c4b83aff4b1205611e3e03e7fbf3839d60acce8c596ee7cbf715117b474fdcfd47c6879d504a4c3401 + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:5.34.0": + version: 5.34.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.34.0" + dependencies: + "@typescript-eslint/types": 5.34.0 + eslint-visitor-keys: ^3.3.0 + checksum: b5574ce8363f905f0a11e14126ec606130bbcc151c326c004d0f510c8e4e884175a70e0299adb0a82ed817db469558d2d385137c09837249118e15cbfa47bff2 languageName: node linkType: hard @@ -3427,12 +3442,12 @@ __metadata: languageName: node linkType: hard -"acorn-jsx@npm:^5.3.1": - version: 5.3.1 - resolution: "acorn-jsx@npm:5.3.1" +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: daf441a9d7b59c0ea1f7fe2934c48aca604a007455129ce35fa62ec3d4c8363e2efc2d4da636d18ce0049979260ba07d8b42bc002ae95182916d2c90901529c2 + checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 languageName: node linkType: hard @@ -3443,21 +3458,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^7.4.0": - version: 7.4.1 - resolution: "acorn@npm:7.4.1" - bin: - acorn: bin/acorn - checksum: 1860f23c2107c910c6177b7b7be71be350db9e1080d814493fae143ae37605189504152d1ba8743ba3178d0b37269ce1ffc42b101547fdc1827078f82671e407 - languageName: node - linkType: hard - -"acorn@npm:^8.1.0, acorn@npm:^8.4.1, acorn@npm:^8.7.0": - version: 8.7.0 - resolution: "acorn@npm:8.7.0" +"acorn@npm:^8.1.0, acorn@npm:^8.4.1, acorn@npm:^8.7.0, acorn@npm:^8.8.0": + version: 8.8.0 + resolution: "acorn@npm:8.8.0" bin: acorn: bin/acorn - checksum: e0f79409d68923fbf1aa6d4166f3eedc47955320d25c89a20cc822e6ba7c48c5963d5bc657bc242d68f7a4ac9faf96eef033e8f73656da6c640d4219935fdfd0 + checksum: 7270ca82b242eafe5687a11fea6e088c960af712683756abf0791b68855ea9cace3057bd5e998ffcef50c944810c1e0ca1da526d02b32110e13c722aa959afdc languageName: node linkType: hard @@ -3538,7 +3544,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^8.0.0, ajv@npm:^8.0.1, ajv@npm:^8.6.0, ajv@npm:^8.6.3, ajv@npm:^8.8.2": +"ajv@npm:^8.0.0, ajv@npm:^8.6.0, ajv@npm:^8.6.3, ajv@npm:^8.8.2": version: 8.9.0 resolution: "ajv@npm:8.9.0" dependencies: @@ -5058,15 +5064,15 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:~4.3.1": - version: 4.3.3 - resolution: "debug@npm:4.3.3" +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.1": + version: 4.3.4 + resolution: "debug@npm:4.3.4" dependencies: ms: 2.1.2 peerDependenciesMeta: supports-color: optional: true - checksum: 14472d56fe4a94dbcfaa6dbed2dd3849f1d72ba78104a1a328047bb564643ca49df0224c3a17fa63533fd11dd3d4c8636cd861191232a2c6735af00cc2d4de16 + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 languageName: node linkType: hard @@ -5497,7 +5503,7 @@ __metadata: languageName: node linkType: hard -"enquirer@npm:^2.3.5, enquirer@npm:^2.3.6": +"enquirer@npm:^2.3.6": version: 2.3.6 resolution: "enquirer@npm:2.3.6" dependencies: @@ -5738,14 +5744,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^8.3.0": - version: 8.3.0 - resolution: "eslint-config-prettier@npm:8.3.0" +"eslint-config-prettier@npm:^8.5.0": + version: 8.5.0 + resolution: "eslint-config-prettier@npm:8.5.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: df4cea3032671995bb5ab07e016169072f7fa59f44a53251664d9ca60951b66cdc872683b5c6a3729c91497c11490ca44a79654b395dd6756beb0c3903a37196 + checksum: 0d0f5c32e7a0ad91249467ce71ca92394ccd343178277d318baf32063b79ea90216f4c81d1065d60f96366fdc60f151d4d68ae7811a58bd37228b84c2083f893 languageName: node linkType: hard @@ -5759,43 +5765,44 @@ __metadata: languageName: node linkType: hard -"eslint-module-utils@npm:^2.7.0": - version: 2.7.1 - resolution: "eslint-module-utils@npm:2.7.1" +"eslint-module-utils@npm:^2.7.3": + version: 2.7.4 + resolution: "eslint-module-utils@npm:2.7.4" dependencies: debug: ^3.2.7 - find-up: ^2.1.0 - pkg-dir: ^2.0.0 - checksum: c30dfa125aafe65e5f6a30a31c26932106fcf09934a2f47d7f8a393ed9106da7b07416f2337b55c85f9db0175c873ee0827be5429a24ec381b49940f342b9ac3 + peerDependenciesMeta: + eslint: + optional: true + checksum: 5da13645daff145a5c922896b258f8bba560722c3767254e458d894ff5fbb505d6dfd945bffa932a5b0ae06714da2379bd41011c4c20d2d59cc83e23895360f7 languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.2": - version: 2.25.2 - resolution: "eslint-plugin-import@npm:2.25.2" +"eslint-plugin-import@npm:^2.26.0": + version: 2.26.0 + resolution: "eslint-plugin-import@npm:2.26.0" dependencies: array-includes: ^3.1.4 array.prototype.flat: ^1.2.5 debug: ^2.6.9 doctrine: ^2.1.0 eslint-import-resolver-node: ^0.3.6 - eslint-module-utils: ^2.7.0 + eslint-module-utils: ^2.7.3 has: ^1.0.3 - is-core-module: ^2.7.0 + is-core-module: ^2.8.1 is-glob: ^4.0.3 - minimatch: ^3.0.4 + minimatch: ^3.1.2 object.values: ^1.1.5 - resolve: ^1.20.0 - tsconfig-paths: ^3.11.0 + resolve: ^1.22.0 + tsconfig-paths: ^3.14.1 peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: 4ca36e37faf72fb1ed25361ea8a6abbcc9daa65f3a9ac1dc0a660029000456e8c8b98a87b8cc2316541b13c6e5915df41d2dc4a1d7fe0729d9b72b9a3bd5b909 + checksum: 0bf77ad80339554481eafa2b1967449e1f816b94c7a6f9614ce33fb4083c4e6c050f10d241dd50b4975d47922880a34de1e42ea9d8e6fd663ebb768baa67e655 languageName: node linkType: hard -"eslint-plugin-prettier@npm:^4.0.0": - version: 4.0.0 - resolution: "eslint-plugin-prettier@npm:4.0.0" +"eslint-plugin-prettier@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-plugin-prettier@npm:4.2.1" dependencies: prettier-linter-helpers: ^1.0.0 peerDependencies: @@ -5804,7 +5811,7 @@ __metadata: peerDependenciesMeta: eslint-config-prettier: optional: true - checksum: 03d69177a3c21fa2229c7e427ce604429f0b20ab7f411e2e824912f572a207c7f5a41fd1f0a95b9b8afe121e291c1b1f1dc1d44c7aad4b0837487f9c19f5210d + checksum: b9e839d2334ad8ec7a5589c5cb0f219bded260839a857d7a486997f9870e95106aa59b8756ff3f37202085ebab658de382b0267cae44c3a7f0eb0bcc03a4f6d6 languageName: node linkType: hard @@ -5818,12 +5825,13 @@ __metadata: languageName: node linkType: hard -"eslint-utils@npm:^2.1.0": - version: 2.1.0 - resolution: "eslint-utils@npm:2.1.0" +"eslint-scope@npm:^7.1.1": + version: 7.1.1 + resolution: "eslint-scope@npm:7.1.1" dependencies: - eslint-visitor-keys: ^1.1.0 - checksum: 27500938f348da42100d9e6ad03ae29b3de19ba757ae1a7f4a087bdcf83ac60949bbb54286492ca61fac1f5f3ac8692dd21537ce6214240bf95ad0122f24d71d + esrecurse: ^4.3.0 + estraverse: ^5.2.0 + checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e languageName: node linkType: hard @@ -5838,13 +5846,6 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^1.1.0, eslint-visitor-keys@npm:^1.3.0": - version: 1.3.0 - resolution: "eslint-visitor-keys@npm:1.3.0" - checksum: 37a19b712f42f4c9027e8ba98c2b06031c17e0c0a4c696cd429bd9ee04eb43889c446f2cd545e1ff51bef9593fcec94ecd2c2ef89129fcbbf3adadbef520376a - languageName: node - linkType: hard - "eslint-visitor-keys@npm:^2.0.0": version: 2.1.0 resolution: "eslint-visitor-keys@npm:2.1.0" @@ -5852,64 +5853,70 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^7.32.0": - version: 7.32.0 - resolution: "eslint@npm:7.32.0" +"eslint-visitor-keys@npm:^3.3.0": + version: 3.3.0 + resolution: "eslint-visitor-keys@npm:3.3.0" + checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808 + languageName: node + linkType: hard + +"eslint@npm:^8.22.0": + version: 8.22.0 + resolution: "eslint@npm:8.22.0" dependencies: - "@babel/code-frame": 7.12.11 - "@eslint/eslintrc": ^0.4.3 - "@humanwhocodes/config-array": ^0.5.0 + "@eslint/eslintrc": ^1.3.0 + "@humanwhocodes/config-array": ^0.10.4 + "@humanwhocodes/gitignore-to-minimatch": ^1.0.2 ajv: ^6.10.0 chalk: ^4.0.0 cross-spawn: ^7.0.2 - debug: ^4.0.1 + debug: ^4.3.2 doctrine: ^3.0.0 - enquirer: ^2.3.5 escape-string-regexp: ^4.0.0 - eslint-scope: ^5.1.1 - eslint-utils: ^2.1.0 - eslint-visitor-keys: ^2.0.0 - espree: ^7.3.1 + eslint-scope: ^7.1.1 + eslint-utils: ^3.0.0 + eslint-visitor-keys: ^3.3.0 + espree: ^9.3.3 esquery: ^1.4.0 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 file-entry-cache: ^6.0.1 + find-up: ^5.0.0 functional-red-black-tree: ^1.0.1 - glob-parent: ^5.1.2 - globals: ^13.6.0 - ignore: ^4.0.6 + glob-parent: ^6.0.1 + globals: ^13.15.0 + globby: ^11.1.0 + grapheme-splitter: ^1.0.4 + ignore: ^5.2.0 import-fresh: ^3.0.0 imurmurhash: ^0.1.4 is-glob: ^4.0.0 - js-yaml: ^3.13.1 + js-yaml: ^4.1.0 json-stable-stringify-without-jsonify: ^1.0.1 levn: ^0.4.1 lodash.merge: ^4.6.2 - minimatch: ^3.0.4 + minimatch: ^3.1.2 natural-compare: ^1.4.0 optionator: ^0.9.1 - progress: ^2.0.0 - regexpp: ^3.1.0 - semver: ^7.2.1 - strip-ansi: ^6.0.0 + regexpp: ^3.2.0 + strip-ansi: ^6.0.1 strip-json-comments: ^3.1.0 - table: ^6.0.9 text-table: ^0.2.0 v8-compile-cache: ^2.0.3 bin: eslint: bin/eslint.js - checksum: cc85af9985a3a11085c011f3d27abe8111006d34cc274291b3c4d7bea51a4e2ff6135780249becd919ba7f6d6d1ecc38a6b73dacb6a7be08d38453b344dc8d37 + checksum: 2d84a7a2207138cdb250759b047fdb05a57fede7f87b7a039d9370edba7f26e23a873a208becfd4b2c9e4b5499029f3fc3b9318da3290e693d25c39084119c80 languageName: node linkType: hard -"espree@npm:^7.3.0, espree@npm:^7.3.1": - version: 7.3.1 - resolution: "espree@npm:7.3.1" +"espree@npm:^9.3.2, espree@npm:^9.3.3": + version: 9.3.3 + resolution: "espree@npm:9.3.3" dependencies: - acorn: ^7.4.0 - acorn-jsx: ^5.3.1 - eslint-visitor-keys: ^1.3.0 - checksum: aa9b50dcce883449af2e23bc2b8d9abb77118f96f4cb313935d6b220f77137eaef7724a83c3f6243b96bc0e4ab14766198e60818caad99f9519ae5a336a39b45 + acorn: ^8.8.0 + acorn-jsx: ^5.3.2 + eslint-visitor-keys: ^3.3.0 + checksum: 33e8a36fc15d082e68672e322e22a53856b564d60aad8f291a667bfc21b2c900c42412d37dd3c7a0f18b9d0d8f8858dabe8776dbd4b4c2f72c5cf4d6afeabf65 languageName: node linkType: hard @@ -6690,6 +6697,15 @@ __metadata: languageName: node linkType: hard +"glob-parent@npm:^6.0.1": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: ^4.0.3 + checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 + languageName: node + linkType: hard + "glob-promise@npm:^3.4.0": version: 3.4.0 resolution: "glob-promise@npm:3.4.0" @@ -6738,12 +6754,12 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.6.0, globals@npm:^13.9.0": - version: 13.9.0 - resolution: "globals@npm:13.9.0" +"globals@npm:^13.15.0": + version: 13.17.0 + resolution: "globals@npm:13.17.0" dependencies: type-fest: ^0.20.2 - checksum: 566b29b475dd793eeb44d5b54823fdbf320e7077f5d1d330856ac2e7e016e4b50c8310b12d498282d5b5b26bdd7a1a6343615f510bf37b8863ec2741d58cc6ad + checksum: fbaf4112e59b92c9f5575e85ce65e9e17c0b82711196ec5f58beb08599bbd92fd72703d6dfc9b080381fd35b644e1b11dcf25b38cc2341ec21df942594cbc8ce languageName: node linkType: hard @@ -6756,7 +6772,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.0, globby@npm:^11.0.1": +"globby@npm:^11.0.0, globby@npm:^11.0.1, globby@npm:^11.0.3, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -6770,20 +6786,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.3": - version: 11.0.4 - resolution: "globby@npm:11.0.4" - dependencies: - array-union: ^2.1.0 - dir-glob: ^3.0.1 - fast-glob: ^3.2.9 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^3.0.0 - checksum: d3e02d5e459e02ffa578b45f040381c33e3c0538ed99b958f0809230c423337999867d7b0dbf752ce93c46157d3bbf154d3fff988a93ccaeb627df8e1841775b - languageName: node - linkType: hard - "graceful-fs@npm:*, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.9": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" @@ -6805,6 +6807,13 @@ __metadata: languageName: node linkType: hard +"grapheme-splitter@npm:^1.0.4": + version: 1.0.4 + resolution: "grapheme-splitter@npm:1.0.4" + checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 + languageName: node + linkType: hard + "handlebars@npm:^4.7.7": version: 4.7.7 resolution: "handlebars@npm:4.7.7" @@ -7082,14 +7091,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^4.0.6": - version: 4.0.6 - resolution: "ignore@npm:4.0.6" - checksum: 248f82e50a430906f9ee7f35e1158e3ec4c3971451dd9f99c9bc1548261b4db2b99709f60ac6c6cac9333494384176cc4cc9b07acbe42d52ac6a09cad734d800 - languageName: node - linkType: hard - -"ignore@npm:^5.1.8, ignore@npm:^5.2.0": +"ignore@npm:^5.2.0": version: 5.2.0 resolution: "ignore@npm:5.2.0" checksum: 6b1f926792d614f64c6c83da3a1f9c83f6196c2839aa41e1e32dd7b8d174cef2e329d75caabb62cb61ce9dc432f75e67d07d122a037312db7caa73166a1bdb77 @@ -7316,12 +7318,12 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.2.0, is-core-module@npm:^2.5.0, is-core-module@npm:^2.7.0": - version: 2.8.1 - resolution: "is-core-module@npm:2.8.1" +"is-core-module@npm:^2.5.0, is-core-module@npm:^2.8.1, is-core-module@npm:^2.9.0": + version: 2.10.0 + resolution: "is-core-module@npm:2.10.0" dependencies: has: ^1.0.3 - checksum: 418b7bc10768a73c41c7ef497e293719604007f88934a6ffc5f7c78702791b8528102fb4c9e56d006d69361549b3d9519440214a74aefc7e0b79e5e4411d377f + checksum: 0f3f77811f430af3256fa7bbc806f9639534b140f8ee69476f632c3e1eb4e28a38be0b9d1b8ecf596179c841b53576129279df95e7051d694dac4ceb6f967593 languageName: node linkType: hard @@ -8820,13 +8822,6 @@ __metadata: languageName: node linkType: hard -"lodash.clonedeep@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.clonedeep@npm:4.5.0" - checksum: 92c46f094b064e876a23c97f57f81fbffd5d760bf2d8a1c61d85db6d1e488c66b0384c943abee4f6af7debf5ad4e4282e74ff83177c9e63d8ff081a4837c3489 - languageName: node - linkType: hard - "lodash.escaperegexp@npm:^4.1.2": version: 4.1.2 resolution: "lodash.escaperegexp@npm:4.1.2" @@ -8911,13 +8906,6 @@ __metadata: languageName: node linkType: hard -"lodash.truncate@npm:^4.4.2": - version: 4.4.2 - resolution: "lodash.truncate@npm:4.4.2" - checksum: b463d8a382cfb5f0e71c504dcb6f807a7bd379ff1ea216669aa42c52fc28c54e404bfbd96791aa09e6df0de2c1d7b8f1b7f4b1a61f324d38fe98bc535aeee4f5 - languageName: node - linkType: hard - "lodash.uniqby@npm:^4.7.0": version: 4.7.0 resolution: "lodash.uniqby@npm:4.7.0" @@ -9282,7 +9270,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2, minimatch@npm:^3.0.3, minimatch@npm:^3.0.4": +"minimatch@npm:3.1.2, minimatch@npm:^3.0.3, minimatch@npm:^3.0.4, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -9302,7 +9290,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5": +"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.6 resolution: "minimist@npm:1.2.6" checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb @@ -10463,7 +10451,7 @@ __metadata: languageName: node linkType: hard -"path-parse@npm:^1.0.6": +"path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a @@ -10535,15 +10523,6 @@ __metadata: languageName: node linkType: hard -"pkg-dir@npm:^2.0.0": - version: 2.0.0 - resolution: "pkg-dir@npm:2.0.0" - dependencies: - find-up: ^2.1.0 - checksum: 8c72b712305b51e1108f0ffda5ec1525a8307e54a5855db8fb1dcf77561a5ae98e2ba3b4814c9806a679f76b2f7e5dd98bde18d07e594ddd9fdd25e9cf242ea1 - languageName: node - linkType: hard - "pkg-dir@npm:^4.2.0": version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" @@ -10733,7 +10712,7 @@ __metadata: languageName: node linkType: hard -"progress@npm:^2.0.0, progress@npm:^2.0.3": +"progress@npm:^2.0.3": version: 2.0.3 resolution: "progress@npm:2.0.3" checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 @@ -11172,10 +11151,10 @@ __metadata: languageName: node linkType: hard -"regexpp@npm:^3.1.0": - version: 3.1.0 - resolution: "regexpp@npm:3.1.0" - checksum: 63bcb2c98d63274774c79bef256e03f716d25f1fa8427267d0302d1436a83fa0d905f4e8a172fdfa99fb4d84833df2fb3bf7da2a1a868f156e913174c32b1139 +"regexpp@npm:^3.2.0": + version: 3.2.0 + resolution: "regexpp@npm:3.2.0" + checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8 languageName: node linkType: hard @@ -11287,23 +11266,29 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.17.0, resolve@npm:^1.20.0": - version: 1.20.0 - resolution: "resolve@npm:1.20.0" +"resolve@npm:^1.10.0, resolve@npm:^1.17.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0": + version: 1.22.1 + resolution: "resolve@npm:1.22.1" dependencies: - is-core-module: ^2.2.0 - path-parse: ^1.0.6 - checksum: 40cf70b2cde00ef57f99daf2dc63c6a56d6c14a1b7fc51735d06a6f0a3b97cb67b4fb7ef6c747b4e13a7baba83b0ef625d7c4ce92a483cd5af923c3b65fd16fe + is-core-module: ^2.9.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 07af5fc1e81aa1d866cbc9e9460fbb67318a10fa3c4deadc35c3ad8a898ee9a71a86a65e4755ac3195e0ea0cfbe201eb323ebe655ce90526fd61917313a34e4e languageName: node linkType: hard -"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin": - version: 1.20.0 - resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=07638b" +"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.0#~builtin": + version: 1.22.1 + resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=07638b" dependencies: - is-core-module: ^2.2.0 - path-parse: ^1.0.6 - checksum: a0dd7d16a8e47af23afa9386df2dff10e3e0debb2c7299a42e581d9d9b04d7ad5d2c53f24f1e043f7b3c250cbdc71150063e53d0b6559683d37f790b7c8c3cd5 + is-core-module: ^2.9.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 5656f4d0bedcf8eb52685c1abdf8fbe73a1603bb1160a24d716e27a57f6cecbe2432ff9c89c2bd57542c3a7b9d14b1882b73bfe2e9d7849c9a4c0b8b39f02b8b languageName: node linkType: hard @@ -11412,12 +11397,12 @@ __metadata: "@types/node-fetch": ^2.5.12 "@types/node-powershell": ^3.1.1 "@types/text-table": ^0.2.2 - "@typescript-eslint/eslint-plugin": ^4.33.0 - "@typescript-eslint/parser": ^4.33.0 - eslint: ^7.32.0 - eslint-config-prettier: ^8.3.0 - eslint-plugin-import: ^2.25.2 - eslint-plugin-prettier: ^4.0.0 + "@typescript-eslint/eslint-plugin": ^5.34.0 + "@typescript-eslint/parser": ^5.34.0 + eslint: ^8.22.0 + eslint-config-prettier: ^8.5.0 + eslint-plugin-import: ^2.26.0 + eslint-plugin-prettier: ^4.2.1 expect: ^27.5.1 fast-glob: ^3.2.7 fetch-mock: ^9.11.0 @@ -11582,14 +11567,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:*, semver@npm:7.3.5, semver@npm:7.x, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5": - version: 7.3.5 - resolution: "semver@npm:7.3.5" +"semver@npm:*, semver@npm:7.x, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7": + version: 7.3.7 + resolution: "semver@npm:7.3.7" dependencies: lru-cache: ^6.0.0 bin: semver: bin/semver.js - checksum: 5eafe6102bea2a7439897c1856362e31cc348ccf96efd455c8b5bc2c61e6f7e7b8250dc26b8828c1d76a56f818a7ee907a36ae9fb37a599d3d24609207001d60 + checksum: 2fa3e877568cd6ce769c75c211beaed1f9fce80b28338cadd9d0b6c40f2e2862bafd62c19a6cff42f3d54292b7c623277bcab8816a2b5521cf15210d43e75232 languageName: node linkType: hard @@ -11611,6 +11596,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:7.3.5": + version: 7.3.5 + resolution: "semver@npm:7.3.5" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 5eafe6102bea2a7439897c1856362e31cc348ccf96efd455c8b5bc2c61e6f7e7b8250dc26b8828c1d76a56f818a7ee907a36ae9fb37a599d3d24609207001d60 + languageName: node + linkType: hard + "semver@npm:^6.0.0, semver@npm:^6.3.0": version: 6.3.0 resolution: "semver@npm:6.3.0" @@ -12285,17 +12281,10 @@ __metadata: languageName: node linkType: hard -"table@npm:^6.0.9": - version: 6.7.1 - resolution: "table@npm:6.7.1" - dependencies: - ajv: ^8.0.1 - lodash.clonedeep: ^4.5.0 - lodash.truncate: ^4.4.2 - slice-ansi: ^4.0.0 - string-width: ^4.2.0 - strip-ansi: ^6.0.0 - checksum: 053b61fa4e8f8396c65ff7a95da90e85620370932652d501ff7a0a3ed7317f1cc549702bd2abf2bd9ed01e20757b73a8b57374f8a8a2ac02fbe0550276263fb6 +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae languageName: node linkType: hard @@ -12647,15 +12636,15 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.11.0": - version: 3.11.0 - resolution: "tsconfig-paths@npm:3.11.0" +"tsconfig-paths@npm:^3.14.1": + version: 3.14.1 + resolution: "tsconfig-paths@npm:3.14.1" dependencies: "@types/json5": ^0.0.29 json5: ^1.0.1 - minimist: ^1.2.0 + minimist: ^1.2.6 strip-bom: ^3.0.0 - checksum: e14aaa6883f316d611db41cbb0fc8779b59c66b31d1e045565ad4540c77ccd3d2bb66f7c261b74ff535d3cc6b4a1ce21dc84774bf2a2a603ed6b0fb96f7e0cc7 + checksum: 8afa01c673ebb4782ba53d3a12df97fa837ce524f8ad38ee4e2b2fd57f5ac79abc21c574e9e9eb014d93efe7fe8214001b96233b5c6ea75bd1ea82afe17a4c6d languageName: node linkType: hard From 496f75391d2a071f96097577942c5ac445506c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Wed, 24 Aug 2022 12:42:22 +0200 Subject: [PATCH 11/11] revert(rulesets): toThrowError --- packages/core/src/ruleset/__tests__/ruleset.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/ruleset/__tests__/ruleset.test.ts b/packages/core/src/ruleset/__tests__/ruleset.test.ts index 96546ce04..7bfdb8130 100644 --- a/packages/core/src/ruleset/__tests__/ruleset.test.ts +++ b/packages/core/src/ruleset/__tests__/ruleset.test.ts @@ -1474,7 +1474,7 @@ describe('Ruleset', () => { }, }); - expect(() => ruleset.rules['valid-header'].getGivenForFormats(new Formats([oas3]))).toThrow( + expect(() => ruleset.rules['valid-header'].getGivenForFormats(new Formats([oas3]))).toThrowError( ReferenceError( 'Alias "HeaderObject" is circular. Resolution stack: HeaderObject -> HeaderObjects -> Components -> HeaderObject', ),