@toon-format/spec 1.3.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.
@@ -0,0 +1,138 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Arrays of objects encoding - list format for non-uniform objects and complex structures",
5
+ "tests": [
6
+ {
7
+ "name": "uses list format for objects with different fields",
8
+ "input": {
9
+ "items": [
10
+ { "id": 1, "name": "First" },
11
+ { "id": 2, "name": "Second", "extra": true }
12
+ ]
13
+ },
14
+ "expected": "items[2]:\n - id: 1\n name: First\n - id: 2\n name: Second\n extra: true",
15
+ "specSection": "7"
16
+ },
17
+ {
18
+ "name": "uses list format for objects with nested values",
19
+ "input": {
20
+ "items": [
21
+ { "id": 1, "nested": { "x": 1 } }
22
+ ]
23
+ },
24
+ "expected": "items[1]:\n - id: 1\n nested:\n x: 1",
25
+ "specSection": "7"
26
+ },
27
+ {
28
+ "name": "preserves field order in list items - array first",
29
+ "input": {
30
+ "items": [{ "nums": [1, 2, 3], "name": "test" }]
31
+ },
32
+ "expected": "items[1]:\n - nums[3]: 1,2,3\n name: test",
33
+ "specSection": "7"
34
+ },
35
+ {
36
+ "name": "preserves field order in list items - primitive first",
37
+ "input": {
38
+ "items": [{ "name": "test", "nums": [1, 2, 3] }]
39
+ },
40
+ "expected": "items[1]:\n - name: test\n nums[3]: 1,2,3",
41
+ "specSection": "7"
42
+ },
43
+ {
44
+ "name": "uses list format for objects containing arrays of arrays",
45
+ "input": {
46
+ "items": [
47
+ { "matrix": [[1, 2], [3, 4]], "name": "grid" }
48
+ ]
49
+ },
50
+ "expected": "items[1]:\n - matrix[2]:\n - [2]: 1,2\n - [2]: 3,4\n name: grid",
51
+ "specSection": "7"
52
+ },
53
+ {
54
+ "name": "uses tabular format for nested uniform object arrays",
55
+ "input": {
56
+ "items": [
57
+ { "users": [{ "id": 1, "name": "Ada" }, { "id": 2, "name": "Bob" }], "status": "active" }
58
+ ]
59
+ },
60
+ "expected": "items[1]:\n - users[2]{id,name}:\n 1,Ada\n 2,Bob\n status: active",
61
+ "specSection": "7"
62
+ },
63
+ {
64
+ "name": "uses list format for nested object arrays with mismatched keys",
65
+ "input": {
66
+ "items": [
67
+ { "users": [{ "id": 1, "name": "Ada" }, { "id": 2 }], "status": "active" }
68
+ ]
69
+ },
70
+ "expected": "items[1]:\n - users[2]:\n - id: 1\n name: Ada\n - id: 2\n status: active",
71
+ "specSection": "7"
72
+ },
73
+ {
74
+ "name": "uses list format for objects with multiple array fields",
75
+ "input": {
76
+ "items": [{ "nums": [1, 2], "tags": ["a", "b"], "name": "test" }]
77
+ },
78
+ "expected": "items[1]:\n - nums[2]: 1,2\n tags[2]: a,b\n name: test",
79
+ "specSection": "7"
80
+ },
81
+ {
82
+ "name": "uses list format for objects with only array fields",
83
+ "input": {
84
+ "items": [{ "nums": [1, 2, 3], "tags": ["a", "b"] }]
85
+ },
86
+ "expected": "items[1]:\n - nums[3]: 1,2,3\n tags[2]: a,b",
87
+ "specSection": "7"
88
+ },
89
+ {
90
+ "name": "handles objects with empty arrays in list format",
91
+ "input": {
92
+ "items": [
93
+ { "name": "test", "data": [] }
94
+ ]
95
+ },
96
+ "expected": "items[1]:\n - name: test\n data[0]:",
97
+ "specSection": "7"
98
+ },
99
+ {
100
+ "name": "places first field of nested tabular arrays on hyphen line",
101
+ "input": {
102
+ "items": [{ "users": [{ "id": 1 }, { "id": 2 }], "note": "x" }]
103
+ },
104
+ "expected": "items[1]:\n - users[2]{id}:\n 1\n 2\n note: x",
105
+ "specSection": "7"
106
+ },
107
+ {
108
+ "name": "places empty arrays on hyphen line when first",
109
+ "input": {
110
+ "items": [{ "data": [], "name": "x" }]
111
+ },
112
+ "expected": "items[1]:\n - data[0]:\n name: x",
113
+ "specSection": "7"
114
+ },
115
+ {
116
+ "name": "uses field order from first object for tabular headers",
117
+ "input": {
118
+ "items": [
119
+ { "a": 1, "b": 2, "c": 3 },
120
+ { "c": 30, "b": 20, "a": 10 }
121
+ ]
122
+ },
123
+ "expected": "items[2]{a,b,c}:\n 1,2,3\n 10,20,30",
124
+ "specSection": "7.2"
125
+ },
126
+ {
127
+ "name": "uses list format when one object has nested column",
128
+ "input": {
129
+ "items": [
130
+ { "id": 1, "data": "string" },
131
+ { "id": 2, "data": { "nested": true } }
132
+ ]
133
+ },
134
+ "expected": "items[2]:\n - id: 1\n data: string\n - id: 2\n data:\n nested: true",
135
+ "specSection": "7"
136
+ }
137
+ ]
138
+ }
@@ -0,0 +1,87 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Primitive array encoding - inline arrays of strings, numbers, booleans",
5
+ "tests": [
6
+ {
7
+ "name": "encodes string arrays inline",
8
+ "input": {
9
+ "tags": ["reading", "gaming"]
10
+ },
11
+ "expected": "tags[2]: reading,gaming",
12
+ "specSection": "7.1"
13
+ },
14
+ {
15
+ "name": "encodes number arrays inline",
16
+ "input": {
17
+ "nums": [1, 2, 3]
18
+ },
19
+ "expected": "nums[3]: 1,2,3",
20
+ "specSection": "7.1"
21
+ },
22
+ {
23
+ "name": "encodes mixed primitive arrays inline",
24
+ "input": {
25
+ "data": ["x", "y", true, 10]
26
+ },
27
+ "expected": "data[4]: x,y,true,10",
28
+ "specSection": "7.1"
29
+ },
30
+ {
31
+ "name": "encodes empty arrays",
32
+ "input": {
33
+ "items": []
34
+ },
35
+ "expected": "items[0]:",
36
+ "specSection": "7.1"
37
+ },
38
+ {
39
+ "name": "handles empty string in single-item array",
40
+ "input": {
41
+ "items": [""]
42
+ },
43
+ "expected": "items[1]: \"\"",
44
+ "specSection": "7.1"
45
+ },
46
+ {
47
+ "name": "handles empty string in multi-item array",
48
+ "input": {
49
+ "items": ["a", "", "b"]
50
+ },
51
+ "expected": "items[3]: a,\"\",b",
52
+ "specSection": "7.1"
53
+ },
54
+ {
55
+ "name": "handles whitespace-only strings in arrays",
56
+ "input": {
57
+ "items": [" ", " "]
58
+ },
59
+ "expected": "items[2]: \" \",\" \"",
60
+ "specSection": "7.1"
61
+ },
62
+ {
63
+ "name": "quotes array strings with comma",
64
+ "input": {
65
+ "items": ["a", "b,c", "d:e"]
66
+ },
67
+ "expected": "items[3]: a,\"b,c\",\"d:e\"",
68
+ "specSection": "7.1"
69
+ },
70
+ {
71
+ "name": "quotes strings that look like booleans in arrays",
72
+ "input": {
73
+ "items": ["x", "true", "42", "-3.14"]
74
+ },
75
+ "expected": "items[4]: x,\"true\",\"42\",\"-3.14\"",
76
+ "specSection": "7.1"
77
+ },
78
+ {
79
+ "name": "quotes strings with structural meanings in arrays",
80
+ "input": {
81
+ "items": ["[5]", "- item", "{key}"]
82
+ },
83
+ "expected": "items[3]: \"[5]\",\"- item\",\"{key}\"",
84
+ "specSection": "7.1"
85
+ }
86
+ ]
87
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Tabular array encoding - arrays of uniform objects with primitive values",
5
+ "tests": [
6
+ {
7
+ "name": "encodes arrays of similar objects in tabular format",
8
+ "input": {
9
+ "items": [
10
+ { "sku": "A1", "qty": 2, "price": 9.99 },
11
+ { "sku": "B2", "qty": 1, "price": 14.5 }
12
+ ]
13
+ },
14
+ "expected": "items[2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5",
15
+ "specSection": "7.2"
16
+ },
17
+ {
18
+ "name": "handles null values in tabular format",
19
+ "input": {
20
+ "items": [
21
+ { "id": 1, "value": null },
22
+ { "id": 2, "value": "test" }
23
+ ]
24
+ },
25
+ "expected": "items[2]{id,value}:\n 1,null\n 2,test",
26
+ "specSection": "7.2"
27
+ },
28
+ {
29
+ "name": "quotes strings containing delimiters in tabular rows",
30
+ "input": {
31
+ "items": [
32
+ { "sku": "A,1", "desc": "cool", "qty": 2 },
33
+ { "sku": "B2", "desc": "wip: test", "qty": 1 }
34
+ ]
35
+ },
36
+ "expected": "items[2]{sku,desc,qty}:\n \"A,1\",cool,2\n B2,\"wip: test\",1",
37
+ "specSection": "7.2"
38
+ },
39
+ {
40
+ "name": "quotes ambiguous strings in tabular rows",
41
+ "input": {
42
+ "items": [
43
+ { "id": 1, "status": "true" },
44
+ { "id": 2, "status": "false" }
45
+ ]
46
+ },
47
+ "expected": "items[2]{id,status}:\n 1,\"true\"\n 2,\"false\"",
48
+ "specSection": "7.2"
49
+ },
50
+ {
51
+ "name": "handles tabular arrays with keys needing quotes",
52
+ "input": {
53
+ "items": [
54
+ { "order:id": 1, "full name": "Ada" },
55
+ { "order:id": 2, "full name": "Bob" }
56
+ ]
57
+ },
58
+ "expected": "items[2]{\"order:id\",\"full name\"}:\n 1,Ada\n 2,Bob",
59
+ "specSection": "7.2"
60
+ }
61
+ ]
62
+ }
@@ -0,0 +1,253 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Delimiter options - tab and pipe delimiters, delimiter-aware quoting",
5
+ "tests": [
6
+ {
7
+ "name": "encodes primitive arrays with tab delimiter",
8
+ "input": {
9
+ "tags": ["reading", "gaming", "coding"]
10
+ },
11
+ "expected": "tags[3\t]: reading\tgaming\tcoding",
12
+ "options": {
13
+ "delimiter": "\t"
14
+ },
15
+ "specSection": "8"
16
+ },
17
+ {
18
+ "name": "encodes primitive arrays with pipe delimiter",
19
+ "input": {
20
+ "tags": ["reading", "gaming", "coding"]
21
+ },
22
+ "expected": "tags[3|]: reading|gaming|coding",
23
+ "options": {
24
+ "delimiter": "|"
25
+ },
26
+ "specSection": "8"
27
+ },
28
+ {
29
+ "name": "encodes primitive arrays with comma delimiter",
30
+ "input": {
31
+ "tags": ["reading", "gaming", "coding"]
32
+ },
33
+ "expected": "tags[3]: reading,gaming,coding",
34
+ "options": {
35
+ "delimiter": ","
36
+ },
37
+ "specSection": "8"
38
+ },
39
+ {
40
+ "name": "encodes tabular arrays with tab delimiter",
41
+ "input": {
42
+ "items": [
43
+ { "sku": "A1", "qty": 2, "price": 9.99 },
44
+ { "sku": "B2", "qty": 1, "price": 14.5 }
45
+ ]
46
+ },
47
+ "expected": "items[2\t]{sku\tqty\tprice}:\n A1\t2\t9.99\n B2\t1\t14.5",
48
+ "options": {
49
+ "delimiter": "\t"
50
+ },
51
+ "specSection": "8"
52
+ },
53
+ {
54
+ "name": "encodes tabular arrays with pipe delimiter",
55
+ "input": {
56
+ "items": [
57
+ { "sku": "A1", "qty": 2, "price": 9.99 },
58
+ { "sku": "B2", "qty": 1, "price": 14.5 }
59
+ ]
60
+ },
61
+ "expected": "items[2|]{sku|qty|price}:\n A1|2|9.99\n B2|1|14.5",
62
+ "options": {
63
+ "delimiter": "|"
64
+ },
65
+ "specSection": "8"
66
+ },
67
+ {
68
+ "name": "encodes nested arrays with tab delimiter",
69
+ "input": {
70
+ "pairs": [["a", "b"], ["c", "d"]]
71
+ },
72
+ "expected": "pairs[2\t]:\n - [2\t]: a\tb\n - [2\t]: c\td",
73
+ "options": {
74
+ "delimiter": "\t"
75
+ },
76
+ "specSection": "8"
77
+ },
78
+ {
79
+ "name": "encodes nested arrays with pipe delimiter",
80
+ "input": {
81
+ "pairs": [["a", "b"], ["c", "d"]]
82
+ },
83
+ "expected": "pairs[2|]:\n - [2|]: a|b\n - [2|]: c|d",
84
+ "options": {
85
+ "delimiter": "|"
86
+ },
87
+ "specSection": "8"
88
+ },
89
+ {
90
+ "name": "encodes root arrays with tab delimiter",
91
+ "input": ["x", "y", "z"],
92
+ "expected": "[3\t]: x\ty\tz",
93
+ "options": {
94
+ "delimiter": "\t"
95
+ },
96
+ "specSection": "8"
97
+ },
98
+ {
99
+ "name": "encodes root arrays with pipe delimiter",
100
+ "input": ["x", "y", "z"],
101
+ "expected": "[3|]: x|y|z",
102
+ "options": {
103
+ "delimiter": "|"
104
+ },
105
+ "specSection": "8"
106
+ },
107
+ {
108
+ "name": "encodes root arrays of objects with tab delimiter",
109
+ "input": [{ "id": 1 }, { "id": 2 }],
110
+ "expected": "[2\t]{id}:\n 1\n 2",
111
+ "options": {
112
+ "delimiter": "\t"
113
+ },
114
+ "specSection": "8"
115
+ },
116
+ {
117
+ "name": "encodes root arrays of objects with pipe delimiter",
118
+ "input": [{ "id": 1 }, { "id": 2 }],
119
+ "expected": "[2|]{id}:\n 1\n 2",
120
+ "options": {
121
+ "delimiter": "|"
122
+ },
123
+ "specSection": "8"
124
+ },
125
+ {
126
+ "name": "quotes strings containing tab delimiter",
127
+ "input": {
128
+ "items": ["a", "b\tc", "d"]
129
+ },
130
+ "expected": "items[3\t]: a\t\"b\\tc\"\td",
131
+ "options": {
132
+ "delimiter": "\t"
133
+ },
134
+ "specSection": "8"
135
+ },
136
+ {
137
+ "name": "quotes strings containing pipe delimiter",
138
+ "input": {
139
+ "items": ["a", "b|c", "d"]
140
+ },
141
+ "expected": "items[3|]: a|\"b|c\"|d",
142
+ "options": {
143
+ "delimiter": "|"
144
+ },
145
+ "specSection": "8"
146
+ },
147
+ {
148
+ "name": "does not quote commas with tab delimiter",
149
+ "input": {
150
+ "items": ["a,b", "c,d"]
151
+ },
152
+ "expected": "items[2\t]: a,b\tc,d",
153
+ "options": {
154
+ "delimiter": "\t"
155
+ },
156
+ "specSection": "8"
157
+ },
158
+ {
159
+ "name": "does not quote commas with pipe delimiter",
160
+ "input": {
161
+ "items": ["a,b", "c,d"]
162
+ },
163
+ "expected": "items[2|]: a,b|c,d",
164
+ "options": {
165
+ "delimiter": "|"
166
+ },
167
+ "specSection": "8"
168
+ },
169
+ {
170
+ "name": "quotes tabular values containing comma delimiter",
171
+ "input": {
172
+ "items": [
173
+ { "id": 1, "note": "a,b" },
174
+ { "id": 2, "note": "c,d" }
175
+ ]
176
+ },
177
+ "expected": "items[2]{id,note}:\n 1,\"a,b\"\n 2,\"c,d\"",
178
+ "options": {
179
+ "delimiter": ","
180
+ },
181
+ "specSection": "8"
182
+ },
183
+ {
184
+ "name": "does not quote commas in tabular values with tab delimiter",
185
+ "input": {
186
+ "items": [
187
+ { "id": 1, "note": "a,b" },
188
+ { "id": 2, "note": "c,d" }
189
+ ]
190
+ },
191
+ "expected": "items[2\t]{id\tnote}:\n 1\ta,b\n 2\tc,d",
192
+ "options": {
193
+ "delimiter": "\t"
194
+ },
195
+ "specSection": "8"
196
+ },
197
+ {
198
+ "name": "does not quote commas in object values with pipe delimiter",
199
+ "input": {
200
+ "note": "a,b"
201
+ },
202
+ "expected": "note: a,b",
203
+ "options": {
204
+ "delimiter": "|"
205
+ },
206
+ "specSection": "8"
207
+ },
208
+ {
209
+ "name": "does not quote commas in object values with tab delimiter",
210
+ "input": {
211
+ "note": "a,b"
212
+ },
213
+ "expected": "note: a,b",
214
+ "options": {
215
+ "delimiter": "\t"
216
+ },
217
+ "specSection": "8"
218
+ },
219
+ {
220
+ "name": "quotes nested array values containing pipe delimiter",
221
+ "input": {
222
+ "pairs": [["a", "b|c"]]
223
+ },
224
+ "expected": "pairs[1|]:\n - [2|]: a|\"b|c\"",
225
+ "options": {
226
+ "delimiter": "|"
227
+ },
228
+ "specSection": "8"
229
+ },
230
+ {
231
+ "name": "quotes nested array values containing tab delimiter",
232
+ "input": {
233
+ "pairs": [["a", "b\tc"]]
234
+ },
235
+ "expected": "pairs[1\t]:\n - [2\t]: a\t\"b\\tc\"",
236
+ "options": {
237
+ "delimiter": "\t"
238
+ },
239
+ "specSection": "8"
240
+ },
241
+ {
242
+ "name": "preserves ambiguity quoting regardless of delimiter",
243
+ "input": {
244
+ "items": ["true", "42", "-3.14"]
245
+ },
246
+ "expected": "items[3|]: \"true\"|\"42\"|\"-3.14\"",
247
+ "options": {
248
+ "delimiter": "|"
249
+ },
250
+ "specSection": "8"
251
+ }
252
+ ]
253
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Non-JSON type normalization - BigInt, Date, undefined, NaN, Infinity, functions, symbols",
5
+ "tests": [
6
+ {
7
+ "name": "converts BigInt to number",
8
+ "input": 123,
9
+ "expected": "123",
10
+ "specSection": "5",
11
+ "note": "BigInt(123) in JavaScript becomes 123"
12
+ },
13
+ {
14
+ "name": "converts BigInt in object to number",
15
+ "input": {
16
+ "id": 456
17
+ },
18
+ "expected": "id: 456",
19
+ "specSection": "5",
20
+ "note": "BigInt(456) in JavaScript becomes 456"
21
+ },
22
+ {
23
+ "name": "converts Date to ISO string",
24
+ "input": "2025-01-01T00:00:00.000Z",
25
+ "expected": "\"2025-01-01T00:00:00.000Z\"",
26
+ "specSection": "5",
27
+ "note": "new Date('2025-01-01T00:00:00.000Z') becomes quoted ISO string"
28
+ },
29
+ {
30
+ "name": "converts Date in object to ISO string",
31
+ "input": {
32
+ "created": "2025-01-01T00:00:00.000Z"
33
+ },
34
+ "expected": "created: \"2025-01-01T00:00:00.000Z\"",
35
+ "specSection": "5"
36
+ },
37
+ {
38
+ "name": "converts undefined to null",
39
+ "input": null,
40
+ "expected": "null",
41
+ "specSection": "5",
42
+ "note": "undefined in JavaScript becomes null"
43
+ },
44
+ {
45
+ "name": "converts undefined in object to null",
46
+ "input": {
47
+ "value": null
48
+ },
49
+ "expected": "value: null",
50
+ "specSection": "5",
51
+ "note": "undefined in JavaScript becomes null"
52
+ },
53
+ {
54
+ "name": "converts Infinity to null",
55
+ "input": null,
56
+ "expected": "null",
57
+ "specSection": "5",
58
+ "note": "Infinity becomes null"
59
+ },
60
+ {
61
+ "name": "converts negative Infinity to null",
62
+ "input": null,
63
+ "expected": "null",
64
+ "specSection": "5",
65
+ "note": "-Infinity becomes null"
66
+ },
67
+ {
68
+ "name": "converts NaN to null",
69
+ "input": null,
70
+ "expected": "null",
71
+ "specSection": "5",
72
+ "note": "Number.NaN becomes null"
73
+ },
74
+ {
75
+ "name": "converts function to null",
76
+ "input": null,
77
+ "expected": "null",
78
+ "specSection": "5",
79
+ "note": "Functions become null"
80
+ },
81
+ {
82
+ "name": "converts function in object to null",
83
+ "input": {
84
+ "fn": null
85
+ },
86
+ "expected": "fn: null",
87
+ "specSection": "5",
88
+ "note": "Functions become null"
89
+ },
90
+ {
91
+ "name": "converts symbol to null",
92
+ "input": null,
93
+ "expected": "null",
94
+ "specSection": "5",
95
+ "note": "Symbols become null"
96
+ },
97
+ {
98
+ "name": "converts symbol in object to null",
99
+ "input": {
100
+ "sym": null
101
+ },
102
+ "expected": "sym: null",
103
+ "specSection": "5",
104
+ "note": "Symbols become null"
105
+ }
106
+ ]
107
+ }