First cut
This commit is contained in:
20
shared/src/canonical-json.ts
Normal file
20
shared/src/canonical-json.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Canonical JSON serialization: sorted keys at every level, 2-space indent, trailing newline.
|
||||
*/
|
||||
|
||||
export type JsonPrimitive = string | number | boolean | null;
|
||||
export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
|
||||
|
||||
function sortKeys(value: unknown): unknown {
|
||||
if (value === null || typeof value !== 'object') return value;
|
||||
if (Array.isArray(value)) return value.map(sortKeys);
|
||||
const sorted: Record<string, unknown> = {};
|
||||
for (const key of Object.keys(value as Record<string, unknown>).sort()) {
|
||||
sorted[key] = sortKeys((value as Record<string, unknown>)[key]);
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
export function stringifyCanonical(value: unknown): string {
|
||||
return JSON.stringify(sortKeys(value), null, 2) + '\n';
|
||||
}
|
||||
Reference in New Issue
Block a user