@plurnk/plurnk-mimetypes-application-json 0.1.0 → 0.2.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationJson.d.ts","sourceRoot":"","sources":["../src/ApplicationJson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"ApplicationJson.d.ts","sourceRoot":"","sources":["../src/ApplicationJson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAe3D,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,WAAW;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAe/B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE;CAazC"}
|
package/dist/ApplicationJson.js
CHANGED
|
@@ -1,64 +1,87 @@
|
|
|
1
1
|
import { BaseHandler } from "@plurnk/plurnk-mimetypes";
|
|
2
|
-
|
|
2
|
+
import { parseTree, printParseErrorCode } from "jsonc-parser";
|
|
3
|
+
// One class serves two mimetype names — application/json (strict) and
|
|
4
|
+
// application/jsonc (comments + trailing commas allowed). The framework
|
|
5
|
+
// constructs one instance per registered name; this.mimetype distinguishes
|
|
6
|
+
// them at runtime.
|
|
3
7
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// caller — this is the contract for "the consumer asserted this is JSON,
|
|
7
|
-
// but it isn't."
|
|
8
|
+
// validate(): strict for application/json (no comments, no trailing commas);
|
|
9
|
+
// permissive for application/jsonc. Errors propagate per SPEC §7.
|
|
8
10
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// have no named top-level keys → empty Symbol[].
|
|
14
|
-
//
|
|
15
|
-
// Line numbers are derived from a single-pass scan of the raw source — JSON.parse
|
|
16
|
-
// itself doesn't preserve positions. The scan is approximate (a `"key":` pattern
|
|
17
|
-
// inside a string value could in principle be mis-matched as a key) but accurate
|
|
18
|
-
// for well-formed documents in practical use.
|
|
11
|
+
// extract(): every key occurrence at every depth as a `field` symbol, with
|
|
12
|
+
// line numbers from jsonc-parser's positional tree (Node.offset).
|
|
13
|
+
// No regex tokenization, no escape-handling reinvention — the
|
|
14
|
+
// parser does it.
|
|
19
15
|
export default class ApplicationJson extends BaseHandler {
|
|
20
16
|
validate(content) {
|
|
21
|
-
|
|
17
|
+
const errors = [];
|
|
18
|
+
const allowsRelaxation = this.mimetype === "application/jsonc";
|
|
19
|
+
parseTree(content, errors, {
|
|
20
|
+
allowTrailingComma: allowsRelaxation,
|
|
21
|
+
disallowComments: !allowsRelaxation,
|
|
22
|
+
});
|
|
23
|
+
if (errors.length === 0)
|
|
24
|
+
return;
|
|
25
|
+
const first = errors[0];
|
|
26
|
+
const { line, column } = offsetToLineCol(content, first.offset);
|
|
27
|
+
throw new SyntaxError(`${printParseErrorCode(first.error)} at line ${line}:${column}`);
|
|
22
28
|
}
|
|
23
29
|
extract(content) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
const errors = [];
|
|
31
|
+
const allowsRelaxation = this.mimetype === "application/jsonc";
|
|
32
|
+
const tree = parseTree(content, errors, {
|
|
33
|
+
allowTrailingComma: allowsRelaxation,
|
|
34
|
+
disallowComments: !allowsRelaxation,
|
|
35
|
+
});
|
|
36
|
+
if (tree === undefined)
|
|
29
37
|
return [];
|
|
38
|
+
const symbols = [];
|
|
39
|
+
collectKeys(tree, content, symbols);
|
|
40
|
+
return symbols;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Walk a jsonc-parser Node tree and emit a field symbol for every property
|
|
44
|
+
// key encountered at every depth. Each property node has a `children` pair:
|
|
45
|
+
// [keyNode, valueNode]. The keyNode's offset gives the source position.
|
|
46
|
+
function collectKeys(node, content, into) {
|
|
47
|
+
if (node.type === "property" && node.children && node.children.length >= 2) {
|
|
48
|
+
const keyNode = node.children[0];
|
|
49
|
+
if (keyNode.type === "string" && typeof keyNode.value === "string") {
|
|
50
|
+
const line = offsetToLineCol(content, keyNode.offset).line;
|
|
51
|
+
into.push({
|
|
52
|
+
name: keyNode.value,
|
|
53
|
+
kind: "field",
|
|
54
|
+
line,
|
|
55
|
+
endLine: line,
|
|
56
|
+
});
|
|
30
57
|
}
|
|
31
|
-
|
|
32
|
-
|
|
58
|
+
// Recurse into the value to find nested keys.
|
|
59
|
+
const valueNode = node.children[1];
|
|
60
|
+
if (valueNode)
|
|
61
|
+
collectKeys(valueNode, content, into);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Objects, arrays, and the root all recurse through children.
|
|
65
|
+
if (node.children) {
|
|
66
|
+
for (const child of node.children) {
|
|
67
|
+
collectKeys(child, content, into);
|
|
33
68
|
}
|
|
34
|
-
const keys = Object.keys(parsed);
|
|
35
|
-
const lineMap = mapKeysToLines(content, keys);
|
|
36
|
-
return keys.map((name) => {
|
|
37
|
-
const line = lineMap.get(name) ?? 1;
|
|
38
|
-
return { name, kind: "field", line, endLine: line };
|
|
39
|
-
});
|
|
40
69
|
}
|
|
41
70
|
}
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
55
|
-
const pattern = new RegExp(`"${escaped}"\\s*:`);
|
|
56
|
-
if (pattern.test(line)) {
|
|
57
|
-
result.set(key, i + 1);
|
|
58
|
-
remaining.delete(key);
|
|
59
|
-
}
|
|
71
|
+
// Convert a byte offset into 1-indexed line/column.
|
|
72
|
+
function offsetToLineCol(content, offset) {
|
|
73
|
+
let line = 1;
|
|
74
|
+
let column = 1;
|
|
75
|
+
const limit = Math.min(offset, content.length);
|
|
76
|
+
for (let i = 0; i < limit; i += 1) {
|
|
77
|
+
if (content.charCodeAt(i) === 0x0a) {
|
|
78
|
+
line += 1;
|
|
79
|
+
column = 1;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
column += 1;
|
|
60
83
|
}
|
|
61
84
|
}
|
|
62
|
-
return
|
|
85
|
+
return { line, column };
|
|
63
86
|
}
|
|
64
87
|
//# sourceMappingURL=ApplicationJson.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationJson.js","sourceRoot":"","sources":["../src/ApplicationJson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"ApplicationJson.js","sourceRoot":"","sources":["../src/ApplicationJson.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-mimetypes-application-json",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "application/json mimetype handler for plurnk-service.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "application/json and application/jsonc mimetype handler for plurnk-service.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publishConfig": {
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"plurnk": {
|
|
14
14
|
"kind": "mimetype",
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
"handlers": [
|
|
16
|
+
{ "name": "application/json", "glyph": "📋", "extensions": [".json"] },
|
|
17
|
+
{ "name": "application/jsonc", "glyph": "📋", "extensions": [".jsonc"] }
|
|
18
|
+
]
|
|
18
19
|
},
|
|
19
20
|
"exports": {
|
|
20
21
|
".": {
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
"prepare": "npm run build"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"@plurnk/plurnk-mimetypes": "^0.
|
|
40
|
+
"@plurnk/plurnk-mimetypes": "^0.2.0",
|
|
41
|
+
"jsonc-parser": "^3.3.1"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@types/node": "^25.8.0",
|