@amritk/lint 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/AI.md +55 -0
  2. package/dist/core/document.js +12 -10
  3. package/dist/core/formats.js +10 -13
  4. package/dist/core/glob.js +96 -118
  5. package/dist/core/index.d.ts +0 -1
  6. package/dist/core/index.js +30 -11
  7. package/dist/core/jsonpath.js +487 -561
  8. package/dist/core/lint.js +78 -85
  9. package/dist/core/plugin.js +21 -29
  10. package/dist/core/pointers.js +107 -151
  11. package/dist/core/ruleset.js +0 -0
  12. package/dist/core/runner.js +214 -272
  13. package/dist/core/types.js +4 -1
  14. package/dist/core/validate-ruleset.js +98 -112
  15. package/dist/fix/apply.d.ts +1 -1
  16. package/dist/fix/apply.js +58 -96
  17. package/dist/fix/index.js +7 -2
  18. package/dist/fix/plugin.js +15 -20
  19. package/dist/fix/types.d.ts +1 -1
  20. package/dist/functions/alphabetical.d.ts +1 -1
  21. package/dist/functions/alphabetical.js +39 -50
  22. package/dist/functions/casing.d.ts +1 -1
  23. package/dist/functions/casing.js +39 -45
  24. package/dist/functions/defined.d.ts +1 -1
  25. package/dist/functions/defined.js +7 -5
  26. package/dist/functions/enumeration.d.ts +1 -1
  27. package/dist/functions/enumeration.js +15 -25
  28. package/dist/functions/falsy.d.ts +1 -1
  29. package/dist/functions/falsy.js +7 -5
  30. package/dist/functions/index.d.ts +1 -1
  31. package/dist/functions/index.js +60 -44
  32. package/dist/functions/length.d.ts +1 -1
  33. package/dist/functions/length.js +22 -32
  34. package/dist/functions/or.d.ts +1 -1
  35. package/dist/functions/or.js +18 -24
  36. package/dist/functions/pattern.d.ts +1 -1
  37. package/dist/functions/pattern.js +39 -49
  38. package/dist/functions/schema.d.ts +1 -1
  39. package/dist/functions/schema.js +93 -119
  40. package/dist/functions/truthy.d.ts +1 -1
  41. package/dist/functions/truthy.js +7 -5
  42. package/dist/functions/typed-enum.d.ts +1 -1
  43. package/dist/functions/typed-enum.js +33 -36
  44. package/dist/functions/undefined.d.ts +1 -1
  45. package/dist/functions/undefined.js +7 -8
  46. package/dist/functions/unreferenced-reusable-object.d.ts +1 -1
  47. package/dist/functions/unreferenced-reusable-object.js +35 -47
  48. package/dist/functions/xor.d.ts +1 -1
  49. package/dist/functions/xor.js +13 -16
  50. package/dist/index.d.ts +17 -4
  51. package/dist/index.js +149 -164
  52. package/dist/parsers/edit-model.js +316 -444
  53. package/dist/parsers/index.d.ts +1 -1
  54. package/dist/parsers/index.js +23 -19
  55. package/dist/parsers/json.js +39 -37
  56. package/dist/parsers/lines.js +23 -26
  57. package/dist/parsers/types.js +9 -7
  58. package/dist/parsers/yaml.js +137 -204
  59. package/dist/rules/openapi/fixers.js +166 -221
  60. package/dist/rules/openapi/formats.js +26 -27
  61. package/dist/rules/openapi/functions/example-validation.d.ts +1 -1
  62. package/dist/rules/openapi/functions/example-validation.js +98 -138
  63. package/dist/rules/openapi/functions/helpers.js +8 -10
  64. package/dist/rules/openapi/functions/index.d.ts +1 -1
  65. package/dist/rules/openapi/functions/index.js +98 -72
  66. package/dist/rules/openapi/functions/oas-additional-operations.d.ts +1 -1
  67. package/dist/rules/openapi/functions/oas-additional-operations.js +16 -22
  68. package/dist/rules/openapi/functions/oas-discriminator.d.ts +1 -1
  69. package/dist/rules/openapi/functions/oas-discriminator.js +24 -22
  70. package/dist/rules/openapi/functions/oas-example-external-value.d.ts +1 -1
  71. package/dist/rules/openapi/functions/oas-example-external-value.js +13 -21
  72. package/dist/rules/openapi/functions/oas-example-value.d.ts +1 -1
  73. package/dist/rules/openapi/functions/oas-example-value.js +24 -27
  74. package/dist/rules/openapi/functions/oas-mutually-exclusive.d.ts +1 -1
  75. package/dist/rules/openapi/functions/oas-mutually-exclusive.js +15 -19
  76. package/dist/rules/openapi/functions/oas-no-nullable.d.ts +1 -1
  77. package/dist/rules/openapi/functions/oas-no-nullable.js +13 -21
  78. package/dist/rules/openapi/functions/oas-op-form-data-consume-check.d.ts +1 -1
  79. package/dist/rules/openapi/functions/oas-op-form-data-consume-check.js +21 -19
  80. package/dist/rules/openapi/functions/oas-op-id-unique.d.ts +1 -1
  81. package/dist/rules/openapi/functions/oas-op-id-unique.js +27 -27
  82. package/dist/rules/openapi/functions/oas-op-params.d.ts +1 -1
  83. package/dist/rules/openapi/functions/oas-op-params.js +36 -42
  84. package/dist/rules/openapi/functions/oas-op-security-defined.d.ts +1 -1
  85. package/dist/rules/openapi/functions/oas-op-security-defined.js +40 -39
  86. package/dist/rules/openapi/functions/oas-op-success-response.d.ts +1 -1
  87. package/dist/rules/openapi/functions/oas-op-success-response.js +11 -13
  88. package/dist/rules/openapi/functions/oas-path-param.d.ts +1 -1
  89. package/dist/rules/openapi/functions/oas-path-param.js +75 -96
  90. package/dist/rules/openapi/functions/oas-schema-example-deprecated.d.ts +1 -1
  91. package/dist/rules/openapi/functions/oas-schema-example-deprecated.js +33 -40
  92. package/dist/rules/openapi/functions/oas-schema.d.ts +1 -1
  93. package/dist/rules/openapi/functions/oas-schema.js +9 -14
  94. package/dist/rules/openapi/functions/oas-server-name-unique.d.ts +1 -1
  95. package/dist/rules/openapi/functions/oas-server-name-unique.js +21 -19
  96. package/dist/rules/openapi/functions/oas-server-variables.d.ts +1 -1
  97. package/dist/rules/openapi/functions/oas-server-variables.js +45 -49
  98. package/dist/rules/openapi/functions/oas-tag-defined.d.ts +1 -1
  99. package/dist/rules/openapi/functions/oas-tag-defined.js +20 -20
  100. package/dist/rules/openapi/functions/oas-tag-kind.d.ts +1 -1
  101. package/dist/rules/openapi/functions/oas-tag-kind.js +16 -16
  102. package/dist/rules/openapi/functions/oas-tag-parent-defined.d.ts +1 -1
  103. package/dist/rules/openapi/functions/oas-tag-parent-defined.js +40 -43
  104. package/dist/rules/openapi/functions/oas-tags-unique.d.ts +1 -1
  105. package/dist/rules/openapi/functions/oas-tags-unique.js +18 -16
  106. package/dist/rules/openapi/functions/oas-unused-component.d.ts +1 -1
  107. package/dist/rules/openapi/functions/oas-unused-component.js +48 -58
  108. package/dist/rules/openapi/functions/ref-siblings.d.ts +1 -1
  109. package/dist/rules/openapi/functions/ref-siblings.js +13 -11
  110. package/dist/rules/openapi/index.d.ts +2 -1
  111. package/dist/rules/openapi/index.js +99 -117
  112. package/dist/rules/openapi/oas.d.ts +1 -1
  113. package/dist/rules/openapi/oas.js +524 -536
  114. package/dist/rules/openapi/schemas/index.js +17 -33
  115. package/dist/rules/openapi/schemas/oas20.json +1 -1592
  116. package/dist/rules/openapi/schemas/oas30.json +1 -1651
  117. package/dist/rules/openapi/schemas/oas31.json +1 -1412
  118. package/dist/rules/openapi/schemas/oas32.json +1 -1684
  119. package/package.json +11 -6
