@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.
- 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.js +31 -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.js +58 -96
- package/dist/fix/index.js +7 -2
- package/dist/fix/plugin.js +15 -20
- package/dist/functions/alphabetical.js +39 -50
- package/dist/functions/casing.js +39 -45
- package/dist/functions/defined.js +7 -5
- package/dist/functions/enumeration.js +15 -25
- package/dist/functions/falsy.js +7 -5
- package/dist/functions/index.js +60 -44
- package/dist/functions/length.js +22 -32
- package/dist/functions/or.js +18 -24
- package/dist/functions/pattern.js +39 -49
- package/dist/functions/schema.js +93 -119
- package/dist/functions/truthy.js +7 -5
- package/dist/functions/typed-enum.js +33 -36
- package/dist/functions/undefined.js +7 -8
- package/dist/functions/unreferenced-reusable-object.js +35 -47
- package/dist/functions/xor.js +13 -16
- package/dist/index.js +114 -164
- package/dist/parsers/edit-model.js +316 -444
- package/dist/parsers/index.js +22 -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.js +98 -138
- package/dist/rules/openapi/functions/helpers.js +8 -10
- package/dist/rules/openapi/functions/index.js +98 -72
- package/dist/rules/openapi/functions/oas-additional-operations.js +16 -22
- package/dist/rules/openapi/functions/oas-discriminator.js +24 -22
- package/dist/rules/openapi/functions/oas-example-external-value.js +13 -21
- package/dist/rules/openapi/functions/oas-example-value.js +24 -27
- package/dist/rules/openapi/functions/oas-mutually-exclusive.js +15 -19
- package/dist/rules/openapi/functions/oas-no-nullable.js +13 -21
- package/dist/rules/openapi/functions/oas-op-form-data-consume-check.js +21 -19
- package/dist/rules/openapi/functions/oas-op-id-unique.js +27 -27
- package/dist/rules/openapi/functions/oas-op-params.js +36 -42
- package/dist/rules/openapi/functions/oas-op-security-defined.js +40 -39
- package/dist/rules/openapi/functions/oas-op-success-response.js +11 -13
- package/dist/rules/openapi/functions/oas-path-param.js +75 -96
- package/dist/rules/openapi/functions/oas-schema-example-deprecated.js +33 -40
- package/dist/rules/openapi/functions/oas-schema.js +9 -14
- package/dist/rules/openapi/functions/oas-server-name-unique.js +21 -19
- package/dist/rules/openapi/functions/oas-server-variables.js +45 -49
- package/dist/rules/openapi/functions/oas-tag-defined.js +20 -20
- package/dist/rules/openapi/functions/oas-tag-kind.js +16 -16
- package/dist/rules/openapi/functions/oas-tag-parent-defined.js +40 -43
- package/dist/rules/openapi/functions/oas-tags-unique.js +18 -16
- package/dist/rules/openapi/functions/oas-unused-component.js +48 -58
- package/dist/rules/openapi/functions/ref-siblings.js +13 -11
- package/dist/rules/openapi/index.js +99 -117
- 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 +5 -5
|
@@ -1,42 +1,35 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
'prefixItems',
|
|
18
|
-
'$ref',
|
|
1
|
+
import { isObject } from "./helpers.js";
|
|
2
|
+
const SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
3
|
+
"type",
|
|
4
|
+
"properties",
|
|
5
|
+
"items",
|
|
6
|
+
"allOf",
|
|
7
|
+
"anyOf",
|
|
8
|
+
"oneOf",
|
|
9
|
+
"not",
|
|
10
|
+
"enum",
|
|
11
|
+
"format",
|
|
12
|
+
"required",
|
|
13
|
+
"additionalProperties",
|
|
14
|
+
"patternProperties",
|
|
15
|
+
"prefixItems",
|
|
16
|
+
"$ref"
|
|
19
17
|
]);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
message: 'Schema "example" is deprecated in OpenAPI 3.1; use "examples" instead.',
|
|
39
|
-
path: [...context.path, 'example'],
|
|
40
|
-
},
|
|
41
|
-
];
|
|
18
|
+
const oasSchemaExampleDeprecated = (input, _options, context) => {
|
|
19
|
+
if (!isObject(input) || input["example"] === void 0)
|
|
20
|
+
return [];
|
|
21
|
+
if ("schema" in input)
|
|
22
|
+
return [];
|
|
23
|
+
const looksLikeSchema = Object.keys(input).some((key) => SCHEMA_KEYWORDS.has(key));
|
|
24
|
+
if (!looksLikeSchema)
|
|
25
|
+
return [];
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
message: 'Schema "example" is deprecated in OpenAPI 3.1; use "examples" instead.',
|
|
29
|
+
path: [...context.path, "example"]
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
};
|
|
33
|
+
export {
|
|
34
|
+
oasSchemaExampleDeprecated
|
|
42
35
|
};
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import { schema as schemaFunction } from
|
|
2
|
-
import { loadOasSchema } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export const oasSchema = (input, options, context) => {
|
|
12
|
-
if (!options?.version)
|
|
13
|
-
return [];
|
|
14
|
-
return schemaFunction(input, { schema: loadOasSchema(options.version) }, context);
|
|
1
|
+
import { schema as schemaFunction } from "../../../functions/index.js";
|
|
2
|
+
import { loadOasSchema } from "../schemas/index.js";
|
|
3
|
+
const oasSchema = (input, options, context) => {
|
|
4
|
+
if (!options?.version)
|
|
5
|
+
return [];
|
|
6
|
+
return schemaFunction(input, { schema: loadOasSchema(options.version) }, context);
|
|
7
|
+
};
|
|
8
|
+
export {
|
|
9
|
+
oasSchema
|
|
15
10
|
};
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
import { isObject } from "./helpers.js";
|
|
2
|
+
const oasServerNameUnique = (servers, _options, context) => {
|
|
3
|
+
if (!Array.isArray(servers))
|
|
4
|
+
return [];
|
|
5
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6
|
+
const results = [];
|
|
7
|
+
servers.forEach((server, index) => {
|
|
8
|
+
if (!isObject(server) || typeof server["name"] !== "string")
|
|
9
|
+
return;
|
|
10
|
+
if (seen.has(server["name"])) {
|
|
11
|
+
results.push({
|
|
12
|
+
message: `Server name "${server["name"]}" must be unique`,
|
|
13
|
+
path: [...context.path, index, "name"]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
seen.add(server["name"]);
|
|
17
|
+
});
|
|
18
|
+
return results;
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
oasServerNameUnique
|
|
20
22
|
};
|
|
@@ -1,52 +1,48 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!
|
|
10
|
-
|
|
11
|
-
const templates = [...server['url'].matchAll(/\{([^}]+)\}/g)].map((m) => m[1]);
|
|
12
|
-
const variables = isObject(server['variables']) ? server['variables'] : {};
|
|
13
|
-
const results = [];
|
|
14
|
-
for (const template of templates) {
|
|
15
|
-
if (!(template in variables)) {
|
|
16
|
-
results.push({ message: `Server variable "${template}" is not defined`, path: [...context.path, 'variables'] });
|
|
17
|
-
}
|
|
1
|
+
import { isObject } from "./helpers.js";
|
|
2
|
+
const oasServerVariables = (server, _options, context) => {
|
|
3
|
+
if (!isObject(server) || typeof server["url"] !== "string")
|
|
4
|
+
return [];
|
|
5
|
+
const templates = [...server["url"].matchAll(/\{([^}]+)\}/g)].map((m) => m[1]);
|
|
6
|
+
const variables = isObject(server["variables"]) ? server["variables"] : {};
|
|
7
|
+
const results = [];
|
|
8
|
+
for (const template of templates) {
|
|
9
|
+
if (!(template in variables)) {
|
|
10
|
+
results.push({ message: `Server variable "${template}" is not defined`, path: [...context.path, "variables"] });
|
|
18
11
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (!isObject(variable))
|
|
27
|
-
continue;
|
|
28
|
-
const hasDefault = variable['default'] !== undefined;
|
|
29
|
-
if (!hasDefault) {
|
|
30
|
-
results.push({
|
|
31
|
-
message: `Server variable "${name}" has a missing default`,
|
|
32
|
-
path: [...context.path, 'variables', name],
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
if ('enum' in variable) {
|
|
36
|
-
const enumValues = Array.isArray(variable['enum']) ? variable['enum'] : [];
|
|
37
|
-
if (enumValues.length === 0) {
|
|
38
|
-
results.push({
|
|
39
|
-
message: `Server variable "${name}" has an empty enum`,
|
|
40
|
-
path: [...context.path, 'variables', name, 'enum'],
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
else if (hasDefault && !enumValues.includes(variable['default'])) {
|
|
44
|
-
results.push({
|
|
45
|
-
message: `Server variable "${name}" has a default not listed in the enum`,
|
|
46
|
-
path: [...context.path, 'variables', name, 'default'],
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
12
|
+
}
|
|
13
|
+
for (const [name, variable] of Object.entries(variables)) {
|
|
14
|
+
if (!templates.includes(name)) {
|
|
15
|
+
results.push({
|
|
16
|
+
message: `Server variable "${name}" is not used in the URL`,
|
|
17
|
+
path: [...context.path, "variables", name]
|
|
18
|
+
});
|
|
50
19
|
}
|
|
51
|
-
|
|
20
|
+
if (!isObject(variable))
|
|
21
|
+
continue;
|
|
22
|
+
const hasDefault = variable["default"] !== void 0;
|
|
23
|
+
if (!hasDefault) {
|
|
24
|
+
results.push({
|
|
25
|
+
message: `Server variable "${name}" has a missing default`,
|
|
26
|
+
path: [...context.path, "variables", name]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if ("enum" in variable) {
|
|
30
|
+
const enumValues = Array.isArray(variable["enum"]) ? variable["enum"] : [];
|
|
31
|
+
if (enumValues.length === 0) {
|
|
32
|
+
results.push({
|
|
33
|
+
message: `Server variable "${name}" has an empty enum`,
|
|
34
|
+
path: [...context.path, "variables", name, "enum"]
|
|
35
|
+
});
|
|
36
|
+
} else if (hasDefault && !enumValues.includes(variable["default"])) {
|
|
37
|
+
results.push({
|
|
38
|
+
message: `Server variable "${name}" has a default not listed in the enum`,
|
|
39
|
+
path: [...context.path, "variables", name, "default"]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return results;
|
|
45
|
+
};
|
|
46
|
+
export {
|
|
47
|
+
oasServerVariables
|
|
52
48
|
};
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
import { isObject } from "./helpers.js";
|
|
2
|
+
const oasTagDefined = (input, _options, context) => {
|
|
3
|
+
const root = context.document.data;
|
|
4
|
+
if (!isObject(root) || !isObject(input))
|
|
5
|
+
return [];
|
|
6
|
+
const globalTags = new Set((Array.isArray(root["tags"]) ? root["tags"] : []).map((tag) => isObject(tag) ? tag["name"] : void 0).filter((name) => typeof name === "string"));
|
|
7
|
+
const tags = Array.isArray(input["tags"]) ? input["tags"] : [];
|
|
8
|
+
const results = [];
|
|
9
|
+
tags.forEach((tag, index) => {
|
|
10
|
+
if (typeof tag === "string" && !globalTags.has(tag)) {
|
|
11
|
+
results.push({
|
|
12
|
+
message: `Operation tag "${tag}" is not defined in the global tags`,
|
|
13
|
+
path: [...context.path, "tags", index]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return results;
|
|
18
|
+
};
|
|
19
|
+
export {
|
|
20
|
+
oasTagDefined
|
|
21
21
|
};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { isObject } from "./helpers.js";
|
|
2
|
+
const REGISTERED_TAG_KINDS = /* @__PURE__ */ new Set(["nav", "badge", "audience"]);
|
|
3
|
+
const oasTagKind = (tag, _options, context) => {
|
|
4
|
+
if (!isObject(tag) || typeof tag["kind"] !== "string")
|
|
5
|
+
return [];
|
|
6
|
+
if (REGISTERED_TAG_KINDS.has(tag["kind"]))
|
|
7
|
+
return [];
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
message: `Tag kind "${tag["kind"]}" is not a registered value (${[...REGISTERED_TAG_KINDS].join(", ")})`,
|
|
11
|
+
path: [...context.path, "kind"]
|
|
12
|
+
}
|
|
13
|
+
];
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
oasTagKind
|
|
17
17
|
};
|
|
@@ -1,45 +1,42 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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,17 +1,19 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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,65 +1,55 @@
|
|
|
1
|
-
import { isObject } from
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
50
|
+
}
|
|
51
|
+
return results;
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
oasUnusedComponent
|
|
65
55
|
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { isObject } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
10
|
+
}
|
|
11
|
+
return results;
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
refSiblings
|
|
13
15
|
};
|