@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,31 +1,28 @@
1
- import { isObject } from './helpers.js';
2
- // OpenAPI 3.2 Example Object exclusivity (MUST-level, per the spec's field
3
- // table). The `value`/`externalValue` pair is intentionally omitted here — the
4
- // 3.x-wide `oas3-examples-value-or-externalValue` rule already covers it, so we
5
- // only police the constraints introduced with the new `dataValue` /
6
- // `serializedValue` fields to avoid double-reporting.
1
+ import { isObject } from "./helpers.js";
7
2
  const EXAMPLE_EXCLUSIONS = [
8
- // dataValue MUST NOT accompany value.
9
- { field: 'dataValue', conflicts: ['value'] },
10
- // serializedValue MUST NOT accompany value or externalValue.
11
- { field: 'serializedValue', conflicts: ['value', 'externalValue'] },
3
+ // dataValue MUST NOT accompany value.
4
+ { field: "dataValue", conflicts: ["value"] },
5
+ // serializedValue MUST NOT accompany value or externalValue.
6
+ { field: "serializedValue", conflicts: ["value", "externalValue"] }
12
7
  ];
13
- /** Flags forbidden field combinations on an OpenAPI 3.2 Example Object. */
14
- export const oasExampleValue = (example, _options, context) => {
15
- if (!isObject(example))
16
- return [];
17
- const results = [];
18
- for (const { field, conflicts } of EXAMPLE_EXCLUSIONS) {
19
- if (example[field] === undefined)
20
- continue;
21
- for (const other of conflicts) {
22
- if (example[other] !== undefined) {
23
- results.push({
24
- message: `"${field}" must not be used together with "${other}"`,
25
- path: [...context.path, other],
26
- });
27
- }
28
- }
8
+ const oasExampleValue = (example, _options, context) => {
9
+ if (!isObject(example))
10
+ return [];
11
+ const results = [];
12
+ for (const { field, conflicts } of EXAMPLE_EXCLUSIONS) {
13
+ if (example[field] === void 0)
14
+ continue;
15
+ for (const other of conflicts) {
16
+ if (example[other] !== void 0) {
17
+ results.push({
18
+ message: `"${field}" must not be used together with "${other}"`,
19
+ path: [...context.path, other]
20
+ });
21
+ }
29
22
  }
30
- return results;
23
+ }
24
+ return results;
25
+ };
26
+ export {
27
+ oasExampleValue
31
28
  };
@@ -1,4 +1,4 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /**
3
3
  * Flags objects that carry more than one of a set of mutually exclusive
4
4
  * properties. OpenAPI 3.1's License Object, for example, defines `identifier`
@@ -1,20 +1,16 @@
1
- import { isObject } from './helpers.js';
2
- /**
3
- * Flags objects that carry more than one of a set of mutually exclusive
4
- * properties. OpenAPI 3.1's License Object, for example, defines `identifier`
5
- * (SPDX) as "mutually exclusive of the url field" — neither, or exactly one, is
6
- * allowed, but not both.
7
- */
8
- export const oasMutuallyExclusive = (input, options, context) => {
9
- if (!isObject(input))
10
- return [];
11
- const present = (options?.properties ?? []).filter((property) => input[property] !== undefined);
12
- if (present.length <= 1)
13
- return [];
14
- // The first present property is the "anchor"; flag every later one as the conflict.
15
- const [anchor, ...conflicts] = present;
16
- return conflicts.map((property) => ({
17
- message: `"${property}" must not be used together with "${anchor}" (mutually exclusive)`,
18
- path: [...context.path, property],
19
- }));
1
+ import { isObject } from "./helpers.js";
2
+ const oasMutuallyExclusive = (input, options, context) => {
3
+ if (!isObject(input))
4
+ return [];
5
+ const present = (options?.properties ?? []).filter((property) => input[property] !== void 0);
6
+ if (present.length <= 1)
7
+ return [];
8
+ const [anchor, ...conflicts] = present;
9
+ return conflicts.map((property) => ({
10
+ message: `"${property}" must not be used together with "${anchor}" (mutually exclusive)`,
11
+ path: [...context.path, property]
12
+ }));
13
+ };
14
+ export {
15
+ oasMutuallyExclusive
20
16
  };
@@ -1,4 +1,4 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /**
3
3
  * Flags a Schema Object's `nullable` keyword, removed in OpenAPI 3.1+ (JSON
4
4
  * Schema 2020-12 uses a `"null"` type instead). Targets the *parent* of a
@@ -1,22 +1,14 @@
1
- import { isObject } from './helpers.js';
2
- /**
3
- * Flags a Schema Object's `nullable` keyword, removed in OpenAPI 3.1+ (JSON
4
- * Schema 2020-12 uses a `"null"` type instead). Targets the *parent* of a
5
- * `nullable` key (`$..nullable^`) rather than `$..nullable` directly, which fixes
6
- * two problems with the naive `then: falsy` approach:
7
- * - a property literally named `nullable` (`properties: { nullable: {...} }`)
8
- * is no longer flagged, because there the `nullable` value is a Schema Object,
9
- * not the boolean keyword, and
10
- * - `nullable: false` is flagged too (a boolean of either value counts as the
11
- * keyword being present), so the migration fixer can drop it.
12
- */
13
- export const oasNoNullable = (parent, _options, context) => {
14
- if (!isObject(parent) || typeof parent['nullable'] !== 'boolean')
15
- return [];
16
- return [
17
- {
18
- message: 'nullable is not available in OpenAPI 3.1 or later; use a "null" type instead.',
19
- path: [...context.path, 'nullable'],
20
- },
21
- ];
1
+ import { isObject } from "./helpers.js";
2
+ const oasNoNullable = (parent, _options, context) => {
3
+ if (!isObject(parent) || typeof parent["nullable"] !== "boolean")
4
+ return [];
5
+ return [
6
+ {
7
+ message: 'nullable is not available in OpenAPI 3.1 or later; use a "null" type instead.',
8
+ path: [...context.path, "nullable"]
9
+ }
10
+ ];
11
+ };
12
+ export {
13
+ oasNoNullable
22
14
  };
@@ -1,3 +1,3 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /** Validates OpenAPI v2 formData operations declare a compatible `consumes`. */
3
3
  export declare const oasOpFormDataConsumeCheck: RulesetFunction;
@@ -1,21 +1,23 @@
1
- import { isObject } from './helpers.js';
2
- /** Validates OpenAPI v2 formData operations declare a compatible `consumes`. */
3
- export const oasOpFormDataConsumeCheck = (operation, _options, context) => {
4
- if (!isObject(operation))
5
- return [];
6
- const params = Array.isArray(operation['parameters']) ? operation['parameters'] : [];
7
- const hasFormData = params.some((param) => isObject(param) && param['in'] === 'formData');
8
- if (!hasFormData)
9
- return [];
10
- const consumes = Array.isArray(operation['consumes']) ? operation['consumes'] : [];
11
- const ok = consumes.some((type) => type === 'application/x-www-form-urlencoded' || type === 'multipart/form-data');
12
- if (!ok) {
13
- return [
14
- {
15
- message: 'Operations with formData parameters must consume application/x-www-form-urlencoded or multipart/form-data',
16
- path: [...context.path, 'consumes'],
17
- },
18
- ];
19
- }
1
+ import { isObject } from "./helpers.js";
2
+ const oasOpFormDataConsumeCheck = (operation, _options, context) => {
3
+ if (!isObject(operation))
20
4
  return [];
5
+ const params = Array.isArray(operation["parameters"]) ? operation["parameters"] : [];
6
+ const hasFormData = params.some((param) => isObject(param) && param["in"] === "formData");
7
+ if (!hasFormData)
8
+ return [];
9
+ const consumes = Array.isArray(operation["consumes"]) ? operation["consumes"] : [];
10
+ const ok = consumes.some((type) => type === "application/x-www-form-urlencoded" || type === "multipart/form-data");
11
+ if (!ok) {
12
+ return [
13
+ {
14
+ message: "Operations with formData parameters must consume application/x-www-form-urlencoded or multipart/form-data",
15
+ path: [...context.path, "consumes"]
16
+ }
17
+ ];
18
+ }
19
+ return [];
20
+ };
21
+ export {
22
+ oasOpFormDataConsumeCheck
21
23
  };
@@ -1,3 +1,3 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /** Ensures `operationId` values are unique across the document. */
3
3
  export declare const oasOpIdUnique: RulesetFunction;
@@ -1,29 +1,29 @@
1
- import { isObject, OPERATION_METHODS } from './helpers.js';
2
- /** Ensures `operationId` values are unique across the document. */
3
- export const oasOpIdUnique = (paths, _options, context) => {
4
- if (!isObject(paths))
5
- return [];
6
- const seen = new Set();
7
- const results = [];
8
- for (const [path, item] of Object.entries(paths)) {
9
- if (!isObject(item))
10
- continue;
11
- for (const [method, operation] of Object.entries(item)) {
12
- // Only real operations carry an `operationId`; an `x-`extension object with
13
- // an `operationId`-looking key would otherwise create a phantom duplicate.
14
- if (!OPERATION_METHODS.has(method) || !isObject(operation))
15
- continue;
16
- const id = operation['operationId'];
17
- if (typeof id !== 'string')
18
- continue;
19
- if (seen.has(id)) {
20
- results.push({
21
- message: `operationId "${id}" must be unique`,
22
- path: [...context.path, path, method, 'operationId'],
23
- });
24
- }
25
- seen.add(id);
26
- }
1
+ import { isObject, OPERATION_METHODS } from "./helpers.js";
2
+ const oasOpIdUnique = (paths, _options, context) => {
3
+ if (!isObject(paths))
4
+ return [];
5
+ const seen = /* @__PURE__ */ new Set();
6
+ const results = [];
7
+ for (const [path, item] of Object.entries(paths)) {
8
+ if (!isObject(item))
9
+ continue;
10
+ for (const [method, operation] of Object.entries(item)) {
11
+ if (!OPERATION_METHODS.has(method) || !isObject(operation))
12
+ continue;
13
+ const id = operation["operationId"];
14
+ if (typeof id !== "string")
15
+ continue;
16
+ if (seen.has(id)) {
17
+ results.push({
18
+ message: `operationId "${id}" must be unique`,
19
+ path: [...context.path, path, method, "operationId"]
20
+ });
21
+ }
22
+ seen.add(id);
27
23
  }
28
- return results;
24
+ }
25
+ return results;
26
+ };
27
+ export {
28
+ oasOpIdUnique
29
29
  };
@@ -1,4 +1,4 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /**
3
3
  * Validates an operation's `parameters` array, mirroring Spectral's `oasOpParams`:
4
4
  * flags duplicate `name`+`in` combinations, and — for OpenAPI 2.0, where the body
@@ -1,46 +1,40 @@
1
- import { isObject } from './helpers.js';
2
- /**
3
- * Validates an operation's `parameters` array, mirroring Spectral's `oasOpParams`:
4
- * flags duplicate `name`+`in` combinations, and — for OpenAPI 2.0, where the body
5
- * is a parameter — flags more than one `in: body` parameter (even with different
6
- * names) as well as mixing `in: body` with `in: formData`. `$ref` entries are
7
- * skipped because their real `name`/`in` is only known after resolution.
8
- */
9
- export const oasOpParams = (params, _options, context) => {
10
- if (!Array.isArray(params))
11
- return [];
12
- const results = [];
13
- const seen = new Set();
14
- const bodyIndices = [];
15
- const formDataIndices = [];
16
- params.forEach((param, index) => {
17
- if (!isObject(param) || '$ref' in param)
18
- return;
19
- if (param['name'] !== undefined && param['in'] !== undefined) {
20
- const key = `${String(param['in'])}:${String(param['name'])}`;
21
- if (seen.has(key)) {
22
- results.push({
23
- message: `Duplicate parameter "${String(param['name'])}" in "${String(param['in'])}"`,
24
- path: [...context.path, index],
25
- });
26
- }
27
- seen.add(key);
28
- }
29
- if (param['in'] === 'body')
30
- bodyIndices.push(index);
31
- else if (param['in'] === 'formData')
32
- formDataIndices.push(index);
33
- });
34
- // OAS2 allows at most one body parameter, and body and formData are mutually
35
- // exclusive within a single operation.
36
- if (bodyIndices.length > 0 && formDataIndices.length > 0) {
37
- results.push({ message: 'Operation must not have both "in:body" and "in:formData" parameters' });
38
- }
39
- for (let i = 1; i < bodyIndices.length; i++) {
1
+ import { isObject } from "./helpers.js";
2
+ const oasOpParams = (params, _options, context) => {
3
+ if (!Array.isArray(params))
4
+ return [];
5
+ const results = [];
6
+ const seen = /* @__PURE__ */ new Set();
7
+ const bodyIndices = [];
8
+ const formDataIndices = [];
9
+ params.forEach((param, index) => {
10
+ if (!isObject(param) || "$ref" in param)
11
+ return;
12
+ if (param["name"] !== void 0 && param["in"] !== void 0) {
13
+ const key = `${String(param["in"])}:${String(param["name"])}`;
14
+ if (seen.has(key)) {
40
15
  results.push({
41
- message: 'Operation must not have more than a single instance of the "in:body" parameter',
42
- path: [...context.path, bodyIndices[i]],
16
+ message: `Duplicate parameter "${String(param["name"])}" in "${String(param["in"])}"`,
17
+ path: [...context.path, index]
43
18
  });
19
+ }
20
+ seen.add(key);
44
21
  }
45
- return results;
22
+ if (param["in"] === "body")
23
+ bodyIndices.push(index);
24
+ else if (param["in"] === "formData")
25
+ formDataIndices.push(index);
26
+ });
27
+ if (bodyIndices.length > 0 && formDataIndices.length > 0) {
28
+ results.push({ message: 'Operation must not have both "in:body" and "in:formData" parameters' });
29
+ }
30
+ for (let i = 1; i < bodyIndices.length; i++) {
31
+ results.push({
32
+ message: 'Operation must not have more than a single instance of the "in:body" parameter',
33
+ path: [...context.path, bodyIndices[i]]
34
+ });
35
+ }
36
+ return results;
37
+ };
38
+ export {
39
+ oasOpParams
46
40
  };
@@ -1,4 +1,4 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /** Validates that every referenced security scheme is defined. */
3
3
  export declare const oasOpSecurityDefined: RulesetFunction<Record<string, unknown>, {
4
4
  schemesPath: string[];
@@ -1,44 +1,45 @@
1
- import { isObject, OPERATION_METHODS } from './helpers.js';
2
- /** Walks `path` into `root`, returning the nested value or undefined. */
1
+ import { isObject, OPERATION_METHODS } from "./helpers.js";
3
2
  const getIn = (root, path) => {
4
- let current = root;
5
- for (const key of path) {
6
- if (!isObject(current))
7
- return undefined;
8
- current = current[key];
9
- }
10
- return current;
3
+ let current = root;
4
+ for (const key of path) {
5
+ if (!isObject(current))
6
+ return void 0;
7
+ current = current[key];
8
+ }
9
+ return current;
11
10
  };
12
- /** Validates that every referenced security scheme is defined. */
13
- export const oasOpSecurityDefined = (root, options, context) => {
14
- if (!isObject(root))
15
- return [];
16
- const schemes = getIn(root, options?.schemesPath ?? []);
17
- const defined = new Set(isObject(schemes) ? Object.keys(schemes) : []);
18
- const results = [];
19
- const check = (security, path) => {
20
- if (!Array.isArray(security))
21
- return;
22
- security.forEach((requirement, index) => {
23
- if (!isObject(requirement))
24
- return;
25
- for (const name of Object.keys(requirement)) {
26
- if (!defined.has(name)) {
27
- results.push({ message: `Security scheme "${name}" is not defined`, path: [...path, index, name] });
28
- }
29
- }
30
- });
31
- };
32
- check(root['security'], [...context.path, 'security']);
33
- const paths = isObject(root['paths']) ? root['paths'] : {};
34
- for (const [path, item] of Object.entries(paths)) {
35
- if (!isObject(item))
36
- continue;
37
- for (const [method, operation] of Object.entries(item)) {
38
- if (OPERATION_METHODS.has(method) && isObject(operation)) {
39
- check(operation['security'], [...context.path, 'paths', path, method, 'security']);
40
- }
11
+ const oasOpSecurityDefined = (root, options, context) => {
12
+ if (!isObject(root))
13
+ return [];
14
+ const schemes = getIn(root, options?.schemesPath ?? []);
15
+ const defined = new Set(isObject(schemes) ? Object.keys(schemes) : []);
16
+ const results = [];
17
+ const check = (security, path) => {
18
+ if (!Array.isArray(security))
19
+ return;
20
+ security.forEach((requirement, index) => {
21
+ if (!isObject(requirement))
22
+ return;
23
+ for (const name of Object.keys(requirement)) {
24
+ if (!defined.has(name)) {
25
+ results.push({ message: `Security scheme "${name}" is not defined`, path: [...path, index, name] });
41
26
  }
27
+ }
28
+ });
29
+ };
30
+ check(root["security"], [...context.path, "security"]);
31
+ const paths = isObject(root["paths"]) ? root["paths"] : {};
32
+ for (const [path, item] of Object.entries(paths)) {
33
+ if (!isObject(item))
34
+ continue;
35
+ for (const [method, operation] of Object.entries(item)) {
36
+ if (OPERATION_METHODS.has(method) && isObject(operation)) {
37
+ check(operation["security"], [...context.path, "paths", path, method, "security"]);
38
+ }
42
39
  }
43
- return results;
40
+ }
41
+ return results;
42
+ };
43
+ export {
44
+ oasOpSecurityDefined
44
45
  };
@@ -1,3 +1,3 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /** Ensures every operation declares at least one 2xx or 3xx response. */
3
3
  export declare const oasOpSuccessResponse: RulesetFunction;
@@ -1,16 +1,14 @@
1
- import { isObject } from './helpers.js';
2
- // A success response is any 2xx/3xx status code, or a `2XX`/`3XX` wildcard (3.x).
3
- // `default` is intentionally NOT counted — it can carry any status, including an
4
- // error, so it does not prove the operation has a success response (this matches
5
- // Spectral, which counts only codes in the [200, 400) range plus the wildcards).
1
+ import { isObject } from "./helpers.js";
6
2
  const SUCCESS_CODE = /^[23](\d\d|XX)$/;
7
- /** Ensures every operation declares at least one 2xx or 3xx response. */
8
- export const oasOpSuccessResponse = (responses) => {
9
- if (!isObject(responses))
10
- return [];
11
- const hasSuccess = Object.keys(responses).some((code) => SUCCESS_CODE.test(code));
12
- if (!hasSuccess) {
13
- return [{ message: 'Operation must define at least one 2xx or 3xx response' }];
14
- }
3
+ const oasOpSuccessResponse = (responses) => {
4
+ if (!isObject(responses))
15
5
  return [];
6
+ const hasSuccess = Object.keys(responses).some((code) => SUCCESS_CODE.test(code));
7
+ if (!hasSuccess) {
8
+ return [{ message: "Operation must define at least one 2xx or 3xx response" }];
9
+ }
10
+ return [];
11
+ };
12
+ export {
13
+ oasOpSuccessResponse
16
14
  };
@@ -1,4 +1,4 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /**
3
3
  * Validates path templating per operation, mirroring Spectral's `oasPathParam`.
4
4
  * For each operation on a path it checks that (a) every `{template}` in the path