@@ -1,549 +1,537 @@
1
- // `query` is a fixed operation field from OpenAPI 3.2 onward. Including it in the
2
- // operation selectors is harmless on older versions (which never carry a `query`
3
- // operation) and lets the operation-scoped rules cover 3.2 `query` operations.
4
- const OPERATIONS = '$.paths[*][get,put,post,delete,options,head,patch,trace,query]';
5
- const WEBHOOK_OPERATIONS = '$.webhooks[*][get,put,post,delete,options,head,patch,trace,query]';
1
+ const OPERATIONS = "$.paths[*][get,put,post,delete,options,head,patch,trace,query]";
2
+ const WEBHOOK_OPERATIONS = "$.webhooks[*][get,put,post,delete,options,head,patch,trace,query]";
6
3
  const OPERATION_ID_URL_SAFE = "^[A-Za-z0-9-._~:/?#\\[\\]@!\\$&'()*+,;=]*$";
7
- // Matches every Schema Object that carries an inline `example` or `default` and
8
- // looks like a schema (it has a JSON Schema keyword), while skipping the
9
- // `properties`/`patternProperties` *maps* — whose keys can coincidentally be
10
- // named like schema keywords. A single filter given (rather than a `$..example^`
11
- // / `$..default^` union) keeps each schema node matched exactly once, so the
12
- // `oasSchemaExample` finding for a schema is never duplicated.
13
4
  const SCHEMA_EXAMPLE_GIVEN = "$..[?(@property !== 'properties' && @property !== 'patternProperties' && @ && (@.example !== void 0 || @.default !== void 0) && (@.type || @.enum || @.format || @.$ref || @.properties || @.items || @.allOf || @.anyOf || @.oneOf))]";
