@creationix/jot 0.0.1 → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +112 -23
- package/dist/jot.cjs +446 -0
- package/dist/jot.d.ts +6 -0
- package/dist/jot.js +442 -0
- package/package.json +34 -4
- package/SUMMARY.md +0 -151
- package/TOKEN_COUNTS.md +0 -97
- package/bun.lock +0 -19
- package/jot.test.ts +0 -133
- package/jot.ts +0 -650
- package/samples/chat.jot +0 -1
- package/samples/chat.json +0 -1
- package/samples/chat.pretty.jot +0 -6
- package/samples/chat.pretty.json +0 -16
- package/samples/firewall.jot +0 -1
- package/samples/firewall.json +0 -1
- package/samples/firewall.pretty.jot +0 -235
- package/samples/firewall.pretty.json +0 -344
- package/samples/github-issue.jot +0 -1
- package/samples/github-issue.json +0 -1
- package/samples/github-issue.pretty.jot +0 -15
- package/samples/github-issue.pretty.json +0 -20
- package/samples/hikes.jot +0 -1
- package/samples/hikes.json +0 -1
- package/samples/hikes.pretty.jot +0 -14
- package/samples/hikes.pretty.json +0 -38
- package/samples/irregular.jot +0 -1
- package/samples/irregular.json +0 -1
- package/samples/irregular.pretty.jot +0 -13
- package/samples/irregular.pretty.json +0 -23
- package/samples/json-counts-cache.jot +0 -1
- package/samples/json-counts-cache.json +0 -1
- package/samples/json-counts-cache.pretty.jot +0 -26
- package/samples/json-counts-cache.pretty.json +0 -26
- package/samples/key-folding-basic.jot +0 -1
- package/samples/key-folding-basic.json +0 -1
- package/samples/key-folding-basic.pretty.jot +0 -7
- package/samples/key-folding-basic.pretty.json +0 -25
- package/samples/key-folding-mixed.jot +0 -1
- package/samples/key-folding-mixed.json +0 -1
- package/samples/key-folding-mixed.pretty.jot +0 -16
- package/samples/key-folding-mixed.pretty.json +0 -24
- package/samples/key-folding-with-array.jot +0 -1
- package/samples/key-folding-with-array.json +0 -1
- package/samples/key-folding-with-array.pretty.jot +0 -6
- package/samples/key-folding-with-array.pretty.json +0 -29
- package/samples/large.jot +0 -1
- package/samples/large.json +0 -1
- package/samples/large.pretty.jot +0 -72
- package/samples/large.pretty.json +0 -93
- package/samples/logs.jot +0 -1
- package/samples/logs.json +0 -1
- package/samples/logs.pretty.jot +0 -96
- package/samples/logs.pretty.json +0 -350
- package/samples/medium.jot +0 -1
- package/samples/medium.json +0 -1
- package/samples/medium.pretty.jot +0 -13
- package/samples/medium.pretty.json +0 -30
- package/samples/metrics.jot +0 -1
- package/samples/metrics.json +0 -1
- package/samples/metrics.pretty.jot +0 -11
- package/samples/metrics.pretty.json +0 -25
- package/samples/package.jot +0 -1
- package/samples/package.json +0 -1
- package/samples/package.pretty.jot +0 -18
- package/samples/package.pretty.json +0 -18
- package/samples/products.jot +0 -1
- package/samples/products.json +0 -1
- package/samples/products.pretty.jot +0 -69
- package/samples/products.pretty.json +0 -235
- package/samples/routes.jot +0 -1
- package/samples/routes.json +0 -1
- package/samples/routes.pretty.jot +0 -142
- package/samples/routes.pretty.json +0 -354
- package/samples/small.jot +0 -1
- package/samples/small.json +0 -1
- package/samples/small.pretty.jot +0 -8
- package/samples/small.pretty.json +0 -12
- package/samples/users-50.jot +0 -1
- package/samples/users-50.json +0 -1
- package/samples/users-50.pretty.jot +0 -53
- package/samples/users-50.pretty.json +0 -354
package/TOKEN_COUNTS.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Token Counts by Format
|
|
2
|
-
|
|
3
|
-
## Qwen Tokenizer (LM Studio)
|
|
4
|
-
|
|
5
|
-
Tokens measured using **Qwen3-Coder-30b** via LM Studio API. This is the primary tokenizer used for testing local model efficiency.
|
|
6
|
-
|
|
7
|
-
<!-- QWEN_CHART_START -->
|
|
8
|
-
```mermaid
|
|
9
|
-
xychart-beta
|
|
10
|
-
title "Token Savings vs JSON (negative = better)"
|
|
11
|
-
x-axis ["Users50", "Hikes", "Medium", "KF-arr", "Firewall", "KF-basic", "Products", "Routes", "Metrics", "Package", "Chat", "KF-mix", "Issue", "Small", "Large", "Irregular", "Logs"]
|
|
12
|
-
y-axis "% vs JSON" -60 --> 40
|
|
13
|
-
line "JSON" [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
14
|
-
line "Jot" [-48, -29, -27, -26, -19, -19, -19, -15, -14, -12, -12, -12, -10, -8, -8, -7, -3]
|
|
15
|
-
line "YAML" [25, 18, 27, 19, 24, 10, 26, 16, 20, 7, 8, 14, 11, 17, 23, 28, 18]
|
|
16
|
-
line "TOON" [-40, -23, -14, 9, 30, 9, 10, 8, -6, 7, -11, 13, 2, 4, 18, 29, 18]
|
|
17
|
-
```
|
|
18
|
-
<!-- QWEN_CHART_END -->
|
|
19
|
-
|
|
20
|
-
### Per-File Breakdown (Qwen)
|
|
21
|
-
|
|
22
|
-
<!-- QWEN_TABLE_START -->
|
|
23
|
-
| Format | Chat | Firewall | Issue | Hikes | Irregular | KF-basic | KF-mix | KF-arr | Large | Logs | Medium | Metrics | Package | Products | Routes | Small | Users50 | Total |
|
|
24
|
-
|--------|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|
|
|
25
|
-
| Jot | [67](jot/chat.jot) | [669](jot/firewall.jot) | [79](jot/github-issue.jot) | [112](jot/hikes.jot) | [63](jot/irregular.jot) | [47](jot/key-folding-basic.jot) | [69](jot/key-folding-mixed.jot) | [43](jot/key-folding-with-array.jot) | [246](jot/large.jot) | [2044](jot/logs.jot) | [71](jot/medium.jot) | [101](jot/metrics.jot) | [85](jot/package.jot) | [702](jot/products.jot) | [1246](jot/routes.jot) | [44](jot/small.jot) | [663](jot/users-50.jot) | 6,351 |
|
|
26
|
-
| JSONito | [86](jsonito/chat.jito) | [919](jsonito/firewall.jito) | [89](jsonito/github-issue.jito) | [158](jsonito/hikes.jito) | [59](jsonito/irregular.jito) | [62](jsonito/key-folding-basic.jito) | [82](jsonito/key-folding-mixed.jito) | [63](jsonito/key-folding-with-array.jito) | [312](jsonito/large.jito) | [1941](jsonito/logs.jito) | [103](jsonito/medium.jito) | [89](jsonito/metrics.jito) | [101](jsonito/package.jito) | [846](jsonito/products.jito) | [1426](jsonito/routes.jito) | [45](jsonito/small.jito) | [1234](jsonito/users-50.jito) | 7,615 |
|
|
27
|
-
| JSON-m | [76](json/chat.json) | [827](json/firewall.json) | [88](json/github-issue.json) | [158](json/hikes.json) | [68](json/irregular.json) | [58](json/key-folding-basic.json) | [78](json/key-folding-mixed.json) | [58](json/key-folding-with-array.json) | [266](json/large.json) | [2108](json/logs.json) | [97](json/medium.json) | [117](json/metrics.json) | [97](json/package.json) | [866](json/products.json) | [1459](json/routes.json) | [48](json/small.json) | [1279](json/users-50.json) | 7,748 |
|
|
28
|
-
| Jot-P | [73](jot/chat.pretty.jot) | [1119](jot/firewall.pretty.jot) | [105](jot/github-issue.pretty.jot) | [142](jot/hikes.pretty.jot) | [91](jot/irregular.pretty.jot) | [54](jot/key-folding-basic.pretty.jot) | [96](jot/key-folding-mixed.pretty.jot) | [52](jot/key-folding-with-array.pretty.jot) | [365](jot/large.pretty.jot) | [2304](jot/logs.pretty.jot) | [100](jot/medium.pretty.jot) | [123](jot/metrics.pretty.jot) | [120](jot/package.pretty.jot) | [828](jot/products.pretty.jot) | [1521](jot/routes.pretty.jot) | [59](jot/small.pretty.jot) | [863](jot/users-50.pretty.jot) | 8,015 |
|
|
29
|
-
| D2 | [80](d2/chat.d2) | [894](d2/firewall.d2) | [97](d2/github-issue.d2) | [173](d2/hikes.d2) | [81](d2/irregular.d2) | [60](d2/key-folding-basic.d2) | [80](d2/key-folding-mixed.d2) | [67](d2/key-folding-with-array.d2) | [316](d2/large.d2) | [2092](d2/logs.d2) | [104](d2/medium.d2) | [138](d2/metrics.d2) | [90](d2/package.d2) | [994](d2/products.d2) | [1536](d2/routes.d2) | [55](d2/small.d2) | [1202](d2/users-50.d2) | 8,059 |
|
|
30
|
-
| TOON | [68](toon/chat.toon) | [1073](toon/firewall.toon) | [90](toon/github-issue.toon) | [122](toon/hikes.toon) | [88](toon/irregular.toon) | [63](toon/key-folding-basic.toon) | [88](toon/key-folding-mixed.toon) | [63](toon/key-folding-with-array.toon) | [313](toon/large.toon) | [2492](toon/logs.toon) | [83](toon/medium.toon) | [110](toon/metrics.toon) | [104](toon/package.toon) | [954](toon/products.toon) | [1574](toon/routes.toon) | [50](toon/small.toon) | [763](toon/users-50.toon) | 8,098 |
|
|
31
|
-
| YAML | [82](yaml/chat.yaml) | [1029](yaml/firewall.yaml) | [98](yaml/github-issue.yaml) | [187](yaml/hikes.yaml) | [87](yaml/irregular.yaml) | [64](yaml/key-folding-basic.yaml) | [89](yaml/key-folding-mixed.yaml) | [69](yaml/key-folding-with-array.yaml) | [327](yaml/large.yaml) | [2487](yaml/logs.yaml) | [123](yaml/medium.yaml) | [140](yaml/metrics.yaml) | [104](yaml/package.yaml) | [1095](yaml/products.yaml) | [1696](yaml/routes.yaml) | [56](yaml/small.yaml) | [1597](yaml/users-50.yaml) | 9,330 |
|
|
32
|
-
| TOML | [84](toml/chat.toml) | [1495](toml/firewall.toml) | [99](toml/github-issue.toml) | [189](toml/hikes.toml) | [86](toml/irregular.toml) | [60](toml/key-folding-basic.toml) | [85](toml/key-folding-mixed.toml) | [61](toml/key-folding-with-array.toml) | [377](toml/large.toml) | [2498](toml/logs.toml) | [118](toml/medium.toml) | [139](toml/metrics.toml) | [104](toml/package.toml) | [1114](toml/products.toml) | [1790](toml/routes.toml) | [56](toml/small.toml) | [1625](toml/users-50.toml) | 9,980 |
|
|
33
|
-
<!-- QWEN_TABLE_END -->
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## Legacy Claude Tokenizer
|
|
38
|
-
|
|
39
|
-
Tokens measured using **@anthropic-ai/tokenizer** (Claude's legacy tokenizer). This is the older tokenizer used by earlier Claude models.
|
|
40
|
-
|
|
41
|
-
<!-- LEGACY_CHART_START -->
|
|
42
|
-
```mermaid
|
|
43
|
-
xychart-beta
|
|
44
|
-
title "Token Savings vs JSON (negative = better)"
|
|
45
|
-
x-axis ["Users50", "Hikes", "Products", "Metrics", "Medium", "Routes", "Chat", "KF-arr", "KF-basic", "Large", "KF-mix", "Issue", "Firewall", "Package", "Logs", "Small", "Irregular"]
|
|
46
|
-
y-axis "% vs JSON" -50 --> 30
|
|
47
|
-
line "JSON" [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
48
|
-
line "Jot" [-37, -26, -20, -20, -20, -11, -10, -10, -8, -8, -6, -6, -2, -2, -1, 0, 2]
|
|
49
|
-
line "YAML" [3, 3, 4, 5, 4, 4, 4, 15, 8, 9, 4, 7, 8, 0, 2, 11, 8]
|
|
50
|
-
line "TOON" [-37, -24, -7, -21, -20, 3, -11, 12, 6, 4, 6, 0, 13, 0, 8, 3, 10]
|
|
51
|
-
```
|
|
52
|
-
<!-- LEGACY_CHART_END -->
|
|
53
|
-
|
|
54
|
-
### Per-File Breakdown (Legacy)
|
|
55
|
-
|
|
56
|
-
<!-- LEGACY_TABLE_START -->
|
|
57
|
-
| Format | Chat | Metrics | Large | KF-mix | Logs | Firewall | Small | Issue | Users50 | Medium | Hikes | Package | KF-basic | Irregular | KF-arr | Products | Routes | Total |
|
|
58
|
-
|--------|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|
|
|
59
|
-
| Jot | [63](jot/chat.jot) | [60](jot/metrics.jot) | [221](jot/large.jot) | [65](jot/key-folding-mixed.jot) | [1737](jot/logs.jot) | [825](jot/firewall.jot) | [36](jot/small.jot) | [68](jot/github-issue.jot) | [837](jot/users-50.jot) | [76](jot/medium.jot) | [103](jot/hikes.jot) | [91](jot/package.jot) | [45](jot/key-folding-basic.jot) | [49](jot/irregular.jot) | [47](jot/key-folding-with-array.jot) | [613](jot/products.jot) | [1352](jot/routes.jot) | 6,288 |
|
|
60
|
-
| JSON-m | [70](json/chat.json) | [75](json/metrics.json) | [239](json/large.json) | [69](json/key-folding-mixed.json) | [1750](json/logs.json) | [845](json/firewall.json) | [36](json/small.json) | [72](json/github-issue.json) | [1326](json/users-50.json) | [95](json/medium.json) | [139](json/hikes.json) | [93](json/package.json) | [49](json/key-folding-basic.json) | [48](json/irregular.json) | [52](json/key-folding-with-array.json) | [771](json/products.json) | [1516](json/routes.json) | 7,245 |
|
|
61
|
-
| YAML | [73](yaml/chat.yaml) | [79](yaml/metrics.yaml) | [260](yaml/large.yaml) | [72](yaml/key-folding-mixed.yaml) | [1780](yaml/logs.yaml) | [911](yaml/firewall.yaml) | [40](yaml/small.yaml) | [77](yaml/github-issue.yaml) | [1365](yaml/users-50.yaml) | [99](yaml/medium.yaml) | [143](yaml/hikes.yaml) | [93](yaml/package.yaml) | [53](yaml/key-folding-basic.yaml) | [52](yaml/irregular.yaml) | [60](yaml/key-folding-with-array.yaml) | [799](yaml/products.yaml) | [1572](yaml/routes.yaml) | 7,528 |
|
|
62
|
-
| TOON | [62](toon/chat.toon) | [59](toon/metrics.toon) | [249](toon/large.toon) | [73](toon/key-folding-mixed.toon) | [1885](toon/logs.toon) | [955](toon/firewall.toon) | [37](toon/small.toon) | [72](toon/github-issue.toon) | [836](toon/users-50.toon) | [76](toon/medium.toon) | [105](toon/hikes.toon) | [93](toon/package.toon) | [52](toon/key-folding-basic.toon) | [53](toon/irregular.toon) | [58](toon/key-folding-with-array.toon) | [720](toon/products.toon) | [1557](toon/routes.toon) | 6,942 |
|
|
63
|
-
<!-- LEGACY_TABLE_END -->
|
|
64
|
-
|
|
65
|
-
Note: The legacy tokenizer may produce different results than modern Claude models, but is useful for comparison and runs locally without API calls.
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## Modern Claude Tokenizer
|
|
70
|
-
|
|
71
|
-
Tokens measured using **Claude API** token counting endpoint (claude-sonnet-4). This represents the actual token usage for modern Claude models. Token counting is free via the API.
|
|
72
|
-
|
|
73
|
-
<!-- CLAUDE_CHART_START -->
|
|
74
|
-
```mermaid
|
|
75
|
-
xychart-beta
|
|
76
|
-
title "Token Savings vs JSON (negative = better)"
|
|
77
|
-
x-axis ["Users50", "Hikes", "Products", "KF-basic", "KF-arr", "Metrics", "Medium", "Large", "Firewall", "KF-mix", "Routes", "Chat", "Issue", "Irregular", "Package", "Small", "Logs"]
|
|
78
|
-
y-axis "% vs JSON" -50 --> 40
|
|
79
|
-
line "JSON" [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
80
|
-
line "Jot" [-39, -29, -24, -24, -24, -23, -22, -16, -15, -15, -14, -12, -9, -6, -6, -4, -2]
|
|
81
|
-
line "YAML" [22, 19, 27, 1, 14, 19, 19, 16, 13, 6, 9, 6, 8, 21, 4, 13, 18]
|
|
82
|
-
line "TOON" [-36, -25, 8, 1, 6, -18, -14, 12, 17, 8, 7, -10, 1, 24, 5, 2, 21]
|
|
83
|
-
```
|
|
84
|
-
<!-- CLAUDE_CHART_END -->
|
|
85
|
-
|
|
86
|
-
### Per-File Breakdown (Claude)
|
|
87
|
-
|
|
88
|
-
<!-- CLAUDE_TABLE_START -->
|
|
89
|
-
| Format | Chat | Metrics | Large | KF-mix | Logs | Firewall | Small | Issue | Users50 | Medium | Hikes | Package | KF-basic | Irregular | KF-arr | Products | Routes | Total |
|
|
90
|
-
|--------|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|------:|
|
|
91
|
-
| Jot | [71](jot/chat.jot) | [68](jot/metrics.jot) | [241](jot/large.jot) | [76](jot/key-folding-mixed.jot) | [1762](jot/logs.jot) | [867](jot/firewall.jot) | [44](jot/small.jot) | [78](jot/github-issue.jot) | [830](jot/users-50.jot) | [83](jot/medium.jot) | [115](jot/hikes.jot) | [99](jot/package.jot) | [53](jot/key-folding-basic.jot) | [59](jot/irregular.jot) | [53](jot/key-folding-with-array.jot) | [634](jot/products.jot) | [1472](jot/routes.jot) | 6,605 |
|
|
92
|
-
| JSON-m | [81](json/chat.json) | [88](json/metrics.json) | [286](json/large.json) | [89](json/key-folding-mixed.json) | [1798](json/logs.json) | [1022](json/firewall.json) | [46](json/small.json) | [86](json/github-issue.json) | [1369](json/users-50.json) | [107](json/medium.json) | [163](json/hikes.json) | [105](json/package.json) | [70](json/key-folding-basic.json) | [63](json/irregular.json) | [70](json/key-folding-with-array.json) | [839](json/products.json) | [1707](json/routes.json) | 7,989 |
|
|
93
|
-
| YAML | [86](yaml/chat.yaml) | [105](yaml/metrics.yaml) | [333](yaml/large.yaml) | [94](yaml/key-folding-mixed.yaml) | [2118](yaml/logs.yaml) | [1152](yaml/firewall.yaml) | [52](yaml/small.yaml) | [93](yaml/github-issue.yaml) | [1666](yaml/users-50.yaml) | [127](yaml/medium.yaml) | [194](yaml/hikes.yaml) | [109](yaml/package.yaml) | [71](yaml/key-folding-basic.yaml) | [76](yaml/irregular.yaml) | [80](yaml/key-folding-with-array.yaml) | [1063](yaml/products.yaml) | [1857](yaml/routes.yaml) | 9,276 |
|
|
94
|
-
| TOON | [73](toon/chat.toon) | [72](toon/metrics.toon) | [319](toon/large.toon) | [96](toon/key-folding-mixed.toon) | [2175](toon/logs.toon) | [1195](toon/firewall.toon) | [47](toon/small.toon) | [87](toon/github-issue.toon) | [879](toon/users-50.toon) | [92](toon/medium.toon) | [123](toon/hikes.toon) | [110](toon/package.toon) | [71](toon/key-folding-basic.toon) | [78](toon/irregular.toon) | [74](toon/key-folding-with-array.toon) | [907](toon/products.toon) | [1822](toon/routes.toon) | 8,220 |
|
|
95
|
-
<!-- CLAUDE_TABLE_END -->
|
|
96
|
-
|
|
97
|
-
Note: Run `ANTHROPIC_API_KEY=... bun scripts/count-claude-tokens.ts` to regenerate Claude counts.
|
package/bun.lock
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"lockfileVersion": 1,
|
|
3
|
-
"workspaces": {
|
|
4
|
-
"": {
|
|
5
|
-
"devDependencies": {
|
|
6
|
-
"@types/bun": "^1.3.5",
|
|
7
|
-
},
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
"packages": {
|
|
11
|
-
"@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
|
|
12
|
-
|
|
13
|
-
"@types/node": ["@types/node@25.0.6", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q=="],
|
|
14
|
-
|
|
15
|
-
"bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
|
|
16
|
-
|
|
17
|
-
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
18
|
-
}
|
|
19
|
-
}
|
package/jot.test.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from "bun:test"
|
|
2
|
-
import { stringify, parse } from "./jot"
|
|
3
|
-
|
|
4
|
-
describe("stringify", () => {
|
|
5
|
-
test("null", () => expect(stringify(null)).toBe("null"))
|
|
6
|
-
test("true", () => expect(stringify(true)).toBe("true"))
|
|
7
|
-
test("false", () => expect(stringify(false)).toBe("false"))
|
|
8
|
-
test("number", () => expect(stringify(42)).toBe("42"))
|
|
9
|
-
test("float", () => expect(stringify(3.14)).toBe("3.14"))
|
|
10
|
-
|
|
11
|
-
describe("strings", () => {
|
|
12
|
-
test("simple string", () => expect(stringify("hello")).toBe("hello"))
|
|
13
|
-
test("string with space", () => expect(stringify("hello world")).toBe("hello world"))
|
|
14
|
-
test("empty string", () => expect(stringify("")).toBe('""'))
|
|
15
|
-
test("numeric string", () => expect(stringify("123")).toBe('"123"'))
|
|
16
|
-
test("reserved word", () => expect(stringify("true")).toBe('"true"'))
|
|
17
|
-
test("contains colon", () => expect(stringify("a:b")).toBe('"a:b"'))
|
|
18
|
-
test("contains semicolon", () => expect(stringify("a;b")).toBe('"a;b"'))
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
describe("arrays", () => {
|
|
22
|
-
test("empty array", () => expect(stringify([])).toBe("[]"))
|
|
23
|
-
test("simple array", () => expect(stringify([1, 2, 3])).toBe("[1,2,3]"))
|
|
24
|
-
test("string array", () => expect(stringify(["a", "b"])).toBe("[a,b]"))
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe("objects", () => {
|
|
28
|
-
test("empty object", () => expect(stringify({})).toBe("{}"))
|
|
29
|
-
test("simple object", () => expect(stringify({ name: "Alice", age: 30 })).toBe("{name:Alice,age:30}"))
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
describe("key folding", () => {
|
|
33
|
-
test("fold 1 level", () => expect(stringify({ a: { b: 1 } })).toBe("{a.b:1}"))
|
|
34
|
-
test("fold 2 levels", () => expect(stringify({ a: { b: { c: 1 } } })).toBe("{a.b.c:1}"))
|
|
35
|
-
test("no fold multi-key", () => expect(stringify({ a: { b: 1, c: 2 } })).toBe("{a:{b:1,c:2}}"))
|
|
36
|
-
test("key with dot", () => expect(stringify({ "a.b": 1 })).toBe('{"a.b":1}'))
|
|
37
|
-
test("key with dot nested", () => expect(stringify({ "a.b": { c: 1 } })).toBe('{"a.b":{c:1}}'))
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
describe("tables", () => {
|
|
41
|
-
test("uniform table", () => expect(stringify([{ a: 1, b: 2 }, { a: 3, b: 4 }])).toBe("{{:a,b;1,2;3,4}}"))
|
|
42
|
-
test("3-row table", () => expect(stringify([{ x: 1 }, { x: 2 }, { x: 3 }])).toBe("{{:x;1;2;3}}"))
|
|
43
|
-
test("mixed schema with reuse", () => expect(stringify([{ a: 1 }, { a: 2 }, { b: 3 }])).toBe("{{:a;1;2;:b;3}}"))
|
|
44
|
-
test("no reuse", () => expect(stringify([{ a: 1 }, { b: 2 }])).toBe("[{a:1},{b:2}]"))
|
|
45
|
-
test("single obj", () => expect(stringify([{ a: 1 }])).toBe("[{a:1}]"))
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
describe("parse", () => {
|
|
50
|
-
test("null", () => expect(parse("null")).toBe(null))
|
|
51
|
-
test("true", () => expect(parse("true")).toBe(true))
|
|
52
|
-
test("number", () => expect(parse("42")).toBe(42))
|
|
53
|
-
test("string", () => expect(parse("hello")).toBe("hello"))
|
|
54
|
-
test("quoted", () => expect(parse('"hello world"')).toBe("hello world"))
|
|
55
|
-
|
|
56
|
-
test("array", () => expect(parse("[1,2,3]")).toEqual([1, 2, 3]))
|
|
57
|
-
test("object", () => expect(parse("{name:Alice,age:30}")).toEqual({ name: "Alice", age: 30 }))
|
|
58
|
-
|
|
59
|
-
describe("key unfolding", () => {
|
|
60
|
-
test("fold", () => expect(parse("{a.b:1}")).toEqual({ a: { b: 1 } }))
|
|
61
|
-
test("fold deep", () => expect(parse("{a.b.c:1}")).toEqual({ a: { b: { c: 1 } } }))
|
|
62
|
-
test("quoted dot key", () => expect(parse('{"a.b":1}')).toEqual({ "a.b": 1 }))
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
describe("tables", () => {
|
|
66
|
-
test("table", () => expect(parse("{{:a,b;1,2;3,4}}")).toEqual([{ a: 1, b: 2 }, { a: 3, b: 4 }]))
|
|
67
|
-
test("schema change", () => expect(parse("{{:a;1;:b;2}}")).toEqual([{ a: 1 }, { b: 2 }]))
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
describe("round-trip", () => {
|
|
72
|
-
const testCases: [string, unknown][] = [
|
|
73
|
-
["null", null],
|
|
74
|
-
["true", true],
|
|
75
|
-
["false", false],
|
|
76
|
-
["number", 42],
|
|
77
|
-
["string", "hello"],
|
|
78
|
-
["empty array", []],
|
|
79
|
-
["number array", [1, 2, 3]],
|
|
80
|
-
["empty object", {}],
|
|
81
|
-
["simple object", { a: 1, b: 2 }],
|
|
82
|
-
["nested 1 level", { a: { b: 1 } }],
|
|
83
|
-
["nested 2 levels", { a: { b: { c: 1 } } }],
|
|
84
|
-
["uniform table", [{ a: 1, b: 2 }, { a: 3, b: 4 }]],
|
|
85
|
-
["mixed schema", [{ a: 1 }, { b: 2 }]],
|
|
86
|
-
["nested table", { users: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }] }],
|
|
87
|
-
["key with dot", { "a.b": 1 }],
|
|
88
|
-
["key with semicolon", { "x;y": "test" }],
|
|
89
|
-
["string with semicolon", "a;b"],
|
|
90
|
-
]
|
|
91
|
-
|
|
92
|
-
for (const [name, original] of testCases) {
|
|
93
|
-
test(name, () => {
|
|
94
|
-
const encoded = stringify(original)
|
|
95
|
-
const decoded = parse(encoded)
|
|
96
|
-
expect(decoded).toEqual(original)
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
describe("samples", () => {
|
|
102
|
-
const { readdirSync, readFileSync } = require("fs")
|
|
103
|
-
const { join } = require("path")
|
|
104
|
-
|
|
105
|
-
const samplesDir = join(__dirname, "samples")
|
|
106
|
-
const jsonFiles = readdirSync(samplesDir)
|
|
107
|
-
.filter((f: string) => f.endsWith(".json") && !f.includes(".pretty."))
|
|
108
|
-
|
|
109
|
-
for (const jsonFile of jsonFiles) {
|
|
110
|
-
const baseName = jsonFile.replace(".json", "")
|
|
111
|
-
const jotFile = `${baseName}.jot`
|
|
112
|
-
|
|
113
|
-
describe(baseName, () => {
|
|
114
|
-
const jsonPath = join(samplesDir, jsonFile)
|
|
115
|
-
const jotPath = join(samplesDir, jotFile)
|
|
116
|
-
|
|
117
|
-
const jsonContent = readFileSync(jsonPath, "utf-8").trim()
|
|
118
|
-
const expectedJot = readFileSync(jotPath, "utf-8").trim()
|
|
119
|
-
const originalData = JSON.parse(jsonContent)
|
|
120
|
-
|
|
121
|
-
test("encoding matches jot", () => {
|
|
122
|
-
const encoded = stringify(originalData)
|
|
123
|
-
expect(encoded).toBe(expectedJot)
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
test("round-trip matches json semantically", () => {
|
|
127
|
-
const encoded = stringify(originalData)
|
|
128
|
-
const decoded = parse(encoded)
|
|
129
|
-
expect(decoded).toEqual(originalData)
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
})
|