@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/parsers/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { type ApplyEditOpsResult, applyEditOps, applyEditOpsWithChanges, type EditOp } from './edit-model.js';
|
|
2
2
|
export { parseJson } from './json.js';
|
|
3
3
|
export { createLineMap, type LineMap } from './lines.js';
|
|
4
|
-
export
|
|
4
|
+
export { DiagnosticSeverity, type IDiagnostic, type ILocation, type IParseResult, type IParserOptions, type IPosition, type IRange, type JsonPath, } from './types.js';
|
|
5
5
|
export { parseYaml } from './yaml.js';
|
|
6
6
|
import type { IParseResult, IParserOptions } from './types.js';
|
|
7
7
|
/** Which concrete parser a document is routed to. */
|
package/dist/parsers/index.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { parseJson } from
|
|
7
|
-
import { parseYaml } from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return trimmed.startsWith('{') || trimmed.startsWith('[') ? 'json' : 'yaml';
|
|
1
|
+
import { applyEditOps, applyEditOpsWithChanges } from "./edit-model.js";
|
|
2
|
+
import { parseJson } from "./json.js";
|
|
3
|
+
import { createLineMap } from "./lines.js";
|
|
4
|
+
import { DiagnosticSeverity } from "./types.js";
|
|
5
|
+
import { parseYaml } from "./yaml.js";
|
|
6
|
+
import { parseJson as parseJson2 } from "./json.js";
|
|
7
|
+
import { parseYaml as parseYaml2 } from "./yaml.js";
|
|
8
|
+
const detectFormat = (source) => {
|
|
9
|
+
const trimmed = source.trimStart();
|
|
10
|
+
return trimmed.startsWith("{") || trimmed.startsWith("[") ? "json" : "yaml";
|
|
12
11
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
const parseWithPointers = (source, options = {}) => {
|
|
13
|
+
const format = options.format ?? detectFormat(source);
|
|
14
|
+
return format === "json" ? parseJson2(source) : parseYaml2(source, options);
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
DiagnosticSeverity,
|
|
18
|
+
applyEditOps,
|
|
19
|
+
applyEditOpsWithChanges,
|
|
20
|
+
createLineMap,
|
|
21
|
+
detectFormat,
|
|
22
|
+
parseJson,
|
|
23
|
+
parseWithPointers,
|
|
24
|
+
parseYaml
|
|
21
25
|
};
|
package/dist/parsers/json.js
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
import { findNodeAtLocation, getNodeValue, parseTree, printParseErrorCode } from
|
|
2
|
-
import { createLineMap } from
|
|
3
|
-
import { DiagnosticSeverity } from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
import { findNodeAtLocation, getNodeValue, parseTree, printParseErrorCode } from "jsonc-parser";
|
|
2
|
+
import { createLineMap } from "./lines.js";
|
|
3
|
+
import { DiagnosticSeverity } from "./types.js";
|
|
4
|
+
const parseJson = (source) => {
|
|
5
|
+
const lineMap = createLineMap(source);
|
|
6
|
+
const errors = [];
|
|
7
|
+
const root = parseTree(source, errors, { allowTrailingComma: false, disallowComments: true });
|
|
8
|
+
const data = root ? getNodeValue(root) : void 0;
|
|
9
|
+
const diagnostics = errors.map((err) => ({
|
|
10
|
+
message: printParseErrorCode(err.error),
|
|
11
|
+
severity: DiagnosticSeverity.Error,
|
|
12
|
+
range: {
|
|
13
|
+
start: lineMap.positionAt(err.offset),
|
|
14
|
+
end: lineMap.positionAt(err.offset + err.length)
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
const getLocationForJsonPath = (path, closest = false) => {
|
|
18
|
+
if (!root)
|
|
19
|
+
return void 0;
|
|
20
|
+
const p = path.slice();
|
|
21
|
+
while (true) {
|
|
22
|
+
const node = findNodeAtLocation(root, p);
|
|
23
|
+
if (node) {
|
|
24
|
+
return {
|
|
25
|
+
range: {
|
|
26
|
+
start: lineMap.positionAt(node.offset),
|
|
27
|
+
end: lineMap.positionAt(node.offset + node.length)
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (!closest || p.length === 0)
|
|
32
|
+
return void 0;
|
|
33
|
+
p.pop();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return { data, diagnostics, getLocationForJsonPath };
|
|
37
|
+
};
|
|
38
|
+
export {
|
|
39
|
+
parseJson
|
|
38
40
|
};
|
package/dist/parsers/lines.js
CHANGED
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
const createLineMap = (source) => {
|
|
2
|
+
const length = source.length;
|
|
3
|
+
const lineStarts = [0];
|
|
4
|
+
for (let i = 0; i < source.length; i++) {
|
|
5
|
+
if (source.charCodeAt(i) === 10)
|
|
6
|
+
lineStarts.push(i + 1);
|
|
7
|
+
}
|
|
8
|
+
const positionAt = (offset) => {
|
|
9
|
+
const clamped = Math.max(0, Math.min(offset, length));
|
|
10
|
+
let low = 0;
|
|
11
|
+
let high = lineStarts.length - 1;
|
|
12
|
+
while (low < high) {
|
|
13
|
+
const mid = low + high + 1 >> 1;
|
|
14
|
+
if ((lineStarts[mid] ?? 0) <= clamped)
|
|
15
|
+
low = mid;
|
|
16
|
+
else
|
|
17
|
+
high = mid - 1;
|
|
12
18
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const mid = (low + high + 1) >> 1;
|
|
20
|
-
if ((lineStarts[mid] ?? 0) <= clamped)
|
|
21
|
-
low = mid;
|
|
22
|
-
else
|
|
23
|
-
high = mid - 1;
|
|
24
|
-
}
|
|
25
|
-
return { line: low, character: clamped - (lineStarts[low] ?? 0) };
|
|
26
|
-
};
|
|
27
|
-
return { positionAt };
|
|
19
|
+
return { line: low, character: clamped - (lineStarts[low] ?? 0) };
|
|
20
|
+
};
|
|
21
|
+
return { positionAt };
|
|
22
|
+
};
|
|
23
|
+
export {
|
|
24
|
+
createLineMap
|
|
28
25
|
};
|
package/dist/parsers/types.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
DiagnosticSeverity[DiagnosticSeverity["Hint"] = 3] = "Hint";
|
|
1
|
+
var DiagnosticSeverity;
|
|
2
|
+
(function(DiagnosticSeverity2) {
|
|
3
|
+
DiagnosticSeverity2[DiagnosticSeverity2["Error"] = 0] = "Error";
|
|
4
|
+
DiagnosticSeverity2[DiagnosticSeverity2["Warning"] = 1] = "Warning";
|
|
5
|
+
DiagnosticSeverity2[DiagnosticSeverity2["Information"] = 2] = "Information";
|
|
6
|
+
DiagnosticSeverity2[DiagnosticSeverity2["Hint"] = 3] = "Hint";
|
|
8
7
|
})(DiagnosticSeverity || (DiagnosticSeverity = {}));
|
|
8
|
+
export {
|
|
9
|
+
DiagnosticSeverity
|
|
10
|
+
};
|
package/dist/parsers/yaml.js
CHANGED
|
@@ -1,213 +1,146 @@
|
|
|
1
|
-
import { isAlias, isMap, isPair, isScalar, isSeq, parseAllDocuments
|
|
2
|
-
import { createLineMap } from
|
|
3
|
-
import { DiagnosticSeverity
|
|
4
|
-
|
|
5
|
-
* Encodes a path into a lookup key. Each segment is tagged by kind (`.` for a
|
|
6
|
-
* key, `[]` for an index) so distinct paths cannot collide: a plain `join` turns
|
|
7
|
-
* a `null` map key into `''` (colliding with the root path `[]`) and cannot tell
|
|
8
|
-
* the numeric index `0` from the string key `"0"`. The tags keep them apart.
|
|
9
|
-
*/
|
|
10
|
-
const pathKey = (path) => path.map((segment) => (typeof segment === 'number' ? `[${segment}]` : `.${segment}`)).join('');
|
|
11
|
-
/**
|
|
12
|
-
* Canonically serializes a complex (map/seq) mapping key into a stable, distinct
|
|
13
|
-
* segment. `toJS`'s `keyText` collapses every complex key to `''`, so two
|
|
14
|
-
* distinct complex keys (and their whole value subtrees) would share one index
|
|
15
|
-
* slot and clobber each other. A structural serialization keeps them apart:
|
|
16
|
-
* `[a,b]` for a sequence key, `{k:v}` for a mapping key, recursively. Strings are
|
|
17
|
-
* quoted so a scalar member can't be confused with structure, and aliases render
|
|
18
|
-
* as `*name` (never expanded, so this stays bounded regardless of the anchor).
|
|
19
|
-
*/
|
|
1
|
+
import { isAlias, isMap, isPair, isScalar, isSeq, parseAllDocuments } from "@amritk/yaml";
|
|
2
|
+
import { createLineMap } from "./lines.js";
|
|
3
|
+
import { DiagnosticSeverity } from "./types.js";
|
|
4
|
+
const pathKey = (path) => path.map((segment) => typeof segment === "number" ? `[${segment}]` : `.${segment}`).join("");
|
|
20
5
|
const serializeComplexKey = (node) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return `*${node.source}`;
|
|
31
|
-
const v = node.value;
|
|
32
|
-
return typeof v === 'string' ? JSON.stringify(v) : v === null ? 'null' : String(v);
|
|
6
|
+
if (isSeq(node))
|
|
7
|
+
return `[${node.items.map(serializeComplexKey).join(",")}]`;
|
|
8
|
+
if (isMap(node)) {
|
|
9
|
+
return `{${node.items.filter(isPair).map((pair) => `${serializeComplexKey(pair.key)}:${pair.value ? serializeComplexKey(pair.value) : "null"}`).join(",")}}`;
|
|
10
|
+
}
|
|
11
|
+
if (isAlias(node))
|
|
12
|
+
return `*${node.source}`;
|
|
13
|
+
const v = node.value;
|
|
14
|
+
return typeof v === "string" ? JSON.stringify(v) : v === null ? "null" : String(v);
|
|
33
15
|
};
|
|
34
|
-
/**
|
|
35
|
-
* Stringifies a mapping key into an index segment. Scalar, null, and alias keys
|
|
36
|
-
* match `toJS`'s `keyText` (`null`, the `String()` form, `*name`) so scalar-keyed
|
|
37
|
-
* paths line up with the projected data. Complex (map/seq) keys — which `toJS`
|
|
38
|
-
* cannot address individually — get a canonical structural serialization instead
|
|
39
|
-
* of collapsing to `''`, so distinct complex keys occupy distinct index slots.
|
|
40
|
-
*/
|
|
41
16
|
const keyToString = (key) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
17
|
+
if (isScalar(key)) {
|
|
18
|
+
const v = key.value;
|
|
19
|
+
return typeof v === "string" ? v : v === null ? "null" : String(v);
|
|
20
|
+
}
|
|
21
|
+
if (isAlias(key))
|
|
22
|
+
return `*${key.source}`;
|
|
23
|
+
return serializeComplexKey(key);
|
|
49
24
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const duplicateKeys = options.duplicateKeys;
|
|
67
|
-
const dedupe = duplicateKeys === 'off' || duplicateKeys === false;
|
|
68
|
-
// A configured severity (Warning/Information/Hint) still detects duplicates; we
|
|
69
|
-
// just re-map the reported severity below. Only `off`/`false` turns detection off.
|
|
70
|
-
const dupSeverity = typeof duplicateKeys === 'number' ? duplicateKeys : DiagnosticSeverity.Error;
|
|
71
|
-
// Incompatible-value detection is opt-in: it runs only when a severity is
|
|
72
|
-
// configured. `undefined`/`off`/`false` leaves it disabled.
|
|
73
|
-
const incompatibleValues = options.incompatibleValues;
|
|
74
|
-
const incompatSeverity = typeof incompatibleValues === 'number' ? incompatibleValues : undefined;
|
|
75
|
-
const docs = parseAllDocuments(source, { uniqueKeys: !dedupe });
|
|
76
|
-
const index = new Map();
|
|
77
|
-
const diagnostics = [];
|
|
78
|
-
const pushError = (severity, message, start, end, code) => {
|
|
79
|
-
diagnostics.push({
|
|
80
|
-
...(code !== undefined ? { code } : {}),
|
|
81
|
-
message,
|
|
82
|
-
severity,
|
|
83
|
-
range: { start: lineMap.positionAt(start), end: lineMap.positionAt(end) },
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
const rangeOf = (node) => ({
|
|
87
|
-
start: lineMap.positionAt(node.start),
|
|
88
|
-
end: lineMap.positionAt(node.end),
|
|
25
|
+
const parseYaml = (source, options = {}) => {
|
|
26
|
+
const lineMap = createLineMap(source);
|
|
27
|
+
const duplicateKeys = options.duplicateKeys;
|
|
28
|
+
const dedupe = duplicateKeys === "off" || duplicateKeys === false;
|
|
29
|
+
const dupSeverity = typeof duplicateKeys === "number" ? duplicateKeys : DiagnosticSeverity.Error;
|
|
30
|
+
const incompatibleValues = options.incompatibleValues;
|
|
31
|
+
const incompatSeverity = typeof incompatibleValues === "number" ? incompatibleValues : void 0;
|
|
32
|
+
const docs = parseAllDocuments(source, { uniqueKeys: !dedupe });
|
|
33
|
+
const index = /* @__PURE__ */ new Map();
|
|
34
|
+
const diagnostics = [];
|
|
35
|
+
const pushError = (severity, message, start, end, code) => {
|
|
36
|
+
diagnostics.push({
|
|
37
|
+
...code !== void 0 ? { code } : {},
|
|
38
|
+
message,
|
|
39
|
+
severity,
|
|
40
|
+
range: { start: lineMap.positionAt(start), end: lineMap.positionAt(end) }
|
|
89
41
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const target = node != null && isAlias(node) ? node.target : node;
|
|
106
|
-
if (target == null)
|
|
107
|
-
return;
|
|
108
|
-
if (isSeq(target)) {
|
|
109
|
-
for (const item of target.items)
|
|
110
|
-
walkMerge(item, path);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (!isMap(target))
|
|
114
|
-
return;
|
|
115
|
-
for (const item of target.items) {
|
|
116
|
-
if (!isPair(item))
|
|
117
|
-
continue;
|
|
118
|
-
if (isMergePair(item)) {
|
|
119
|
-
walkMerge(item.value, path);
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
const childPath = [...path, keyToString(item.key)];
|
|
123
|
-
if (!index.has(pathKey(childPath)))
|
|
124
|
-
walk(item.value, childPath);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
const walk = (node, path) => {
|
|
128
|
-
if (node == null || budget-- <= 0)
|
|
129
|
-
return;
|
|
130
|
-
index.set(pathKey(path), rangeOf(node));
|
|
131
|
-
if (isScalar(node)) {
|
|
132
|
-
// The core schema projects `.nan`/`.inf`/`-.inf` to non-finite JS numbers,
|
|
133
|
-
// which `JSON.stringify` silently rewrites to `null`. Report them when the
|
|
134
|
-
// caller opted in, so a value that won't survive a JSON round-trip is caught.
|
|
135
|
-
const value = node.value;
|
|
136
|
-
if (incompatSeverity !== undefined && typeof value === 'number' && !Number.isFinite(value)) {
|
|
137
|
-
pushError(incompatSeverity, `Value ${String(value)} cannot be represented in JSON and will serialize to null.`, node.start, node.end, 'INCOMPATIBLE_VALUE');
|
|
138
|
-
}
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
// Follow an alias to its anchor definition so paths reachable only through the
|
|
142
|
-
// alias resolve to the anchored node (the alias itself keeps the range set
|
|
143
|
-
// above); an unresolved alias has no target and simply stops here.
|
|
144
|
-
const target = isAlias(node) ? node.target : node;
|
|
145
|
-
if (target == null)
|
|
146
|
-
return;
|
|
147
|
-
if (isMap(target)) {
|
|
148
|
-
const merges = [];
|
|
149
|
-
for (const item of target.items) {
|
|
150
|
-
if (!isPair(item))
|
|
151
|
-
continue;
|
|
152
|
-
if (isMergePair(item)) {
|
|
153
|
-
merges.push(item.value);
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
walk(item.value, [...path, keyToString(item.key)]);
|
|
157
|
-
}
|
|
158
|
-
// Merged keys fill positions the explicit keys above did not claim.
|
|
159
|
-
for (const merge of merges)
|
|
160
|
-
walkMerge(merge, path);
|
|
161
|
-
}
|
|
162
|
-
else if (isSeq(target)) {
|
|
163
|
-
target.items.forEach((item, i) => {
|
|
164
|
-
walk(item, [...path, i]);
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
const collectProblems = (doc) => {
|
|
169
|
-
for (const err of doc.errors) {
|
|
170
|
-
// Duplicate keys honor the configured severity; every other parser error is
|
|
171
|
-
// a hard error.
|
|
172
|
-
const severity = err.code === 'DUPLICATE_KEY' ? dupSeverity : DiagnosticSeverity.Error;
|
|
173
|
-
pushError(severity, err.message, err.start, err.end);
|
|
174
|
-
}
|
|
175
|
-
for (const warn of doc.warnings) {
|
|
176
|
-
pushError(DiagnosticSeverity.Warning, warn.message, warn.start, warn.end);
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
let data;
|
|
180
|
-
if (docs.length > 1) {
|
|
181
|
-
// Multi-document stream: index each document under its own `[i, …]` prefix and
|
|
182
|
-
// project to an array of per-document values.
|
|
183
|
-
data = docs.map((doc, i) => {
|
|
184
|
-
walk(doc.contents, [i]);
|
|
185
|
-
collectProblems(doc);
|
|
186
|
-
return doc.toJS();
|
|
187
|
-
});
|
|
42
|
+
};
|
|
43
|
+
const rangeOf = (node) => ({
|
|
44
|
+
start: lineMap.positionAt(node.start),
|
|
45
|
+
end: lineMap.positionAt(node.end)
|
|
46
|
+
});
|
|
47
|
+
let budget = Math.max(1e5, source.length * 100);
|
|
48
|
+
const isMergePair = (pair) => isScalar(pair.key) && pair.key.source === "<<";
|
|
49
|
+
const walkMerge = (node, path) => {
|
|
50
|
+
const target = node != null && isAlias(node) ? node.target : node;
|
|
51
|
+
if (target == null)
|
|
52
|
+
return;
|
|
53
|
+
if (isSeq(target)) {
|
|
54
|
+
for (const item of target.items)
|
|
55
|
+
walkMerge(item, path);
|
|
56
|
+
return;
|
|
188
57
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
58
|
+
if (!isMap(target))
|
|
59
|
+
return;
|
|
60
|
+
for (const item of target.items) {
|
|
61
|
+
if (!isPair(item))
|
|
62
|
+
continue;
|
|
63
|
+
if (isMergePair(item)) {
|
|
64
|
+
walkMerge(item.value, path);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const childPath = [...path, keyToString(item.key)];
|
|
68
|
+
if (!index.has(pathKey(childPath)))
|
|
69
|
+
walk(item.value, childPath);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const walk = (node, path) => {
|
|
73
|
+
if (node == null || budget-- <= 0)
|
|
74
|
+
return;
|
|
75
|
+
index.set(pathKey(path), rangeOf(node));
|
|
76
|
+
if (isScalar(node)) {
|
|
77
|
+
const value = node.value;
|
|
78
|
+
if (incompatSeverity !== void 0 && typeof value === "number" && !Number.isFinite(value)) {
|
|
79
|
+
pushError(incompatSeverity, `Value ${String(value)} cannot be represented in JSON and will serialize to null.`, node.start, node.end, "INCOMPATIBLE_VALUE");
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
200
82
|
}
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
83
|
+
const target = isAlias(node) ? node.target : node;
|
|
84
|
+
if (target == null)
|
|
85
|
+
return;
|
|
86
|
+
if (isMap(target)) {
|
|
87
|
+
const merges = [];
|
|
88
|
+
for (const item of target.items) {
|
|
89
|
+
if (!isPair(item))
|
|
90
|
+
continue;
|
|
91
|
+
if (isMergePair(item)) {
|
|
92
|
+
merges.push(item.value);
|
|
93
|
+
continue;
|
|
210
94
|
}
|
|
211
|
-
|
|
212
|
-
|
|
95
|
+
walk(item.value, [...path, keyToString(item.key)]);
|
|
96
|
+
}
|
|
97
|
+
for (const merge of merges)
|
|
98
|
+
walkMerge(merge, path);
|
|
99
|
+
} else if (isSeq(target)) {
|
|
100
|
+
target.items.forEach((item, i) => {
|
|
101
|
+
walk(item, [...path, i]);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const collectProblems = (doc) => {
|
|
106
|
+
for (const err of doc.errors) {
|
|
107
|
+
const severity = err.code === "DUPLICATE_KEY" ? dupSeverity : DiagnosticSeverity.Error;
|
|
108
|
+
pushError(severity, err.message, err.start, err.end);
|
|
109
|
+
}
|
|
110
|
+
for (const warn of doc.warnings) {
|
|
111
|
+
pushError(DiagnosticSeverity.Warning, warn.message, warn.start, warn.end);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
let data;
|
|
115
|
+
if (docs.length > 1) {
|
|
116
|
+
data = docs.map((doc, i) => {
|
|
117
|
+
walk(doc.contents, [i]);
|
|
118
|
+
collectProblems(doc);
|
|
119
|
+
return doc.toJS();
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
const doc = docs[0];
|
|
123
|
+
if (doc) {
|
|
124
|
+
walk(doc.contents, []);
|
|
125
|
+
collectProblems(doc);
|
|
126
|
+
data = doc.toJS();
|
|
127
|
+
} else {
|
|
128
|
+
data = null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const getLocationForJsonPath = (path, closest = false) => {
|
|
132
|
+
const p = path.slice();
|
|
133
|
+
while (true) {
|
|
134
|
+
const range = index.get(pathKey(p));
|
|
135
|
+
if (range)
|
|
136
|
+
return { range };
|
|
137
|
+
if (!closest || p.length === 0)
|
|
138
|
+
return void 0;
|
|
139
|
+
p.pop();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
return { data, diagnostics, getLocationForJsonPath };
|
|
143
|
+
};
|
|
144
|
+
export {
|
|
145
|
+
parseYaml
|
|
213
146
|
};
|