Skip to content

Commit 110d1c5

Browse files
committed
Refactor JSONC file validation: remove sorter and implement verification in a new module
1 parent dd02ef2 commit 110d1c5

File tree

3 files changed

+82
-69
lines changed

3 files changed

+82
-69
lines changed

src/build.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { getInterfaceElementMergeData } from "./build/webref/elements.js";
1313
import { getInterfaceToEventMap } from "./build/webref/events.js";
1414
import { getWebidls } from "./build/webref/idl.js";
1515
import jsonc from "jsonc-parser";
16-
import { sortFiles } from "./build/sorter.js";
1716

1817
function mergeNamesakes(filtered: Browser.WebIdl) {
1918
const targets = [
@@ -397,4 +396,3 @@ async function emitDom() {
397396
}
398397

399398
await emitDom();
400-
sortFiles();

src/build/sorter.ts

Lines changed: 0 additions & 67 deletions
This file was deleted.

src/verifyFiles.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { readFileSync } from "fs";
2+
import { parse, ParseError, visit } from "jsonc-parser";
3+
import { URL } from "url";
4+
5+
/**
6+
* Recursively verify that all object keys are sorted alphabetically.
7+
* Throws an error if any object has unsorted keys.
8+
*/
9+
function verifyObjectKeysSorted(obj: unknown, path: string = ""): void {
10+
if (obj && typeof obj === "object" && !Array.isArray(obj)) {
11+
const keys = Object.keys(obj);
12+
const sortedKeys = [...keys].sort();
13+
14+
for (let i = 0; i < keys.length; i++) {
15+
if (keys[i] !== sortedKeys[i]) {
16+
throw new Error(
17+
`❌ Keys are not sorted at ${path || "root object"}.\nExpected order: ${sortedKeys.join(", ")}`,
18+
);
19+
}
20+
}
21+
22+
for (const key of keys) {
23+
verifyObjectKeysSorted(
24+
(obj as Record<string, unknown>)[key],
25+
path ? `${path}.${key}` : key,
26+
);
27+
}
28+
} else if (Array.isArray(obj)) {
29+
obj.forEach((item, index) =>
30+
verifyObjectKeysSorted(item, `${path}[${index}]`),
31+
);
32+
}
33+
}
34+
35+
/**
36+
* Check if the given JSONC content has trailing commas.
37+
*/
38+
function hasTrailingCommas(content: string): boolean {
39+
let found = false;
40+
41+
visit(content, {
42+
onObjectEnd: (offset) => {
43+
if (content[offset - 1] === ",") found = true;
44+
},
45+
onArrayEnd: (offset) => {
46+
if (content[offset - 1] === ",") found = true;
47+
},
48+
});
49+
50+
return found;
51+
}
52+
53+
/**
54+
* Verify and validate multiple JSONC files:
55+
* - Check for syntax errors
56+
* - Disallow trailing commas
57+
* - Ensure keys are sorted
58+
*/
59+
export function verifyFiles(): void {
60+
const filenames = ["overridingTypes", "removedTypes", "addedTypes"];
61+
62+
for (const name of filenames) {
63+
const filePath = new URL(`../inputfiles/${name}.jsonc`, import.meta.url);
64+
const content = readFileSync(filePath, "utf-8");
65+
66+
const errors: ParseError[] = [];
67+
const parsed = parse(content, errors, { allowTrailingComma: true });
68+
69+
if (errors.length > 0) {
70+
throw new Error(`❌ ${name}.jsonc contains syntax error(s).`);
71+
}
72+
73+
if (hasTrailingCommas(content)) {
74+
throw new Error(`❌ ${name}.jsonc has trailing comma(s).`);
75+
}
76+
77+
verifyObjectKeysSorted(parsed);
78+
79+
console.log(`✅ ${name}.jsonc is valid, sorted, and clean.`);
80+
}
81+
}
82+
verifyFiles();

0 commit comments

Comments
 (0)