feat: support rule/ as a prefix for configurable rules (#1062)

* feat: support rule/ as a prefix for configurable rules

* chore: Run prettier

* feat: Add a warning about use of the old syntax

* docs: update configurable rules doc to reflect updated rule/ notation

* Update packages/core/src/config/config-resolvers.ts

Co-authored-by: Andrew Tatomyr <andrew.tatomyr@redocly.com>

* chore: run prettier

* chore: move deprication warning inside config transformer

---------

Co-authored-by: Andrew Tatomyr <andrew.tatomyr@redocly.com>
This commit is contained in:
Lorna Jane Mitchell
2023-05-30 09:57:30 +01:00
committed by GitHub
parent 04ff9e53d7
commit 3e287a80eb
62 changed files with 377 additions and 352 deletions

View File

@@ -5,4 +5,4 @@ apis:
decorators: decorators:
plugin/resolve-x: on plugin/resolve-x: on
plugins: plugins:
- "./plugin.js" - './plugin.js'

View File

@@ -17,6 +17,8 @@ Error was generated by the configuration spec rule.
❌ Your config has 1 error. ❌ Your config has 1 error.
The 'assert/' syntax in assert/path-item-mutually-required is deprecated. Update your configuration to use 'rule/' instead. Examples and more information: https://redocly.com/docs/cli/rules/configurable-rules/
validating ../__fixtures__/valid-openapi.yaml... validating ../__fixtures__/valid-openapi.yaml...
../__fixtures__/valid-openapi.yaml: validated in <test>ms ../__fixtures__/valid-openapi.yaml: validated in <test>ms

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/path-item-mutually-required: rule/path-item-mutually-required:
subject: subject:
type: Operation type: Operation
assertions: assertions:

View File

@@ -5,7 +5,7 @@ apis:
plugins: plugins:
- ./plugin.js - ./plugin.js
rules: rules:
assert/minLength: rule/minLength:
subject: subject:
type: Schema type: Schema
assertions: assertions:

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/named-parameters-camelCase: rule/named-parameters-camelCase:
subject: subject:
type: NamedParameters type: NamedParameters
message: Parameters must use camelCase message: Parameters must use camelCase

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/operation-get: rule/operation-get:
subject: subject:
type: Operation type: Operation
filterInParentKeys: [get] filterInParentKeys: [get]
@@ -13,8 +13,7 @@ rules:
casing: camelCase casing: camelCase
message: Operation id for get operation should be camelCase message: Operation id for get operation should be camelCase
rule/operation-id-camel-case:
assert/operation-id-camel-case:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId
@@ -22,7 +21,7 @@ rules:
assertions: assertions:
casing: camelCase casing: camelCase
assert/camel-case-on-value: rule/camel-case-on-value:
subject: subject:
type: NamedParameters type: NamedParameters
assertions: assertions:

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/operation-get: rule/operation-get:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId
@@ -12,7 +12,7 @@ rules:
casing: kebab-case casing: kebab-case
message: Operation id should be kebab-case message: Operation id should be kebab-case
assert/operation-id-kebab-case: rule/operation-id-kebab-case:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/operation-get: rule/operation-get:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId
@@ -12,7 +12,7 @@ rules:
casing: PascalCase casing: PascalCase
message: Operation id should be PascalCase message: Operation id should be PascalCase
assert/operation-id-pascal-case: rule/operation-id-pascal-case:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/operation-id-pascal-case: rule/operation-id-pascal-case:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId
@@ -12,7 +12,7 @@ rules:
assertions: assertions:
casing: PascalCase casing: PascalCase
assert/operation-id-snake-case: rule/operation-id-snake-case:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId

View File

@@ -4,7 +4,7 @@ apis:
plugins: plugins:
- ./plugin.js - ./plugin.js
rules: rules:
assert/operation-summary-length-custom: rule/operation-summary-length-custom:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -25,8 +25,7 @@ rules:
local/checkWordsCount: local/checkWordsCount:
min: 3 min: 3
rule/operation-summary-length:
assert/operation-summary-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -46,7 +45,7 @@ rules:
local/checkWordsCount: local/checkWordsCount:
min: 3 min: 3
assert/operation-summary-length-with-where: rule/operation-summary-length-with-where:
where: where:
- subject: - subject:
type: Operation type: Operation

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/response-content-defined: rule/response-content-defined:
subject: subject:
type: Response type: Response
property: content property: content
@@ -11,7 +11,7 @@ rules:
message: Response content should be defined message: Response content should be defined
assertions: assertions:
defined: true defined: true
assert/operation-security: rule/operation-security:
subject: subject:
type: Operation type: Operation
property: security property: security

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/operation-summary-value: rule/operation-summary-value:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/media-type-application-json: rule/media-type-application-json:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
message: Only application/json can be used message: Only application/json can be used

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/tag-description-pattern: rule/tag-description-pattern:
subject: subject:
type: Tag type: Tag
property: description property: description
@@ -13,21 +13,21 @@ rules:
minLength: 13 minLength: 13
pattern: /\.$/ pattern: /\.$/
# property example # property example
assert/path-item-get-defined: rule/path-item-get-defined:
subject: subject:
type: PathItem type: PathItem
property: get property: get
message: Every path item must have a GET operation. message: Every path item must have a GET operation.
assertions: assertions:
defined: true defined: true
assert/path-item-get-required: rule/path-item-get-required:
subject: subject:
type: PathItem type: PathItem
message: Every path item must have a GET(required) operation. message: Every path item must have a GET(required) operation.
assertions: assertions:
required: required:
- get - get
assert/tag-name-and-desc: rule/tag-name-and-desc:
subject: subject:
type: Tag type: Tag
property: property:
@@ -37,7 +37,7 @@ rules:
assertions: assertions:
defined: true defined: true
# context example # context example
assert/operation-w-context: rule/operation-w-context:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
where: where:
@@ -57,7 +57,7 @@ rules:
message: Media type should not be pdf message: Media type should not be pdf
# enum example # enum example
assert/media-type-pdf: rule/media-type-pdf:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
message: Only application/pdf can be used message: Only application/pdf can be used
@@ -65,7 +65,7 @@ rules:
assertions: assertions:
enum: enum:
- application/pdf - application/pdf
assert/operation-summary-suggest: rule/operation-summary-suggest:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -79,7 +79,7 @@ rules:
- My resource - My resource
- My collection - My collection
# pattern example # pattern example
assert/operation-summary-pattern: rule/operation-summary-pattern:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -88,7 +88,7 @@ rules:
assertions: assertions:
pattern: /resource/ pattern: /resource/
# casing # casing
assert/operation-id-camel-case: rule/operation-id-camel-case:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId
@@ -97,17 +97,17 @@ rules:
assertions: assertions:
casing: camelCase casing: camelCase
# mutuallyExclusive example # mutuallyExclusive example
assert/operation-mutually-exclusive: rule/operation-mutually-exclusive:
subject: subject:
type: Operation type: Operation
message: "Operation must not define both properties together: description and externalDocs" message: 'Operation must not define both properties together: description and externalDocs'
severity: error severity: error
assertions: assertions:
mutuallyExclusive: mutuallyExclusive:
- description - description
- externalDocs - externalDocs
# mutuallyRequired example # mutuallyRequired example
assert/operation-mutually-required: rule/operation-mutually-required:
subject: subject:
type: SchemaProperties type: SchemaProperties
where: where:
@@ -122,7 +122,7 @@ rules:
- created_at - created_at
- updated_at - updated_at
# mutuallyRequired example with context # mutuallyRequired example with context
assert/operation-mutually-required-w-context: rule/operation-mutually-required-w-context:
subject: subject:
type: Responses type: Responses
where: where:
@@ -139,7 +139,7 @@ rules:
- '200' - '200'
- '201' - '201'
# disallowed example # disallowed example
assert/operation-disallowed: rule/operation-disallowed:
subject: subject:
type: Operation type: Operation
message: x-code-samples and x-internal must not be defined message: x-code-samples and x-internal must not be defined
@@ -149,7 +149,7 @@ rules:
- x-code-samples - x-code-samples
- x-internal - x-internal
# defined example # defined example
assert/operation-x-code-samples-defined: rule/operation-x-code-samples-defined:
subject: subject:
type: Operation type: Operation
property: x-codeSamples property: x-codeSamples
@@ -158,7 +158,7 @@ rules:
assertions: assertions:
defined: true defined: true
# undefined example # undefined example
assert/operation-x-code-samples-undefined: rule/operation-x-code-samples-undefined:
subject: subject:
type: Operation type: Operation
property: x-code-samples property: x-code-samples
@@ -169,7 +169,7 @@ rules:
assertions: assertions:
defined: false defined: false
# nonEmpty example # nonEmpty example
assert/operation-summary-non-empty: rule/operation-summary-non-empty:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -178,7 +178,7 @@ rules:
assertions: assertions:
nonEmpty: true nonEmpty: true
# minLength example # minLength example
assert/operation-summary-min-length: rule/operation-summary-min-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -187,7 +187,7 @@ rules:
assertions: assertions:
minLength: 2 minLength: 2
# maxLength example # maxLength example
assert/operation-summary-max-length: rule/operation-summary-max-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -196,7 +196,7 @@ rules:
assertions: assertions:
maxLength: 2 maxLength: 2
# Example map subject example # Example map subject example
assert/exampleMap: rule/exampleMap:
subject: subject:
type: ExamplesMap type: ExamplesMap
message: Examples names must use camelCase message: Examples names must use camelCase
@@ -204,7 +204,7 @@ rules:
casing: camelCase casing: camelCase
severity: error severity: error
# any subject type example # any subject type example
assert/anyType: rule/anyType:
subject: subject:
type: any type: any
property: description property: description

View File

@@ -4,19 +4,19 @@ apis:
extends: [] extends: []
rules: rules:
assert/TagList: rule/TagList:
subject: subject:
type: TagList type: TagList
assertions: assertions:
defined: false defined: false
assert/ServerList: rule/ServerList:
subject: subject:
type: ServerList type: ServerList
assertions: assertions:
maxLength: 0 maxLength: 0
assert/SecurityRequirementList: rule/SecurityRequirementList:
subject: subject:
type: SecurityRequirementList type: SecurityRequirementList
assertions: assertions:

View File

@@ -3,32 +3,32 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/headerMap: rule/headerMap:
subject: subject:
type: HeadersMap type: HeadersMap
property: x-next property: x-next
assertions: assertions:
defined: false defined: false
assert/encodingMap: rule/encodingMap:
subject: subject:
type: EncodingMap type: EncodingMap
assertions: assertions:
casing: kebab-case casing: kebab-case
assert/linkMap: rule/linkMap:
subject: subject:
type: LinksMap type: LinksMap
assertions: assertions:
pattern: /^pet/ pattern: /^pet/
assert/serverVariableMap: rule/serverVariableMap:
subject: subject:
type: ServerVariablesMap type: ServerVariablesMap
assertions: assertions:
casing: flatcase casing: flatcase
assert/callbackMap: rule/callbackMap:
subject: subject:
type: CallbacksMap type: CallbacksMap
assertions: assertions:

View File

@@ -2,7 +2,7 @@ apis:
main: main:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/match-parent-keys-with-defined: rule/match-parent-keys-with-defined:
subject: subject:
type: Operation type: Operation
matchParentKeys: /^p/ matchParentKeys: /^p/
@@ -11,7 +11,7 @@ rules:
defined: true defined: true
const: true const: true
assert/match-parent-keys-example-without-defined: rule/match-parent-keys-example-without-defined:
subject: subject:
type: Operation type: Operation
matchParentKeys: /^p/ matchParentKeys: /^p/

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/tags-max-length: rule/tags-max-length:
subject: subject:
type: Operation type: Operation
property: tags property: tags

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/description-max-length: rule/description-max-length:
subject: subject:
type: Info type: Info
property: description property: description

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/tags-min-length: rule/tags-min-length:
subject: subject:
type: Operation type: Operation
property: tags property: tags

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/description-min-length: rule/description-min-length:
subject: subject:
type: Info type: Info
property: description property: description

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/path-item-mutually-exclusive: rule/path-item-mutually-exclusive:
where: where:
- subject: - subject:
type: PathItem type: PathItem

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/path-item-mutually-required: rule/path-item-mutually-required:
where: where:
- subject: - subject:
type: PathItem type: PathItem

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/summary-non-empty: rule/summary-non-empty:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/summary-non-empty: rule/summary-non-empty:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/summary-non-empty: rule/summary-non-empty:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/summary-pattern: rule/summary-pattern:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -2,7 +2,7 @@ apis:
main: main:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/no-description-future-past: rule/no-description-future-past:
subject: subject:
type: any type: any
property: description property: description

View File

@@ -2,7 +2,7 @@ apis:
main: main:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/query-in-parameters: rule/query-in-parameters:
where: where:
- subject: - subject:
type: Parameter type: Parameter

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/ref-forbidden: rule/ref-forbidden:
where: where:
- subject: - subject:
type: Response type: Response
@@ -15,7 +15,7 @@ rules:
message: Response MediaType schema should NOT have a ref message: Response MediaType schema should NOT have a ref
assertions: assertions:
ref: false ref: false
assert/ref-forbidden-no-property: rule/ref-forbidden-no-property:
subject: subject:
type: PathItem type: PathItem
message: PathItems should NOT should have a ref message: PathItems should NOT should have a ref

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/ref-pattern: rule/ref-pattern:
where: where:
- subject: - subject:
type: Response type: Response
@@ -15,7 +15,7 @@ rules:
message: Response MediaType schema should contain ref to components/schemas folder message: Response MediaType schema should contain ref to components/schemas folder
assertions: assertions:
ref: ^(\.\/)?components\/schemas\/.*\.yaml$ ref: ^(\.\/)?components\/schemas\/.*\.yaml$
assert/ref-pattern-no-properties: rule/ref-pattern-no-properties:
subject: subject:
type: PathItem type: PathItem
message: PathItem should contain ref to components/paths folder message: PathItem should contain ref to components/paths folder

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/ref-required: rule/ref-required:
where: where:
- subject: - subject:
type: Response type: Response
@@ -15,7 +15,7 @@ rules:
message: Response MediaType schema should have a ref message: Response MediaType schema should have a ref
assertions: assertions:
ref: true ref: true
assert/ref-required-no-property: rule/ref-required-no-property:
subject: subject:
type: PathItem type: PathItem
message: PathItems should have refs message: PathItems should have refs

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/operation-require-any-description-or-external: rule/operation-require-any-description-or-external:
subject: subject:
type: Operation type: Operation
message: 'Operation must have one of properties defined: description or externalDocs' message: 'Operation must have one of properties defined: description or externalDocs'

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/path-item-suggest: rule/path-item-suggest:
where: where:
- subject: - subject:
type: PathItem type: PathItem

View File

@@ -2,7 +2,7 @@ apis:
main: main:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/no-type-integer-in-parameter: rule/no-type-integer-in-parameter:
where: where:
- subject: - subject:
type: Parameter type: Parameter

View File

@@ -2,7 +2,7 @@ apis:
main: main:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/type-integer-in-schema-response: rule/type-integer-in-schema-response:
where: where:
- subject: - subject:
type: Operation type: Operation

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/summary-undefined: rule/summary-undefined:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/vendor-extension: rule/vendor-extension:
subject: subject:
type: SpecExtension type: SpecExtension
property: prop property: prop
@@ -11,7 +11,7 @@ rules:
severity: error severity: error
assertions: assertions:
enum: [foo, bar] enum: [foo, bar]
assert/vendor-extension-in-info-section: rule/vendor-extension-in-info-section:
subject: subject:
type: SpecExtension type: SpecExtension
property: prop2 property: prop2
@@ -26,7 +26,7 @@ rules:
enum: [foo, bar] enum: [foo, bar]
# built-in vendor extension should be processed as generic SpecExtension too # built-in vendor extension should be processed as generic SpecExtension too
# assert/vendor-extension-built-in: # rule/vendor-extension-built-in:
# subject: # subject:
# type: SpecExtension # type: SpecExtension
# filterInParentKeys: ['x-logo'] # filterInParentKeys: ['x-logo']

View File

@@ -3,7 +3,7 @@ apis:
root: ./openapi.yaml root: ./openapi.yaml
rules: rules:
assert/tag-description: rule/tag-description:
subject: subject:
type: Tag type: Tag
property: description property: description
@@ -13,21 +13,21 @@ rules:
minLength: 13 minLength: 13
pattern: /\.$/ pattern: /\.$/
# property example # property example
assert/path-item-get-defined: rule/path-item-get-defined:
subject: subject:
type: PathItem type: PathItem
property: get property: get
message: Every path item must have a GET operation. message: Every path item must have a GET operation.
assertions: assertions:
defined: true defined: true
assert/path-item-get-required: rule/path-item-get-required:
subject: subject:
type: PathItem type: PathItem
message: Every path item must have a GET operation. message: Every path item must have a GET operation.
assertions: assertions:
required: required:
- get - get
assert/tag-name-and-desc: rule/tag-name-and-desc:
subject: subject:
type: Tag type: Tag
property: property:
@@ -38,7 +38,7 @@ rules:
defined: true defined: true
# context example # context example
assert/media-type-map-not-pdf: rule/media-type-map-not-pdf:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
assertions: assertions:
@@ -59,7 +59,7 @@ rules:
defined: true defined: true
# enum example # enum example
assert/media-type-map-enum: rule/media-type-map-enum:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
message: Only application/json and application/pdf can be used message: Only application/json and application/pdf can be used
@@ -69,7 +69,7 @@ rules:
- application/json - application/json
- application/pdf - application/pdf
assert/operation-summary-suggest: rule/operation-summary-suggest:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -84,7 +84,7 @@ rules:
- My collection - My collection
# pattern example # pattern example
assert/operation-summary-pattern: rule/operation-summary-pattern:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -93,7 +93,7 @@ rules:
assertions: assertions:
pattern: /resource/ pattern: /resource/
# casing # casing
assert/operation-id-casing: rule/operation-id-casing:
subject: subject:
type: Operation type: Operation
property: operationId property: operationId
@@ -102,7 +102,7 @@ rules:
assertions: assertions:
casing: camelCase casing: camelCase
# mutuallyExclusive example # mutuallyExclusive example
assert/operation-mutually-exclusive: rule/operation-mutually-exclusive:
subject: subject:
type: Operation type: Operation
message: 'Operation must not define both properties together: description and externalDocs' message: 'Operation must not define both properties together: description and externalDocs'
@@ -112,7 +112,7 @@ rules:
- description - description
- externalDocs - externalDocs
# mutuallyRequired example # mutuallyRequired example
assert/schema-properties-mutually-required: rule/schema-properties-mutually-required:
subject: subject:
type: SchemaProperties type: SchemaProperties
assertions: assertions:
@@ -129,7 +129,7 @@ rules:
defined: true defined: true
# mutuallyRequired example with context # mutuallyRequired example with context
assert/response-map-required-with-context: rule/response-map-required-with-context:
subject: subject:
type: Responses type: Responses
assertions: assertions:
@@ -147,7 +147,7 @@ rules:
severity: error severity: error
# requireAny example # requireAny example
assert/operation-require-any-description-or-external: rule/operation-require-any-description-or-external:
subject: subject:
type: Operation type: Operation
message: 'Operation must have one of properties defined: description or externalDocs' message: 'Operation must have one of properties defined: description or externalDocs'
@@ -158,7 +158,7 @@ rules:
- externalDocs - externalDocs
# disallowed example # disallowed example
assert/operation-disallowed: rule/operation-disallowed:
subject: subject:
type: Operation type: Operation
message: x-code-samples and x-internal must not be defined message: x-code-samples and x-internal must not be defined
@@ -169,7 +169,7 @@ rules:
- x-internal - x-internal
# defined example # defined example
assert/operation-defined: rule/operation-defined:
subject: subject:
type: Operation type: Operation
property: x-codeSamples property: x-codeSamples
@@ -179,7 +179,7 @@ rules:
defined: true defined: true
# nonEmpty example # nonEmpty example
assert/operation-non-empty: rule/operation-non-empty:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -189,7 +189,7 @@ rules:
nonEmpty: true nonEmpty: true
# minLength example # minLength example
assert/operation-min-length: rule/operation-min-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -199,7 +199,7 @@ rules:
minLength: 2 minLength: 2
# maxLength example # maxLength example
assert/operation-max-length: rule/operation-max-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -209,7 +209,7 @@ rules:
maxLength: 20 maxLength: 20
# ref example # ref example
assert/ref: rule/ref:
subject: subject:
type: PathItem type: PathItem
message: No refs on Path Items message: No refs on Path Items

View File

@@ -11,18 +11,18 @@ Configure flexible rules to meet any situation not covered by the [built-in rule
```yaml ```yaml
rules: rules:
assert/assertion-name: rule/my-rule-name:
... ...
assert/one-more-assertion-name: rule/one-more-rule-name:
... ...
``` ```
A configurable rule describes the contents that the linter expects to find in your API definition. During the validation process, the linter goes through your API definition and checks if its contents match the expectations. If something was described in an assertion, but the API definition doesn't correspond to the description, the linter shows you a warning or error message in the log. A configurable rule describes the contents that the linter expects to find in your API definition. During the validation process, the linter goes through your API definition and checks if its contents match the expectations. If something was described in a configurable rule, but the API definition doesn't correspond to the description, the linter shows you a warning or error message in the log.
Pattern Property | Type | Description Pattern Property | Type | Description
-- | -- | -- -- | -- | --
assert/{string} | [Configurable rule object](#configurable-rule-object) | Configurable rule definitions enforce your custom API design standards. Add or edit your configurable rules in the configuration file. A configurable rule is a rule that starts with a `assert/` prefix followed by a unique rule name. Rule names display in the lint log if the assertions fail. More than one assertion may be defined, and any configurable rule may have multiple assertions. rule/{string} | [Configurable rule object](#configurable-rule-object) | Configurable rule definitions enforce your custom API design standards. Add or edit your configurable rules in the configuration file. A configurable rule is a rule that starts with a `rule/` prefix followed by a unique rule name. Rule names display in the lint log if the assertions fail. More than one configurable rule may be defined, and any configurable rule may have multiple assertions.
## Configurable rule object ## Configurable rule object
@@ -87,7 +87,7 @@ Without the `where`, the assertion would evaluate every `MediaTypesMap` property
To restrict the evaluation, use the `where` feature to limit what is evaluated. To restrict the evaluation, use the `where` feature to limit what is evaluated.
```yaml ```yaml
assert/no-pdf-in-ok-response: rule/no-pdf-in-ok-response:
where: where:
- subject: - subject:
type: Operation type: Operation
@@ -109,11 +109,11 @@ assert/no-pdf-in-ok-response:
- 'application/pdf' - 'application/pdf'
``` ```
Where enables complex assertions based on sibling values. The `where` section enables complex assertions based on sibling values.
The following example asserts that the `limit` parameter must have a schema with `type: integer`. The following example asserts that the `limit` parameter must have a schema with `type: integer`.
```yaml ```yaml
assert/limit-is-integer: rule/limit-is-integer:
subject: subject:
type: Schema type: Schema
property: type property: type
@@ -145,7 +145,7 @@ The following example shows how to configure those assertions:
```yaml ```yaml
rules: rules:
assert/tag-description: rule/tag-description:
subject: subject:
type: Tag type: Tag
property: description property: description
@@ -154,7 +154,7 @@ rules:
minLength: 30 minLength: 30
pattern: /\.$/ pattern: /\.$/
message: Tag description must be at least 30 characters and end with a full stop. message: Tag description must be at least 30 characters and end with a full stop.
assert/operation-description: rule/operation-description:
subject: subject:
type: Operation type: Operation
property: description property: description
@@ -164,7 +164,7 @@ rules:
pattern: /\.$/ pattern: /\.$/
message: Operation description must be at least 30 characters and end with a full stop. message: Operation description must be at least 30 characters and end with a full stop.
severity: warn severity: warn
assert/info-description: rule/info-description:
subject: subject:
type: Info type: Info
property: description property: description
@@ -173,7 +173,7 @@ rules:
minLength: 30 minLength: 30
pattern: /\.$/ pattern: /\.$/
message: Info description must be at least 30 characters and end with a full stop. message: Info description must be at least 30 characters and end with a full stop.
assert/operation-summary: rule/operation-summary:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -212,7 +212,7 @@ location | `Location Object` | Location in the source document. See [Location Ob
`.redocly.yaml` `.redocly.yaml`
```yaml ```yaml
assert/operation-summary-check: rule/operation-summary-check:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -273,7 +273,7 @@ The following example asserts the casing style is `PascalCase` for `NamedExample
```yaml ```yaml
rules: rules:
assert/named-examples-pascal-case: rule/named-examples-pascal-case:
subject: subject:
type: NamedExamples type: NamedExamples
assertions: assertions:
@@ -295,7 +295,7 @@ The following example asserts that only `application/json` can be used as a key
```yaml keys ```yaml keys
rules: rules:
assert/media-type-map-application-json: rule/media-type-map-application-json:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
assertions: assertions:
@@ -309,7 +309,7 @@ The following example asserts that `x-codeSamples` is defined.
```yaml ```yaml
rules: rules:
assert/x-code-samples-defined: rule/x-code-samples-defined:
subject: subject:
type: Operation type: Operation
property: x-codeSamples property: x-codeSamples
@@ -321,7 +321,7 @@ The following example asserts that `x-code-samples` is undefined.
```yaml ```yaml
rules: rules:
assert/x-code-samples-undefined: rule/x-code-samples-undefined:
subject: subject:
type: Operation type: Operation
property: x-code-samples property: x-code-samples
@@ -337,7 +337,7 @@ The following example asserts that `x-code-samples` and `x-internal` are not def
```yaml ```yaml
rules: rules:
assert/no-x-code-samples-and-x-internal: rule/no-x-code-samples-and-x-internal:
subject: subject:
type: Operation type: Operation
assertions: assertions:
@@ -353,7 +353,7 @@ It has the same effect as the `const` assertion.
```yaml keys ```yaml keys
rules: rules:
assert/media-type-map-application-json: rule/media-type-map-application-json:
subject: subject:
type: MediaTypesMap type: MediaTypesMap
assertions: assertions:
@@ -366,7 +366,7 @@ The following example asserts that the operation summary must match one of the l
```yaml values ```yaml values
rules: rules:
assert/operation-summary-match: rule/operation-summary-match:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -386,7 +386,7 @@ The following example asserts that the maximum length of each operation summary
```yaml ```yaml
rules: rules:
assert/operation-summary-max-length: rule/operation-summary-max-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -401,7 +401,7 @@ The following example asserts that the minimum length of each operation summary
```yaml ```yaml
rules: rules:
assert/operation-summary-min-length: rule/operation-summary-min-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -417,7 +417,7 @@ This assertion evaluates only property keys for the node, but not property value
```yaml ```yaml
rules: rules:
assert/operation-no-both-description-and-external-docs: rule/operation-no-both-description-and-external-docs:
subject: subject:
type: Operation type: Operation
assertions: assertions:
@@ -433,7 +433,7 @@ This assertion evaluates only property keys for the node, but not property value
```yaml Schema example ```yaml Schema example
rules: rules:
assert/schema-properties-both-created-at-and-updated-at: rule/schema-properties-both-created-at-and-updated-at:
subject: subject:
type: SchemaProperties type: SchemaProperties
assertions: assertions:
@@ -446,7 +446,7 @@ The following example asserts that when `PUT` requests have either `200` or `201
```yaml Response example ```yaml Response example
rules: rules:
assert/put-200-and-201: rule/put-200-and-201:
subject: subject:
type: Responses type: Responses
where: where:
@@ -469,7 +469,7 @@ The following example asserts that the operation summary is not empty.
```yaml ```yaml
rules: rules:
assert/operation-summary-non-empty: rule/operation-summary-non-empty:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -483,7 +483,7 @@ The following example asserts that the operation summary doesn't start with "The
```yaml ```yaml
rules: rules:
assert/operation-summary-contains-test: rule/operation-summary-contains-test:
subject: subject:
type: Operation type: Operation
property: The summary property: The summary
@@ -497,7 +497,7 @@ The following example asserts that the operation summary contains "test".
```yaml ```yaml
rules: rules:
assert/operation-summary-contains-test: rule/operation-summary-contains-test:
subject: subject:
type: Operation type: Operation
property: summary property: summary
@@ -511,7 +511,7 @@ The following example asserts that schema in MediaType contains a Reference obje
```yaml ```yaml
rules: rules:
assert/mediatype-schema-has-ref: rule/mediatype-schema-has-ref:
subject: subject:
type: MediaType type: MediaType
property: schema property: schema
@@ -523,7 +523,7 @@ Also, you can specify a Regular Expression to check if the reference object conf
```yaml ```yaml
rules: rules:
assert/mediatype-schema-ref-pattern: rule/mediatype-schema-ref-pattern:
subject: subject:
type: MediaType type: MediaType
property: schema property: schema
@@ -540,7 +540,7 @@ The difference between `mutuallyRequired` is that neither `200` and `201` need t
```yaml Response example ```yaml Response example
rules: rules:
assert/put-200-and-201: rule/put-200-and-201:
subject: subject:
type: Responses type: Responses
where: where:
@@ -564,7 +564,7 @@ This assertion evaluates only property keys for the node, but not property value
```yaml Response example ```yaml Response example
rules: rules:
assert/operation-no-both-description-and-external-docs: rule/operation-no-both-description-and-external-docs:
subject: subject:
type: Operation type: Operation
assertions: assertions:
@@ -587,7 +587,7 @@ The following example asserts that the maximum length of each description is 20
```yaml ```yaml
rules: rules:
assert/description-max-length: rule/description-max-length:
subject: subject:
type: any type: any
property: description property: description
@@ -602,7 +602,7 @@ The following example asserts that every path item has a GET operation defined.
```yaml ```yaml
rules: rules:
assert/path-item-get-operation-defined: rule/path-item-get-operation-defined:
subject: subject:
type: PathItem type: PathItem
property: get property: get
@@ -615,7 +615,7 @@ Notice we don't need to include `property` in this approach.
```yaml ```yaml
rules: rules:
assert/path-item-operation-required: rule/path-item-operation-required:
subject: subject:
type: PathItem type: PathItem
assertions: assertions:
@@ -628,7 +628,7 @@ The following example asserts that Tags have both name and description defined.
```yaml ```yaml
rules: rules:
assert/tag-name-and-desc-defined: rule/tag-name-and-desc-defined:
subject: subject:
type: Tag type: Tag
property: property:
@@ -643,7 +643,7 @@ Another way to compose that rule is to require the subject keys:
```yaml ```yaml
rules: rules:
assert/tag-name-and-desc-required: rule/tag-name-and-desc-required:
subject: subject:
type: Tag type: Tag
assertions: assertions:

View File

@@ -60,7 +60,7 @@ describe('lint', () => {
no-invalid-media-type-examples: error no-invalid-media-type-examples: error
path-http-verbs-order: error path-http-verbs-order: error
boolean-parameter-prefixes: off boolean-parameter-prefixes: off
assert/operation-summary-length: rule/operation-summary-length:
subject: subject:
type: Operation type: Operation
property: summary property: summary

View File

@@ -2,7 +2,7 @@ plugins:
- plugin.js - plugin.js
rules: rules:
operation-2xx-response: error operation-2xx-response: error
assert/path-item-get-defined: rule/path-item-get-defined:
subject: PathItem subject: PathItem
property: get property: get
message: Every path item must have a GET operation. message: Every path item must have a GET operation.

View File

@@ -1,7 +1,7 @@
rules: rules:
no-invalid-media-type-examples: warn no-invalid-media-type-examples: warn
operation-4xx-response: off operation-4xx-response: off
assert/tag-description: rule/tag-description:
subject: subject:
type: Tag type: Tag
property: description property: description

View File

@@ -1,7 +1,7 @@
rules: rules:
no-invalid-media-type-examples: warn no-invalid-media-type-examples: warn
operation-4xx-response: off operation-4xx-response: off
assert/tag-description: rule/tag-description:
subject: Tag subject: Tag
property: description property: description
message: Tag description must be at least 13 characters and end with a full stop. message: Tag description must be at least 13 characters and end with a full stop.

View File

@@ -1,7 +1,7 @@
rules: rules:
no-invalid-media-type-examples: warn no-invalid-media-type-examples: warn
operation-4xx-response: off operation-4xx-response: off
assert/tag-description: rule/tag-description:
subject: Tag subject: Tag
property: description property: description
message: Tag description must have at least 3 words. message: Tag description must have at least 3 words.

View File

@@ -414,7 +414,13 @@ function groupStyleguideAssertionRules({
// Collect assertion rules // Collect assertion rules
const assertions: Assertion[] = []; const assertions: Assertion[] = [];
for (const [ruleKey, rule] of Object.entries(rules)) { for (const [ruleKey, rule] of Object.entries(rules)) {
if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) { // keep the old assert/ syntax as an alias
if (
(ruleKey.startsWith('rule/') || ruleKey.startsWith('assert/')) &&
typeof rule === 'object' &&
rule !== null
) {
const assertion = rule as RawAssertion; const assertion = rule as RawAssertion;
if (plugins) { if (plugins) {
@@ -427,7 +433,7 @@ function groupStyleguideAssertionRules({
} }
assertions.push({ assertions.push({
...assertion, ...assertion,
assertionId: ruleKey.replace('assert/', ''), assertionId: ruleKey.replace(/rule\/|assert\//, ''),
}); });
} else { } else {
// If it's not an assertion, keep it as is // If it's not an assertion, keep it as is

View File

@@ -291,7 +291,7 @@ export function transformConfig(
const { styleguideConfig, rawConfigRest } = extractFlatConfig(rest); const { styleguideConfig, rawConfigRest } = extractFlatConfig(rest);
return { const transformedConfig: RawConfig = {
theme: { theme: {
openapi: { openapi: {
...referenceDocs, ...referenceDocs,
@@ -307,6 +307,22 @@ export function transformConfig(
styleguide: styleguideConfig || lint, styleguide: styleguideConfig || lint,
...rawConfigRest, ...rawConfigRest,
}; };
showDeprecationMessages(transformedConfig);
return transformedConfig;
}
function showDeprecationMessages(config: RawConfig) {
let allRules = { ...config.styleguide?.rules };
for (const api of Object.values(config.apis || {})) {
allRules = { ...allRules, ...api?.styleguide?.rules };
}
for (const ruleKey of Object.keys(allRules)) {
if (ruleKey.startsWith('assert/')) {
logger.warn(
`\nThe 'assert/' syntax in ${ruleKey} is deprecated. Update your configuration to use 'rule/' instead. Examples and more information: https://redocly.com/docs/cli/rules/configurable-rules/\n`
);
}
}
} }
export function getResolveConfig(resolve?: RawResolveConfig): ResolveConfig { export function getResolveConfig(resolve?: RawResolveConfig): ResolveConfig {

View File

@@ -225,7 +225,10 @@ const ConfigRootTheme: NodeType = {
const Rules: NodeType = { const Rules: NodeType = {
properties: {}, properties: {},
additionalProperties: (value: unknown, key: string) => { additionalProperties: (value: unknown, key: string) => {
if (key.startsWith('assert/')) { if (key.startsWith('rule/')) {
return 'Assert';
} else if (key.startsWith('assert/')) {
// keep the old assert/ prefix as an alias
return 'Assert'; return 'Assert';
} else if (builtInRulesList.includes(key) || isCustomRuleId(key)) { } else if (builtInRulesList.includes(key) || isCustomRuleId(key)) {
if (typeof value === 'string') { if (typeof value === 'string') {