14
- /** Rules shared across OpenAPI v2 and v3. */
15
5
  const sharedRules = {
16
- 'contact-properties': {
17
- description: 'Contact object must have name, url, and email.',
18
- given: '$.info.contact',
19
- severity: 'warn',
20
- recommended: false,
21
- then: [
22
- { field: 'name', function: 'truthy' },
23
- { field: 'url', function: 'truthy' },
24
- { field: 'email', function: 'truthy' },
25
- ],
26
- },
27
- 'duplicated-entry-in-enum': {
28
- description: 'Enum values must not have duplicate entries.',
29
- given: '$..enum',
30
- severity: 'warn',
31
- then: { function: 'schema', functionOptions: { schema: { type: 'array', uniqueItems: true } } },
32
- },
33
- 'info-contact': {
34
- description: 'Info object must have a contact object.',
35
- given: '$.info',
36
- then: { field: 'contact', function: 'truthy' },
37
- },
38
- 'info-description': {
39
- description: 'Info object must have a description.',
40
- given: '$.info',
41
- then: { field: 'description', function: 'truthy' },
42
- },
43
- 'info-license': {
44
- description: 'Info object should have a license.',
45
- given: '$.info',
46
- severity: 'warn',
47
- recommended: false,
48
- then: { field: 'license', function: 'truthy' },
49
- },
50
- 'license-url': {
51
- description: 'License object should have a url.',
52
- given: '$.info.license',
53
- severity: 'warn',
54
- recommended: false,
55
- then: { field: 'url', function: 'truthy' },
56
- },
57
- 'no-$ref-siblings': {
58
- description: 'Sibling values alongside $ref are ignored.',
59
- // OpenAPI 3.1 (JSON Schema 2020-12) permits siblings next to `$ref`, so this
60
- // rule is gated to 2.0 / 3.0 — matching `spectral:oas`.
61
- formats: ['oas2', 'oas3_0'],
62
- given: '$..$ref^',
63
- severity: 'error',
64
- resolved: false,
65
- then: { function: 'refSiblings' },
66
- },
67
- 'no-eval-in-markdown': {
68
- description: 'Markdown descriptions must not contain "eval(".',
69
- // Spectral scans both `description` and `title` markdown fields.
70
- given: ['$..description', '$..title'],
71
- then: { function: 'pattern', functionOptions: { notMatch: 'eval\\(' } },
72
- },
73
- 'no-script-tags-in-markdown': {
74
- description: 'Markdown descriptions must not contain <script> tags.',
75
- given: ['$..description', '$..title'],
76
- then: { function: 'pattern', functionOptions: { notMatch: '<script' } },
77
- },
78
- 'openapi-tags': {
79
- description: 'Top-level tags should be present and non-empty.',
80
- given: '$.tags',
81
- severity: 'warn',
82
- recommended: false,
83
- then: { function: 'length', functionOptions: { min: 1 } },
84
- },
85
- 'openapi-tags-alphabetical': {
86
- description: 'Top-level tags should be in alphabetical order.',
87
- given: '$.tags',
88
- severity: 'warn',
89
- recommended: false,
90
- then: { function: 'alphabetical', functionOptions: { keyedBy: 'name' } },
91
- },
92
- 'openapi-tags-uniqueness': {
93
- description: 'Top-level tag names must be unique.',
94
- given: '$.tags',
95
- severity: 'error',
96
- then: { function: 'oasTagsUnique' },
97
- },
98
- 'operation-description': {
99
- description: 'Operation must have a description.',
100
- given: OPERATIONS,
101
- then: { field: 'description', function: 'truthy' },
102
- },
103
- 'operation-operationId': {
104
- description: 'Operation must have an operationId.',
105
- given: OPERATIONS,
106
- then: { field: 'operationId', function: 'truthy' },
107
- },
108
- 'operation-operationId-unique': {
109
- description: 'Every operationId must be unique.',
110
- given: '$.paths',
111
- severity: 'error',
112
- then: { function: 'oasOpIdUnique' },
113
- },
114
- 'operation-operationId-valid-in-url': {
115
- description: 'operationId must use URL-safe characters.',
116
- given: OPERATIONS,
117
- then: { field: 'operationId', function: 'pattern', functionOptions: { match: OPERATION_ID_URL_SAFE } },
118
- },
119
- 'operation-parameters': {
120
- description: 'Operation parameters must be unique and non-repeating.',
121
- given: '$.paths[*][*].parameters',
122
- then: { function: 'oasOpParams' },
123
- },
124
- 'operation-singular-tag': {
125
- description: 'Operation should have a single tag.',
126
- given: OPERATIONS,
127
- severity: 'warn',
128
- recommended: false,
129
- then: { field: 'tags', function: 'length', functionOptions: { max: 1 } },
130
- },
131
- 'operation-success-response': {
132
- description: 'Operation must have at least one 2xx or 3xx response.',
133
- given: OPERATIONS,
134
- then: { field: 'responses', function: 'oasOpSuccessResponse' },
135
- },
136
- 'operation-tags': {
137
- description: 'Operation must have non-empty tags.',
138
- given: OPERATIONS,
139
- then: { field: 'tags', function: 'truthy' },
140
- },
141
- 'operation-tag-defined': {
142
- description: 'Operation tags must be defined in the global tags list.',
143
- given: OPERATIONS,
144
- then: { function: 'oasTagDefined' },
145
- },
146
- 'path-declarations-must-exist': {
147
- description: 'Path parameter declarations must not be empty ({}).',
148
- given: '$.paths',
149
- then: { field: '@key', function: 'pattern', functionOptions: { notMatch: '{}' } },
150
- },
151
- 'path-keys-no-trailing-slash': {
152
- description: 'Path keys should not end with a slash.',
153
- given: '$.paths',
154
- then: { field: '@key', function: 'pattern', functionOptions: { notMatch: '.+\\/$' } },
155
- },
156
- 'path-not-include-query': {
157
- description: 'Path keys should not include query strings.',
158
- given: '$.paths',
159
- then: { field: '@key', function: 'pattern', functionOptions: { notMatch: '\\?' } },
160
- },
161
- 'path-params': {
162
- description: 'Path parameters must be defined and not duplicated.',
163
- given: '$.paths',
164
- severity: 'error',
165
- then: { function: 'oasPathParam' },
166
- },
167
- 'tag-description': {
168
- description: 'Tags should have a description.',
169
- given: '$.tags[*]',
170
- severity: 'warn',
171
- recommended: false,
172
- then: { field: 'description', function: 'truthy' },
173
- },
174
- 'typed-enum': {
175
- description: 'Enum values must respect the specified type.',
176
- given: '$..enum^',
177
- then: { function: 'typedEnum' },
178
- },
179
- 'array-items': {
180
- // Not part of `spectral:oas` — a Loupe extension. `type: array` without
181
- // `items` is valid in JSON Schema 2020-12 (OpenAPI 3.1/3.2), so this is gated
182
- // to the versions where `items` is genuinely required (2.0 and 3.0.x) to
183
- // avoid false positives on valid 3.1+ tuple/unconstrained-array schemas.
184
- description: 'Schemas of type array must define items (OpenAPI 2.0 / 3.0 only; Loupe extension).',
185
- formats: ['oas2', 'oas3_0'],
186
- given: "$..[?(@ && @.type === 'array')]",
187
- severity: 'error',
188
- then: { field: 'items', function: 'defined' },
189
- },
6
+ "contact-properties": {
7
+ description: "Contact object must have name, url, and email.",
8
+ given: "$.info.contact",
9
+ severity: "warn",
10
+ recommended: false,
11
+ then: [
12
+ { field: "name", function: "truthy" },
13
+ { field: "url", function: "truthy" },
14
+ { field: "email", function: "truthy" }
15
+ ]
16
+ },
17
+ "duplicated-entry-in-enum": {
18
+ description: "Enum values must not have duplicate entries.",
19
+ given: "$..enum",
20
+ severity: "warn",
21
+ then: { function: "schema", functionOptions: { schema: { type: "array", uniqueItems: true } } }
22
+ },
23
+ "info-contact": {
24
+ description: "Info object must have a contact object.",
25
+ given: "$.info",
26
+ then: { field: "contact", function: "truthy" }
27
+ },
28
+ "info-description": {
29
+ description: "Info object must have a description.",
30
+ given: "$.info",
31
+ then: { field: "description", function: "truthy" }
32
+ },
33
+ "info-license": {
34
+ description: "Info object should have a license.",
35
+ given: "$.info",
36
+ severity: "warn",
37
+ recommended: false,
38
+ then: { field: "license", function: "truthy" }
39
+ },
40
+ "license-url": {
41
+ description: "License object should have a url.",
42
+ given: "$.info.license",
43
+ severity: "warn",
44
+ recommended: false,
45
+ then: { field: "url", function: "truthy" }
46
+ },
47
+ "no-$ref-siblings": {
48
+ description: "Sibling values alongside $ref are ignored.",
49
+ // OpenAPI 3.1 (JSON Schema 2020-12) permits siblings next to `$ref`, so this
50
+ // rule is gated to 2.0 / 3.0 — matching `spectral:oas`.
51
+ formats: ["oas2", "oas3_0"],
52
+ given: "$..$ref^",
53
+ severity: "error",
54
+ resolved: false,
55
+ then: { function: "refSiblings" }
56
+ },
57
+ "no-eval-in-markdown": {
58
+ description: 'Markdown descriptions must not contain "eval(".',
59
+ // Spectral scans both `description` and `title` markdown fields.
60
+ given: ["$..description", "$..title"],
61
+ then: { function: "pattern", functionOptions: { notMatch: "eval\\(" } }
62
+ },
63
+ "no-script-tags-in-markdown": {
64
+ description: "Markdown descriptions must not contain <script> tags.",
65
+ given: ["$..description", "$..title"],
66
+ then: { function: "pattern", functionOptions: { notMatch: "<script" } }
67
+ },
68
+ "openapi-tags": {
69
+ description: "Top-level tags should be present and non-empty.",
70
+ given: "$.tags",
71
+ severity: "warn",
72
+ recommended: false,
73
+ then: { function: "length", functionOptions: { min: 1 } }
74
+ },
75
+ "openapi-tags-alphabetical": {
76
+ description: "Top-level tags should be in alphabetical order.",
77
+ given: "$.tags",
78
+ severity: "warn",
79
+ recommended: false,
80
+ then: { function: "alphabetical", functionOptions: { keyedBy: "name" } }
81
+ },
82
+ "openapi-tags-uniqueness": {
83
+ description: "Top-level tag names must be unique.",
84
+ given: "$.tags",
85
+ severity: "error",
86
+ then: { function: "oasTagsUnique" }
87
+ },
88
+ "operation-description": {
89
+ description: "Operation must have a description.",
90
+ given: OPERATIONS,
91
+ then: { field: "description", function: "truthy" }
92
+ },
93
+ "operation-operationId": {
94
+ description: "Operation must have an operationId.",
95
+ given: OPERATIONS,
96
+ then: { field: "operationId", function: "truthy" }
97
+ },
98
+ "operation-operationId-unique": {
99
+ description: "Every operationId must be unique.",
100
+ given: "$.paths",
101
+ severity: "error",
102
+ then: { function: "oasOpIdUnique" }
103
+ },
104
+ "operation-operationId-valid-in-url": {
105
+ description: "operationId must use URL-safe characters.",
106
+ given: OPERATIONS,
107
+ then: { field: "operationId", function: "pattern", functionOptions: { match: OPERATION_ID_URL_SAFE } }
108
+ },
109
+ "operation-parameters": {
110
+ description: "Operation parameters must be unique and non-repeating.",
111
+ given: "$.paths[*][*].parameters",
112
+ then: { function: "oasOpParams" }
113
+ },
114
+ "operation-singular-tag": {
115
+ description: "Operation should have a single tag.",
116
+ given: OPERATIONS,
117
+ severity: "warn",
118
+ recommended: false,
119
+ then: { field: "tags", function: "length", functionOptions: { max: 1 } }
120
+ },
121
+ "operation-success-response": {
122
+ description: "Operation must have at least one 2xx or 3xx response.",
123
+ given: OPERATIONS,
124
+ then: { field: "responses", function: "oasOpSuccessResponse" }
125
+ },
126
+ "operation-tags": {
127
+ description: "Operation must have non-empty tags.",
128
+ given: OPERATIONS,
129
+ then: { field: "tags", function: "truthy" }
130
+ },
131
+ "operation-tag-defined": {
132
+ description: "Operation tags must be defined in the global tags list.",
133
+ given: OPERATIONS,
134
+ then: { function: "oasTagDefined" }
135
+ },
136
+ "path-declarations-must-exist": {
137
+ description: "Path parameter declarations must not be empty ({}).",
138
+ given: "$.paths",
139
+ then: { field: "@key", function: "pattern", functionOptions: { notMatch: "{}" } }
140
+ },
141
+ "path-keys-no-trailing-slash": {
142
+ description: "Path keys should not end with a slash.",
143
+ given: "$.paths",
144
+ then: { field: "@key", function: "pattern", functionOptions: { notMatch: ".+\\/$" } }
145
+ },
146
+ "path-not-include-query": {
147
+ description: "Path keys should not include query strings.",
148
+ given: "$.paths",
149
+ then: { field: "@key", function: "pattern", functionOptions: { notMatch: "\\?" } }
150
+ },
151
+ "path-params": {
152
+ description: "Path parameters must be defined and not duplicated.",
153
+ given: "$.paths",
154
+ severity: "error",
155
+ then: { function: "oasPathParam" }
156
+ },
157
+ "tag-description": {
158
+ description: "Tags should have a description.",
159
+ given: "$.tags[*]",
160
+ severity: "warn",
161
+ recommended: false,
162
+ then: { field: "description", function: "truthy" }
163
+ },
164
+ "typed-enum": {
165
+ description: "Enum values must respect the specified type.",
166
+ given: "$..enum^",
167
+ then: { function: "typedEnum" }
168
+ },
169
+ "array-items": {
170
+ // Not part of `spectral:oas` — a Loupe extension. `type: array` without
171
+ // `items` is valid in JSON Schema 2020-12 (OpenAPI 3.1/3.2), so this is gated
172
+ // to the versions where `items` is genuinely required (2.0 and 3.0.x) to
173
+ // avoid false positives on valid 3.1+ tuple/unconstrained-array schemas.
174
+ description: "Schemas of type array must define items (OpenAPI 2.0 / 3.0 only; Loupe extension).",
175
+ formats: ["oas2", "oas3_0"],
176
+ given: "$..[?(@ && @.type === 'array')]",
177
+ severity: "error",
178
+ then: { field: "items", function: "defined" }
179
+ }
190
180
  };
