@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.
- package/AI.md +55 -0
- package/dist/core/document.js +12 -10
- package/dist/core/formats.js +10 -13
- package/dist/core/glob.js +96 -118
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +30 -11
- package/dist/core/jsonpath.js +487 -561
- package/dist/core/lint.js +78 -85
- package/dist/core/plugin.js +21 -29
- package/dist/core/pointers.js +107 -151
- package/dist/core/ruleset.js +0 -0
- package/dist/core/runner.js +214 -272
- package/dist/core/types.js +4 -1
- package/dist/core/validate-ruleset.js +98 -112
- package/dist/fix/apply.d.ts +1 -1
- package/dist/fix/apply.js +58 -96
- package/dist/fix/index.js +7 -2
- package/dist/fix/plugin.js +15 -20
- package/dist/fix/types.d.ts +1 -1
- package/dist/functions/alphabetical.d.ts +1 -1
- package/dist/functions/alphabetical.js +39 -50
- package/dist/functions/casing.d.ts +1 -1
- package/dist/functions/casing.js +39 -45
- package/dist/functions/defined.d.ts +1 -1
- package/dist/functions/defined.js +7 -5
- package/dist/functions/enumeration.d.ts +1 -1
- package/dist/functions/enumeration.js +15 -25
- package/dist/functions/falsy.d.ts +1 -1
- package/dist/functions/falsy.js +7 -5
- package/dist/functions/index.d.ts +1 -1
- package/dist/functions/index.js +60 -44
- package/dist/functions/length.d.ts +1 -1
- package/dist/functions/length.js +22 -32
- package/dist/functions/or.d.ts +1 -1
- package/dist/functions/or.js +18 -24
- package/dist/functions/pattern.d.ts +1 -1
- package/dist/functions/pattern.js +39 -49
- package/dist/functions/schema.d.ts +1 -1
- package/dist/functions/schema.js +93 -119
- package/dist/functions/truthy.d.ts +1 -1
- package/dist/functions/truthy.js +7 -5
- package/dist/functions/typed-enum.d.ts +1 -1
- package/dist/functions/typed-enum.js +33 -36
- package/dist/functions/undefined.d.ts +1 -1
- package/dist/functions/undefined.js +7 -8
- package/dist/functions/unreferenced-reusable-object.d.ts +1 -1
- package/dist/functions/unreferenced-reusable-object.js +35 -47
- package/dist/functions/xor.d.ts +1 -1
- package/dist/functions/xor.js +13 -16
- package/dist/index.d.ts +17 -4
- package/dist/index.js +149 -164
- package/dist/parsers/edit-model.js +316 -444
- package/dist/parsers/index.d.ts +1 -1
- package/dist/parsers/index.js +23 -19
- package/dist/parsers/json.js +39 -37
- package/dist/parsers/lines.js +23 -26
- package/dist/parsers/types.js +9 -7
- package/dist/parsers/yaml.js +137 -204
- package/dist/rules/openapi/fixers.js +166 -221
- package/dist/rules/openapi/formats.js +26 -27
- package/dist/rules/openapi/functions/example-validation.d.ts +1 -1
- package/dist/rules/openapi/functions/example-validation.js +98 -138
- package/dist/rules/openapi/functions/helpers.js +8 -10
- package/dist/rules/openapi/functions/index.d.ts +1 -1
- package/dist/rules/openapi/functions/index.js +98 -72
- package/dist/rules/openapi/functions/oas-additional-operations.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-additional-operations.js +16 -22
- package/dist/rules/openapi/functions/oas-discriminator.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-discriminator.js +24 -22
- package/dist/rules/openapi/functions/oas-example-external-value.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-example-external-value.js +13 -21
- package/dist/rules/openapi/functions/oas-example-value.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-example-value.js +24 -27
- package/dist/rules/openapi/functions/oas-mutually-exclusive.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-mutually-exclusive.js +15 -19
- package/dist/rules/openapi/functions/oas-no-nullable.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-no-nullable.js +13 -21
- package/dist/rules/openapi/functions/oas-op-form-data-consume-check.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-op-form-data-consume-check.js +21 -19
- package/dist/rules/openapi/functions/oas-op-id-unique.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-op-id-unique.js +27 -27
- package/dist/rules/openapi/functions/oas-op-params.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-op-params.js +36 -42
- package/dist/rules/openapi/functions/oas-op-security-defined.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-op-security-defined.js +40 -39
- package/dist/rules/openapi/functions/oas-op-success-response.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-op-success-response.js +11 -13
- package/dist/rules/openapi/functions/oas-path-param.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-path-param.js +75 -96
- package/dist/rules/openapi/functions/oas-schema-example-deprecated.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-schema-example-deprecated.js +33 -40
- package/dist/rules/openapi/functions/oas-schema.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-schema.js +9 -14
- package/dist/rules/openapi/functions/oas-server-name-unique.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-server-name-unique.js +21 -19
- package/dist/rules/openapi/functions/oas-server-variables.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-server-variables.js +45 -49
- package/dist/rules/openapi/functions/oas-tag-defined.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-tag-defined.js +20 -20
- package/dist/rules/openapi/functions/oas-tag-kind.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-tag-kind.js +16 -16
- package/dist/rules/openapi/functions/oas-tag-parent-defined.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-tag-parent-defined.js +40 -43
- package/dist/rules/openapi/functions/oas-tags-unique.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-tags-unique.js +18 -16
- package/dist/rules/openapi/functions/oas-unused-component.d.ts +1 -1
- package/dist/rules/openapi/functions/oas-unused-component.js +48 -58
- package/dist/rules/openapi/functions/ref-siblings.d.ts +1 -1
- package/dist/rules/openapi/functions/ref-siblings.js +13 -11
- package/dist/rules/openapi/index.d.ts +2 -1
- package/dist/rules/openapi/index.js +99 -117
- package/dist/rules/openapi/oas.d.ts +1 -1
- package/dist/rules/openapi/oas.js +524 -536
- package/dist/rules/openapi/schemas/index.js +17 -33
- package/dist/rules/openapi/schemas/oas20.json +1 -1592
- package/dist/rules/openapi/schemas/oas30.json +1 -1651
- package/dist/rules/openapi/schemas/oas31.json +1 -1412
- package/dist/rules/openapi/schemas/oas32.json +1 -1684
- package/package.json +11 -6
package/dist/functions/schema.js
CHANGED
|
@@ -1,129 +1,103 @@
|
|
|
1
|
-
import { validate as buildValidator } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// `validateFormats: true`); keep that by opting into all formats here.
|
|
11
|
-
validator = buildValidator(schema, { formats: 'all' });
|
|
12
|
-
validators.set(schema, validator);
|
|
13
|
-
}
|
|
14
|
-
return validator;
|
|
1
|
+
import { validate as buildValidator } from "@amritk/runtime-validators";
|
|
2
|
+
const validators = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
const getValidator = (schema2) => {
|
|
4
|
+
let validator = validators.get(schema2);
|
|
5
|
+
if (!validator) {
|
|
6
|
+
validator = buildValidator(schema2, { formats: "all" });
|
|
7
|
+
validators.set(schema2, validator);
|
|
8
|
+
}
|
|
9
|
+
return validator;
|
|
15
10
|
};
|
|
16
|
-
const KNOWN_TYPES = new Set([
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const SCHEMA_LIST_KEYS = ['allOf', 'anyOf', 'oneOf'];
|
|
22
|
-
const SCHEMA_MAP_KEYS = ['properties', 'patternProperties', 'definitions', '$defs', 'dependencies'];
|
|
23
|
-
/**
|
|
24
|
-
* Walks a schema looking for a `type` keyword whose value is not a JSON Schema
|
|
25
|
-
* type. `@amritk/runtime-validators` treats an unknown `type` as "always
|
|
26
|
-
* matches" (so it never rejects data it does not model), which means a typo like
|
|
27
|
-
* `type: "Pascal"` would silently disable the rule. Finding it up front lets us
|
|
28
|
-
* report it instead. Returns the offending type, or `undefined` when the schema
|
|
29
|
-
* only uses known types.
|
|
30
|
-
*/
|
|
11
|
+
const KNOWN_TYPES = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean", "null", "object", "array"]);
|
|
12
|
+
const SCHEMA_VALUE_KEYS = ["additionalProperties", "not", "if", "then", "else", "propertyNames", "contains"];
|
|
13
|
+
const SCHEMA_ITEMS_KEYS = ["items", "additionalItems"];
|
|
14
|
+
const SCHEMA_LIST_KEYS = ["allOf", "anyOf", "oneOf"];
|
|
15
|
+
const SCHEMA_MAP_KEYS = ["properties", "patternProperties", "definitions", "$defs", "dependencies"];
|
|
31
16
|
const findInvalidType = (node) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
for (const key of SCHEMA_VALUE_KEYS) {
|
|
45
|
-
const found = findInvalidType(schema[key]);
|
|
46
|
-
if (found !== undefined)
|
|
47
|
-
return found;
|
|
17
|
+
if (Array.isArray(node) || typeof node !== "object" || node === null)
|
|
18
|
+
return void 0;
|
|
19
|
+
const schema2 = node;
|
|
20
|
+
const declared = schema2["type"];
|
|
21
|
+
if (declared !== void 0) {
|
|
22
|
+
const types = Array.isArray(declared) ? declared : [declared];
|
|
23
|
+
for (const type of types) {
|
|
24
|
+
if (typeof type !== "string" || !KNOWN_TYPES.has(type)) {
|
|
25
|
+
return typeof type === "string" ? type : String(type);
|
|
26
|
+
}
|
|
48
27
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
28
|
+
}
|
|
29
|
+
for (const key of SCHEMA_VALUE_KEYS) {
|
|
30
|
+
const found = findInvalidType(schema2[key]);
|
|
31
|
+
if (found !== void 0)
|
|
32
|
+
return found;
|
|
33
|
+
}
|
|
34
|
+
for (const key of SCHEMA_ITEMS_KEYS) {
|
|
35
|
+
const value = schema2[key];
|
|
36
|
+
const list = Array.isArray(value) ? value : [value];
|
|
37
|
+
for (const item of list) {
|
|
38
|
+
const found = findInvalidType(item);
|
|
39
|
+
if (found !== void 0)
|
|
40
|
+
return found;
|
|
57
41
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
42
|
+
}
|
|
43
|
+
for (const key of SCHEMA_LIST_KEYS) {
|
|
44
|
+
const value = schema2[key];
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
for (const item of value) {
|
|
47
|
+
const found = findInvalidType(item);
|
|
48
|
+
if (found !== void 0)
|
|
49
|
+
return found;
|
|
50
|
+
}
|
|
67
51
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
52
|
+
}
|
|
53
|
+
for (const key of SCHEMA_MAP_KEYS) {
|
|
54
|
+
const value = schema2[key];
|
|
55
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
56
|
+
for (const item of Object.values(value)) {
|
|
57
|
+
const found = findInvalidType(item);
|
|
58
|
+
if (found !== void 0)
|
|
59
|
+
return found;
|
|
60
|
+
}
|
|
77
61
|
}
|
|
78
|
-
|
|
62
|
+
}
|
|
63
|
+
return void 0;
|
|
79
64
|
};
|
|
80
|
-
const pointerToPath = (pointer) => pointer
|
|
81
|
-
.split('/')
|
|
82
|
-
.slice(1)
|
|
83
|
-
.map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))
|
|
84
|
-
.map((segment) => (/^\d+$/.test(segment) ? Number(segment) : segment));
|
|
65
|
+
const pointerToPath = (pointer) => pointer.split("/").slice(1).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")).map((segment) => /^\d+$/.test(segment) ? Number(segment) : segment);
|
|
85
66
|
const formatError = (error) => {
|
|
86
|
-
|
|
87
|
-
|
|
67
|
+
const location = error.path || "value";
|
|
68
|
+
return `${location} ${error.message}`.trim();
|
|
88
69
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// failure. Honor the same default and only expand to the full list when the
|
|
123
|
-
// caller opts in.
|
|
124
|
-
const errors = options.allErrors ? result.errors : result.errors.slice(0, 1);
|
|
125
|
-
return errors.map((error) => ({
|
|
126
|
-
message: formatError(error),
|
|
127
|
-
path: [...context.path, ...pointerToPath(error.path)],
|
|
128
|
-
}));
|
|
70
|
+
const schema = (input, options, context) => {
|
|
71
|
+
if (!options?.schema)
|
|
72
|
+
return [];
|
|
73
|
+
const invalidType = findInvalidType(options.schema);
|
|
74
|
+
if (invalidType !== void 0) {
|
|
75
|
+
return [
|
|
76
|
+
{
|
|
77
|
+
message: `Invalid schema: unknown type "${invalidType}". Valid types are: ${[...KNOWN_TYPES].join(", ")}`,
|
|
78
|
+
path: [...context.path]
|
|
79
|
+
}
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
let result;
|
|
83
|
+
try {
|
|
84
|
+
result = getValidator(options.schema)(input);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
return [
|
|
87
|
+
{
|
|
88
|
+
message: `Invalid schema: ${error instanceof Error ? error.message : String(error)}`,
|
|
89
|
+
path: [...context.path]
|
|
90
|
+
}
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
if (result === true)
|
|
94
|
+
return [];
|
|
95
|
+
const errors = options.allErrors ? result.errors : result.errors.slice(0, 1);
|
|
96
|
+
return errors.map((error) => ({
|
|
97
|
+
message: formatError(error),
|
|
98
|
+
path: [...context.path, ...pointerToPath(error.path)]
|
|
99
|
+
}));
|
|
100
|
+
};
|
|
101
|
+
export {
|
|
102
|
+
schema
|
|
129
103
|
};
|
package/dist/functions/truthy.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const truthy = (input) => {
|
|
2
|
+
if (!input)
|
|
3
|
+
return [{ message: "The value must be truthy" }];
|
|
4
|
+
return [];
|
|
5
|
+
};
|
|
6
|
+
export {
|
|
7
|
+
truthy
|
|
6
8
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { RulesetFunction } from '../core/
|
|
1
|
+
import type { RulesetFunction } from '../core/types.js';
|
|
2
2
|
/** Validates that each `enum` entry matches the schema's declared `type`. */
|
|
3
3
|
export declare const typedEnum: RulesetFunction<Record<string, unknown>, never>;
|
|
@@ -1,40 +1,37 @@
|
|
|
1
1
|
const JS_TYPES = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
string: (v) => typeof v === "string",
|
|
3
|
+
number: (v) => typeof v === "number",
|
|
4
|
+
integer: (v) => typeof v === "number" && Number.isInteger(v),
|
|
5
|
+
boolean: (v) => typeof v === "boolean",
|
|
6
|
+
null: (v) => v === null,
|
|
7
|
+
array: (v) => Array.isArray(v),
|
|
8
|
+
object: (v) => typeof v === "object" && v !== null && !Array.isArray(v)
|
|
9
9
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
const typedEnum = (input, _options, context) => {
|
|
11
|
+
if (typeof input !== "object" || input === null)
|
|
12
|
+
return [];
|
|
13
|
+
const declaredType = input["type"];
|
|
14
|
+
const values = input["enum"];
|
|
15
|
+
if (declaredType === void 0 || !Array.isArray(values))
|
|
16
|
+
return [];
|
|
17
|
+
const types = Array.isArray(declaredType) ? [...declaredType] : [declaredType];
|
|
18
|
+
if ((input["nullable"] === true || input["x-nullable"] === true) && !types.includes("null")) {
|
|
19
|
+
types.push("null");
|
|
20
|
+
}
|
|
21
|
+
const checkers = types.map((type) => JS_TYPES[String(type)]).filter((fn) => Boolean(fn));
|
|
22
|
+
if (checkers.length === 0)
|
|
23
|
+
return [];
|
|
24
|
+
const results = [];
|
|
25
|
+
values.forEach((value, index) => {
|
|
26
|
+
if (!checkers.some((check) => check(value))) {
|
|
27
|
+
results.push({
|
|
28
|
+
message: `Enum value \`${JSON.stringify(value)}\` must be of type "${types.join(" | ")}"`,
|
|
29
|
+
path: [...context.path, "enum", index]
|
|
30
|
+
});
|
|
24
31
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const results = [];
|
|
31
|
-
values.forEach((value, index) => {
|
|
32
|
-
if (!checkers.some((check) => check(value))) {
|
|
33
|
-
results.push({
|
|
34
|
-
message: `Enum value \`${JSON.stringify(value)}\` must be of type "${types.join(' | ')}"`,
|
|
35
|
-
path: [...context.path, 'enum', index],
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
return results;
|
|
32
|
+
});
|
|
33
|
+
return results;
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
typedEnum
|
|
40
37
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RulesetFunction } from '../core/
|
|
1
|
+
import type { RulesetFunction } from '../core/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Flags a value that is defined. Exported as `undefinedFn` because `undefined`
|
|
4
4
|
* is a reserved identifier; it is registered under the name `undefined`.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return [];
|
|
1
|
+
const undefinedFn = (input) => {
|
|
2
|
+
if (input !== void 0)
|
|
3
|
+
return [{ message: "The value must be undefined" }];
|
|
4
|
+
return [];
|
|
5
|
+
};
|
|
6
|
+
export {
|
|
7
|
+
undefinedFn
|
|
9
8
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RulesetFunction } from '../core/
|
|
1
|
+
import type { RulesetFunction } from '../core/types.js';
|
|
2
2
|
/** Options for {@link unreferencedReusableObject}. */
|
|
3
3
|
export type IUnreferencedReusableObjectOptions = {
|
|
4
4
|
/** JSON pointer to the map of reusable objects, e.g. "#/components/schemas". */
|
|
@@ -1,52 +1,40 @@
|
|
|
1
|
-
/** Collects every `$ref` string anywhere in `node` into `into`. */
|
|
2
1
|
const collectRefs = (node, into) => {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
2
|
+
if (Array.isArray(node)) {
|
|
3
|
+
for (const item of node)
|
|
4
|
+
collectRefs(item, into);
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
if (typeof node === "object" && node !== null) {
|
|
8
|
+
for (const [key, value] of Object.entries(node)) {
|
|
9
|
+
if (key === "$ref" && typeof value === "string")
|
|
10
|
+
into.add(value);
|
|
11
|
+
else
|
|
12
|
+
collectRefs(value, into);
|
|
15
13
|
}
|
|
14
|
+
}
|
|
16
15
|
};
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
if (!
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
for (const key of Object.keys(input)) {
|
|
36
|
-
// A key such as "a/b" appears in a pointer as "a~1b", so escape it before
|
|
37
|
-
// building the expected reference. Without this a legitimately referenced
|
|
38
|
-
// object with a special character in its name looks unreferenced.
|
|
39
|
-
const base = `${location}/${escapePointerSegment(key)}`;
|
|
40
|
-
// A reference can point straight at the object (`base`) or deeper into it
|
|
41
|
-
// (e.g. `base/properties/x`); either counts as a use, so match the exact
|
|
42
|
-
// pointer or any pointer nested beneath it.
|
|
43
|
-
const referenced = refs.has(base) || [...refs].some((ref) => ref.startsWith(`${base}/`));
|
|
44
|
-
if (!referenced) {
|
|
45
|
-
results.push({
|
|
46
|
-
message: 'This reusable object is never referenced',
|
|
47
|
-
path: [...context.path, key],
|
|
48
|
-
});
|
|
49
|
-
}
|
|
16
|
+
const escapePointerSegment = (key) => key.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
17
|
+
const unreferencedReusableObject = (input, options, context) => {
|
|
18
|
+
if (typeof input !== "object" || input === null)
|
|
19
|
+
return [];
|
|
20
|
+
const location = options?.reusableObjectsLocation;
|
|
21
|
+
if (!location)
|
|
22
|
+
return [];
|
|
23
|
+
const refs = /* @__PURE__ */ new Set();
|
|
24
|
+
collectRefs(context.document.data, refs);
|
|
25
|
+
const results = [];
|
|
26
|
+
for (const key of Object.keys(input)) {
|
|
27
|
+
const base = `${location}/${escapePointerSegment(key)}`;
|
|
28
|
+
const referenced = refs.has(base) || [...refs].some((ref) => ref.startsWith(`${base}/`));
|
|
29
|
+
if (!referenced) {
|
|
30
|
+
results.push({
|
|
31
|
+
message: "This reusable object is never referenced",
|
|
32
|
+
path: [...context.path, key]
|
|
33
|
+
});
|
|
50
34
|
}
|
|
51
|
-
|
|
35
|
+
}
|
|
36
|
+
return results;
|
|
37
|
+
};
|
|
38
|
+
export {
|
|
39
|
+
unreferencedReusableObject
|
|
52
40
|
};
|
package/dist/functions/xor.d.ts
CHANGED
package/dist/functions/xor.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (typeof input !== 'object' || input === null)
|
|
4
|
-
return [];
|
|
5
|
-
const properties = options?.properties;
|
|
6
|
-
// Spectral validates the option schema (an array of at least two strings)
|
|
7
|
-
// before the function runs and no-ops when it fails, so with fewer than two
|
|
8
|
-
// properties there is nothing meaningful to check. We deliberately skip in
|
|
9
|
-
// silence rather than push an error: an empty or single-element list would
|
|
10
|
-
// otherwise flag every node with a message that names nothing useful.
|
|
11
|
-
if (!Array.isArray(properties) || properties.length < 2)
|
|
12
|
-
return [];
|
|
13
|
-
const present = properties.filter((property) => property in input);
|
|
14
|
-
if (present.length !== 1) {
|
|
15
|
-
return [{ message: `Exactly one of ${properties.map((p) => `"${p}"`).join(', ')} must be defined` }];
|
|
16
|
-
}
|
|
1
|
+
const xor = (input, options) => {
|
|
2
|
+
if (typeof input !== "object" || input === null)
|
|
17
3
|
return [];
|
|
4
|
+
const properties = options?.properties;
|
|
5
|
+
if (!Array.isArray(properties) || properties.length < 2)
|
|
6
|
+
return [];
|
|
7
|
+
const present = properties.filter((property) => property in input);
|
|
8
|
+
if (present.length !== 1) {
|
|
9
|
+
return [{ message: `Exactly one of ${properties.map((p) => `"${p}"`).join(", ")} must be defined` }];
|
|
10
|
+
}
|
|
11
|
+
return [];
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
xor
|
|
18
15
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type IDocumentOptions, type LintPlugin, type LintResolver, type ResolvedExtend, type Ruleset } from './core/index.js';
|
|
2
|
+
import type { IDiagnostic, RulesetDefinition } from './core/types.js';
|
|
2
3
|
import { type AppliedFix, type FixerRegistry } from './fix/index.js';
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
4
|
+
export { type AliasDefinition, type CompiledPath, compileQuery, createDocument, createLinter, type Document, detectFormats, type ExtendModifier, type ExtendResolver, type Format, globToRegExp, type IDocumentOptions, type IQueryMatch, type IRulesetProblem, type IRunOptions, type Linter, type LintOptions, type LintPlugin, type LintPluginContext, type LintPluginResult, type LintResolver, type LintResolverResult, type LintResult, lint, lintWithResult, matchesGlob, type PluginRunResult, pointerToPath, query, queryCompiled, queryMany, type ResolvedExtend, type Ruleset, type RulesetOptions, resolveSourceOrigin, resolveSourceOriginFromMap, resolveSourcePath, runPlugins, validateRuleset, } from './core/index.js';
|
|
5
|
+
export { type AppliedFix, type ApplyFixesOptions, applyFixes, createFixPlugin, type EditOp, FIX_PLUGIN_NAME, type FixContext, type Fixer, type FixerRegistry, type FixPluginData, type FixResult, type ParserFormat, } from './fix/index.js';
|
|
6
|
+
export { alphabetical, builtinFunctions, type CasingType, casing, defined, enumeration, falsy, type IAlphabeticalOptions, type ICasingOptions, type IOrOptions, type ISchemaOptions, type IUnreferencedReusableObjectOptions, type IXorOptions, length, or, pattern, schema, truthy, typedEnum, undefinedFn, unreferencedReusableObject, xor, } from './functions/index.js';
|
|
6
7
|
export { detectFormat, parseWithPointers } from './parsers/index.js';
|
|
7
8
|
/**
|
|
8
9
|
* Resolves an `extends` reference to a ruleset definition. Supports:
|
|
@@ -53,6 +54,18 @@ export type ILintResult = {
|
|
|
53
54
|
* Lints a JSON/YAML `input` end to end: parses with source maps and applies the
|
|
54
55
|
* ruleset. Returns just the findings; use {@link lintDocumentWithResult} for the
|
|
55
56
|
* full result.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* const ruleset = {
|
|
61
|
+
* rules: {
|
|
62
|
+
* 'require-name': { given: '$', severity: 'error', then: { field: 'name', function: 'truthy' } },
|
|
63
|
+
* },
|
|
64
|
+
* }
|
|
65
|
+
* const findings = await lintDocument('version: 1\n', { ruleset, source: 'service.yaml' })
|
|
66
|
+
* // findings[].range is ZERO-based; add 1 to line/character to print file:line:col.
|
|
67
|
+
* // findings[].severity is numeric (0 error, 1 warn, 2 info, 3 hint).
|
|
68
|
+
* ```
|
|
56
69
|
*/
|
|
57
70
|
export declare const lintDocument: (input: string, options?: ILintOptions) => Promise<IDiagnostic[]>;
|
|
58
71
|
/**
|