@amritk/lint 0.4.7 → 0.5.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.
- package/AI.md +73 -4
- package/README.md +65 -14
- package/dist/core/filter-expression.js +17 -4
- package/dist/core/filter.js +82 -35
- package/dist/core/glob.js +25 -31
- package/dist/core/jsonpath.d.ts +9 -1
- package/dist/core/jsonpath.js +74 -16
- package/dist/core/lint.d.ts +8 -1
- package/dist/core/lint.js +4 -18
- package/dist/core/order.d.ts +30 -0
- package/dist/core/order.js +36 -0
- package/dist/core/own-key.d.ts +18 -0
- package/dist/core/own-key.js +12 -0
- package/dist/core/pointers.d.ts +3 -2
- package/dist/core/pointers.js +27 -18
- package/dist/core/ruleset.js +74 -27
- package/dist/core/runner.js +16 -23
- package/dist/core/severity.d.ts +11 -0
- package/dist/core/severity.js +13 -0
- package/dist/fix/apply.js +9 -2
- package/dist/fix/plugin.js +2 -1
- package/dist/functions/alphabetical.d.ts +14 -0
- package/dist/functions/alphabetical.js +4 -3
- package/dist/functions/or.js +1 -1
- package/dist/functions/ref-index.d.ts +15 -0
- package/dist/functions/ref-index.js +33 -0
- package/dist/functions/schema.d.ts +15 -0
- package/dist/functions/schema.js +2 -0
- package/dist/functions/typed-enum.js +2 -1
- package/dist/functions/unreferenced-reusable-object.js +3 -20
- package/dist/functions/xor.js +1 -1
- package/dist/index.d.ts +16 -16
- package/dist/index.js +25 -94
- package/dist/rules/asyncapi/asyncapi.d.ts +3 -0
- package/dist/rules/asyncapi/asyncapi.js +563 -0
- package/dist/rules/asyncapi/formats.d.ts +23 -0
- package/dist/rules/asyncapi/formats.js +49 -0
- package/dist/rules/asyncapi/functions/aas-server-variables.d.ts +8 -0
- package/dist/rules/asyncapi/functions/aas-server-variables.js +5 -0
- package/dist/rules/asyncapi/functions/aas-tags-unique.d.ts +2 -0
- package/dist/rules/asyncapi/functions/aas-tags-unique.js +5 -0
- package/dist/rules/asyncapi/functions/asyncapi-channel-parameters.d.ts +7 -0
- package/dist/rules/asyncapi/functions/asyncapi-channel-parameters.js +46 -0
- package/dist/rules/asyncapi/functions/asyncapi-channel-servers.d.ts +27 -0
- package/dist/rules/asyncapi/functions/asyncapi-channel-servers.js +61 -0
- package/dist/rules/asyncapi/functions/asyncapi-document-schema.d.ts +17 -0
- package/dist/rules/asyncapi/functions/asyncapi-document-schema.js +12 -0
- package/dist/rules/asyncapi/functions/asyncapi-headers-object.d.ts +23 -0
- package/dist/rules/asyncapi/functions/asyncapi-headers-object.js +25 -0
- package/dist/rules/asyncapi/functions/asyncapi-message-examples.d.ts +8 -0
- package/dist/rules/asyncapi/functions/asyncapi-message-examples.js +42 -0
- package/dist/rules/asyncapi/functions/asyncapi-message-id-unique.d.ts +3 -0
- package/dist/rules/asyncapi/functions/asyncapi-message-id-unique.js +30 -0
- package/dist/rules/asyncapi/functions/asyncapi-operation-id-unique.d.ts +3 -0
- package/dist/rules/asyncapi/functions/asyncapi-operation-id-unique.js +30 -0
- package/dist/rules/asyncapi/functions/asyncapi-payload.d.ts +14 -0
- package/dist/rules/asyncapi/functions/asyncapi-payload.js +32 -0
- package/dist/rules/asyncapi/functions/asyncapi-schema-validation.d.ts +11 -0
- package/dist/rules/asyncapi/functions/asyncapi-schema-validation.js +17 -0
- package/dist/rules/asyncapi/functions/asyncapi-security.d.ts +22 -0
- package/dist/rules/asyncapi/functions/asyncapi-security.js +78 -0
- package/dist/rules/asyncapi/functions/helpers.d.ts +51 -0
- package/dist/rules/asyncapi/functions/helpers.js +91 -0
- package/dist/rules/asyncapi/functions/index.d.ts +15 -0
- package/dist/rules/asyncapi/functions/index.js +53 -0
- package/dist/rules/asyncapi/functions/pointer.d.ts +11 -0
- package/dist/rules/asyncapi/functions/pointer.js +11 -0
- package/dist/rules/asyncapi/functions/schema-format.d.ts +4 -0
- package/dist/rules/asyncapi/functions/schema-format.js +7 -0
- package/dist/rules/asyncapi/index.d.ts +33 -0
- package/dist/rules/asyncapi/index.js +60 -0
- package/dist/rules/asyncapi/schemas/aas20.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas20.js +4 -0
- package/dist/rules/asyncapi/schemas/aas21.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas21.js +4 -0
- package/dist/rules/asyncapi/schemas/aas22.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas22.js +4 -0
- package/dist/rules/asyncapi/schemas/aas23.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas23.js +4 -0
- package/dist/rules/asyncapi/schemas/aas24.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas24.js +4 -0
- package/dist/rules/asyncapi/schemas/aas25.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas25.js +4 -0
- package/dist/rules/asyncapi/schemas/aas26.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas26.js +4 -0
- package/dist/rules/asyncapi/schemas/aas30.d.ts +2 -0
- package/dist/rules/asyncapi/schemas/aas30.js +4 -0
- package/dist/rules/asyncapi/schemas/index.d.ts +20 -0
- package/dist/rules/asyncapi/schemas/index.js +45 -0
- package/dist/rules/openapi/fixers.d.ts +6 -2
- package/dist/rules/openapi/fixers.js +9 -6
- package/dist/rules/openapi/functions/oas-discriminator.js +1 -1
- package/dist/rules/openapi/functions/oas-mutually-exclusive.js +1 -1
- package/dist/rules/openapi/functions/oas-op-security-defined.js +1 -1
- package/dist/rules/openapi/functions/oas-path-param.js +5 -4
- package/dist/rules/openapi/functions/oas-server-variables.d.ts +6 -6
- package/dist/rules/openapi/functions/oas-server-variables.js +2 -45
- package/dist/rules/openapi/functions/oas-tags-unique.d.ts +2 -3
- package/dist/rules/openapi/functions/oas-tags-unique.js +2 -16
- package/dist/rules/openapi/functions/oas-unused-component.js +3 -25
- package/dist/rules/openapi/index.d.ts +9 -2
- package/dist/rules/openapi/index.js +15 -70
- package/dist/rules/openapi/schemas/index.js +5 -1
- package/dist/rules/shared/helpers.d.ts +2 -0
- package/dist/rules/shared/helpers.js +4 -0
- package/dist/rules/shared/server-variables.d.ts +27 -0
- package/dist/rules/shared/server-variables.js +55 -0
- package/dist/rules/shared/tags-unique.d.ts +7 -0
- package/dist/rules/shared/tags-unique.js +19 -0
- package/dist/ruleset-files.d.ts +47 -0
- package/dist/ruleset-files.js +92 -0
- package/package.json +9 -5
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ResolvedExtend } from './core/index.js';
|
|
2
|
+
import type { FunctionRegistry, RulesetDefinition, RulesetFunction } from './core/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* An optional directory that everything a ruleset pulls off disk — `extends`
|
|
5
|
+
* targets and custom function modules — must resolve inside.
|
|
6
|
+
*
|
|
7
|
+
* This is opt-in and off by default, because `basePath` on its own is only a
|
|
8
|
+
* *resolution origin*: an `extends` of `/etc/thing.js` or `../../../elsewhere`
|
|
9
|
+
* resolves and loads exactly as written. See the "Trust boundary" section of the
|
|
10
|
+
* README — a ruleset that can name a `.js` file can run code, restricted root or
|
|
11
|
+
* not. This narrows *which* files it can name; it is not a sandbox.
|
|
12
|
+
*/
|
|
13
|
+
export type IRulesetTrustOptions = {
|
|
14
|
+
/** Directory that `extends` files and custom functions must resolve under. */
|
|
15
|
+
restrictTo?: string;
|
|
16
|
+
};
|
|
17
|
+
/** Enforces {@link IRulesetTrustOptions.restrictTo}, if one was configured, on a resolved file path. */
|
|
18
|
+
export declare const assertWithinRoot: (file: string, restrictTo: string | undefined, what: string) => void;
|
|
19
|
+
/** Loads a ruleset definition from a file path by extension (YAML/JSON parsed, JS/CJS/MJS required). */
|
|
20
|
+
export declare const loadRulesetFile: (file: string) => RulesetDefinition;
|
|
21
|
+
/**
|
|
22
|
+
* Resolves an `extends` reference that names a file or an npm package:
|
|
23
|
+
* - local file paths (relative to `basePath`, or absolute): `.yaml` / `.yml` / `.json` / `.js`,
|
|
24
|
+
* - npm package specifiers (resolved from `basePath`), including subpaths.
|
|
25
|
+
*
|
|
26
|
+
* Callers that also recognize named presets (`@amritk/lint/rules/openapi` knows
|
|
27
|
+
* `oas`) check those first and only fall through to here.
|
|
28
|
+
*/
|
|
29
|
+
export declare const resolveRulesetFile: (name: string, basePath: string, options?: IRulesetTrustOptions) => ResolvedExtend;
|
|
30
|
+
/** Loads a single custom function module (`<dir>/<name>.{js,cjs,mjs}` or a bare path). */
|
|
31
|
+
export declare const loadFunctionByName: (basePath: string, dir: string, name: string, restrictTo: string | undefined) => RulesetFunction;
|
|
32
|
+
/** How {@link collectCustomFunctions} follows a string `extends` target. */
|
|
33
|
+
export type ICollectOptions = IRulesetTrustOptions & {
|
|
34
|
+
/**
|
|
35
|
+
* Resolves a string `extends` target to its definition and base directory.
|
|
36
|
+
* Return `undefined` for a name that is a built-in preset rather than a file —
|
|
37
|
+
* such a target has no directory of its own to load functions from.
|
|
38
|
+
*/
|
|
39
|
+
resolveExtend: (name: string, basePath: string) => ResolvedExtend | undefined;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Walks a ruleset definition (and its string `extends`) collecting custom
|
|
43
|
+
* functions declared via `functions` / `functionsDir`, each loaded relative to
|
|
44
|
+
* the directory of the ruleset that declared it. YAML/JSON rulesets reference
|
|
45
|
+
* functions by name; JS rulesets can instead pass direct references in `then`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const collectCustomFunctions: (definition: RulesetDefinition, basePath: string, into: FunctionRegistry, seen: Set<unknown>, options: ICollectOptions) => void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, isAbsolute, resolve as resolvePath, sep } from "node:path";
|
|
4
|
+
import { setOwnKey } from "./core/own-key.js";
|
|
5
|
+
import { parseWithPointers } from "./parsers/index.js";
|
|
6
|
+
const require2 = createRequire(import.meta.url);
|
|
7
|
+
const assertWithinRoot = (file, restrictTo, what) => {
|
|
8
|
+
if (restrictTo === void 0)
|
|
9
|
+
return;
|
|
10
|
+
const root = resolvePath(restrictTo);
|
|
11
|
+
const resolved = resolvePath(file);
|
|
12
|
+
if (resolved !== root && !resolved.startsWith(root.endsWith(sep) ? root : `${root}${sep}`)) {
|
|
13
|
+
throw new Error(`${what} "${file}" resolves outside the permitted root ${root}`);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const loadRulesetFile = (file) => {
|
|
17
|
+
if (/\.(ya?ml|json)$/i.test(file)) {
|
|
18
|
+
return parseWithPointers(readFileSync(file, "utf8")).data;
|
|
19
|
+
}
|
|
20
|
+
const module = require2(file);
|
|
21
|
+
return module.default ?? module;
|
|
22
|
+
};
|
|
23
|
+
const resolveRulesetFile = (name, basePath, options = {}) => {
|
|
24
|
+
if (name.startsWith(".") || isAbsolute(name)) {
|
|
25
|
+
const file2 = resolvePath(basePath, name);
|
|
26
|
+
assertWithinRoot(file2, options.restrictTo, "Extended ruleset");
|
|
27
|
+
return { definition: loadRulesetFile(file2), basePath: dirname(file2) };
|
|
28
|
+
}
|
|
29
|
+
let file;
|
|
30
|
+
try {
|
|
31
|
+
file = require2.resolve(name, { paths: [basePath] });
|
|
32
|
+
} catch {
|
|
33
|
+
throw new Error(`Cannot resolve extended ruleset "${name}" from ${basePath}`);
|
|
34
|
+
}
|
|
35
|
+
assertWithinRoot(file, options.restrictTo, "Extended ruleset");
|
|
36
|
+
return { definition: loadRulesetFile(file), basePath: dirname(file) };
|
|
37
|
+
};
|
|
38
|
+
const loadFunctionByName = (basePath, dir, name, restrictTo) => {
|
|
39
|
+
const baseFile = resolvePath(basePath, dir, name);
|
|
40
|
+
assertWithinRoot(baseFile, restrictTo, "Custom function");
|
|
41
|
+
for (const candidate of [baseFile, `${baseFile}.js`, `${baseFile}.cjs`, `${baseFile}.mjs`]) {
|
|
42
|
+
try {
|
|
43
|
+
const resolvedFile = require2.resolve(candidate);
|
|
44
|
+
const module = require2(resolvedFile);
|
|
45
|
+
const fn = module.default ?? module;
|
|
46
|
+
if (typeof fn !== "function")
|
|
47
|
+
throw new Error(`"${name}" did not export a function`);
|
|
48
|
+
return fn;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error.code !== "MODULE_NOT_FOUND")
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`Cannot resolve custom function "${name}" from ${resolvePath(basePath, dir)}`);
|
|
55
|
+
};
|
|
56
|
+
const collectCustomFunctions = (definition, basePath, into, seen, options) => {
|
|
57
|
+
if (typeof definition !== "object" || definition === null)
|
|
58
|
+
return;
|
|
59
|
+
if (seen.has(definition))
|
|
60
|
+
return;
|
|
61
|
+
seen.add(definition);
|
|
62
|
+
if (definition.extends) {
|
|
63
|
+
const entries = Array.isArray(definition.extends) ? definition.extends : [definition.extends];
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
const target = Array.isArray(entry) ? entry[0] : entry;
|
|
66
|
+
if (typeof target === "string") {
|
|
67
|
+
const key = `${basePath}\0${target}`;
|
|
68
|
+
if (seen.has(key))
|
|
69
|
+
continue;
|
|
70
|
+
seen.add(key);
|
|
71
|
+
const resolved = options.resolveExtend(target, basePath);
|
|
72
|
+
if (resolved)
|
|
73
|
+
collectCustomFunctions(resolved.definition, resolved.basePath, into, seen, options);
|
|
74
|
+
} else {
|
|
75
|
+
collectCustomFunctions(target, basePath, into, seen, options);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(definition.functions)) {
|
|
80
|
+
const dir = definition.functionsDir ?? "functions";
|
|
81
|
+
for (const name of definition.functions) {
|
|
82
|
+
setOwnKey(into, name, loadFunctionByName(basePath, dir, name, options.restrictTo));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
export {
|
|
87
|
+
assertWithinRoot,
|
|
88
|
+
collectCustomFunctions,
|
|
89
|
+
loadFunctionByName,
|
|
90
|
+
loadRulesetFile,
|
|
91
|
+
resolveRulesetFile
|
|
92
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A fast, format-agnostic JSON/YAML style-guide linter with JSON Schema and custom rules.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -60,17 +60,21 @@
|
|
|
60
60
|
"./rules/openapi": {
|
|
61
61
|
"types": "./dist/rules/openapi/index.d.ts",
|
|
62
62
|
"default": "./dist/rules/openapi/index.js"
|
|
63
|
+
},
|
|
64
|
+
"./rules/asyncapi": {
|
|
65
|
+
"types": "./dist/rules/asyncapi/index.d.ts",
|
|
66
|
+
"default": "./dist/rules/asyncapi/index.js"
|
|
63
67
|
}
|
|
64
68
|
},
|
|
65
69
|
"dependencies": {
|
|
66
|
-
"@amritk/runtime-validators": "^0.
|
|
67
|
-
"@amritk/yaml": "^0.7.
|
|
70
|
+
"@amritk/runtime-validators": "^0.12.0",
|
|
71
|
+
"@amritk/yaml": "^0.7.2",
|
|
68
72
|
"jsonc-parser": "^3.3.1"
|
|
69
73
|
},
|
|
70
74
|
"devDependencies": {
|
|
71
|
-
"@amritk/resolve-refs": "^0.
|
|
75
|
+
"@amritk/resolve-refs": "^0.7.1",
|
|
72
76
|
"@stoplight/spectral-core": "^1.23.1",
|
|
73
77
|
"@stoplight/spectral-parsers": "^1.0.5",
|
|
74
|
-
"@stoplight/spectral-rulesets": "^1.22.
|
|
78
|
+
"@stoplight/spectral-rulesets": "^1.22.7"
|
|
75
79
|
}
|
|
76
80
|
}
|