@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.
package/VERSIONING.md ADDED
@@ -0,0 +1,150 @@
1
+ # TOON Specification Versioning Policy
2
+
3
+ This document outlines the versioning policy for the TOON specification.
4
+
5
+ ## Semantic Versioning
6
+
7
+ The TOON specification follows [Semantic Versioning](https://semver.org/) with a `MAJOR.MINOR` format (specifications don't need PATCH versions).
8
+
9
+ ### Version Format
10
+
11
+ **`MAJOR.MINOR`**
12
+
13
+ - **MAJOR version** - Incremented for breaking changes that are incompatible with previous versions
14
+ - **MINOR version** - Incremented for backward-compatible additions, clarifications, or non-breaking changes
15
+
16
+ **Example:** Moving from v1.3 to v1.4 means your implementation keeps working. Moving from v1.3 to v2.0 means you'll likely need to update your code.
17
+
18
+ ## What Constitutes a Breaking Change
19
+
20
+ Breaking changes (requiring a MAJOR version bump) include:
21
+
22
+ ### Syntax Changes
23
+
24
+ - Removing or changing existing syntax.
25
+ - Changing the meaning of existing constructs.
26
+ - Adding new reserved characters that could conflict with existing valid TOON documents.
27
+ - Changing encoding/decoding behavior in incompatible ways.
28
+
29
+ ### Semantic Changes
30
+
31
+ - Changing how valid TOON should be interpreted.
32
+ - Modifying type conversion rules in incompatible ways.
33
+ - Changing quoting rules in ways that break existing documents.
34
+ - Altering delimiter behavior.
35
+
36
+ ### Conformance Changes
37
+
38
+ - Making previously valid TOON invalid.
39
+ - Adding new MUST requirements that existing implementations don't meet.
40
+ - Changing error handling in ways that break round-trip compatibility.
41
+
42
+ ## What Constitutes a Non-Breaking Change
43
+
44
+ Non-breaking changes (MINOR version bump) include:
45
+
46
+ ### Clarifications
47
+
48
+ - Clarifying ambiguous language without changing behavior.
49
+ - Adding examples to illustrate existing rules.
50
+ - Improving specification wording for clarity.
51
+ - Adding informative (non-normative) sections.
52
+
53
+ ### Backward-Compatible Additions
54
+
55
+ - Adding optional features that don't affect existing documents.
56
+ - Adding new SHOULD or MAY recommendations.
57
+ - Expanding the specification to cover previously undefined behavior (if done in a backward-compatible way).
58
+ - Adding new test cases that existing conformant implementations already pass.
59
+
60
+ ### Documentation Improvements
61
+
62
+ - Grammar and typo fixes.
63
+ - Reorganizing content for better readability.
64
+ - Adding cross-references.
65
+ - Improving examples.
66
+
67
+ ## Version Lifecycle
68
+
69
+ ### Working Draft
70
+
71
+ - Current development version.
72
+ - May receive updates without version changes.
73
+ - Indicated by "Status: Working Draft" in the specification.
74
+
75
+ ### Stable Release
76
+
77
+ - Released versions are immutable.
78
+ - Version number is assigned when changes are merged.
79
+ - Previous versions remain available for reference.
80
+
81
+ ### Deprecation
82
+
83
+ If we need to make a breaking change (MAJOR version bump):
84
+
85
+ 1. **Announcement:** We add a deprecation notice to the current spec
86
+ 2. **Migration Period:** The next MINOR version includes migration guidance
87
+ 3. **New Major Version:** Breaking changes are released in the next MAJOR version
88
+ 4. **Support:** Previous MAJOR versions remain available – we don't break old links
89
+
90
+ ## Implementation Compatibility
91
+
92
+ ### Specification Version Support
93
+
94
+ If you're implementing TOON, clearly document which spec version you support:
95
+
96
+ ```json
97
+ {
98
+ "toon-spec": "1.3"
99
+ }
100
+ ```
101
+
102
+ This helps users know what behavior to expect.
103
+
104
+ ### Forward Compatibility
105
+
106
+ Your implementation can support multiple spec versions. If you do:
107
+
108
+ 1. Default to the latest supported version
109
+ 2. Let users specify which version to target
110
+ 3. Document version-specific behavior clearly
111
+
112
+ ### Backward Compatibility
113
+
114
+ **When a new MINOR version is released:**
115
+
116
+ - Your implementation stays conformant – no code changes needed
117
+ - Updates may be recommended but aren't required
118
+
119
+ **When a new MAJOR version is released:**
120
+
121
+ - You may need updates to support the new version
122
+ - Previous version implementations remain valid
123
+ - We'll provide a migration guide
124
+
125
+ ## Version Numbering Examples
126
+
127
+ ### Current: v1.3
128
+
129
+ **Next minor update (clarifications, additions):**
130
+ - v1.4
131
+
132
+ **Next major update (breaking changes):**
133
+ - v2.0
134
+
135
+ **After v2.0, next minor update:**
136
+ - v2.1
137
+
138
+ ## Version History
139
+
140
+ See [CHANGELOG.md](./CHANGELOG.md) for detailed version history.
141
+
142
+ ## Questions
143
+
144
+ Not sure if your proposed change is breaking or non-breaking?
145
+
146
+ 1. Open an issue with the `[RFC]` tag
147
+ 2. Describe the proposed change
148
+ 3. Ask for feedback from maintainers and community
149
+
150
+ When in doubt, we err on the side of caution and treat potentially breaking changes as MAJOR version bumps.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@toon-format/spec",
3
+ "type": "module",
4
+ "version": "1.3.0",
5
+ "packageManager": "pnpm@10.19.0",
6
+ "description": "Official specification for Token-Oriented Object Notation (TOON)",
7
+ "author": "Johann Schopplich <hello@johannschopplich.com>",
8
+ "license": "MIT",
9
+ "homepage": "https://github.com/toon-format/spec",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/toon-format/spec.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/toon-format/spec/issues"
16
+ },
17
+ "keywords": [
18
+ "toon",
19
+ "format",
20
+ "specification",
21
+ "llm",
22
+ "token-efficiency",
23
+ "data-format"
24
+ ],
25
+ "files": [
26
+ "CHANGELOG.md",
27
+ "CONTRIBUTING.md",
28
+ "SPEC.md",
29
+ "VERSIONING.md",
30
+ "tests"
31
+ ],
32
+ "scripts": {
33
+ "lint": "eslint .",
34
+ "release": "bumpp"
35
+ },
36
+ "devDependencies": {
37
+ "@antfu/eslint-config": "^6.2.0",
38
+ "bumpp": "^10.3.1",
39
+ "eslint": "^9.39.0",
40
+ "vitest": "^4.0.6"
41
+ }
42
+ }
@@ -0,0 +1,218 @@
1
+ # TOON Test Fixtures
2
+
3
+ This directory contains **comprehensive language-agnostic JSON test fixtures** for validating TOON implementations against the specification. These fixtures cover all specification requirements and provide a standardized conformance test suite.
4
+
5
+ ## Purpose
6
+
7
+ The test fixtures serve multiple purposes:
8
+
9
+ - **Conformance validation:** Verify implementations follow the specification
10
+ - **Regression testing:** Catch behavioral changes across versions
11
+ - **Implementation guide:** Demonstrate expected encoding/decoding behavior
12
+ - **Cross-language consistency:** Ensure all implementations produce identical output
13
+
14
+ ## Directory Structure
15
+
16
+ ```
17
+ tests/
18
+ ├── fixtures.schema.json # JSON Schema for fixture validation
19
+ ├── fixtures/
20
+ │ ├── encode/ # Encoding tests (JSON → TOON)
21
+ │ │ ├── primitives.json
22
+ │ │ ├── objects.json
23
+ │ │ ├── arrays-primitive.json
24
+ │ │ ├── arrays-tabular.json
25
+ │ │ ├── arrays-nested.json
26
+ │ │ ├── arrays-objects.json
27
+ │ │ ├── delimiters.json
28
+ │ │ ├── normalization.json
29
+ │ │ ├── whitespace.json
30
+ │ │ └── options.json
31
+ │ └── decode/ # Decoding tests (TOON → JSON)
32
+ │ ├── primitives.json
33
+ │ ├── objects.json
34
+ │ ├── arrays-primitive.json
35
+ │ ├── arrays-tabular.json
36
+ │ ├── arrays-nested.json
37
+ │ ├── delimiters.json
38
+ │ ├── validation-errors.json
39
+ │ ├── indentation-errors.json
40
+ │ └── blank-lines.json
41
+ └── README.md # This file
42
+ ```
43
+
44
+ ## Fixture Format
45
+
46
+ All test fixtures follow a standard JSON structure defined in [`fixtures.schema.json`](./fixtures.schema.json):
47
+
48
+ ```json
49
+ {
50
+ "version": "1.3",
51
+ "category": "encode",
52
+ "description": "Brief description of test category",
53
+ "tests": [
54
+ {
55
+ "name": "descriptive test name",
56
+ "input": "JSON value or TOON string",
57
+ "expected": "TOON string or JSON value",
58
+ "options": {},
59
+ "specSection": "7.2",
60
+ "note": "Optional explanation"
61
+ }
62
+ ]
63
+ }
64
+ ```
65
+
66
+ ### Field Descriptions
67
+
68
+ | Field | Required | Description |
69
+ |-------|----------|-------------|
70
+ | `version` | Yes | TOON specification version (e.g., `"1.3"`) |
71
+ | `category` | Yes | Test category: `"encode"` or `"decode"` |
72
+ | `description` | Yes | Brief description of what this fixture tests |
73
+ | `tests` | Yes | Array of test cases |
74
+ | `tests[].name` | Yes | Descriptive name explaining what is validated |
75
+ | `tests[].input` | Yes | Input value (JSON for encode, TOON string for decode) |
76
+ | `tests[].expected` | Yes | Expected output (TOON string for encode, JSON for decode) |
77
+ | `tests[].shouldError` | No | If `true`, expects an error (default: `false`) |
78
+ | `tests[].options` | No | Encoder/decoder options (see below) |
79
+ | `tests[].specSection` | No | Reference to specification section (e.g., `"7.2"`, `"§6"`) |
80
+ | `tests[].note` | No | Optional explanation for special cases |
81
+ | `tests[].minSpecVersion` | No | Minimum spec version required (e.g., `"1.3"`) |
82
+
83
+ ### Options
84
+
85
+ #### Encoding Options
86
+
87
+ ```json
88
+ {
89
+ "delimiter": ",",
90
+ "indent": 2,
91
+ "lengthMarker": ""
92
+ }
93
+ ```
94
+
95
+ - `delimiter`: `","` (comma, default), `"\t"` (tab), or `"|"` (pipe)
96
+ - `indent`: Number of spaces per indentation level (default: `2`)
97
+ - `lengthMarker`: `"#"` to prefix array lengths, or `""` for no marker (default: `""`)
98
+
99
+ #### Decoding Options
100
+
101
+ ```json
102
+ {
103
+ "indent": 2,
104
+ "strict": true
105
+ }
106
+ ```
107
+
108
+ - `indent`: Expected number of spaces per level (default: `2`)
109
+ - `strict`: Enable strict validation (default: `true`)
110
+
111
+ ### Error Tests
112
+
113
+ Error tests use `shouldError: true` to indicate that the test expects an error to be thrown:
114
+
115
+ ```json
116
+ {
117
+ "name": "throws on array length mismatch",
118
+ "input": "tags[3]: a,b",
119
+ "expected": null,
120
+ "shouldError": true,
121
+ "options": { "strict": true }
122
+ }
123
+ ```
124
+
125
+ **Note:** Error tests do not specify expected error messages, as these are implementation-specific and vary across languages.
126
+
127
+ ## Using These Tests
128
+
129
+ To validate your TOON implementation against these fixtures:
130
+
131
+ 1. **Load a fixture file** from `fixtures/encode/` or `fixtures/decode/`.
132
+ 2. **Iterate through the `tests` array** in the fixture.
133
+ 3. **For each test case:**
134
+ - If `shouldError` is `true`: verify your implementation throws an error.
135
+ - Otherwise: assert that your encoder/decoder produces the `expected` output when given the `input`.
136
+ 4. **Pass options** from `test.options` to your encoder/decoder (if present).
137
+
138
+ The fixture format is language-agnostic JSON, so you can load and iterate it using your language's standard JSON parser and test framework.
139
+
140
+ ## Test Coverage
141
+
142
+ ### Encoding Tests (`fixtures/encode/`)
143
+
144
+ | File | Description | Spec Sections |
145
+ |------|-------------|---------------|
146
+ | `primitives.json` | String, number, boolean, null encoding and escaping | §5 |
147
+ | `objects.json` | Simple objects, nested objects, key encoding | §6 |
148
+ | `arrays-primitive.json` | Inline primitive arrays, empty arrays | §7.1 |
149
+ | `arrays-tabular.json` | Tabular format with header and rows | §7.2 |
150
+ | `arrays-nested.json` | Arrays of arrays, mixed arrays | §7.3 |
151
+ | `arrays-objects.json` | Objects as list items, complex nesting | §7 |
152
+ | `delimiters.json` | Tab and pipe delimiter options | §8 |
153
+ | `normalization.json` | BigInt, Date, undefined, NaN, Infinity handling | §5 |
154
+ | `whitespace.json` | Formatting invariants and indentation | §4 |
155
+ | `options.json` | Length marker and delimiter option combinations | §3 |
156
+
157
+ ### Decoding Tests (`fixtures/decode/`)
158
+
159
+ | File | Description | Spec Sections |
160
+ |------|-------------|---------------|
161
+ | `primitives.json` | Parsing primitives, unescaping, ambiguity | §5 |
162
+ | `objects.json` | Parsing objects, keys, nesting | §6 |
163
+ | `arrays-primitive.json` | Inline array parsing | §7.1 |
164
+ | `arrays-tabular.json` | Tabular format parsing | §7.2 |
165
+ | `arrays-nested.json` | Nested and mixed array parsing | §7.3 |
166
+ | `delimiters.json` | Delimiter detection and parsing | §8 |
167
+ | `validation-errors.json` | Syntax errors, length mismatches, malformed input | §9 |
168
+ | `indentation-errors.json` | Strict mode indentation validation | §9 |
169
+ | `blank-lines.json` | Blank line handling in arrays | §9 |
170
+
171
+ ## Validating Fixtures
172
+
173
+ All fixture files should validate against [`fixtures.schema.json`](./fixtures.schema.json). You can use standard JSON Schema validators:
174
+
175
+ ```bash
176
+ # Using ajv-cli
177
+ npx ajv-cli validate -s fixtures.schema.json -d "fixtures/**/*.json"
178
+
179
+ # Using check-jsonschema (Python)
180
+ pip install check-jsonschema
181
+ check-jsonschema --schemafile fixtures.schema.json fixtures/**/*.json
182
+ ```
183
+
184
+ ## Contributing Test Cases
185
+
186
+ To contribute new test cases:
187
+
188
+ 1. **Identify the category:** Which fixture file should contain the test?
189
+ 2. **Follow the format:** Use the structure defined in `fixtures.schema.json`
190
+ 3. **Add spec references:** Link to relevant specification sections
191
+ 4. **Validate:** Ensure your fixture validates against the schema
192
+ 5. **Test with reference implementation:** Verify expected output is correct
193
+ 6. **Submit PR:** Include clear description of what the test validates
194
+
195
+ See [CONTRIBUTING.md](../CONTRIBUTING.md) for detailed guidelines.
196
+
197
+ ## Reference Implementation
198
+
199
+ The reference implementation in TypeScript/JavaScript is maintained at: [github.com/toon-format/toon](https://github.com/toon-format/toon)
200
+
201
+ ## Questions or Issues?
202
+
203
+ If you find:
204
+
205
+ - Test cases that contradict the specification
206
+ - Missing coverage for edge cases
207
+ - Ambiguous expected outputs
208
+ - Schema validation issues
209
+
210
+ Please [open an issue](https://github.com/toon-format/spec/issues) with:
211
+
212
+ - Fixture file and test case name
213
+ - Description of the issue
214
+ - Proposed fix (if applicable)
215
+
216
+ ## License
217
+
218
+ These test fixtures are released under the MIT License, the same as the specification.
@@ -0,0 +1,156 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "decode",
4
+ "description": "Nested and mixed array decoding - list format, arrays of arrays, root arrays, mixed types",
5
+ "tests": [
6
+ {
7
+ "name": "parses list arrays for non-uniform objects",
8
+ "input": "items[2]:\n - id: 1\n name: First\n - id: 2\n name: Second\n extra: true",
9
+ "expected": {
10
+ "items": [
11
+ { "id": 1, "name": "First" },
12
+ { "id": 2, "name": "Second", "extra": true }
13
+ ]
14
+ },
15
+ "specSection": "7"
16
+ },
17
+ {
18
+ "name": "parses objects with nested values inside list items",
19
+ "input": "items[1]:\n - id: 1\n nested:\n x: 1",
20
+ "expected": {
21
+ "items": [
22
+ { "id": 1, "nested": { "x": 1 } }
23
+ ]
24
+ },
25
+ "specSection": "7"
26
+ },
27
+ {
28
+ "name": "parses nested tabular arrays as first field on hyphen line",
29
+ "input": "items[1]:\n - users[2]{id,name}:\n 1,Ada\n 2,Bob\n status: active",
30
+ "expected": {
31
+ "items": [
32
+ {
33
+ "users": [
34
+ { "id": 1, "name": "Ada" },
35
+ { "id": 2, "name": "Bob" }
36
+ ],
37
+ "status": "active"
38
+ }
39
+ ]
40
+ },
41
+ "specSection": "7"
42
+ },
43
+ {
44
+ "name": "parses objects containing arrays (including empty arrays) in list format",
45
+ "input": "items[1]:\n - name: test\n data[0]:",
46
+ "expected": {
47
+ "items": [
48
+ { "name": "test", "data": [] }
49
+ ]
50
+ },
51
+ "specSection": "7"
52
+ },
53
+ {
54
+ "name": "parses arrays of arrays within objects",
55
+ "input": "items[1]:\n - matrix[2]:\n - [2]: 1,2\n - [2]: 3,4\n name: grid",
56
+ "expected": {
57
+ "items": [
58
+ { "matrix": [[1, 2], [3, 4]], "name": "grid" }
59
+ ]
60
+ },
61
+ "specSection": "7"
62
+ },
63
+ {
64
+ "name": "parses nested arrays of primitives",
65
+ "input": "pairs[2]:\n - [2]: a,b\n - [2]: c,d",
66
+ "expected": {
67
+ "pairs": [["a", "b"], ["c", "d"]]
68
+ },
69
+ "specSection": "7.3"
70
+ },
71
+ {
72
+ "name": "parses quoted strings and mixed lengths in nested arrays",
73
+ "input": "pairs[2]:\n - [2]: a,b\n - [3]: \"c,d\",\"e:f\",\"true\"",
74
+ "expected": {
75
+ "pairs": [["a", "b"], ["c,d", "e:f", "true"]]
76
+ },
77
+ "specSection": "7.3"
78
+ },
79
+ {
80
+ "name": "parses empty inner arrays",
81
+ "input": "pairs[2]:\n - [0]:\n - [0]:",
82
+ "expected": {
83
+ "pairs": [[], []]
84
+ },
85
+ "specSection": "7.3"
86
+ },
87
+ {
88
+ "name": "parses mixed-length inner arrays",
89
+ "input": "pairs[2]:\n - [1]: 1\n - [2]: 2,3",
90
+ "expected": {
91
+ "pairs": [[1], [2, 3]]
92
+ },
93
+ "specSection": "7.3"
94
+ },
95
+ {
96
+ "name": "parses root arrays of primitives (inline)",
97
+ "input": "[5]: x,y,\"true\",true,10",
98
+ "expected": ["x", "y", "true", true, 10],
99
+ "specSection": "7"
100
+ },
101
+ {
102
+ "name": "parses root arrays of uniform objects in tabular format",
103
+ "input": "[2]{id}:\n 1\n 2",
104
+ "expected": [{ "id": 1 }, { "id": 2 }],
105
+ "specSection": "7.2"
106
+ },
107
+ {
108
+ "name": "parses root arrays of non-uniform objects in list format",
109
+ "input": "[2]:\n - id: 1\n - id: 2\n name: Ada",
110
+ "expected": [{ "id": 1 }, { "id": 2, "name": "Ada" }],
111
+ "specSection": "7"
112
+ },
113
+ {
114
+ "name": "parses empty root arrays",
115
+ "input": "[0]:",
116
+ "expected": [],
117
+ "specSection": "7"
118
+ },
119
+ {
120
+ "name": "parses root arrays of arrays",
121
+ "input": "[2]:\n - [2]: 1,2\n - [0]:",
122
+ "expected": [[1, 2], []],
123
+ "specSection": "7.3"
124
+ },
125
+ {
126
+ "name": "parses complex mixed object with arrays and nested objects",
127
+ "input": "user:\n id: 123\n name: Ada\n tags[2]: reading,gaming\n active: true\n prefs[0]:",
128
+ "expected": {
129
+ "user": {
130
+ "id": 123,
131
+ "name": "Ada",
132
+ "tags": ["reading", "gaming"],
133
+ "active": true,
134
+ "prefs": []
135
+ }
136
+ },
137
+ "specSection": "6"
138
+ },
139
+ {
140
+ "name": "parses arrays mixing primitives, objects and strings (list format)",
141
+ "input": "items[3]:\n - 1\n - a: 1\n - text",
142
+ "expected": {
143
+ "items": [1, { "a": 1 }, "text"]
144
+ },
145
+ "specSection": "7.3"
146
+ },
147
+ {
148
+ "name": "parses arrays mixing objects and arrays",
149
+ "input": "items[2]:\n - a: 1\n - [2]: 1,2",
150
+ "expected": {
151
+ "items": [{ "a": 1 }, [1, 2]]
152
+ },
153
+ "specSection": "7.3"
154
+ }
155
+ ]
156
+ }
@@ -0,0 +1,87 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "decode",
4
+ "description": "Primitive array decoding - inline arrays of strings, numbers, booleans, quoted strings",
5
+ "tests": [
6
+ {
7
+ "name": "parses string arrays inline",
8
+ "input": "tags[3]: reading,gaming,coding",
9
+ "expected": {
10
+ "tags": ["reading", "gaming", "coding"]
11
+ },
12
+ "specSection": "7.1"
13
+ },
14
+ {
15
+ "name": "parses number arrays inline",
16
+ "input": "nums[3]: 1,2,3",
17
+ "expected": {
18
+ "nums": [1, 2, 3]
19
+ },
20
+ "specSection": "7.1"
21
+ },
22
+ {
23
+ "name": "parses mixed primitive arrays inline",
24
+ "input": "data[4]: x,y,true,10",
25
+ "expected": {
26
+ "data": ["x", "y", true, 10]
27
+ },
28
+ "specSection": "7.1"
29
+ },
30
+ {
31
+ "name": "parses empty arrays",
32
+ "input": "items[0]:",
33
+ "expected": {
34
+ "items": []
35
+ },
36
+ "specSection": "7.1"
37
+ },
38
+ {
39
+ "name": "parses single-item array with empty string",
40
+ "input": "items[1]: \"\"",
41
+ "expected": {
42
+ "items": [""]
43
+ },
44
+ "specSection": "7.1"
45
+ },
46
+ {
47
+ "name": "parses multi-item array with empty string",
48
+ "input": "items[3]: a,\"\",b",
49
+ "expected": {
50
+ "items": ["a", "", "b"]
51
+ },
52
+ "specSection": "7.1"
53
+ },
54
+ {
55
+ "name": "parses whitespace-only strings in arrays",
56
+ "input": "items[2]: \" \",\" \"",
57
+ "expected": {
58
+ "items": [" ", " "]
59
+ },
60
+ "specSection": "7.1"
61
+ },
62
+ {
63
+ "name": "parses strings with delimiters in arrays",
64
+ "input": "items[3]: a,\"b,c\",\"d:e\"",
65
+ "expected": {
66
+ "items": ["a", "b,c", "d:e"]
67
+ },
68
+ "specSection": "7.1"
69
+ },
70
+ {
71
+ "name": "parses strings that look like primitives when quoted",
72
+ "input": "items[4]: x,\"true\",\"42\",\"-3.14\"",
73
+ "expected": {
74
+ "items": ["x", "true", "42", "-3.14"]
75
+ },
76
+ "specSection": "7.1"
77
+ },
78
+ {
79
+ "name": "parses strings with structural tokens in arrays",
80
+ "input": "items[3]: \"[5]\",\"- item\",\"{key}\"",
81
+ "expected": {
82
+ "items": ["[5]", "- item", "{key}"]
83
+ },
84
+ "specSection": "7.1"
85
+ }
86
+ ]
87
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "decode",
4
+ "description": "Tabular array decoding - parsing arrays of uniform objects with headers",
5
+ "tests": [
6
+ {
7
+ "name": "parses tabular arrays of uniform objects",
8
+ "input": "items[2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5",
9
+ "expected": {
10
+ "items": [
11
+ { "sku": "A1", "qty": 2, "price": 9.99 },
12
+ { "sku": "B2", "qty": 1, "price": 14.5 }
13
+ ]
14
+ },
15
+ "specSection": "7.2"
16
+ },
17
+ {
18
+ "name": "parses nulls and quoted values in tabular rows",
19
+ "input": "items[2]{id,value}:\n 1,null\n 2,\"test\"",
20
+ "expected": {
21
+ "items": [
22
+ { "id": 1, "value": null },
23
+ { "id": 2, "value": "test" }
24
+ ]
25
+ },
26
+ "specSection": "7.2"
27
+ },
28
+ {
29
+ "name": "parses quoted header keys in tabular arrays",
30
+ "input": "items[2]{\"order:id\",\"full name\"}:\n 1,Ada\n 2,Bob",
31
+ "expected": {
32
+ "items": [
33
+ { "order:id": 1, "full name": "Ada" },
34
+ { "order:id": 2, "full name": "Bob" }
35
+ ]
36
+ },
37
+ "specSection": "7.2"
38
+ }
39
+ ]
40
+ }