@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,153 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "decode",
4
+ "description": "Blank line handling - strict mode errors on blank lines inside arrays, accepts blank lines outside arrays",
5
+ "tests": [
6
+ {
7
+ "name": "throws on blank line inside list array",
8
+ "input": "items[3]:\n - a\n\n - b\n - c",
9
+ "expected": null,
10
+ "shouldError": true,
11
+ "options": {
12
+ "strict": true
13
+ },
14
+ "specSection": "9"
15
+ },
16
+ {
17
+ "name": "throws on blank line inside tabular array",
18
+ "input": "items[2]{id}:\n 1\n\n 2",
19
+ "expected": null,
20
+ "shouldError": true,
21
+ "options": {
22
+ "strict": true
23
+ },
24
+ "specSection": "9"
25
+ },
26
+ {
27
+ "name": "throws on multiple blank lines inside array",
28
+ "input": "items[2]:\n - a\n\n\n - b",
29
+ "expected": null,
30
+ "shouldError": true,
31
+ "options": {
32
+ "strict": true
33
+ },
34
+ "specSection": "9"
35
+ },
36
+ {
37
+ "name": "throws on blank line with spaces inside array",
38
+ "input": "items[2]:\n - a\n \n - b",
39
+ "expected": null,
40
+ "shouldError": true,
41
+ "options": {
42
+ "strict": true
43
+ },
44
+ "specSection": "9"
45
+ },
46
+ {
47
+ "name": "throws on blank line in nested list array",
48
+ "input": "outer[2]:\n - inner[2]:\n - a\n\n - b\n - x",
49
+ "expected": null,
50
+ "shouldError": true,
51
+ "options": {
52
+ "strict": true
53
+ },
54
+ "specSection": "9"
55
+ },
56
+ {
57
+ "name": "accepts blank line between root-level fields",
58
+ "input": "a: 1\n\nb: 2",
59
+ "expected": {
60
+ "a": 1,
61
+ "b": 2
62
+ },
63
+ "options": {
64
+ "strict": true
65
+ },
66
+ "specSection": "9"
67
+ },
68
+ {
69
+ "name": "accepts trailing newline at end of file",
70
+ "input": "a: 1\n",
71
+ "expected": {
72
+ "a": 1
73
+ },
74
+ "options": {
75
+ "strict": true
76
+ },
77
+ "specSection": "9"
78
+ },
79
+ {
80
+ "name": "accepts multiple trailing newlines",
81
+ "input": "a: 1\n\n\n",
82
+ "expected": {
83
+ "a": 1
84
+ },
85
+ "options": {
86
+ "strict": true
87
+ },
88
+ "specSection": "9"
89
+ },
90
+ {
91
+ "name": "accepts blank line after array ends",
92
+ "input": "items[1]:\n - a\n\nb: 2",
93
+ "expected": {
94
+ "items": ["a"],
95
+ "b": 2
96
+ },
97
+ "options": {
98
+ "strict": true
99
+ },
100
+ "specSection": "9"
101
+ },
102
+ {
103
+ "name": "accepts blank line between nested object fields",
104
+ "input": "a:\n b: 1\n\n c: 2",
105
+ "expected": {
106
+ "a": {
107
+ "b": 1,
108
+ "c": 2
109
+ }
110
+ },
111
+ "options": {
112
+ "strict": true
113
+ },
114
+ "specSection": "9"
115
+ },
116
+ {
117
+ "name": "ignores blank lines inside list array when strict=false",
118
+ "input": "items[3]:\n - a\n\n - b\n - c",
119
+ "expected": {
120
+ "items": ["a", "b", "c"]
121
+ },
122
+ "options": {
123
+ "strict": false
124
+ },
125
+ "specSection": "9"
126
+ },
127
+ {
128
+ "name": "ignores blank lines inside tabular array when strict=false",
129
+ "input": "items[2]{id,name}:\n 1,Alice\n\n 2,Bob",
130
+ "expected": {
131
+ "items": [
132
+ { "id": 1, "name": "Alice" },
133
+ { "id": 2, "name": "Bob" }
134
+ ]
135
+ },
136
+ "options": {
137
+ "strict": false
138
+ },
139
+ "specSection": "9"
140
+ },
141
+ {
142
+ "name": "ignores multiple blank lines in arrays when strict=false",
143
+ "input": "items[2]:\n - a\n\n\n - b",
144
+ "expected": {
145
+ "items": ["a", "b"]
146
+ },
147
+ "options": {
148
+ "strict": false
149
+ },
150
+ "specSection": "9"
151
+ }
152
+ ]
153
+ }
@@ -0,0 +1,237 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "decode",
4
+ "description": "Delimiter decoding - tab and pipe delimiter parsing, delimiter-aware value splitting",
5
+ "tests": [
6
+ {
7
+ "name": "parses primitive arrays with tab delimiter",
8
+ "input": "tags[3\t]: reading\tgaming\tcoding",
9
+ "expected": {
10
+ "tags": ["reading", "gaming", "coding"]
11
+ },
12
+ "specSection": "8"
13
+ },
14
+ {
15
+ "name": "parses primitive arrays with pipe delimiter",
16
+ "input": "tags[3|]: reading|gaming|coding",
17
+ "expected": {
18
+ "tags": ["reading", "gaming", "coding"]
19
+ },
20
+ "specSection": "8"
21
+ },
22
+ {
23
+ "name": "parses primitive arrays with comma delimiter",
24
+ "input": "tags[3]: reading,gaming,coding",
25
+ "expected": {
26
+ "tags": ["reading", "gaming", "coding"]
27
+ },
28
+ "specSection": "8"
29
+ },
30
+ {
31
+ "name": "parses tabular arrays with tab delimiter",
32
+ "input": "items[2\t]{sku\tqty\tprice}:\n A1\t2\t9.99\n B2\t1\t14.5",
33
+ "expected": {
34
+ "items": [
35
+ { "sku": "A1", "qty": 2, "price": 9.99 },
36
+ { "sku": "B2", "qty": 1, "price": 14.5 }
37
+ ]
38
+ },
39
+ "specSection": "8"
40
+ },
41
+ {
42
+ "name": "parses tabular arrays with pipe delimiter",
43
+ "input": "items[2|]{sku|qty|price}:\n A1|2|9.99\n B2|1|14.5",
44
+ "expected": {
45
+ "items": [
46
+ { "sku": "A1", "qty": 2, "price": 9.99 },
47
+ { "sku": "B2", "qty": 1, "price": 14.5 }
48
+ ]
49
+ },
50
+ "specSection": "8"
51
+ },
52
+ {
53
+ "name": "parses nested arrays with tab delimiter",
54
+ "input": "pairs[2\t]:\n - [2\t]: a\tb\n - [2\t]: c\td",
55
+ "expected": {
56
+ "pairs": [["a", "b"], ["c", "d"]]
57
+ },
58
+ "specSection": "8"
59
+ },
60
+ {
61
+ "name": "parses nested arrays with pipe delimiter",
62
+ "input": "pairs[2|]:\n - [2|]: a|b\n - [2|]: c|d",
63
+ "expected": {
64
+ "pairs": [["a", "b"], ["c", "d"]]
65
+ },
66
+ "specSection": "8"
67
+ },
68
+ {
69
+ "name": "nested arrays inside list items default to comma delimiter",
70
+ "input": "items[1\t]:\n - tags[3]: a,b,c",
71
+ "expected": {
72
+ "items": [{ "tags": ["a", "b", "c"] }]
73
+ },
74
+ "specSection": "8",
75
+ "note": "Parent uses tab, nested defaults to comma"
76
+ },
77
+ {
78
+ "name": "nested arrays inside list items default to comma with pipe parent",
79
+ "input": "items[1|]:\n - tags[3]: a,b,c",
80
+ "expected": {
81
+ "items": [{ "tags": ["a", "b", "c"] }]
82
+ },
83
+ "specSection": "8"
84
+ },
85
+ {
86
+ "name": "parses root arrays with tab delimiter",
87
+ "input": "[3\t]: x\ty\tz",
88
+ "expected": ["x", "y", "z"],
89
+ "specSection": "8"
90
+ },
91
+ {
92
+ "name": "parses root arrays with pipe delimiter",
93
+ "input": "[3|]: x|y|z",
94
+ "expected": ["x", "y", "z"],
95
+ "specSection": "8"
96
+ },
97
+ {
98
+ "name": "parses root arrays of objects with tab delimiter",
99
+ "input": "[2\t]{id}:\n 1\n 2",
100
+ "expected": [{ "id": 1 }, { "id": 2 }],
101
+ "specSection": "8"
102
+ },
103
+ {
104
+ "name": "parses root arrays of objects with pipe delimiter",
105
+ "input": "[2|]{id}:\n 1\n 2",
106
+ "expected": [{ "id": 1 }, { "id": 2 }],
107
+ "specSection": "8"
108
+ },
109
+ {
110
+ "name": "parses values containing tab delimiter when quoted",
111
+ "input": "items[3\t]: a\t\"b\\tc\"\td",
112
+ "expected": {
113
+ "items": ["a", "b\tc", "d"]
114
+ },
115
+ "specSection": "8"
116
+ },
117
+ {
118
+ "name": "parses values containing pipe delimiter when quoted",
119
+ "input": "items[3|]: a|\"b|c\"|d",
120
+ "expected": {
121
+ "items": ["a", "b|c", "d"]
122
+ },
123
+ "specSection": "8"
124
+ },
125
+ {
126
+ "name": "does not split on commas when using tab delimiter",
127
+ "input": "items[2\t]: a,b\tc,d",
128
+ "expected": {
129
+ "items": ["a,b", "c,d"]
130
+ },
131
+ "specSection": "8"
132
+ },
133
+ {
134
+ "name": "does not split on commas when using pipe delimiter",
135
+ "input": "items[2|]: a,b|c,d",
136
+ "expected": {
137
+ "items": ["a,b", "c,d"]
138
+ },
139
+ "specSection": "8"
140
+ },
141
+ {
142
+ "name": "parses tabular values containing comma with comma delimiter",
143
+ "input": "items[2]{id,note}:\n 1,\"a,b\"\n 2,\"c,d\"",
144
+ "expected": {
145
+ "items": [
146
+ { "id": 1, "note": "a,b" },
147
+ { "id": 2, "note": "c,d" }
148
+ ]
149
+ },
150
+ "specSection": "8"
151
+ },
152
+ {
153
+ "name": "does not require quoting commas with tab delimiter",
154
+ "input": "items[2\t]{id\tnote}:\n 1\ta,b\n 2\tc,d",
155
+ "expected": {
156
+ "items": [
157
+ { "id": 1, "note": "a,b" },
158
+ { "id": 2, "note": "c,d" }
159
+ ]
160
+ },
161
+ "specSection": "8"
162
+ },
163
+ {
164
+ "name": "does not require quoting commas in object values",
165
+ "input": "note: a,b",
166
+ "expected": {
167
+ "note": "a,b"
168
+ },
169
+ "specSection": "8",
170
+ "note": "Object values don't require comma quoting regardless of delimiter"
171
+ },
172
+ {
173
+ "name": "parses nested array values containing pipe delimiter",
174
+ "input": "pairs[1|]:\n - [2|]: a|\"b|c\"",
175
+ "expected": {
176
+ "pairs": [["a", "b|c"]]
177
+ },
178
+ "specSection": "8"
179
+ },
180
+ {
181
+ "name": "parses nested array values containing tab delimiter",
182
+ "input": "pairs[1\t]:\n - [2\t]: a\t\"b\\tc\"",
183
+ "expected": {
184
+ "pairs": [["a", "b\tc"]]
185
+ },
186
+ "specSection": "8"
187
+ },
188
+ {
189
+ "name": "preserves quoted ambiguity with pipe delimiter",
190
+ "input": "items[3|]: \"true\"|\"42\"|\"-3.14\"",
191
+ "expected": {
192
+ "items": ["true", "42", "-3.14"]
193
+ },
194
+ "specSection": "8"
195
+ },
196
+ {
197
+ "name": "preserves quoted ambiguity with tab delimiter",
198
+ "input": "items[3\t]: \"true\"\t\"42\"\t\"-3.14\"",
199
+ "expected": {
200
+ "items": ["true", "42", "-3.14"]
201
+ },
202
+ "specSection": "8"
203
+ },
204
+ {
205
+ "name": "parses structural-looking strings when quoted with pipe delimiter",
206
+ "input": "items[3|]: \"[5]\"|\"{key}\"|\"- item\"",
207
+ "expected": {
208
+ "items": ["[5]", "{key}", "- item"]
209
+ },
210
+ "specSection": "8"
211
+ },
212
+ {
213
+ "name": "parses structural-looking strings when quoted with tab delimiter",
214
+ "input": "items[3\t]: \"[5]\"\t\"{key}\"\t\"- item\"",
215
+ "expected": {
216
+ "items": ["[5]", "{key}", "- item"]
217
+ },
218
+ "specSection": "8"
219
+ },
220
+ {
221
+ "name": "parses tabular headers with keys containing the active delimiter",
222
+ "input": "items[2|]{\"a|b\"}:\n 1\n 2",
223
+ "expected": {
224
+ "items": [{ "a|b": 1 }, { "a|b": 2 }]
225
+ },
226
+ "specSection": "8"
227
+ },
228
+ {
229
+ "name": "accepts length marker with pipe delimiter",
230
+ "input": "tags[#3|]: reading|gaming|coding",
231
+ "expected": {
232
+ "tags": ["reading", "gaming", "coding"]
233
+ },
234
+ "specSection": "8"
235
+ }
236
+ ]
237
+ }
@@ -0,0 +1,197 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "decode",
4
+ "description": "Strict mode indentation validation - non-multiple indentation, tab characters, custom indent sizes",
5
+ "tests": [
6
+ {
7
+ "name": "throws when object field has non-multiple indentation (3 spaces with indent=2)",
8
+ "input": "a:\n b: 1",
9
+ "expected": null,
10
+ "shouldError": true,
11
+ "options": {
12
+ "indent": 2,
13
+ "strict": true
14
+ },
15
+ "specSection": "9"
16
+ },
17
+ {
18
+ "name": "throws when list item has non-multiple indentation (3 spaces with indent=2)",
19
+ "input": "items[2]:\n - id: 1\n - id: 2",
20
+ "expected": null,
21
+ "shouldError": true,
22
+ "options": {
23
+ "indent": 2,
24
+ "strict": true
25
+ },
26
+ "specSection": "9"
27
+ },
28
+ {
29
+ "name": "throws with custom indent size when non-multiple (3 spaces with indent=4)",
30
+ "input": "a:\n b: 1",
31
+ "expected": null,
32
+ "shouldError": true,
33
+ "options": {
34
+ "indent": 4,
35
+ "strict": true
36
+ },
37
+ "specSection": "9"
38
+ },
39
+ {
40
+ "name": "accepts correct indentation with custom indent size (4 spaces with indent=4)",
41
+ "input": "a:\n b: 1",
42
+ "expected": {
43
+ "a": {
44
+ "b": 1
45
+ }
46
+ },
47
+ "options": {
48
+ "indent": 4,
49
+ "strict": true
50
+ },
51
+ "specSection": "9"
52
+ },
53
+ {
54
+ "name": "throws when tab character used in indentation",
55
+ "input": "a:\n\tb: 1",
56
+ "expected": null,
57
+ "shouldError": true,
58
+ "options": {
59
+ "strict": true
60
+ },
61
+ "specSection": "9"
62
+ },
63
+ {
64
+ "name": "throws when mixed tabs and spaces in indentation",
65
+ "input": "a:\n \tb: 1",
66
+ "expected": null,
67
+ "shouldError": true,
68
+ "options": {
69
+ "strict": true
70
+ },
71
+ "specSection": "9"
72
+ },
73
+ {
74
+ "name": "throws when tab at start of line",
75
+ "input": "\ta: 1",
76
+ "expected": null,
77
+ "shouldError": true,
78
+ "options": {
79
+ "strict": true
80
+ },
81
+ "specSection": "9"
82
+ },
83
+ {
84
+ "name": "accepts tabs in quoted string values",
85
+ "input": "text: \"hello\tworld\"",
86
+ "expected": {
87
+ "text": "hello\tworld"
88
+ },
89
+ "options": {
90
+ "strict": true
91
+ },
92
+ "specSection": "9"
93
+ },
94
+ {
95
+ "name": "accepts tabs in quoted keys",
96
+ "input": "\"key\ttab\": value",
97
+ "expected": {
98
+ "key\ttab": "value"
99
+ },
100
+ "options": {
101
+ "strict": true
102
+ },
103
+ "specSection": "9"
104
+ },
105
+ {
106
+ "name": "accepts tabs in quoted array elements",
107
+ "input": "items[2]: \"a\tb\",\"c\td\"",
108
+ "expected": {
109
+ "items": ["a\tb", "c\td"]
110
+ },
111
+ "options": {
112
+ "strict": true
113
+ },
114
+ "specSection": "9"
115
+ },
116
+ {
117
+ "name": "accepts non-multiple indentation when strict=false",
118
+ "input": "a:\n b: 1",
119
+ "expected": {
120
+ "a": {
121
+ "b": 1
122
+ }
123
+ },
124
+ "options": {
125
+ "indent": 2,
126
+ "strict": false
127
+ },
128
+ "specSection": "9"
129
+ },
130
+ {
131
+ "name": "accepts tab indentation when strict=false (tabs ignored, depth=0)",
132
+ "input": "a:\n\tb: 1",
133
+ "expected": {
134
+ "a": {},
135
+ "b": 1
136
+ },
137
+ "options": {
138
+ "strict": false
139
+ },
140
+ "specSection": "9",
141
+ "note": "Tabs are ignored in indentation counting, so b appears at root level"
142
+ },
143
+ {
144
+ "name": "accepts deeply nested non-multiples when strict=false",
145
+ "input": "a:\n b:\n c: 1",
146
+ "expected": {
147
+ "a": {
148
+ "b": {
149
+ "c": 1
150
+ }
151
+ }
152
+ },
153
+ "options": {
154
+ "indent": 2,
155
+ "strict": false
156
+ },
157
+ "specSection": "9"
158
+ },
159
+ {
160
+ "name": "empty lines do not trigger validation errors",
161
+ "input": "a: 1\n\nb: 2",
162
+ "expected": {
163
+ "a": 1,
164
+ "b": 2
165
+ },
166
+ "options": {
167
+ "strict": true
168
+ },
169
+ "specSection": "9"
170
+ },
171
+ {
172
+ "name": "root-level content (0 indentation) is always valid",
173
+ "input": "a: 1\nb: 2\nc: 3",
174
+ "expected": {
175
+ "a": 1,
176
+ "b": 2,
177
+ "c": 3
178
+ },
179
+ "options": {
180
+ "strict": true
181
+ },
182
+ "specSection": "9"
183
+ },
184
+ {
185
+ "name": "lines with only spaces are not validated if empty",
186
+ "input": "a: 1\n \nb: 2",
187
+ "expected": {
188
+ "a": 1,
189
+ "b": 2
190
+ },
191
+ "options": {
192
+ "strict": true
193
+ },
194
+ "specSection": "9"
195
+ }
196
+ ]
197
+ }