191
- /** OpenAPI v2.0-only rules. */
192
181
  const oas2Rules = {
193
- 'oas2-anyOf': {
194
- description: 'anyOf is not available in OpenAPI v2.0.',
195
- formats: ['oas2'],
196
- given: '$..anyOf',
197
- then: { function: 'falsy' },
198
- },
199
- 'oas2-oneOf': {
200
- description: 'oneOf is not available in OpenAPI v2.0.',
201
- formats: ['oas2'],
202
- given: '$..oneOf',
203
- then: { function: 'falsy' },
204
- },
205
- 'oas2-api-host': {
206
- description: 'OpenAPI host must be present and non-empty.',
207
- formats: ['oas2'],
208
- given: '$',
209
- then: { field: 'host', function: 'truthy' },
210
- },
211
- 'oas2-api-schemes': {
212
- description: 'OpenAPI schemes must be present and non-empty.',
213
- formats: ['oas2'],
214
- // Target the root and the `schemes` field so a *missing* `schemes` (not just
215
- // an empty array) is reported — `given: '$.schemes'` matches nothing when the
216
- // key is absent, so the rule never fired for a document with no schemes.
217
- given: '$',
218
- then: {
219
- field: 'schemes',
220
- function: 'schema',
221
- functionOptions: { schema: { type: 'array', minItems: 1 } },
222
- },
223
- },
224
- 'oas2-discriminator': {
225
- description: 'Discriminator must reference a required property.',
226
- formats: ['oas2'],
227
- given: '$.definitions[*]',
228
- severity: 'error',
229
- then: { function: 'oasDiscriminator' },
230
- },
231
- 'oas2-host-not-example': {
232
- description: 'Host should not point to example.com.',
233
- formats: ['oas2'],
234
- given: '$',
235
- severity: 'warn',
236
- recommended: false,
237
- then: { field: 'host', function: 'pattern', functionOptions: { notMatch: 'example\\.com' } },
238
- },
239
- 'oas2-host-trailing-slash': {
240
- description: 'Host should not have a trailing slash.',
241
- formats: ['oas2'],
242
- given: '$',
243
- then: { field: 'host', function: 'pattern', functionOptions: { notMatch: '/$' } },
244
- },
245
- 'oas2-operation-formData-consume-check': {
246
- description: 'formData operations must consume form media types.',
247
- formats: ['oas2'],
248
- given: OPERATIONS,
249
- then: { function: 'oasOpFormDataConsumeCheck' },
250
- },
251
- 'oas2-operation-security-defined': {
252
- description: 'Operation security must reference defined securityDefinitions.',
253
- formats: ['oas2'],
254
- given: '$',
255
- then: { function: 'oasOpSecurityDefined', functionOptions: { schemesPath: ['securityDefinitions'] } },
256
- },
257
- 'oas2-parameter-description': {
258
- description: 'Parameters should have a description.',
259
- formats: ['oas2'],
260
- given: '$..parameters[*]',
261
- severity: 'warn',
262
- recommended: false,
263
- then: { field: 'description', function: 'truthy' },
264
- },
265
- 'oas2-unused-definition': {
266
- description: 'Definitions should be referenced.',
267
- formats: ['oas2'],
268
- given: '$.definitions',
269
- severity: 'warn',
270
- resolved: false,
271
- then: { function: 'unreferencedReusableObject', functionOptions: { reusableObjectsLocation: '#/definitions' } },
272
- },
273
- 'oas2-valid-schema-example': {
274
- description: 'Schema examples must be valid against their schema.',
275
- formats: ['oas2'],
276
- given: SCHEMA_EXAMPLE_GIVEN,
277
- severity: 'error',
278
- then: { function: 'oasSchemaExample' },
279
- },
280
- 'oas2-valid-media-example': {
281
- description: 'Media type examples must be valid against their schema.',
282
- formats: ['oas2'],
283
- // In OpenAPI 2.0 examples live on the Response Object as a MIME-type → value
284
- // map alongside a sibling `schema`, so target responses that have both.
285
- given: '$..responses..[?(@ && @.schema && @.examples)]',
286
- severity: 'error',
287
- then: { function: 'oasMediaExample', functionOptions: { oasVersion: 2 } },
288
- },
289
- 'oas2-schema': {
290
- description: 'Validate structure of OpenAPI v2 specification.',
291
- formats: ['oas2'],
292
- severity: 'error',
293
- recommended: true,
294
- resolved: false,
295
- given: '$',
296
- then: { function: 'oasSchema', functionOptions: { version: '2.0' } },
297
- },
182
+ "oas2-anyOf": {
183
+ description: "anyOf is not available in OpenAPI v2.0.",
184
+ formats: ["oas2"],
185
+ given: "$..anyOf",
186
+ then: { function: "falsy" }
187
+ },
188
+ "oas2-oneOf": {
189
+ description: "oneOf is not available in OpenAPI v2.0.",
190
+ formats: ["oas2"],
191
+ given: "$..oneOf",
192
+ then: { function: "falsy" }
193
+ },
194
+ "oas2-api-host": {
195
+ description: "OpenAPI host must be present and non-empty.",
196
+ formats: ["oas2"],
197
+ given: "$",
198
+ then: { field: "host", function: "truthy" }
199
+ },
200
+ "oas2-api-schemes": {
201
+ description: "OpenAPI schemes must be present and non-empty.",
202
+ formats: ["oas2"],
203
+ // Target the root and the `schemes` field so a *missing* `schemes` (not just
204
+ // an empty array) is reported — `given: '$.schemes'` matches nothing when the
205
+ // key is absent, so the rule never fired for a document with no schemes.
206
+ given: "$",
207
+ then: {
208
+ field: "schemes",
209
+ function: "schema",
210
+ functionOptions: { schema: { type: "array", minItems: 1 } }
211
+ }
212
+ },
213
+ "oas2-discriminator": {
214
+ description: "Discriminator must reference a required property.",
215
+ formats: ["oas2"],
216
+ given: "$.definitions[*]",
217
+ severity: "error",
218
+ then: { function: "oasDiscriminator" }
219
+ },
220
+ "oas2-host-not-example": {
221
+ description: "Host should not point to example.com.",
222
+ formats: ["oas2"],
223
+ given: "$",
224
+ severity: "warn",
225
+ recommended: false,
226
+ then: { field: "host", function: "pattern", functionOptions: { notMatch: "example\\.com" } }
227
+ },
228
+ "oas2-host-trailing-slash": {
229
+ description: "Host should not have a trailing slash.",
230
+ formats: ["oas2"],
231
+ given: "$",
232
+ then: { field: "host", function: "pattern", functionOptions: { notMatch: "/$" } }
233
+ },
234
+ "oas2-operation-formData-consume-check": {
235
+ description: "formData operations must consume form media types.",
236
+ formats: ["oas2"],
237
+ given: OPERATIONS,
238
+ then: { function: "oasOpFormDataConsumeCheck" }
239
+ },
240
+ "oas2-operation-security-defined": {
241
+ description: "Operation security must reference defined securityDefinitions.",
242
+ formats: ["oas2"],
243
+ given: "$",
244
+ then: { function: "oasOpSecurityDefined", functionOptions: { schemesPath: ["securityDefinitions"] } }
245
+ },
246
+ "oas2-parameter-description": {
247
+ description: "Parameters should have a description.",
248
+ formats: ["oas2"],
249
+ given: "$..parameters[*]",
250
+ severity: "warn",
251
+ recommended: false,
252
+ then: { field: "description", function: "truthy" }
253
+ },
254
+ "oas2-unused-definition": {
255
+ description: "Definitions should be referenced.",
256
+ formats: ["oas2"],
257
+ given: "$.definitions",
258
+ severity: "warn",
259
+ resolved: false,
260
+ then: { function: "unreferencedReusableObject", functionOptions: { reusableObjectsLocation: "#/definitions" } }
261
+ },
262
+ "oas2-valid-schema-example": {
263
+ description: "Schema examples must be valid against their schema.",
264
+ formats: ["oas2"],
265
+ given: SCHEMA_EXAMPLE_GIVEN,
266
+ severity: "error",
267
+ then: { function: "oasSchemaExample" }
268
+ },
269
+ "oas2-valid-media-example": {
270
+ description: "Media type examples must be valid against their schema.",
271
+ formats: ["oas2"],
272
+ // In OpenAPI 2.0 examples live on the Response Object as a MIME-type → value
273
+ // map alongside a sibling `schema`, so target responses that have both.
274
+ given: "$..responses..[?(@ && @.schema && @.examples)]",
275
+ severity: "error",
276
+ then: { function: "oasMediaExample", functionOptions: { oasVersion: 2 } }
277
+ },
278
+ "oas2-schema": {
279
+ description: "Validate structure of OpenAPI v2 specification.",
280
+ formats: ["oas2"],
281
+ severity: "error",
282
+ recommended: true,
283
+ resolved: false,
284
+ given: "$",
285
+ then: { function: "oasSchema", functionOptions: { version: "2.0" } }
286
+ }
298
287
  };
