@amritk/lint 0.3.2 → 0.3.3

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 (72) hide show
  1. package/dist/core/document.js +12 -10
  2. package/dist/core/formats.js +10 -13
  3. package/dist/core/glob.js +96 -118
  4. package/dist/core/index.js +31 -11
  5. package/dist/core/jsonpath.js +487 -561
  6. package/dist/core/lint.js +78 -85
  7. package/dist/core/plugin.js +21 -29
  8. package/dist/core/pointers.js +107 -151
  9. package/dist/core/ruleset.js +0 -0
  10. package/dist/core/runner.js +214 -272
  11. package/dist/core/types.js +4 -1
  12. package/dist/core/validate-ruleset.js +98 -112
  13. package/dist/fix/apply.js +58 -96
  14. package/dist/fix/index.js +7 -2
  15. package/dist/fix/plugin.js +15 -20
  16. package/dist/functions/alphabetical.js +39 -50
  17. package/dist/functions/casing.js +39 -45
  18. package/dist/functions/defined.js +7 -5
  19. package/dist/functions/enumeration.js +15 -25
  20. package/dist/functions/falsy.js +7 -5
  21. package/dist/functions/index.js +60 -44
  22. package/dist/functions/length.js +22 -32
  23. package/dist/functions/or.js +18 -24
  24. package/dist/functions/pattern.js +39 -49
  25. package/dist/functions/schema.js +93 -119
  26. package/dist/functions/truthy.js +7 -5
  27. package/dist/functions/typed-enum.js +33 -36
  28. package/dist/functions/undefined.js +7 -8
  29. package/dist/functions/unreferenced-reusable-object.js +35 -47
  30. package/dist/functions/xor.js +13 -16
  31. package/dist/index.js +114 -164
  32. package/dist/parsers/edit-model.js +316 -444
  33. package/dist/parsers/index.js +22 -19
  34. package/dist/parsers/json.js +39 -37
  35. package/dist/parsers/lines.js +23 -26
  36. package/dist/parsers/types.js +9 -7
  37. package/dist/parsers/yaml.js +137 -204
  38. package/dist/rules/openapi/fixers.js +166 -221
  39. package/dist/rules/openapi/formats.js +26 -27
  40. package/dist/rules/openapi/functions/example-validation.js +98 -138
  41. package/dist/rules/openapi/functions/helpers.js +8 -10
  42. package/dist/rules/openapi/functions/index.js +98 -72
  43. package/dist/rules/openapi/functions/oas-additional-operations.js +16 -22
  44. package/dist/rules/openapi/functions/oas-discriminator.js +24 -22
  45. package/dist/rules/openapi/functions/oas-example-external-value.js +13 -21
  46. package/dist/rules/openapi/functions/oas-example-value.js +24 -27
  47. package/dist/rules/openapi/functions/oas-mutually-exclusive.js +15 -19
  48. package/dist/rules/openapi/functions/oas-no-nullable.js +13 -21
  49. package/dist/rules/openapi/functions/oas-op-form-data-consume-check.js +21 -19
  50. package/dist/rules/openapi/functions/oas-op-id-unique.js +27 -27
  51. package/dist/rules/openapi/functions/oas-op-params.js +36 -42
  52. package/dist/rules/openapi/functions/oas-op-security-defined.js +40 -39
  53. package/dist/rules/openapi/functions/oas-op-success-response.js +11 -13
  54. package/dist/rules/openapi/functions/oas-path-param.js +75 -96
  55. package/dist/rules/openapi/functions/oas-schema-example-deprecated.js +33 -40
  56. package/dist/rules/openapi/functions/oas-schema.js +9 -14
  57. package/dist/rules/openapi/functions/oas-server-name-unique.js +21 -19
  58. package/dist/rules/openapi/functions/oas-server-variables.js +45 -49
  59. package/dist/rules/openapi/functions/oas-tag-defined.js +20 -20
  60. package/dist/rules/openapi/functions/oas-tag-kind.js +16 -16
  61. package/dist/rules/openapi/functions/oas-tag-parent-defined.js +40 -43
  62. package/dist/rules/openapi/functions/oas-tags-unique.js +18 -16
  63. package/dist/rules/openapi/functions/oas-unused-component.js +48 -58
  64. package/dist/rules/openapi/functions/ref-siblings.js +13 -11
  65. package/dist/rules/openapi/index.js +99 -117
  66. package/dist/rules/openapi/oas.js +524 -536
  67. package/dist/rules/openapi/schemas/index.js +17 -33
  68. package/dist/rules/openapi/schemas/oas20.json +1 -1592
  69. package/dist/rules/openapi/schemas/oas30.json +1 -1651
  70. package/dist/rules/openapi/schemas/oas31.json +1 -1412
  71. package/dist/rules/openapi/schemas/oas32.json +1 -1684
  72. package/package.json +5 -5
@@ -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
  };