-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcanon.ts
71 lines (66 loc) · 1.65 KB
/
canon.ts
1
2
3
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* This module provides canonicalization of JSON trees. This complies with
* RFC 8785, also known as JCS (JSON Canonicalization Scheme).
* @license LGPL-3.0-or-later
*/
/**
* Represents a JSON tree.
*/
export type Tree =
| null
| boolean
| number
| string
| TreeArray
| TreeObject;
// deno-lint-ignore no-empty-interface
interface TreeArray extends Array<Tree> {
}
interface TreeObject {
[_: string]: Tree;
}
function serialize(tree: Tree, buffer: string[]): void {
if (tree == null || typeof tree !== "object") {
// ES6 JSON partially complies with RFC 8785 (JCS: JSON Canonicalization
// Scheme) except for objects and arrays:
buffer.push(JSON.stringify(tree));
} else if (Array.isArray(tree)) {
buffer.push("[");
let notFirst = false;
for (const item of tree) {
if (notFirst) {
buffer.push(",");
}
notFirst = true;
serialize(item, buffer);
}
buffer.push("]");
} else {
// Object keys must be sorted in JSON.
const keys = Object.keys(tree);
keys.sort();
buffer.push("{");
let notFirst = false;
for (const key of keys) {
if (notFirst) {
buffer.push(",");
}
notFirst = true;
buffer.push(JSON.stringify(key));
buffer.push(":");
serialize(tree[key], buffer);
}
buffer.push("}");
}
}
/**
* Serializes a tree into a JSON string which complies with RFC 8785
* (JCS: JSON Canonicalization Scheme).
* @param tree The tree to serialize.
* @returns The canonicalized JSON string.
*/
export function canonicalize(tree: Tree): string {
const buffer: string[] = [];
serialize(tree, buffer);
return buffer.join("");
}