299
- /** OpenAPI v3.x rules. */
300
288
  const oas3Rules = {
301
- 'oas3-api-servers': {
302
- description: 'OpenAPI 3 documents must have a non-empty servers array.',
303
- formats: ['oas3'],
304
- // Target the root and the `servers` field so a *missing* `servers` (not just
305
- // an empty array) is reported — `given: '$.servers'` matches nothing when the
306
- // key is absent, so the rule never fired for a document with no servers.
307
- given: '$',
308
- then: {
309
- field: 'servers',
310
- function: 'schema',
311
- functionOptions: { schema: { type: 'array', minItems: 1, items: { type: 'object' } } },
312
- },
313
- },
314
- 'oas3-examples-value-or-externalValue': {
315
- description: 'Example objects must use either value or externalValue, not both.',
316
- formats: ['oas3'],
317
- given: [
318
- '$.components.examples[*]',
319
- '$..content[*].examples[*]',
320
- '$..parameters[*].examples[*]',
321
- '$..headers[*].examples[*]',
322
- ],
323
- then: { function: 'oasExampleExternalValue' },
324
- },
325
- 'oas3-operation-security-defined': {
326
- description: 'Operation security must reference defined securitySchemes.',
327
- formats: ['oas3'],
328
- given: '$',
329
- then: { function: 'oasOpSecurityDefined', functionOptions: { schemesPath: ['components', 'securitySchemes'] } },
330
- },
331
- 'oas3-parameter-description': {
332
- description: 'Parameters should have a description.',
333
- formats: ['oas3'],
334
- given: '$..parameters[*]',
335
- severity: 'warn',
336
- recommended: false,
337
- then: { field: 'description', function: 'truthy' },
338
- },
339
- 'oas3-server-not-example.com': {
340
- description: 'Server URLs should not point to example.com.',
341
- formats: ['oas3'],
342
- given: '$.servers[*].url',
343
- severity: 'warn',
344
- recommended: false,
345
- then: { function: 'pattern', functionOptions: { notMatch: 'example\\.com' } },
346
- },
347
- 'oas3-server-trailing-slash': {
348
- description: 'Server URLs should not have trailing slashes.',
349
- formats: ['oas3'],
350
- given: '$.servers[*].url',
351
- then: { function: 'pattern', functionOptions: { notMatch: './$' } },
352
- },
353
- 'oas3-server-variables': {
354
- description: 'Server variables must be defined and used.',
355
- formats: ['oas3'],
356
- // Servers can appear at the root, on a path item, on an operation, and on a
357
- // Link Object, so cover every location rather than just the root servers.
358
- given: [
359
- '$.servers[*]',
360
- '$.paths[*].servers[*]',
361
- '$.paths[*][*].servers[*]',
362
- '$..links[*].server',
363
- '$.webhooks[*].servers[*]',
364
- '$.webhooks[*][*].servers[*]',
365
- ],
366
- severity: 'error',
367
- then: { function: 'oasServerVariables' },
368
- },
369
- 'oas3-callbacks-in-callbacks': {
370
- description: 'Callbacks must not be defined within other callbacks.',
371
- formats: ['oas3'],
372
- given: '$..callbacks..callbacks',
373
- then: { function: 'falsy' },
374
- },
375
- 'oas3-unused-component': {
376
- description: 'Reusable components should be referenced.',
377
- formats: ['oas3'],
378
- given: '$.components',
379
- severity: 'warn',
380
- resolved: false,
381
- then: { function: 'oasUnusedComponent' },
382
- },
383
- 'oas3-valid-schema-example': {
384
- description: 'Schema examples must be valid against their schema.',
385
- formats: ['oas3'],
386
- given: SCHEMA_EXAMPLE_GIVEN,
387
- severity: 'error',
388
- then: { function: 'oasSchemaExample' },
389
- },
390
- 'oas3-valid-media-example': {
391
- description: 'Media type examples must be valid against their schema.',
392
- formats: ['oas3'],
393
- // Spectral validates examples on media types, parameters, and headers.
394
- given: ['$..content[*]', '$..parameters[*]', '$..headers[*]'],
395
- severity: 'error',
396
- then: { function: 'oasMediaExample', functionOptions: { oasVersion: 3 } },
397
- },
398
- 'oas3-schema': {
399
- description: 'Validate structure of OpenAPI v3.0.x specification.',
400
- formats: ['oas3_0'],
401
- severity: 'error',
402
- recommended: true,
403
- resolved: false,
404
- given: '$',
405
- then: { function: 'oasSchema', functionOptions: { version: '3.0' } },
406
- },
289
+ "oas3-api-servers": {
290
+ description: "OpenAPI 3 documents must have a non-empty servers array.",
291
+ formats: ["oas3"],
292
+ // Target the root and the `servers` field so a *missing* `servers` (not just
293
+ // an empty array) is reported — `given: '$.servers'` matches nothing when the
294
+ // key is absent, so the rule never fired for a document with no servers.
295
+ given: "$",
296
+ then: {
297
+ field: "servers",
298
+ function: "schema",
299
+ functionOptions: { schema: { type: "array", minItems: 1, items: { type: "object" } } }
300
+ }
301
+ },
302
+ "oas3-examples-value-or-externalValue": {
303
+ description: "Example objects must use either value or externalValue, not both.",
304
+ formats: ["oas3"],
305
+ given: [
306
+ "$.components.examples[*]",
307
+ "$..content[*].examples[*]",
308
+ "$..parameters[*].examples[*]",
309
+ "$..headers[*].examples[*]"
310
+ ],
311
+ then: { function: "oasExampleExternalValue" }
312
+ },
313
+ "oas3-operation-security-defined": {
314
+ description: "Operation security must reference defined securitySchemes.",
315
+ formats: ["oas3"],
316
+ given: "$",
317
+ then: { function: "oasOpSecurityDefined", functionOptions: { schemesPath: ["components", "securitySchemes"] } }
318
+ },
319
+ "oas3-parameter-description": {
320
+ description: "Parameters should have a description.",
321
+ formats: ["oas3"],
322
+ given: "$..parameters[*]",
323
+ severity: "warn",
324
+ recommended: false,
325
+ then: { field: "description", function: "truthy" }
326
+ },
327
+ "oas3-server-not-example.com": {
328
+ description: "Server URLs should not point to example.com.",
329
+ formats: ["oas3"],
330
+ given: "$.servers[*].url",
331
+ severity: "warn",
332
+ recommended: false,
333
+ then: { function: "pattern", functionOptions: { notMatch: "example\\.com" } }
334
+ },
335
+ "oas3-server-trailing-slash": {
336
+ description: "Server URLs should not have trailing slashes.",
337
+ formats: ["oas3"],
338
+ given: "$.servers[*].url",
339
+ then: { function: "pattern", functionOptions: { notMatch: "./$" } }
340
+ },
341
+ "oas3-server-variables": {
342
+ description: "Server variables must be defined and used.",
343
+ formats: ["oas3"],
344
+ // Servers can appear at the root, on a path item, on an operation, and on a
345
+ // Link Object, so cover every location rather than just the root servers.
346
+ given: [
347
+ "$.servers[*]",
348
+ "$.paths[*].servers[*]",
349
+ "$.paths[*][*].servers[*]",
350
+ "$..links[*].server",
351
+ "$.webhooks[*].servers[*]",
352
+ "$.webhooks[*][*].servers[*]"
353
+ ],
354
+ severity: "error",
355
+ then: { function: "oasServerVariables" }
356
+ },
357
+ "oas3-callbacks-in-callbacks": {
358
+ description: "Callbacks must not be defined within other callbacks.",
359
+ formats: ["oas3"],
360
+ given: "$..callbacks..callbacks",
361
+ then: { function: "falsy" }
362
+ },
363
+ "oas3-unused-component": {
364
+ description: "Reusable components should be referenced.",
365
+ formats: ["oas3"],
366
+ given: "$.components",
367
+ severity: "warn",
368
+ resolved: false,
369
+ then: { function: "oasUnusedComponent" }
370
+ },
371
+ "oas3-valid-schema-example": {
372
+ description: "Schema examples must be valid against their schema.",
373
+ formats: ["oas3"],
374
+ given: SCHEMA_EXAMPLE_GIVEN,
375
+ severity: "error",
376
+ then: { function: "oasSchemaExample" }
377
+ },
378
+ "oas3-valid-media-example": {
379
+ description: "Media type examples must be valid against their schema.",
380
+ formats: ["oas3"],
381
+ // Spectral validates examples on media types, parameters, and headers.
382
+ given: ["$..content[*]", "$..parameters[*]", "$..headers[*]"],
383
+ severity: "error",
384
+ then: { function: "oasMediaExample", functionOptions: { oasVersion: 3 } }
385
+ },
386
+ "oas3-schema": {
387
+ description: "Validate structure of OpenAPI v3.0.x specification.",
388
+ formats: ["oas3_0"],
389
+ severity: "error",
390
+ recommended: true,
391
+ resolved: false,
392
+ given: "$",
393
+ then: { function: "oasSchema", functionOptions: { version: "3.0" } }
394
+ }
407
395
  };
