@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,45 +1,42 @@
1
- import { isObject } from './helpers.js';
2
- /**
3
- * Validates the OpenAPI 3.2 Tag Object `parent` hierarchy: every `parent` must
4
- * name a tag that exists in the top-level `tags` list, a tag must not be its own
5
- * parent, and the parent chain must not form a cycle.
6
- */
7
- export const oasTagParentDefined = (tags, _options, context) => {
8
- if (!Array.isArray(tags))
9
- return [];
10
- const byName = new Map();
11
- for (const tag of tags) {
12
- if (isObject(tag) && typeof tag['name'] === 'string')
13
- byName.set(tag['name'], tag);
1
+ import { isObject } from "./helpers.js";
2
+ const oasTagParentDefined = (tags, _options, context) => {
3
+ if (!Array.isArray(tags))
4
+ return [];
5
+ const byName = /* @__PURE__ */ new Map();
6
+ for (const tag of tags) {
7
+ if (isObject(tag) && typeof tag["name"] === "string")
8
+ byName.set(tag["name"], tag);
9
+ }
10
+ const results = [];
11
+ tags.forEach((tag, index) => {
12
+ if (!isObject(tag) || typeof tag["parent"] !== "string")
13
+ return;
14
+ const parent = tag["parent"];
15
+ const name = typeof tag["name"] === "string" ? tag["name"] : void 0;
16
+ if (!byName.has(parent)) {
17
+ results.push({
18
+ message: `Tag parent "${parent}" is not defined in the global tags`,
19
+ path: [...context.path, index, "parent"]
20
+ });
21
+ return;
14
22
  }
15
- const results = [];
16
- tags.forEach((tag, index) => {
17
- if (!isObject(tag) || typeof tag['parent'] !== 'string')
18
- return;
19
- const parent = tag['parent'];
20
- const name = typeof tag['name'] === 'string' ? tag['name'] : undefined;
21
- if (!byName.has(parent)) {
22
- results.push({
23
- message: `Tag parent "${parent}" is not defined in the global tags`,
24
- path: [...context.path, index, 'parent'],
25
- });
26
- return;
27
- }
28
- // Walk the parent chain from this tag; a repeat means a cycle (incl. self-parent).
29
- const visited = new Set(name ? [name] : []);
30
- let current = parent;
31
- while (current !== undefined) {
32
- if (visited.has(current)) {
33
- results.push({
34
- message: `Tag "${name ?? '(unnamed)'}" has a circular parent reference via "${current}"`,
35
- path: [...context.path, index, 'parent'],
36
- });
37
- break;
38
- }
39
- visited.add(current);
40
- const next = byName.get(current)?.['parent'];
41
- current = typeof next === 'string' ? next : undefined;
42
- }
43
- });
44
- return results;
23
+ const visited = new Set(name ? [name] : []);
24
+ let current = parent;
25
+ while (current !== void 0) {
26
+ if (visited.has(current)) {
27
+ results.push({
28
+ message: `Tag "${name ?? "(unnamed)"}" has a circular parent reference via "${current}"`,
29
+ path: [...context.path, index, "parent"]
30
+ });
31
+ break;
32
+ }
33
+ visited.add(current);
34
+ const next = byName.get(current)?.["parent"];
35
+ current = typeof next === "string" ? next : void 0;
36
+ }
37
+ });
38
+ return results;
39
+ };
40
+ export {
41
+ oasTagParentDefined
45
42
  };
@@ -1,3 +1,3 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /** Flags duplicate global tag names. */
3
3
  export declare const oasTagsUnique: RulesetFunction;
@@ -1,17 +1,19 @@
1
- import { isObject } from './helpers.js';
2
- /** Flags duplicate global tag names. */
3
- export const oasTagsUnique = (tags, _options, context) => {
4
- if (!Array.isArray(tags))
5
- return [];
6
- const seen = new Set();
7
- const results = [];
8
- tags.forEach((tag, index) => {
9
- if (!isObject(tag) || typeof tag['name'] !== 'string')
10
- return;
11
- if (seen.has(tag['name'])) {
12
- results.push({ message: `Duplicate tag name "${tag['name']}"`, path: [...context.path, index, 'name'] });
13
- }
14
- seen.add(tag['name']);
15
- });
16
- return results;
1
+ import { isObject } from "./helpers.js";
2
+ const oasTagsUnique = (tags, _options, context) => {
3
+ if (!Array.isArray(tags))
4
+ return [];
5
+ const seen = /* @__PURE__ */ new Set();
6
+ const results = [];
7
+ tags.forEach((tag, index) => {
8
+ if (!isObject(tag) || typeof tag["name"] !== "string")
9
+ return;
10
+ if (seen.has(tag["name"])) {
11
+ results.push({ message: `Duplicate tag name "${tag["name"]}"`, path: [...context.path, index, "name"] });
12
+ }
13
+ seen.add(tag["name"]);
14
+ });
15
+ return results;
16
+ };
17
+ export {
18
+ oasTagsUnique
17
19
  };
@@ -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 reusable `components/*` entries that nothing `$ref`s. Spectral's
4
4
  * `oas3-unused-component` checks every reusable component type (not just
@@ -1,65 +1,55 @@
1
- import { isObject } from './helpers.js';
2
- // Reusable component types that are referenced via `$ref` (securitySchemes are
3
- // referenced by name in `security`, not via `$ref`, so they are excluded).
4
- // `pathItems` was added in OpenAPI 3.1 (referenced from `webhooks` / `callbacks`).
1
+ import { isObject } from "./helpers.js";
5
2
  const REUSABLE_COMPONENT_TYPES = [
6
- 'schemas',
7
- 'responses',
8
- 'parameters',
9
- 'examples',
10
- 'requestBodies',
11
- 'headers',
12
- 'links',
13
- 'callbacks',
14
- 'pathItems',
3
+ "schemas",
4
+ "responses",
5
+ "parameters",
6
+ "examples",
7
+ "requestBodies",
8
+ "headers",
9
+ "links",
10
+ "callbacks",
11
+ "pathItems"
15
12
  ];
16
- /** Collects every `$ref` string anywhere in `node` into `into`. */
17
13
  const collectRefs = (node, into) => {
18
- if (Array.isArray(node)) {
19
- for (const item of node)
20
- collectRefs(item, into);
21
- return;
22
- }
23
- if (isObject(node)) {
24
- for (const [key, value] of Object.entries(node)) {
25
- if (key === '$ref' && typeof value === 'string')
26
- into.add(value);
27
- else
28
- collectRefs(value, into);
29
- }
14
+ if (Array.isArray(node)) {
15
+ for (const item of node)
16
+ collectRefs(item, into);
17
+ return;
18
+ }
19
+ if (isObject(node)) {
20
+ for (const [key, value] of Object.entries(node)) {
21
+ if (key === "$ref" && typeof value === "string")
22
+ into.add(value);
23
+ else
24
+ collectRefs(value, into);
30
25
  }
26
+ }
31
27
  };
32
- /**
33
- * Flags reusable `components/*` entries that nothing `$ref`s. Spectral's
34
- * `oas3-unused-component` checks every reusable component type (not just
35
- * schemas), so we do too — run on the unresolved document.
36
- */
37
- export const oasUnusedComponent = (components, _options, context) => {
38
- if (!isObject(components))
39
- return [];
40
- const refs = new Set();
41
- collectRefs(context.document.data, refs);
42
- // A component counts as used when a `$ref` targets it OR points *into* it
43
- // (e.g. `#/components/schemas/Pet/properties/id` still uses `Pet`), so match by
44
- // prefix rather than exact string — an interior ref must not leave the parent
45
- // flagged as unused.
46
- const isReferenced = (base) => {
47
- for (const ref of refs) {
48
- if (ref === base || ref.startsWith(`${base}/`))
49
- return true;
50
- }
51
- return false;
52
- };
53
- const results = [];
54
- for (const type of REUSABLE_COMPONENT_TYPES) {
55
- const group = components[type];
56
- if (!isObject(group))
57
- continue;
58
- for (const key of Object.keys(group)) {
59
- if (!isReferenced(`#/components/${type}/${key}`)) {
60
- results.push({ message: 'Potentially unused component has been detected.', path: [...context.path, type, key] });
61
- }
62
- }
28
+ const oasUnusedComponent = (components, _options, context) => {
29
+ if (!isObject(components))
30
+ return [];
31
+ const refs = /* @__PURE__ */ new Set();
32
+ collectRefs(context.document.data, refs);
33
+ const isReferenced = (base) => {
34
+ for (const ref of refs) {
35
+ if (ref === base || ref.startsWith(`${base}/`))
36
+ return true;
37
+ }
38
+ return false;
39
+ };
40
+ const results = [];
41
+ for (const type of REUSABLE_COMPONENT_TYPES) {
42
+ const group = components[type];
43
+ if (!isObject(group))
44
+ continue;
45
+ for (const key of Object.keys(group)) {
46
+ if (!isReferenced(`#/components/${type}/${key}`)) {
47
+ results.push({ message: "Potentially unused component has been detected.", path: [...context.path, type, key] });
48
+ }
63
49
  }
64
- return results;
50
+ }
51
+ return results;
52
+ };
53
+ export {
54
+ oasUnusedComponent
65
55
  };
@@ -1,3 +1,3 @@
1
- import type { RulesetFunction } from '../../../core/index.js';
1
+ import type { RulesetFunction } from '../../../core/types.js';
2
2
  /** Flags objects that mix `$ref` with sibling keys (which are ignored per spec). */
3
3
  export declare const refSiblings: RulesetFunction;
@@ -1,13 +1,15 @@
1
- import { isObject } from './helpers.js';
2
- /** Flags objects that mix `$ref` with sibling keys (which are ignored per spec). */
3
- export const refSiblings = (input, _options, context) => {
4
- if (!isObject(input) || !('$ref' in input))
5
- return [];
6
- const results = [];
7
- for (const key of Object.keys(input)) {
8
- if (key !== '$ref') {
9
- results.push({ message: `$ref must not be placed next to "${key}"`, path: [...context.path, key] });
10
- }
1
+ import { isObject } from "./helpers.js";
2
+ const refSiblings = (input, _options, context) => {
3
+ if (!isObject(input) || !("$ref" in input))
4
+ return [];
5
+ const results = [];
6
+ for (const key of Object.keys(input)) {
7
+ if (key !== "$ref") {
8
+ results.push({ message: `$ref must not be placed next to "${key}"`, path: [...context.path, key] });
11
9
  }
12
- return results;
10
+ }
11
+ return results;
12
+ };
13
+ export {
14
+ refSiblings
13
15
  };
@@ -1,4 +1,5 @@
1
- import { type FunctionRegistry, type ResolvedExtend, type Ruleset, type RulesetDefinition } from '../../core/index.js';
1
+ import { type ResolvedExtend, type Ruleset } from '../../core/index.js';
2
+ import type { FunctionRegistry, RulesetDefinition } from '../../core/types.js';
2
3
  export { oasFixers } from './fixers.js';
3
4
  export { oas2, oas3, oas3_0, oas3_1, oas3_2, oasFormats } from './formats.js';
4
5
  export { oasFunctions } from './functions/index.js';
@@ -1,127 +1,109 @@
1
- import { readFileSync } from 'node:fs';
2
- import { createRequire } from 'node:module';
3
- import { dirname, isAbsolute, resolve as resolvePath } from 'node:path';
4
- import { createRuleset as createCoreRuleset, } from '../../core/index.js';
5
- import { builtinFunctions } from '../../functions/index.js';
6
- import { parseWithPointers } from '../../parsers/index.js';
7
- import { oasFormats } from './formats.js';
8
- import { oasFunctions } from './functions/index.js';
9
- import { oas } from './oas.js';
10
- export { oasFixers } from './fixers.js';
11
- export { oas2, oas3, oas3_0, oas3_1, oas3_2, oasFormats } from './formats.js';
12
- export { oasFunctions } from './functions/index.js';
13
- export { oas } from './oas.js';
14
- export { loadOasSchema } from './schemas/index.js';
15
- /** The built-in `@amritk/lint` functions plus the OpenAPI-specific ones, keyed by name. */
16
- export const allFunctions = { ...builtinFunctions, ...oasFunctions };
17
- const require = createRequire(import.meta.url);
18
- /** The names that resolve to the built-in OpenAPI ruleset (incl. the legacy Spectral alias). */
19
- const OAS_RULESET_NAMES = new Set(['oas', 'loupe:oas', 'spectral:oas']);
20
- /** Loads a ruleset definition from a file path by extension (YAML/JSON parsed, JS/CJS/MJS required). */
1
+ import { readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, isAbsolute, resolve as resolvePath } from "node:path";
4
+ import { createRuleset as createCoreRuleset } from "../../core/index.js";
5
+ import { builtinFunctions } from "../../functions/index.js";
6
+ import { parseWithPointers } from "../../parsers/index.js";
7
+ import { oasFormats } from "./formats.js";
8
+ import { oasFunctions } from "./functions/index.js";
9
+ import { oas } from "./oas.js";
10
+ import { oasFixers } from "./fixers.js";
11
+ import { oas2, oas3, oas3_0, oas3_1, oas3_2, oasFormats as oasFormats2 } from "./formats.js";
12
+ import { oasFunctions as oasFunctions2 } from "./functions/index.js";
13
+ import { oas as oas4 } from "./oas.js";
14
+ import { loadOasSchema } from "./schemas/index.js";
15
+ const allFunctions = { ...builtinFunctions, ...oasFunctions };
16
+ const require2 = createRequire(import.meta.url);
17
+ const OAS_RULESET_NAMES = /* @__PURE__ */ new Set(["oas", "loupe:oas", "spectral:oas"]);
21
18
  const loadRulesetFile = (file) => {
22
- if (/\.(ya?ml|json)$/i.test(file)) {
23
- return parseWithPointers(readFileSync(file, 'utf8')).data;
24
- }
25
- const module = require(file);
26
- return (module.default ?? module);
19
+ if (/\.(ya?ml|json)$/i.test(file)) {
20
+ return parseWithPointers(readFileSync(file, "utf8")).data;
21
+ }
22
+ const module = require2(file);
23
+ return module.default ?? module;
27
24
  };
28
- /**
29
- * Resolves an `extends` reference to a ruleset definition. Extends the generic
30
- * file/package resolution with the OpenAPI preset names:
31
- * - `oas` / `loupe:oas` / `spectral:oas` → the built-in {@link oas} ruleset,
32
- * - local file paths (relative to `basePath`, or absolute): `.yaml` / `.yml` / `.json` / `.js`,
33
- * - npm package specifiers (resolved from `basePath`), including subpaths.
34
- */
35
- export const resolveOpenApiRuleset = (name, basePath = process.cwd()) => {
36
- if (OAS_RULESET_NAMES.has(name))
37
- return { definition: oas, basePath };
38
- if (name.startsWith('.') || isAbsolute(name)) {
39
- const file = resolvePath(basePath, name);
40
- return { definition: loadRulesetFile(file), basePath: dirname(file) };
41
- }
42
- let file;
43
- try {
44
- file = require.resolve(name, { paths: [basePath] });
45
- }
46
- catch {
47
- throw new Error(`Cannot resolve extended ruleset "${name}" from ${basePath}`);
48
- }
49
- return { definition: loadRulesetFile(file), basePath: dirname(file) };
25
+ const resolveOpenApiRuleset = (name, basePath = process.cwd()) => {
26
+ if (OAS_RULESET_NAMES.has(name))
27
+ return { definition: oas, basePath };
28
+ if (name.startsWith(".") || isAbsolute(name)) {
29
+ const file2 = resolvePath(basePath, name);
30
+ return { definition: loadRulesetFile(file2), basePath: dirname(file2) };
31
+ }
32
+ let file;
33
+ try {
34
+ file = require2.resolve(name, { paths: [basePath] });
35
+ } catch {
36
+ throw new Error(`Cannot resolve extended ruleset "${name}" from ${basePath}`);
37
+ }
38
+ return { definition: loadRulesetFile(file), basePath: dirname(file) };
50
39
  };
51
- /** Loads a single custom function module (`<dir>/<name>.{js,cjs,mjs}` or a bare path). */
52
40
  const loadFunctionByName = (basePath, dir, name) => {
53
- const baseFile = resolvePath(basePath, dir, name);
54
- for (const candidate of [baseFile, `${baseFile}.js`, `${baseFile}.cjs`, `${baseFile}.mjs`]) {
55
- try {
56
- const resolvedFile = require.resolve(candidate);
57
- const module = require(resolvedFile);
58
- const fn = module.default ?? module;
59
- if (typeof fn !== 'function')
60
- throw new Error(`"${name}" did not export a function`);
61
- return fn;
62
- }
63
- catch (error) {
64
- if (error.code !== 'MODULE_NOT_FOUND')
65
- throw error;
66
- }
41
+ const baseFile = resolvePath(basePath, dir, name);
42
+ for (const candidate of [baseFile, `${baseFile}.js`, `${baseFile}.cjs`, `${baseFile}.mjs`]) {
43
+ try {
44
+ const resolvedFile = require2.resolve(candidate);
45
+ const module = require2(resolvedFile);
46
+ const fn = module.default ?? module;
47
+ if (typeof fn !== "function")
48
+ throw new Error(`"${name}" did not export a function`);
49
+ return fn;
50
+ } catch (error) {
51
+ if (error.code !== "MODULE_NOT_FOUND")
52
+ throw error;
67
53
  }
68
- throw new Error(`Cannot resolve custom function "${name}" from ${resolvePath(basePath, dir)}`);
54
+ }
55
+ throw new Error(`Cannot resolve custom function "${name}" from ${resolvePath(basePath, dir)}`);
69
56
  };
70
- /**
71
- * Walks a ruleset definition (and its string `extends`) collecting custom
72
- * functions declared via `functions` / `functionsDir`, each loaded relative to
73
- * the directory of the ruleset that declared it. The built-in `oas` names carry
74
- * no custom functions, so they are skipped.
75
- */
76
57
  const collectCustomFunctions = (definition, basePath, into, seen) => {
77
- if (seen.has(definition))
78
- return;
79
- seen.add(definition);
80
- if (definition.extends) {
81
- const entries = Array.isArray(definition.extends) ? definition.extends : [definition.extends];
82
- for (const entry of entries) {
83
- const target = Array.isArray(entry) ? entry[0] : entry;
84
- if (typeof target === 'string') {
85
- if (OAS_RULESET_NAMES.has(target))
86
- continue;
87
- const resolved = resolveOpenApiRuleset(target, basePath);
88
- collectCustomFunctions(resolved.definition, resolved.basePath, into, seen);
89
- }
90
- else {
91
- collectCustomFunctions(target, basePath, into, seen);
92
- }
93
- }
94
- }
95
- if (Array.isArray(definition.functions)) {
96
- const dir = definition.functionsDir ?? 'functions';
97
- for (const name of definition.functions)
98
- into[name] = loadFunctionByName(basePath, dir, name);
58
+ if (seen.has(definition))
59
+ return;
60
+ seen.add(definition);
61
+ if (definition.extends) {
62
+ const entries = Array.isArray(definition.extends) ? definition.extends : [definition.extends];
63
+ for (const entry of entries) {
64
+ const target = Array.isArray(entry) ? entry[0] : entry;
65
+ if (typeof target === "string") {
66
+ if (OAS_RULESET_NAMES.has(target))
67
+ continue;
68
+ const resolved = resolveOpenApiRuleset(target, basePath);
69
+ collectCustomFunctions(resolved.definition, resolved.basePath, into, seen);
70
+ } else {
71
+ collectCustomFunctions(target, basePath, into, seen);
72
+ }
99
73
  }
74
+ }
75
+ if (Array.isArray(definition.functions)) {
76
+ const dir = definition.functionsDir ?? "functions";
77
+ for (const name of definition.functions)
78
+ into[name] = loadFunctionByName(basePath, dir, name);
79
+ }
80
+ };
81
+ const createOpenApiRuleset = (definition, basePath) => {
82
+ const resolved = definition ?? { extends: [oas] };
83
+ let functions = allFunctions;
84
+ const custom = {};
85
+ collectCustomFunctions(resolved, basePath ?? process.cwd(), custom, /* @__PURE__ */ new Set());
86
+ if (Object.keys(custom).length > 0)
87
+ functions = { ...allFunctions, ...custom };
88
+ return createCoreRuleset(resolved, {
89
+ functions,
90
+ formats: oasFormats,
91
+ resolve: resolveOpenApiRuleset,
92
+ ...basePath !== void 0 ? { basePath } : {}
93
+ });
100
94
  };
101
- /**
102
- * Builds a runnable {@link Ruleset} for OpenAPI, layering the built-in and
103
- * OpenAPI functions (plus any custom ones the definition declares), the OpenAPI
104
- * `formats`, and `extends` resolution that understands the `oas` / `loupe:oas` /
105
- * `spectral:oas` names. With no definition it defaults to `extends: [oas]`
106
- * (recommended rules only). Feed the result to `@amritk/lint`'s core
107
- * `lintWithResult` (with a `$ref` resolver for `resolved: true` rules).
108
- */
109
- export const createOpenApiRuleset = (definition, basePath) => {
110
- // With no explicit ruleset, behave like `extends: [oas]` so only `recommended`
111
- // rules run by default. A user-supplied ruleset is used as-is (its own rules
112
- // run regardless of `recommended`).
113
- const resolved = definition ?? { extends: [oas] };
114
- // Custom functions referenced by name (YAML/JSON rulesets) are loaded relative
115
- // to the declaring ruleset's directory and layered over the built-ins.
116
- let functions = allFunctions;
117
- const custom = {};
118
- collectCustomFunctions(resolved, basePath ?? process.cwd(), custom, new Set());
119
- if (Object.keys(custom).length > 0)
120
- functions = { ...allFunctions, ...custom };
121
- return createCoreRuleset(resolved, {
122
- functions,
123
- formats: oasFormats,
124
- resolve: resolveOpenApiRuleset,
125
- ...(basePath !== undefined ? { basePath } : {}),
126
- });
95
+ export {
96
+ allFunctions,
97
+ createOpenApiRuleset,
98
+ loadOasSchema,
99
+ oas4 as oas,
100
+ oas2,
101
+ oas3,
102
+ oas3_0,
103
+ oas3_1,
104
+ oas3_2,
105
+ oasFixers,
106
+ oasFormats2 as oasFormats,
107
+ oasFunctions2 as oasFunctions,
108
+ resolveOpenApiRuleset
127
109
  };
@@ -1,3 +1,3 @@
1
- import type { RulesetDefinition } from '../../core/index.js';
1
+ import type { RulesetDefinition } from '../../core/types.js';
2
2
  /** Loupe's built-in OpenAPI ruleset (`loupe:oas`). */
3
3
  export declare const oas: RulesetDefinition;