|
1 |
| -import * as fs from "fs"; |
2 |
| -import commentJson from "comment-json"; |
| 1 | +import { readFileSync } from "fs"; |
| 2 | +import { parse, ParseError, visit } from "jsonc-parser"; |
| 3 | +import { URL } from "url"; |
3 | 4 |
|
4 |
| -// A helper function to recursively sort object keys alphabetically. |
| 5 | +// Recursively sort object keys |
5 | 6 | function sortObjectKeys<T>(obj: T): T {
|
6 | 7 | if (obj && typeof obj === "object" && !Array.isArray(obj)) {
|
7 |
| - const sorted = {} as any; |
8 |
| - Object.keys(obj) |
9 |
| - .sort() |
10 |
| - .forEach((key) => { |
11 |
| - // Recursively sort keys if the value is an object |
12 |
| - sorted[key] = sortObjectKeys((obj as any)[key]); |
13 |
| - }); |
14 |
| - return sorted; |
| 8 | + const sorted: Record<string, unknown> = {}; |
| 9 | + for (const key of Object.keys(obj).sort()) { |
| 10 | + sorted[key] = sortObjectKeys((obj as any)[key]); |
| 11 | + } |
| 12 | + return sorted as T; |
15 | 13 | }
|
16 | 14 | return obj;
|
17 | 15 | }
|
18 | 16 |
|
19 |
| -export function sortFiles() { |
20 |
| - const files = ["overridingTypes", "removedTypes", "addedTypes"]; |
21 |
| - files.forEach((file) => { |
22 |
| - const filePath = new URL(`../../inputfiles/${file}.jsonc`, import.meta.url); // Replace with your JSONC file path |
| 17 | +// Check if the content has trailing commas |
| 18 | +function hasTrailingCommas(content: string): boolean { |
| 19 | + let foundTrailingComma = false; |
23 | 20 |
|
24 |
| - // Read the JSONC file content |
25 |
| - const fileContent = fs.readFileSync(filePath, "utf-8"); |
| 21 | + visit(content, { |
| 22 | + onObjectEnd: (offset) => { |
| 23 | + const lastChar = content[offset - 1]; |
| 24 | + if (lastChar === ",") { |
| 25 | + foundTrailingComma = true; |
| 26 | + } |
| 27 | + }, |
| 28 | + onArrayEnd: (offset) => { |
| 29 | + const lastChar = content[offset - 1]; |
| 30 | + if (lastChar === ",") { |
| 31 | + foundTrailingComma = true; |
| 32 | + } |
| 33 | + }, |
| 34 | + }); |
| 35 | + |
| 36 | + return foundTrailingComma; |
| 37 | +} |
26 | 38 |
|
27 |
| - // Parse the JSONC file while preserving comments |
28 |
| - const parsed = commentJson.parse(fileContent, undefined, true); |
| 39 | +export function sortFiles(): void { |
| 40 | + const filenames = ["overridingTypes", "removedTypes", "addedTypes"]; |
29 | 41 |
|
30 |
| - // Sort the object keys alphabetically (recursively) |
31 |
| - const sortedObject = sortObjectKeys(parsed); |
| 42 | + for (const name of filenames) { |
| 43 | + const filePath = new URL(`../../inputfiles/${name}.jsonc`, import.meta.url); |
| 44 | + const content = readFileSync(filePath, "utf-8"); |
32 | 45 |
|
33 |
| - // Stringify the sorted object back to JSONC format (preserving comments) |
34 |
| - const sortedJsonC = commentJson.stringify(sortedObject, null, 2); |
| 46 | + const errors: ParseError[] = []; |
| 47 | + const parsed = parse(content, errors, { allowTrailingComma: true }); |
35 | 48 |
|
36 |
| - // Write the sorted content back to the file |
37 |
| - fs.writeFileSync(filePath, sortedJsonC, "utf-8"); |
38 |
| - }); |
| 49 | + if (errors.length > 0) { |
| 50 | + throw new Error(`❌ Syntax error(s) found in ${name}.jsonc:`); |
| 51 | + } |
39 | 52 |
|
40 |
| - console.log("JSONC file keys sorted successfully."); |
| 53 | + if (hasTrailingCommas(content)) { |
| 54 | + throw new Error(`❌ Trailing comma detected in ${name}.jsonc`); |
| 55 | + } |
| 56 | + |
| 57 | + const sorted = sortObjectKeys(parsed); |
| 58 | + const originalStr = JSON.stringify(parsed); |
| 59 | + const sortedStr = JSON.stringify(sorted); |
| 60 | + |
| 61 | + if (originalStr !== sortedStr) { |
| 62 | + throw new Error(`❌ Keys are not sorted in ${name}.jsonc`); |
| 63 | + } |
| 64 | + |
| 65 | + console.log(`✅ ${name}.jsonc is valid, sorted, and clean.`); |
| 66 | + } |
41 | 67 | }
|
0 commit comments