408
- /** Rules for features introduced in OpenAPI 3.1 (and still in 3.2). */
409
396
  const oas31Rules = {
410
- 'oas3_1-servers-in-webhook': {
411
- description: 'Webhooks must not define servers.',
412
- // Servers can sit on the webhook Path Item itself (`$.webhooks[*]`) as well as
413
- // on each operation, so target both. Also applies to 3.2.
414
- formats: ['oas3_1', 'oas3_2'],
415
- given: [WEBHOOK_OPERATIONS, '$.webhooks[*]'],
416
- then: { field: 'servers', function: 'falsy' },
417
- },
418
- 'oas3_1-callbacks-in-webhook': {
419
- description: 'Webhooks must not define callbacks.',
420
- formats: ['oas3_1', 'oas3_2'],
421
- given: WEBHOOK_OPERATIONS,
422
- then: { field: 'callbacks', function: 'falsy' },
423
- },
424
- 'oas3_1-no-nullable': {
425
- // `nullable` was removed in OpenAPI 3.1 (JSON Schema 2020-12 uses a `null`
426
- // type instead) and stays gone in 3.2 — mirroring the oas2-anyOf/oneOf
427
- // "feature not available in this version" rules. A custom function (targeting
428
- // the parent of a `nullable` key) is used instead of `$..nullable` + `falsy`
429
- // so a property literally named `nullable` is not flagged and `nullable: false`
430
- // still is (so the migration fixer can drop it).
431
- description: 'nullable is not available in OpenAPI 3.1 or later; use a "null" type instead.',
432
- formats: ['oas3_1', 'oas3_2'],
433
- given: '$..nullable^',
434
- then: { function: 'oasNoNullable' },
435
- },
436
- 'oas3_1-license-identifier': {
437
- // The License Object's `identifier` (SPDX) field was added in 3.1 and is
438
- // "mutually exclusive of the url field".
439
- description: 'License object identifier and url are mutually exclusive.',
440
- formats: ['oas3_1', 'oas3_2'],
441
- given: '$.info.license',
442
- severity: 'error',
443
- then: { function: 'oasMutuallyExclusive', functionOptions: { properties: ['identifier', 'url'] } },
444
- },
445
- 'oas3_1-schema': {
446
- // The official, self-contained OpenAPI 3.1 meta-schema (spec.openapis.org).
447
- // 3.1 realigned Schema Objects with JSON Schema 2020-12, so the official
448
- // schema validates the whole document *envelope* while leaving Schema Object
449
- // internals permissive (a local `$dynamicRef` "#meta" that the runtime
450
- // validator resolves natively). The 3.0-only `oas3-schema` rule does not
451
- // apply to 3.1 (different `openapi` version and structure).
452
- description: 'Validate structure of OpenAPI v3.1 specification.',
453
- formats: ['oas3_1'],
454
- severity: 'error',
455
- recommended: true,
456
- resolved: false,
457
- given: '$',
458
- then: { function: 'oasSchema', functionOptions: { version: '3.1' } },
459
- },
460
- 'oas3_1-schema-example-deprecated': {
461
- // JSON Schema 2020-12 deprecates a Schema Object's singular `example` in
462
- // favor of the `examples` array. Off by default (recommended: false) since
463
- // singular examples remain widespread and valid-but-deprecated.
464
- description: 'Schema "example" is deprecated in OpenAPI 3.1; use "examples" instead.',
465
- formats: ['oas3_1', 'oas3_2'],
466
- given: '$..example^',
467
- severity: 'warn',
468
- recommended: false,
469
- then: { function: 'oasSchemaExampleDeprecated' },
470
- },
397
+ "oas3_1-servers-in-webhook": {
398
+ description: "Webhooks must not define servers.",
399
+ // Servers can sit on the webhook Path Item itself (`$.webhooks[*]`) as well as
400
+ // on each operation, so target both. Also applies to 3.2.
401
+ formats: ["oas3_1", "oas3_2"],
402
+ given: [WEBHOOK_OPERATIONS, "$.webhooks[*]"],
403
+ then: { field: "servers", function: "falsy" }
404
+ },
405
+ "oas3_1-callbacks-in-webhook": {
406
+ description: "Webhooks must not define callbacks.",
407
+ formats: ["oas3_1", "oas3_2"],
408
+ given: WEBHOOK_OPERATIONS,
409
+ then: { field: "callbacks", function: "falsy" }
410
+ },
411
+ "oas3_1-no-nullable": {
412
+ // `nullable` was removed in OpenAPI 3.1 (JSON Schema 2020-12 uses a `null`
413
+ // type instead) and stays gone in 3.2 — mirroring the oas2-anyOf/oneOf
414
+ // "feature not available in this version" rules. A custom function (targeting
415
+ // the parent of a `nullable` key) is used instead of `$..nullable` + `falsy`
416
+ // so a property literally named `nullable` is not flagged and `nullable: false`
417
+ // still is (so the migration fixer can drop it).
418
+ description: 'nullable is not available in OpenAPI 3.1 or later; use a "null" type instead.',
419
+ formats: ["oas3_1", "oas3_2"],
420
+ given: "$..nullable^",
421
+ then: { function: "oasNoNullable" }
422
+ },
423
+ "oas3_1-license-identifier": {
424
+ // The License Object's `identifier` (SPDX) field was added in 3.1 and is
425
+ // "mutually exclusive of the url field".
426
+ description: "License object identifier and url are mutually exclusive.",
427
+ formats: ["oas3_1", "oas3_2"],
428
+ given: "$.info.license",
429
+ severity: "error",
430
+ then: { function: "oasMutuallyExclusive", functionOptions: { properties: ["identifier", "url"] } }
431
+ },
432
+ "oas3_1-schema": {
433
+ // The official, self-contained OpenAPI 3.1 meta-schema (spec.openapis.org).
434
+ // 3.1 realigned Schema Objects with JSON Schema 2020-12, so the official
435
+ // schema validates the whole document *envelope* while leaving Schema Object
436
+ // internals permissive (a local `$dynamicRef` "#meta" that the runtime
437
+ // validator resolves natively). The 3.0-only `oas3-schema` rule does not
438
+ // apply to 3.1 (different `openapi` version and structure).
439
+ description: "Validate structure of OpenAPI v3.1 specification.",
440
+ formats: ["oas3_1"],
441
+ severity: "error",
442
+ recommended: true,
443
+ resolved: false,
444
+ given: "$",
445
+ then: { function: "oasSchema", functionOptions: { version: "3.1" } }
446
+ },
447
+ "oas3_1-schema-example-deprecated": {
448
+ // JSON Schema 2020-12 deprecates a Schema Object's singular `example` in
449
+ // favor of the `examples` array. Off by default (recommended: false) since
450
+ // singular examples remain widespread and valid-but-deprecated.
451
+ description: 'Schema "example" is deprecated in OpenAPI 3.1; use "examples" instead.',
452
+ formats: ["oas3_1", "oas3_2"],
453
+ given: "$..example^",
454
+ severity: "warn",
455
+ recommended: false,
456
+ then: { function: "oasSchemaExampleDeprecated" }
457
+ }
471
458
  };
