From 1d7743dbe244b959c557cee122806ec657763788 Mon Sep 17 00:00:00 2001 From: Andrew Tatomyr Date: Mon, 27 Apr 2026 15:41:48 +0300 Subject: [PATCH 1/6] fix: improve built-in decorator validation in config --- .changeset/orange-squids-fail.md | 6 + .../__snapshots__/redocly-yaml.test.ts.snap | 34 ++++- packages/core/src/config/types.ts | 62 +++++---- packages/core/src/decorators/oas2/index.ts | 3 +- packages/core/src/decorators/oas3/index.ts | 10 +- .../media-type-examples-override.ts | 0 packages/core/src/index.ts | 14 +-- packages/core/src/oas-types.ts | 44 +++---- packages/core/src/types/redocly-yaml.ts | 119 ++++++++++++++++-- packages/core/src/visitors.ts | 16 +-- 10 files changed, 227 insertions(+), 81 deletions(-) create mode 100644 .changeset/orange-squids-fail.md rename packages/core/src/decorators/{common => oas3}/media-type-examples-override.ts (100%) diff --git a/.changeset/orange-squids-fail.md b/.changeset/orange-squids-fail.md new file mode 100644 index 0000000000..7c7b889002 --- /dev/null +++ b/.changeset/orange-squids-fail.md @@ -0,0 +1,6 @@ +--- +"@redocly/openapi-core": patch +"@redocly/cli": patch +--- + +Improved Redocly config validation by recognizing built-in decorator names. diff --git a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap index 9b65744a02..31b52927d5 100644 --- a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap @@ -174,6 +174,18 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`] }, }, }, + "BuiltinDecorator": { + "additionalProperties": {}, + "description": "Built-in decorators are the default decorators included with Redocly CLI.", + "documentationLink": "https://redocly.com/docs/cli/decorators#list-of-decorators", + "properties": {}, + }, + "BuiltinPreprocessor": { + "additionalProperties": {}, + "description": "Built-in preprocessors are the default preprocessors included with Redocly CLI.", + "documentationLink": "https://redocly.com/docs/cli/decorators#list-of-decorators", + "properties": {}, + }, "BuiltinRule": { "additionalProperties": {}, "description": "Built-in rules are the default linting rules included with Redocly CLI. They enforce widely accepted API design standards and best practices. Each built-in rule has a default severity of error, but you can change the severity or turn off any built-in rule in your configuration file.", @@ -516,8 +528,26 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`] "assertions", ], }, - "Decorators": { + "CustomDecorator": { + "additionalProperties": {}, + "description": "Custom decorators are defined by users via plugins.", + "documentationLink": "https://redocly.com/docs/cli/custom-plugins/custom-decorators", + "properties": {}, + }, + "CustomPreprocessor": { "additionalProperties": {}, + "description": "Custom preprocessors are defined by users via plugins.", + "documentationLink": "https://redocly.com/docs/cli/custom-plugins/custom-decorators", + "properties": {}, + }, + "CustomRule": { + "additionalProperties": {}, + "description": "Custom rules are defined by users via plugins.", + "documentationLink": "https://redocly.com/docs/cli/custom-plugins/custom-rules", + "properties": {}, + }, + "Decorators": { + "additionalProperties": [Function], "description": "Decorators define transformations that can be applied to the API document during the bundle step.", "documentationLink": "https://redocly.com/docs/cli/configuration/reference/decorators", "properties": {}, @@ -723,7 +753,7 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`] "required": undefined, }, "Preprocessors": { - "additionalProperties": {}, + "additionalProperties": [Function], "description": "Preprocessors define transformations that can be applied to the API document before bundling.", "documentationLink": "https://redocly.com/docs/cli/configuration/reference/preprocessors", "properties": {}, diff --git a/packages/core/src/config/types.ts b/packages/core/src/config/types.ts index d91ece0f99..f23bc30826 100644 --- a/packages/core/src/config/types.ts +++ b/packages/core/src/config/types.ts @@ -2,29 +2,22 @@ import type { ApiConfig, RedoclyConfig } from '@redocly/config'; import type { JSONSchema } from 'json-schema-to-ts'; import type { - Oas3PreprocessorsSet, SpecMajorVersion, Oas3DecoratorsSet, Oas2RuleSet, - Oas2PreprocessorsSet, Oas2DecoratorsSet, Oas3RuleSet, SpecVersion, - Async2PreprocessorsSet, Async2DecoratorsSet, Async2RuleSet, - Async3PreprocessorsSet, Async3DecoratorsSet, Async3RuleSet, Arazzo1RuleSet, - Arazzo1PreprocessorsSet, Arazzo1DecoratorsSet, RuleMap, - Overlay1PreprocessorsSet, Overlay1DecoratorsSet, Overlay1RuleSet, OpenRpc1RuleSet, - OpenRpc1PreprocessorsSet, OpenRpc1DecoratorsSet, } from '../oas-types.js'; import type { Location } from '../ref-utils.js'; @@ -38,6 +31,8 @@ import type { BuiltInOverlay1RuleId, BuiltInOpenRpc1RuleId, BuiltInCommonRuleId, + BuiltInOas2DecoratorId, + BuiltInOas3DecoratorId, } from '../types/redocly-yaml.js'; import type { SkipFunctionContext } from '../visitors.js'; import type { ProblemSeverity, UserContext } from '../walk.js'; @@ -99,11 +94,23 @@ export type RawGovernanceConfig = overlay1Rules?: RuleMap; openrpc1Rules?: RuleMap; - preprocessors?: Record; - oas2Preprocessors?: Record; - oas3_0Preprocessors?: Record; - oas3_1Preprocessors?: Record; - oas3_2Preprocessors?: Record; + preprocessors?: Record; + oas2Preprocessors?: Record< + T extends 'built-in' ? BuiltInOas2DecoratorId : string, + DecoratorConfig + >; + oas3_0Preprocessors?: Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + DecoratorConfig + >; + oas3_1Preprocessors?: Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + DecoratorConfig + >; + oas3_2Preprocessors?: Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + DecoratorConfig + >; async2Preprocessors?: Record; async3Preprocessors?: Record; arazzo1Preprocessors?: Record; @@ -111,10 +118,19 @@ export type RawGovernanceConfig = openrpc1Preprocessors?: Record; decorators?: Record; - oas2Decorators?: Record; - oas3_0Decorators?: Record; - oas3_1Decorators?: Record; - oas3_2Decorators?: Record; + oas2Decorators?: Record; + oas3_0Decorators?: Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + DecoratorConfig + >; + oas3_1Decorators?: Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + DecoratorConfig + >; + oas3_2Decorators?: Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + DecoratorConfig + >; async2Decorators?: Record; async3Decorators?: Record; arazzo1Decorators?: Record; @@ -125,13 +141,13 @@ export type RawGovernanceConfig = export type ResolvedGovernanceConfig = Omit; export type PreprocessorsConfig = { - oas3?: Oas3PreprocessorsSet; - oas2?: Oas2PreprocessorsSet; - async2?: Async2PreprocessorsSet; - async3?: Async3PreprocessorsSet; - arazzo1?: Arazzo1PreprocessorsSet; - overlay1?: Overlay1PreprocessorsSet; - openrpc1?: OpenRpc1PreprocessorsSet; + oas3?: Oas3DecoratorsSet; + oas2?: Oas2DecoratorsSet; + async2?: Async2DecoratorsSet; + async3?: Async3DecoratorsSet; + arazzo1?: Arazzo1DecoratorsSet; + overlay1?: Overlay1DecoratorsSet; + openrpc1?: OpenRpc1DecoratorsSet; }; export type DecoratorsConfig = { diff --git a/packages/core/src/decorators/oas2/index.ts b/packages/core/src/decorators/oas2/index.ts index 60bf7f36f7..91e62aed04 100644 --- a/packages/core/src/decorators/oas2/index.ts +++ b/packages/core/src/decorators/oas2/index.ts @@ -1,3 +1,4 @@ +import { type Oas2DecoratorsSet } from '../../oas-types.js'; import type { Oas2Decorator } from '../../visitors.js'; import { FilterIn } from '../common/filters/filter-in.js'; import { FilterOut } from '../common/filters/filter-out.js'; @@ -8,7 +9,7 @@ import { RemoveXInternal } from '../common/remove-x-internal.js'; import { TagDescriptionOverride } from '../common/tag-description-override.js'; import { RemoveUnusedComponents } from './remove-unused-components.js'; -export const decorators = { +export const decorators: Oas2DecoratorsSet<'built-in'> = { 'operation-description-override': OperationDescriptionOverride as Oas2Decorator, 'tag-description-override': TagDescriptionOverride as Oas2Decorator, 'info-description-override': InfoDescriptionOverride as Oas2Decorator, diff --git a/packages/core/src/decorators/oas3/index.ts b/packages/core/src/decorators/oas3/index.ts index 746915d80a..2d1ee5b10b 100644 --- a/packages/core/src/decorators/oas3/index.ts +++ b/packages/core/src/decorators/oas3/index.ts @@ -1,16 +1,16 @@ -// FIXME: rename common to common-oas -import type { Oas3Decorator } from '../../visitors.js'; +import { type Oas3DecoratorsSet } from '../../oas-types.js'; +import { type Oas3Decorator } from '../../visitors.js'; import { FilterIn } from '../common/filters/filter-in.js'; import { FilterOut } from '../common/filters/filter-out.js'; import { InfoDescriptionOverride } from '../common/info-description-override.js'; import { InfoOverride } from '../common/info-override.js'; -import { MediaTypeExamplesOverride } from '../common/media-type-examples-override.js'; import { OperationDescriptionOverride } from '../common/operation-description-override.js'; import { RemoveXInternal } from '../common/remove-x-internal.js'; import { TagDescriptionOverride } from '../common/tag-description-override.js'; +import { MediaTypeExamplesOverride } from './media-type-examples-override.js'; import { RemoveUnusedComponents } from './remove-unused-components.js'; -export const decorators = { +export const decorators: Oas3DecoratorsSet<'built-in'> = { 'operation-description-override': OperationDescriptionOverride as Oas3Decorator, 'tag-description-override': TagDescriptionOverride as Oas3Decorator, 'info-description-override': InfoDescriptionOverride as Oas3Decorator, @@ -18,6 +18,6 @@ export const decorators = { 'remove-x-internal': RemoveXInternal as Oas3Decorator, 'filter-in': FilterIn as Oas3Decorator, 'filter-out': FilterOut as Oas3Decorator, - 'media-type-examples-override': MediaTypeExamplesOverride as Oas3Decorator, + 'media-type-examples-override': MediaTypeExamplesOverride, 'remove-unused-components': RemoveUnusedComponents, }; diff --git a/packages/core/src/decorators/common/media-type-examples-override.ts b/packages/core/src/decorators/oas3/media-type-examples-override.ts similarity index 100% rename from packages/core/src/decorators/common/media-type-examples-override.ts rename to packages/core/src/decorators/oas3/media-type-examples-override.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c0d8b45678..18f83efec0 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -90,13 +90,13 @@ export { type Arazzo1Decorator, type Overlay1Decorator, type OpenRpc1Decorator, - type Oas3Preprocessor, - type Oas2Preprocessor, - type Async2Preprocessor, - type Async3Preprocessor, - type Arazzo1Preprocessor, - type Overlay1Preprocessor, - type OpenRpc1Preprocessor, + type Oas3Decorator as Oas3Preprocessor, + type Oas2Decorator as Oas2Preprocessor, + type Async2Decorator as Async2Preprocessor, + type Async3Decorator as Async3Preprocessor, + type Arazzo1Decorator as Arazzo1Preprocessor, + type Overlay1Decorator as Overlay1Preprocessor, + type OpenRpc1Decorator as OpenRpc1Preprocessor, } from './visitors.js'; export { WalkContext, diff --git a/packages/core/src/oas-types.ts b/packages/core/src/oas-types.ts index 4e7cb848fa..04c9bdb74e 100644 --- a/packages/core/src/oas-types.ts +++ b/packages/core/src/oas-types.ts @@ -16,21 +16,23 @@ import type { BuiltInOverlay1RuleId, BuiltInCommonRuleId, BuiltInOpenRpc1RuleId, + BuiltInOas2DecoratorId, + BuiltInOas3DecoratorId, } from './types/redocly-yaml.js'; import type { Oas3Rule, - Oas3Preprocessor, + Oas3Decorator, Oas2Rule, - Oas2Preprocessor, - Async2Preprocessor, + Oas2Decorator, + Async2Decorator, Async2Rule, - Async3Preprocessor, + Async3Decorator, Async3Rule, - Arazzo1Preprocessor, + Arazzo1Decorator, Arazzo1Rule, - Overlay1Preprocessor, + Overlay1Decorator, Overlay1Rule, - OpenRpc1Preprocessor, + OpenRpc1Decorator, OpenRpc1Rule, } from './visitors.js'; @@ -110,21 +112,19 @@ export type OpenRpc1RuleSet = RuleMap< T >; -export type Oas3PreprocessorsSet = Record; -export type Oas2PreprocessorsSet = Record; -export type Async2PreprocessorsSet = Record; -export type Async3PreprocessorsSet = Record; -export type Arazzo1PreprocessorsSet = Record; -export type Overlay1PreprocessorsSet = Record; -export type OpenRpc1PreprocessorsSet = Record; - -export type Oas3DecoratorsSet = Record; -export type Oas2DecoratorsSet = Record; -export type Async2DecoratorsSet = Record; -export type Async3DecoratorsSet = Record; -export type Arazzo1DecoratorsSet = Record; -export type Overlay1DecoratorsSet = Record; -export type OpenRpc1DecoratorsSet = Record; +export type Oas3DecoratorsSet = Record< + T extends 'built-in' ? BuiltInOas3DecoratorId : string, + Oas3Decorator +>; +export type Oas2DecoratorsSet = Record< + T extends 'built-in' ? BuiltInOas2DecoratorId : string, + Oas2Decorator +>; +export type Async2DecoratorsSet = Record; +export type Async3DecoratorsSet = Record; +export type Arazzo1DecoratorsSet = Record; +export type Overlay1DecoratorsSet = Record; +export type OpenRpc1DecoratorsSet = Record; export function getTypes(spec: SpecVersion) { return typesMap[spec]; diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts index eddeecf698..b0780135ef 100644 --- a/packages/core/src/types/redocly-yaml.ts +++ b/packages/core/src/types/redocly-yaml.ts @@ -55,7 +55,6 @@ const builtInOAS2Rules = [ 'response-mime-type', 'no-duplicated-tag-names', ] as const; - export type BuiltInOAS2RuleId = (typeof builtInOAS2Rules)[number]; const builtInOAS3Rules = [ @@ -121,7 +120,6 @@ const builtInOAS3Rules = [ 'spec-example-values', 'spec-querystring-parameters', ] as const; - export type BuiltInOAS3RuleId = (typeof builtInOAS3Rules)[number]; const builtInAsync2Rules = [ @@ -138,6 +136,7 @@ const builtInAsync2Rules = [ 'no-mixed-number-range-constraints', 'no-schema-type-mismatch', ] as const; +export type BuiltInAsync2RuleId = (typeof builtInAsync2Rules)[number]; const builtInAsync3Rules = [ 'info-contact', @@ -153,9 +152,6 @@ const builtInAsync3Rules = [ 'no-mixed-number-range-constraints', 'no-schema-type-mismatch', ] as const; - -export type BuiltInAsync2RuleId = (typeof builtInAsync2Rules)[number]; - export type BuiltInAsync3RuleId = (typeof builtInAsync3Rules)[number]; const builtInArazzo1Rules = [ @@ -182,11 +178,9 @@ const builtInArazzo1Rules = [ 'no-schema-type-mismatch', 'x-security-scheme-name-reference', ] as const; - export type BuiltInArazzo1RuleId = (typeof builtInArazzo1Rules)[number]; const builtInOverlay1Rules = ['info-contact'] as const; - export type BuiltInOverlay1RuleId = (typeof builtInOverlay1Rules)[number]; const builtInOpenRpc1Rules = [ @@ -196,11 +190,9 @@ const builtInOpenRpc1Rules = [ 'spec-no-duplicated-method-params', 'spec-no-required-params-after-optional', ] as const; - export type BuiltInOpenRpc1RuleId = (typeof builtInOpenRpc1Rules)[number]; const builtInCommonRules = ['struct', 'no-unresolved-refs'] as const; - export type BuiltInCommonRuleId = (typeof builtInCommonRules)[number]; const builtInRules = [ @@ -213,9 +205,36 @@ const builtInRules = [ ...builtInOpenRpc1Rules, ...builtInCommonRules, ] as const; - type BuiltInRuleId = (typeof builtInRules)[number]; +const builtInOas2Decorators = [ + 'operation-description-override', + 'tag-description-override', + 'info-description-override', + 'info-override', + 'remove-x-internal', + 'filter-in', + 'filter-out', + 'remove-unused-components', +] as const; +export type BuiltInOas2DecoratorId = (typeof builtInOas2Decorators)[number]; + +const builtInOas3Decorators = [ + 'operation-description-override', + 'tag-description-override', + 'info-description-override', + 'info-override', + 'remove-x-internal', + 'filter-in', + 'filter-out', + 'media-type-examples-override', + 'remove-unused-components', +] as const; +export type BuiltInOas3DecoratorId = (typeof builtInOas3Decorators)[number]; + +const builtInDecorators = [...builtInOas3Decorators, ...builtInOas2Decorators] as const; +type BuiltInDecoratorId = (typeof builtInDecorators)[number]; + const configGovernanceProperties: Record< keyof RawGovernanceConfig, NodeType['properties'][string] @@ -329,12 +348,18 @@ const Rules: NodeType = { } else { return 'ConfigurableRule'; } - } else if (builtInRules.includes(key as BuiltInRuleId) || isCustomRuleId(key)) { + } else if (builtInRules.includes(key as BuiltInRuleId)) { if (typeof value === 'string') { return { enum: ['error', 'warn', 'off'] }; } else { return 'BuiltinRule'; } + } else if (isCustomRuleId(key)) { + if (typeof value === 'string') { + return { enum: ['error', 'warn', 'off'] }; + } else { + return 'CustomRule'; + } } else if (key === 'metadata-schema' || key === 'custom-fields-schema') { return 'Schema'; } @@ -354,20 +379,83 @@ const BuiltinRule: NodeType = { documentationLink: 'https://redocly.com/docs/cli/rules/built-in-rules', }; -const Decorators: NodeType = { +const CustomRule: NodeType = { properties: {}, additionalProperties: {}, + description: 'Custom rules are defined by users via plugins.', + documentationLink: 'https://redocly.com/docs/cli/custom-plugins/custom-rules', +}; + +const Decorators: NodeType = { + properties: {}, description: 'Decorators define transformations that can be applied to the API document during the bundle step.', documentationLink: 'https://redocly.com/docs/cli/configuration/reference/decorators', + additionalProperties: (value: unknown, key: string) => { + if (builtInDecorators.includes(key as BuiltInDecoratorId)) { + if (typeof value === 'string') { + return { enum: ['on', 'off'] }; + } else { + return 'BuiltinDecorator'; + } + } else if (isCustomRuleId(key)) { + return 'CustomDecorator'; + } + // Otherwise is considered as invalid + return; + }, }; -const Preprocessors: NodeType = { +const BuiltinDecorator: NodeType = { + properties: {}, + additionalProperties: {}, + description: 'Built-in decorators are the default decorators included with Redocly CLI.', + documentationLink: 'https://redocly.com/docs/cli/decorators#list-of-decorators', +}; + +const CustomDecorator: NodeType = { properties: {}, additionalProperties: {}, + description: 'Custom decorators are defined by users via plugins.', + documentationLink: 'https://redocly.com/docs/cli/custom-plugins/custom-decorators', +}; + +const Preprocessors: NodeType = { + properties: {}, description: 'Preprocessors define transformations that can be applied to the API document before bundling.', documentationLink: 'https://redocly.com/docs/cli/configuration/reference/preprocessors', + additionalProperties: (value: unknown, key: string) => { + if (builtInDecorators.includes(key as BuiltInDecoratorId)) { + if (typeof value === 'string') { + return { enum: ['on', 'off'] }; + } else { + return 'BuiltinPreprocessor'; + } + } else if (isCustomRuleId(key)) { + if (typeof value === 'string') { + return { enum: ['on', 'off'] }; + } else { + return 'CustomPreprocessor'; + } + } + // Otherwise is considered as invalid + return; + }, +}; + +const BuiltinPreprocessor: NodeType = { + properties: {}, + additionalProperties: {}, + description: 'Built-in preprocessors are the default preprocessors included with Redocly CLI.', + documentationLink: 'https://redocly.com/docs/cli/decorators#list-of-decorators', +}; + +const CustomPreprocessor: NodeType = { + properties: {}, + additionalProperties: {}, + description: 'Custom preprocessors are defined by users via plugins.', + documentationLink: 'https://redocly.com/docs/cli/custom-plugins/custom-decorators', }; // TODO: add better type tree for this @@ -630,6 +718,11 @@ const CoreConfigTypes: Record = { ConfigHTTP, Where, BuiltinRule, + CustomRule, + BuiltinDecorator, + CustomDecorator, + BuiltinPreprocessor, + CustomPreprocessor, Schema, Rules, Decorators, diff --git a/packages/core/src/visitors.ts b/packages/core/src/visitors.ts index 73ba8d677f..3daabd2beb 100644 --- a/packages/core/src/visitors.ts +++ b/packages/core/src/visitors.ts @@ -440,13 +440,13 @@ export type OpenRpc1Rule = (options: Record) => OpenRpc1Visitor | O export type CatalogEntityRule = ( options: Record ) => CatalogEntityVisitor | CatalogEntityVisitor[]; -export type Oas3Preprocessor = (options: Record) => Oas3Visitor; -export type Oas2Preprocessor = (options: Record) => Oas2Visitor; -export type Async2Preprocessor = (options: Record) => Async2Visitor; -export type Async3Preprocessor = (options: Record) => Async3Visitor; -export type Arazzo1Preprocessor = (options: Record) => Arazzo1Visitor; -export type Overlay1Preprocessor = (options: Record) => Overlay1Visitor; -export type OpenRpc1Preprocessor = (options: Record) => OpenRpc1Visitor; +export type Oas3Preprocessor = Oas3Decorator; +export type Oas2Preprocessor = Oas2Decorator; +export type Async2Preprocessor = Async2Decorator; +export type Async3Preprocessor = Async3Decorator; +export type Arazzo1Preprocessor = Arazzo1Decorator; +export type Overlay1Preprocessor = Overlay1Decorator; +export type OpenRpc1Preprocessor = OpenRpc1Decorator; export type Oas3Decorator = (options: Record) => Oas3Visitor; export type Oas2Decorator = (options: Record) => Oas2Visitor; export type Async2Decorator = (options: Record) => Async2Visitor; @@ -458,7 +458,7 @@ export type OpenRpc1Decorator = (options: Record) => OpenRpc1Visito // alias for the latest version supported // every time we update it - consider semver export type OasRule = Oas3Rule; -export type OasPreprocessor = Oas3Preprocessor; +export type OasPreprocessor = Oas3Decorator; export type OasDecorator = Oas3Decorator; export type RuleInstanceConfig = { From 664249acaaf68a4a6ee92bc61d6da85788700e55 Mon Sep 17 00:00:00 2001 From: Andrew Tatomyr Date: Mon, 27 Apr 2026 17:06:09 +0300 Subject: [PATCH 2/6] improve tests --- .../__snapshots__/redocly-yaml.test.ts.snap | 13 ++++- .../core/src/__tests__/redocly-yaml.test.ts | 51 ++++++++++++++++++- packages/core/src/types/redocly-yaml.ts | 11 +++- .../redocly.yaml | 4 -- .../snapshot.txt | 9 ++-- .../redocly.yaml | 4 -- .../redocly.yaml | 4 -- .../snapshot.txt | 9 ++-- .../redocly.yaml | 4 -- .../snapshot.txt | 14 ++--- .../redocly.yaml | 9 ---- .../invalid-custom-rule-config/redocly.yaml | 3 ++ .../snapshot.txt | 13 +++-- .../config-with-error.snapshot.txt | 11 ++-- .../config-with-warn.snapshot.txt | 11 ++-- .../redocly.yaml | 4 -- tests/e2e/lint-config/lint-config.test.ts | 2 +- 17 files changed, 106 insertions(+), 70 deletions(-) delete mode 100644 tests/e2e/lint-config/invalid-config-assertation-name/redocly.yaml create mode 100644 tests/e2e/lint-config/invalid-custom-rule-config/redocly.yaml rename tests/e2e/lint-config/{invalid-config-assertation-name => invalid-custom-rule-config}/snapshot.txt (55%) diff --git a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap index 31b52927d5..8ae658129c 100644 --- a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap @@ -544,7 +544,18 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`] "additionalProperties": {}, "description": "Custom rules are defined by users via plugins.", "documentationLink": "https://redocly.com/docs/cli/custom-plugins/custom-rules", - "properties": {}, + "properties": { + "severity": { + "enum": [ + "error", + "warn", + "off", + ], + }, + }, + "required": [ + "severity", + ], }, "Decorators": { "additionalProperties": [Function], diff --git a/packages/core/src/__tests__/redocly-yaml.test.ts b/packages/core/src/__tests__/redocly-yaml.test.ts index b9b4ad63d8..87bef586c2 100644 --- a/packages/core/src/__tests__/redocly-yaml.test.ts +++ b/packages/core/src/__tests__/redocly-yaml.test.ts @@ -1,6 +1,7 @@ import * as redoclyConfig from '@redocly/config'; -import { createConfigTypes } from '../types/redocly-yaml.js'; +import type { ResolveTypeFn } from '../types/index.js'; +import { ConfigTypes, createConfigTypes } from '../types/redocly-yaml.js'; describe('createConfigTypes', () => { it('matches snapshot for the default config schema', () => { @@ -15,3 +16,51 @@ describe('createConfigTypes', () => { ).toMatchSnapshot(); }); }); + +describe('Rules NodeType resolving', () => { + const rulesResolver = ConfigTypes.Rules.additionalProperties as ResolveTypeFn; + + it('resolves built-in rule names', () => { + expect(rulesResolver({}, 'no-unresolved-refs')).toBe('BuiltinRule'); + }); + + it('resolves custom (plugin-prefixed) rule names', () => { + expect(rulesResolver({}, 'my-plugin/my-custom-rule')).toBe('CustomRule'); + }); + + it('resolves configurable rule names (rule/ prefix)', () => { + expect(rulesResolver({}, 'rule/my-configurable-rule')).toBe('ConfigurableRule'); + }); + + it('resolves schema-related keys', () => { + expect(rulesResolver({}, 'metadata-schema')).toBe('Schema'); + expect(rulesResolver({}, 'custom-fields-schema')).toBe('Schema'); + }); + + it('returns undefined for unknown rule names', () => { + expect(rulesResolver({}, 'not-a-real-rule')).toBeUndefined(); + }); +}); + +describe('Decorators / Preprocessors NodeType resolving', () => { + const decoratorsResolver = ConfigTypes.Decorators.additionalProperties as ResolveTypeFn; + const preprocessorsResolver = ConfigTypes.Preprocessors.additionalProperties as ResolveTypeFn; + + it('resolves built-in decorator names', () => { + expect(decoratorsResolver({}, 'remove-unused-components')).toBe('BuiltinDecorator'); + }); + + it('resolves custom (plugin-prefixed) decorator names', () => { + expect(decoratorsResolver({}, 'my-plugin/my-custom-decorator')).toBe('CustomDecorator'); + }); + + it('returns undefined for unknown decorator names', () => { + expect(decoratorsResolver({}, 'not-a-real-decorator')).toBeUndefined(); + }); + + it('resolves built-in and custom preprocessor names', () => { + expect(preprocessorsResolver({}, 'remove-unused-components')).toBe('BuiltinPreprocessor'); + expect(preprocessorsResolver({}, 'my-plugin/my-preprocessor')).toBe('CustomPreprocessor'); + expect(preprocessorsResolver({}, 'unknown')).toBeUndefined(); + }); +}); diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts index b0780135ef..dc18d7d7ca 100644 --- a/packages/core/src/types/redocly-yaml.ts +++ b/packages/core/src/types/redocly-yaml.ts @@ -380,8 +380,11 @@ const BuiltinRule: NodeType = { }; const CustomRule: NodeType = { - properties: {}, + properties: { + severity: { enum: ['error', 'warn', 'off'] }, + }, additionalProperties: {}, + required: ['severity'], description: 'Custom rules are defined by users via plugins.', documentationLink: 'https://redocly.com/docs/cli/custom-plugins/custom-rules', }; @@ -399,7 +402,11 @@ const Decorators: NodeType = { return 'BuiltinDecorator'; } } else if (isCustomRuleId(key)) { - return 'CustomDecorator'; + if (typeof value === 'string') { + return { enum: ['on', 'off'] }; + } else { + return 'CustomDecorator'; + } } // Otherwise is considered as invalid return; diff --git a/tests/e2e/lint-config/invalid-config--lint-config-error/redocly.yaml b/tests/e2e/lint-config/invalid-config--lint-config-error/redocly.yaml index 97c5577a70..6489cf696a 100644 --- a/tests/e2e/lint-config/invalid-config--lint-config-error/redocly.yaml +++ b/tests/e2e/lint-config/invalid-config--lint-config-error/redocly.yaml @@ -1,6 +1,2 @@ -apis: - main: - root: ./openapi.yaml - rules: context: diff --git a/tests/e2e/lint-config/invalid-config--lint-config-error/snapshot.txt b/tests/e2e/lint-config/invalid-config--lint-config-error/snapshot.txt index 37a243cc3f..46a99ce876 100644 --- a/tests/e2e/lint-config/invalid-config--lint-config-error/snapshot.txt +++ b/tests/e2e/lint-config/invalid-config--lint-config-error/snapshot.txt @@ -1,12 +1,11 @@ -[1] redocly.yaml:6:3 at #/rules/context +[1] redocly.yaml:2:3 at #/rules/context Property `context` is not expected here. -4 | -5 | rules: -6 | context: +1 | rules: +2 | context: | ^^^^^^^^ -7 | +3 | Error was generated by the configuration struct rule. diff --git a/tests/e2e/lint-config/invalid-config--lint-config-off/redocly.yaml b/tests/e2e/lint-config/invalid-config--lint-config-off/redocly.yaml index 97c5577a70..6489cf696a 100644 --- a/tests/e2e/lint-config/invalid-config--lint-config-off/redocly.yaml +++ b/tests/e2e/lint-config/invalid-config--lint-config-off/redocly.yaml @@ -1,6 +1,2 @@ -apis: - main: - root: ./openapi.yaml - rules: context: diff --git a/tests/e2e/lint-config/invalid-config--lint-config-warn/redocly.yaml b/tests/e2e/lint-config/invalid-config--lint-config-warn/redocly.yaml index 97c5577a70..6489cf696a 100644 --- a/tests/e2e/lint-config/invalid-config--lint-config-warn/redocly.yaml +++ b/tests/e2e/lint-config/invalid-config--lint-config-warn/redocly.yaml @@ -1,6 +1,2 @@ -apis: - main: - root: ./openapi.yaml - rules: context: diff --git a/tests/e2e/lint-config/invalid-config--lint-config-warn/snapshot.txt b/tests/e2e/lint-config/invalid-config--lint-config-warn/snapshot.txt index 6fbc475ef1..c916f70c61 100644 --- a/tests/e2e/lint-config/invalid-config--lint-config-warn/snapshot.txt +++ b/tests/e2e/lint-config/invalid-config--lint-config-warn/snapshot.txt @@ -1,12 +1,11 @@ -[1] redocly.yaml:6:3 at #/rules/context +[1] redocly.yaml:2:3 at #/rules/context Property `context` is not expected here. -4 | -5 | rules: -6 | context: +1 | rules: +2 | context: | ^^^^^^^^ -7 | +3 | Warning was generated by the configuration struct rule. diff --git a/tests/e2e/lint-config/invalid-config-assertation-config-type/redocly.yaml b/tests/e2e/lint-config/invalid-config-assertation-config-type/redocly.yaml index a1869c3356..aecb12042a 100644 --- a/tests/e2e/lint-config/invalid-config-assertation-config-type/redocly.yaml +++ b/tests/e2e/lint-config/invalid-config-assertation-config-type/redocly.yaml @@ -1,7 +1,3 @@ -apis: - main: - root: ./openapi.yaml - rules: rule/path-item-mutually-required: where: diff --git a/tests/e2e/lint-config/invalid-config-assertation-config-type/snapshot.txt b/tests/e2e/lint-config/invalid-config-assertation-config-type/snapshot.txt index 360112f7c6..ec4778d4ff 100644 --- a/tests/e2e/lint-config/invalid-config-assertation-config-type/snapshot.txt +++ b/tests/e2e/lint-config/invalid-config-assertation-config-type/snapshot.txt @@ -1,13 +1,13 @@ -[1] redocly.yaml:9:17 at #/rules/rule~1path-item-mutually-required/where/0/subject/type +[1] redocly.yaml:5:17 at #/rules/rule~1path-item-mutually-required/where/0/subject/type `type` can be one of the following only: "any", "Root", "Tag", "TagList", "TagGroups", "TagGroup", "ExternalDocs", "Example", "ExamplesMap", "EnumDescriptions", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Logo", "Paths", "PathItem", "Parameter", "ParameterItems", "ParameterList", "Operation", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "XCodeSample", "XCodeSampleList", "XServerList", "XServer", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Encoding", "EncodingMap", "HeadersMap", "Link", "DiscriminatorMapping", "Discriminator", "Components", "LinksMap", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "XUsePkce", "WebhooksMap", "PatternProperties", "NamedPathItems", "DependentRequired", "DeviceAuthorization", "NamedMediaTypes", "HttpServerBinding", "HttpChannelBinding", "HttpMessageBinding", "HttpOperationBinding", "WsServerBinding", "WsChannelBinding", "WsMessageBinding", "WsOperationBinding", "KafkaServerBinding", "KafkaTopicConfiguration", "KafkaChannelBinding", "KafkaMessageBinding", "KafkaOperationBinding", "AnypointmqServerBinding", "AnypointmqChannelBinding", "AnypointmqMessageBinding", "AnypointmqOperationBinding", "AmqpServerBinding", "AmqpChannelBinding", "AmqpMessageBinding", "AmqpOperationBinding", "Amqp1ServerBinding", "Amqp1ChannelBinding", "Amqp1MessageBinding", "Amqp1OperationBinding", "MqttServerBindingLastWill", "MqttServerBinding", "MqttChannelBinding", "MqttMessageBinding", "MqttOperationBinding", "Mqtt5ServerBinding", "Mqtt5ChannelBinding", "Mqtt5MessageBinding", "Mqtt5OperationBinding", "NatsServerBinding", "NatsChannelBinding", "NatsMessageBinding", "NatsOperationBinding", "JmsServerBinding", "JmsChannelBinding", "JmsMessageBinding", "JmsOperationBinding", "SolaceServerBinding", "SolaceChannelBinding", "SolaceMessageBinding", "SolaceDestination", "SolaceOperationBinding", "StompServerBinding", "StompChannelBinding", "StompMessageBinding", "StompOperationBinding", "RedisServerBinding", "RedisChannelBinding", "RedisMessageBinding", "RedisOperationBinding", "MercureServerBinding", "MercureChannelBinding", "MercureMessageBinding", "MercureOperationBinding", "ServerBindings", "ChannelBindings", "MessageBindings", "OperationBindings", "ServerMap", "ChannelMap", "Channel", "ParametersMap", "MessageExample", "NamedMessages", "NamedMessageTraits", "NamedOperationTraits", "NamedCorrelationIds", "SecuritySchemeFlows", "Message", "OperationTrait", "OperationTraitList", "MessageTrait", "MessageTraitList", "MessageExampleList", "CorrelationId", "Dependencies", "OperationReply", "OperationReplyAddress", "NamedTags", "NamedExternalDocs", "NamedChannels", "NamedOperations", "NamedOperationReplies", "NamedOperationRelyAddresses", "SecuritySchemeList", "MessageList", "SourceDescriptions", "OpenAPISourceDescription", "ArazzoSourceDescription", "Parameters", "ReusableObject", "Workflows", "Workflow", "Steps", "Step", "Replacement", "ExtendedOperation", "ExtendedSecurityList", "ExtendedSecurity", "Outputs", "CriterionObject", "XPathCriterion", "JSONPathCriterion", "SuccessActionObject", "OnSuccessActionList", "FailureActionObject", "OnFailureActionList", "NamedInputs", "NamedSuccessActions", "NamedFailureActions", "Actions", "Action", "Method", "MethodList", "ContentDescriptor", "ContentDescriptorList", "ExamplePairing", "ExamplePairingList", "ExampleList", "LinkList", "ErrorObject", "ErrorList", "NamedContentDescriptors", "NamedErrors", "NamedExamplePairingObjects", "SpecExtension". - 7 | where: - 8 | - subject: - 9 | type: Invalid-type - | ^^^^^^^^^^^^ -10 | property: property -11 | assertions: +3 | where: +4 | - subject: +5 | type: Invalid-type + | ^^^^^^^^^^^^ +6 | property: property +7 | assertions: Warning was generated by the configuration struct rule. diff --git a/tests/e2e/lint-config/invalid-config-assertation-name/redocly.yaml b/tests/e2e/lint-config/invalid-config-assertation-name/redocly.yaml deleted file mode 100644 index 731ff4cc6f..0000000000 --- a/tests/e2e/lint-config/invalid-config-assertation-name/redocly.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apis: - main: - root: ./openapi.yaml - -rules: - asset/path-item-mutually-required: - context: - - type: PathItem - subject: Operation diff --git a/tests/e2e/lint-config/invalid-custom-rule-config/redocly.yaml b/tests/e2e/lint-config/invalid-custom-rule-config/redocly.yaml new file mode 100644 index 0000000000..160ec105d7 --- /dev/null +++ b/tests/e2e/lint-config/invalid-custom-rule-config/redocly.yaml @@ -0,0 +1,3 @@ +rules: + my-plugin/lacks-severity: + key: value diff --git a/tests/e2e/lint-config/invalid-config-assertation-name/snapshot.txt b/tests/e2e/lint-config/invalid-custom-rule-config/snapshot.txt similarity index 55% rename from tests/e2e/lint-config/invalid-config-assertation-name/snapshot.txt rename to tests/e2e/lint-config/invalid-custom-rule-config/snapshot.txt index 11b76c047f..00c698989c 100644 --- a/tests/e2e/lint-config/invalid-config-assertation-name/snapshot.txt +++ b/tests/e2e/lint-config/invalid-custom-rule-config/snapshot.txt @@ -1,13 +1,12 @@ -[1] redocly.yaml:6:3 at #/rules/asset~1path-item-mutually-required +[1] redocly.yaml:2:3 at #/rules/my-plugin~1lacks-severity The field `severity` must be present on this level. +1 | rules: +2 | my-plugin/lacks-severity: + | ^^^^^^^^^^^^^^^^^^^^^^^^ +3 | key: value 4 | -5 | rules: -6 | asset/path-item-mutually-required: - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -7 | context: -8 | - type: PathItem Warning was generated by the configuration struct rule. @@ -19,5 +18,5 @@ validating ../__fixtures__/valid-openapi.yaml... Woohoo! Your API description is valid. 🎉 -[WARNING] Unused rules found in redocly.yaml: asset/path-item-mutually-required. +[WARNING] Unused rules found in redocly.yaml: my-plugin/lacks-severity. Check the spelling and verify the added plugin prefix. diff --git a/tests/e2e/lint-config/invalid-definition-and-config/config-with-error.snapshot.txt b/tests/e2e/lint-config/invalid-definition-and-config/config-with-error.snapshot.txt index 655a32046a..55fffaed1e 100644 --- a/tests/e2e/lint-config/invalid-definition-and-config/config-with-error.snapshot.txt +++ b/tests/e2e/lint-config/invalid-definition-and-config/config-with-error.snapshot.txt @@ -1,13 +1,12 @@ -[1] redocly.yaml:6:3 at #/rules/context +[1] redocly.yaml:2:3 at #/rules/context Property `context` is not expected here. -4 | -5 | rules: -6 | context: +1 | rules: +2 | context: | ^^^^^^^^ -7 | -8 | extends: +3 | +4 | extends: Error was generated by the configuration struct rule. diff --git a/tests/e2e/lint-config/invalid-definition-and-config/config-with-warn.snapshot.txt b/tests/e2e/lint-config/invalid-definition-and-config/config-with-warn.snapshot.txt index 9812cba2de..e8f7b5b5ae 100644 --- a/tests/e2e/lint-config/invalid-definition-and-config/config-with-warn.snapshot.txt +++ b/tests/e2e/lint-config/invalid-definition-and-config/config-with-warn.snapshot.txt @@ -1,13 +1,12 @@ -[1] redocly.yaml:6:3 at #/rules/context +[1] redocly.yaml:2:3 at #/rules/context Property `context` is not expected here. -4 | -5 | rules: -6 | context: +1 | rules: +2 | context: | ^^^^^^^^ -7 | -8 | extends: +3 | +4 | extends: Warning was generated by the configuration struct rule. diff --git a/tests/e2e/lint-config/invalid-definition-and-config/redocly.yaml b/tests/e2e/lint-config/invalid-definition-and-config/redocly.yaml index 76a7696425..b9d5ea753f 100644 --- a/tests/e2e/lint-config/invalid-definition-and-config/redocly.yaml +++ b/tests/e2e/lint-config/invalid-definition-and-config/redocly.yaml @@ -1,7 +1,3 @@ -apis: - main: - root: ./openapi.yaml - rules: context: diff --git a/tests/e2e/lint-config/lint-config.test.ts b/tests/e2e/lint-config/lint-config.test.ts index 2c19d2d38b..c0ba9486cc 100644 --- a/tests/e2e/lint-config/lint-config.test.ts +++ b/tests/e2e/lint-config/lint-config.test.ts @@ -13,7 +13,7 @@ describe('lint-config', () => { { dirName: 'invalid-config--lint-config-error', option: 'error' }, { dirName: 'invalid-lint-config-severity', option: 'something' }, { dirName: 'invalid-config--no-option', option: null }, - { dirName: 'invalid-config-assertation-name', option: 'warn' }, + { dirName: 'invalid-custom-rule-config', option: 'warn' }, { dirName: 'invalid-config-assertation-config-type', option: 'warn' }, { dirName: 'invalid-config-format-json', option: 'warn', format: 'json' }, { dirName: 'config-with-refs', option: 'warn' }, From 42e0fd90d53c39dd1b817ff5154b597148a7b4a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81=C4=99kawa?= <164185257+JLekawa@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:59:10 +0200 Subject: [PATCH 3/6] Apply suggestion from @JLekawa --- .changeset/orange-squids-fail.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/orange-squids-fail.md b/.changeset/orange-squids-fail.md index 7c7b889002..5522b6b9d9 100644 --- a/.changeset/orange-squids-fail.md +++ b/.changeset/orange-squids-fail.md @@ -3,4 +3,4 @@ "@redocly/cli": patch --- -Improved Redocly config validation by recognizing built-in decorator names. +Improved Redocly config validation: now the config checks for typos in built-in decorator names. From 6702cb286f877ad0f56783bff1d193d7613a01f5 Mon Sep 17 00:00:00 2001 From: Andrew Tatomyr Date: Tue, 28 Apr 2026 11:05:06 +0200 Subject: [PATCH 4/6] Update packages/core/src/types/redocly-yaml.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jacek Łękawa <164185257+JLekawa@users.noreply.github.com> --- packages/core/src/types/redocly-yaml.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts index dc18d7d7ca..a1b19a776a 100644 --- a/packages/core/src/types/redocly-yaml.ts +++ b/packages/core/src/types/redocly-yaml.ts @@ -461,7 +461,7 @@ const BuiltinPreprocessor: NodeType = { const CustomPreprocessor: NodeType = { properties: {}, additionalProperties: {}, - description: 'Custom preprocessors are defined by users via plugins.', + description: 'Custom preprocessors are defined by users via plugins. The available options are the same for decorators and preprocessors.', documentationLink: 'https://redocly.com/docs/cli/custom-plugins/custom-decorators', }; From d4c32d6da35d9b5cb2dd6b92efb5afe9e7347090 Mon Sep 17 00:00:00 2001 From: Andrew Tatomyr Date: Tue, 28 Apr 2026 12:15:19 +0300 Subject: [PATCH 5/6] fix test snapshots --- .../core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap | 2 +- packages/core/src/types/redocly-yaml.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap index 8ae658129c..fcee228736 100644 --- a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap @@ -536,7 +536,7 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`] }, "CustomPreprocessor": { "additionalProperties": {}, - "description": "Custom preprocessors are defined by users via plugins.", + "description": "Custom preprocessors are defined by users via plugins. The available options are the same for decorators and preprocessors.", "documentationLink": "https://redocly.com/docs/cli/custom-plugins/custom-decorators", "properties": {}, }, diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts index a1b19a776a..e48a9a4a40 100644 --- a/packages/core/src/types/redocly-yaml.ts +++ b/packages/core/src/types/redocly-yaml.ts @@ -461,7 +461,8 @@ const BuiltinPreprocessor: NodeType = { const CustomPreprocessor: NodeType = { properties: {}, additionalProperties: {}, - description: 'Custom preprocessors are defined by users via plugins. The available options are the same for decorators and preprocessors.', + description: + 'Custom preprocessors are defined by users via plugins. The available options are the same for decorators and preprocessors.', documentationLink: 'https://redocly.com/docs/cli/custom-plugins/custom-decorators', }; From 46f6d2bcb20470e900394a953e973ae0c7424c8f Mon Sep 17 00:00:00 2001 From: Andrew Tatomyr Date: Tue, 28 Apr 2026 12:21:47 +0300 Subject: [PATCH 6/6] fix test snapshots --- .../core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap | 2 +- packages/core/src/types/redocly-yaml.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap index fcee228736..d6006601f3 100644 --- a/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/redocly-yaml.test.ts.snap @@ -182,7 +182,7 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`] }, "BuiltinPreprocessor": { "additionalProperties": {}, - "description": "Built-in preprocessors are the default preprocessors included with Redocly CLI.", + "description": "Built-in preprocessors are the default preprocessors included with Redocly CLI. The available options are the same for decorators and preprocessors.", "documentationLink": "https://redocly.com/docs/cli/decorators#list-of-decorators", "properties": {}, }, diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts index e48a9a4a40..e1a4686f07 100644 --- a/packages/core/src/types/redocly-yaml.ts +++ b/packages/core/src/types/redocly-yaml.ts @@ -454,7 +454,8 @@ const Preprocessors: NodeType = { const BuiltinPreprocessor: NodeType = { properties: {}, additionalProperties: {}, - description: 'Built-in preprocessors are the default preprocessors included with Redocly CLI.', + description: + 'Built-in preprocessors are the default preprocessors included with Redocly CLI. The available options are the same for decorators and preprocessors.', documentationLink: 'https://redocly.com/docs/cli/decorators#list-of-decorators', };