472
- /** Rules for features introduced in OpenAPI 3.2. */
473
459
  const oas32Rules = {
474
- 'oas3_2-schema': {
475
- // The official, self-contained OpenAPI 3.2 meta-schema (spec.openapis.org).
476
- // Like `oas3_1-schema`, it validates the document envelope and leaves Schema
477
- // Object internals to JSON Schema 2020-12 via a local `$dynamicRef`.
478
- description: 'Validate structure of OpenAPI v3.2 specification.',
479
- formats: ['oas3_2'],
480
- severity: 'error',
481
- recommended: true,
482
- resolved: false,
483
- given: '$',
484
- then: { function: 'oasSchema', functionOptions: { version: '3.2' } },
485
- },
486
- 'oas3_2-additional-operations-standard-method': {
487
- // `additionalOperations` is for HTTP methods without a dedicated fixed
488
- // field; the spec forbids redefining a standard method there.
489
- description: 'additionalOperations must not redefine a standard HTTP method that has its own fixed field.',
490
- formats: ['oas3_2'],
491
- given: '$..additionalOperations',
492
- severity: 'error',
493
- then: { function: 'oasAdditionalOperations' },
494
- },
495
- 'oas3_2-server-name-unique': {
496
- description: 'Server names should be unique across the servers array.',
497
- formats: ['oas3_2'],
498
- given: '$.servers',
499
- severity: 'warn',
500
- then: { function: 'oasServerNameUnique' },
501
- },
502
- 'oas3_2-tag-parent-defined': {
503
- // Tag hierarchies (3.2): a `parent` must name a defined tag, with no cycles.
504
- // Mirrors `operation-tag-defined` for the new nesting feature.
505
- description: 'Tag parent must reference a tag defined in the global tags list, without cycles.',
506
- formats: ['oas3_2'],
507
- given: '$.tags',
508
- severity: 'warn',
509
- then: { function: 'oasTagParentDefined' },
510
- },
511
- 'oas3_2-tag-kind': {
512
- // `kind` is free-form with a community registry of conventional values, so
513
- // this is off by default (recommended: false) to avoid flagging valid
514
- // custom kinds. Only a present-but-unregistered value is flagged.
515
- description: 'Tag kind should use a registered value (nav, badge, audience).',
516
- formats: ['oas3_2'],
517
- given: '$.tags[*]',
518
- severity: 'warn',
519
- recommended: false,
520
- then: { function: 'oasTagKind' },
521
- },
522
- 'oas3_2-example-value': {
523
- // 3.2 added `dataValue`/`serializedValue` to the Example Object with
524
- // MUST-level exclusivity: dataValue excludes value; serializedValue excludes
525
- // value and externalValue. (The value/externalValue pair is left to the
526
- // 3.x-wide oas3-examples-value-or-externalValue rule.)
527
- description: 'Example object dataValue/serializedValue must not be combined with value or externalValue.',
528
- formats: ['oas3_2'],
529
- given: [
530
- '$.components.examples[*]',
531
- '$..content[*].examples[*]',
532
- '$..parameters[*].examples[*]',
533
- '$..headers[*].examples[*]',
534
- ],
535
- severity: 'error',
536
- then: { function: 'oasExampleValue' },
537
- },
460
+ "oas3_2-schema": {
461
+ // The official, self-contained OpenAPI 3.2 meta-schema (spec.openapis.org).
462
+ // Like `oas3_1-schema`, it validates the document envelope and leaves Schema
463
+ // Object internals to JSON Schema 2020-12 via a local `$dynamicRef`.
464
+ description: "Validate structure of OpenAPI v3.2 specification.",
465
+ formats: ["oas3_2"],
466
+ severity: "error",
467
+ recommended: true,
468
+ resolved: false,
469
+ given: "$",
470
+ then: { function: "oasSchema", functionOptions: { version: "3.2" } }
471
+ },
472
+ "oas3_2-additional-operations-standard-method": {
473
+ // `additionalOperations` is for HTTP methods without a dedicated fixed
474
+ // field; the spec forbids redefining a standard method there.
475
+ description: "additionalOperations must not redefine a standard HTTP method that has its own fixed field.",
476
+ formats: ["oas3_2"],
477
+ given: "$..additionalOperations",
478
+ severity: "error",
479
+ then: { function: "oasAdditionalOperations" }
480
+ },
481
+ "oas3_2-server-name-unique": {
482
+ description: "Server names should be unique across the servers array.",
483
+ formats: ["oas3_2"],
484
+ given: "$.servers",
485
+ severity: "warn",
486
+ then: { function: "oasServerNameUnique" }
487
+ },
488
+ "oas3_2-tag-parent-defined": {
489
+ // Tag hierarchies (3.2): a `parent` must name a defined tag, with no cycles.
490
+ // Mirrors `operation-tag-defined` for the new nesting feature.
491
+ description: "Tag parent must reference a tag defined in the global tags list, without cycles.",
492
+ formats: ["oas3_2"],
493
+ given: "$.tags",
494
+ severity: "warn",
495
+ then: { function: "oasTagParentDefined" }
496
+ },
497
+ "oas3_2-tag-kind": {
498
+ // `kind` is free-form with a community registry of conventional values, so
499
+ // this is off by default (recommended: false) to avoid flagging valid
500
+ // custom kinds. Only a present-but-unregistered value is flagged.
501
+ description: "Tag kind should use a registered value (nav, badge, audience).",
502
+ formats: ["oas3_2"],
503
+ given: "$.tags[*]",
504
+ severity: "warn",
505
+ recommended: false,
506
+ then: { function: "oasTagKind" }
507
+ },
508
+ "oas3_2-example-value": {
509
+ // 3.2 added `dataValue`/`serializedValue` to the Example Object with
510
+ // MUST-level exclusivity: dataValue excludes value; serializedValue excludes
511
+ // value and externalValue. (The value/externalValue pair is left to the
512
+ // 3.x-wide oas3-examples-value-or-externalValue rule.)
513
+ description: "Example object dataValue/serializedValue must not be combined with value or externalValue.",
514
+ formats: ["oas3_2"],
515
+ given: [
516
+ "$.components.examples[*]",
517
+ "$..content[*].examples[*]",
518
+ "$..parameters[*].examples[*]",
519
+ "$..headers[*].examples[*]"
520
+ ],
521
+ severity: "error",
522
+ then: { function: "oasExampleValue" }
523
+ }
538
524
  };
539
- /** Loupe's built-in OpenAPI ruleset (`loupe:oas`). */
540
- export const oas = {
541
- formats: ['oas2', 'oas3'],
542
- rules: {
543
- ...sharedRules,
544
- ...oas2Rules,
545
- ...oas3Rules,
546
- ...oas31Rules,
547
- ...oas32Rules,
548
- },
525
+ const oas = {
526
+ formats: ["oas2", "oas3"],
527
+ rules: {
528
+ ...sharedRules,
529
+ ...oas2Rules,
530
+ ...oas3Rules,
531
+ ...oas31Rules,
532
+ ...oas32Rules
533
+ }
534
+ };
535
+ export {
536
+ oas
549
537
  };