Pure OCaml Yaml 1.2 reader and writer using Bytesrw

split out cram yml

+199 -149
+18 -5
lib/emitter.ml
··· 287 287 t.need_separator <- false; 288 288 t.state <- In_flow_mapping_value 289 289 | In_flow_mapping_value -> 290 - write_anchor t anchor; 291 - write_tag t ~implicit:plain_implicit tag; 292 - write_scalar t ~style value; 293 - t.need_separator <- true; 294 - t.state <- In_flow_mapping_key 290 + if t.need_separator then begin 291 + (* We just finished a nested structure (array/mapping), 292 + so this scalar is the next key, not a value *) 293 + write t ", "; 294 + write_anchor t anchor; 295 + write_tag t ~implicit:plain_implicit tag; 296 + write_scalar t ~style value; 297 + write t ": "; 298 + t.need_separator <- false; 299 + t.state <- In_flow_mapping_value 300 + end else begin 301 + (* Normal value scalar *) 302 + write_anchor t anchor; 303 + write_tag t ~implicit:plain_implicit tag; 304 + write_scalar t ~style value; 305 + t.need_separator <- true; 306 + t.state <- In_flow_mapping_key 307 + end 295 308 | _ -> 296 309 if t.need_separator then write t ", "; 297 310 t.need_separator <- true;
+8 -8
tests/cram/collections.t
··· 119 119 Test collections_block.yml with flow output 120 120 121 121 $ yamlcat --flow collections_block.yml 122 - {simple_sequence: [apple, banana, cherry, date]simple_mapping, {name: John Doe, age: 30, city: New York, country: USA}, nested_sequences: [[alpha, beta, gamma], [one, two, three], [red, green, blue]]nested_mappings, {person: {name: Alice, contact: {email: alice@example.com, phone: 555-1234}address, {street: 123 Main St, city: Boston}}}, mapping_with_sequences: {colors: [red, green, blue]sizes, [small, medium, large], numbers: [1, 2, 3]}sequence_with_mappings, [{name: Alice, age: 25, role: developer}, {name: Bob, age: 30, role: designer}, {name: Charlie, age: 35, role: manager}], deep_nesting: {level1: {level2: {level3: {level4: [deeply, nested, values]another_key, value: }items, [item1, item2]}metadata, {created: 2024-01-01, modified: 2024-12-04}}}complex_structure, {database: {connections: [{host: db1.example.com, port: 5432, credentials: {username: admin, password: secret}}, {host: db2.example.com, port: 5432, credentials: {username: readonly, password: public}}]}services, [{name: api, endpoints: [/users, /posts, /comments]config, {timeout: 30, retries: 3}}, {name: worker, tasks: [email, reports]config, {concurrency: 10}}]}, empty_collections: {empty_sequence: []empty_mapping, {}, sequence_with_empty: [value1, [], value2]mapping_with_empty, {key1: value1, key2: {}key3, value3: }}} 122 + {simple_sequence: [apple, banana, cherry, date], simple_mapping: {name: John Doe, age: 30, city: New York, country: USA}, nested_sequences: [[alpha, beta, gamma], [one, two, three], [red, green, blue]], nested_mappings: {person: {name: Alice, contact: {email: alice@example.com, phone: 555-1234}, address: {street: 123 Main St, city: Boston}}}, mapping_with_sequences: {colors: [red, green, blue], sizes: [small, medium, large], numbers: [1, 2, 3]}, sequence_with_mappings: [{name: Alice, age: 25, role: developer}, {name: Bob, age: 30, role: designer}, {name: Charlie, age: 35, role: manager}], deep_nesting: {level1: {level2: {level3: {level4: [deeply, nested, values], another_key: value}, items: [item1, item2]}, metadata: {created: 2024-01-01, modified: 2024-12-04}}}, complex_structure: {database: {connections: [{host: db1.example.com, port: 5432, credentials: {username: admin, password: secret}}, {host: db2.example.com, port: 5432, credentials: {username: readonly, password: public}}]}, services: [{name: api, endpoints: [/users, /posts, /comments], config: {timeout: 30, retries: 3}}, {name: worker, tasks: [email, reports], config: {concurrency: 10}}]}, empty_collections: {empty_sequence: [], empty_mapping: {}, sequence_with_empty: [value1, [], value2], mapping_with_empty: {key1: value1, key2: {}, key3: value3}}} 123 123 124 124 Test collections_compact.yml - Compact notation 125 125 ··· 314 314 Test collections_compact.yml with flow output 315 315 316 316 $ yamlcat --flow collections_compact.yml 317 - {compact_sequence: [{name: Alice, age: 25, city: Boston}, {name: Bob, age: 30, city: Seattle}, {name: Charlie, age: 35, city: Portland}]compact_nested, [{id: 1, details: {type: admin, permissions: [read, write, delete]}}, {id: 2, details: {type: user, permissions: [read]}}], compact_complex: [{key1: value1, key2: value2, nested: {sub1: val1, sub2: val2}}, {key1: value3, key2: value4, nested: {sub1: val3, sub2: val4}}]users, [{username: alice, email: alice@example.com, active: true}, {username: bob, email: bob@example.com, active: false}], compact_with_flow: [{name: service1, ports: [8080, 8443]env, {DEBUG: true, MODE: production}}, {name: service2, ports: [3000]env, {DEBUG: false, MODE: development}}]deep_compact, [{category: electronics, items: [{name: laptop, specs: {cpu: Intel i7, ram: 16GB, storage: 512GB SSD}}, {name: phone, specs: {os: Android, ram: 8GB, storage: 256GB}}]}, {category: furniture, items: [{name: desk, dimensions: {width: 150cm, depth: 75cm, height: 75cm}}, {name: chair, dimensions: {width: 60cm, depth: 60cm, height: 120cm}}]}], mixed_compact: {databases: [{type: postgresql, connection: {host: localhost, port: 5432}credentials, {user: admin, password: secret}}, {type: mongodb, connection: {host: localhost, port: 27017}credentials, {user: root, password: root}}]}single_line_compact, [{name: Alice, age: 25, role: developer}, {name: Bob, age: 30, role: designer}, {name: Charlie, age: 35, role: manager}], sequences_in_compact: [{title: Project A, members: [Alice, Bob, Charlie]tags, [urgent, backend]}, {title: Project B, members: [David, Eve]tags, [frontend, design]}]compact_with_empty, [{id: 1, data: []meta, {}}, {id: 2, data: [item1]meta, {key: value}}], compact_complex_nesting: [{level: 1, children: [{level: 2a, children: [{level: 3a, value: leaf1}, {level: 3b, value: leaf2}]}, {level: 2b, children: [{level: 3c, value: leaf3}]}]}]api_endpoints, [{path: /users, method: GET, auth: required, params: [{name: page, type: integer, default: 1}, {name: limit, type: integer, default: 10}]}, {path: '/users/:id', method: GET, auth: required, params: []}, {path: /users, method: POST, auth: required, body: {username: string, email: string, password: string}}], compact_types: [{string_val: hello, number_val: 42, float_val: 3.14, bool_val: true, null_val: null}, {string_val: world, number_val: 100, float_val: 2.71, bool_val: false, null_val: null}]minimal, [{a: 1}, {b: 2}, {c: 3}]} 317 + {compact_sequence: [{name: Alice, age: 25, city: Boston}, {name: Bob, age: 30, city: Seattle}, {name: Charlie, age: 35, city: Portland}], compact_nested: [{id: 1, details: {type: admin, permissions: [read, write, delete]}}, {id: 2, details: {type: user, permissions: [read]}}], compact_complex: [{key1: value1, key2: value2, nested: {sub1: val1, sub2: val2}}, {key1: value3, key2: value4, nested: {sub1: val3, sub2: val4}}], users: [{username: alice, email: alice@example.com, active: true}, {username: bob, email: bob@example.com, active: false}], compact_with_flow: [{name: service1, ports: [8080, 8443], env: {DEBUG: true, MODE: production}}, {name: service2, ports: [3000], env: {DEBUG: false, MODE: development}}], deep_compact: [{category: electronics, items: [{name: laptop, specs: {cpu: Intel i7, ram: 16GB, storage: 512GB SSD}}, {name: phone, specs: {os: Android, ram: 8GB, storage: 256GB}}]}, {category: furniture, items: [{name: desk, dimensions: {width: 150cm, depth: 75cm, height: 75cm}}, {name: chair, dimensions: {width: 60cm, depth: 60cm, height: 120cm}}]}], mixed_compact: {databases: [{type: postgresql, connection: {host: localhost, port: 5432}, credentials: {user: admin, password: secret}}, {type: mongodb, connection: {host: localhost, port: 27017}, credentials: {user: root, password: root}}]}, single_line_compact: [{name: Alice, age: 25, role: developer}, {name: Bob, age: 30, role: designer}, {name: Charlie, age: 35, role: manager}], sequences_in_compact: [{title: Project A, members: [Alice, Bob, Charlie], tags: [urgent, backend]}, {title: Project B, members: [David, Eve], tags: [frontend, design]}], compact_with_empty: [{id: 1, data: [], meta: {}}, {id: 2, data: [item1], meta: {key: value}}], compact_complex_nesting: [{level: 1, children: [{level: 2a, children: [{level: 3a, value: leaf1}, {level: 3b, value: leaf2}]}, {level: 2b, children: [{level: 3c, value: leaf3}]}]}], api_endpoints: [{path: /users, method: GET, auth: required, params: [{name: page, type: integer, default: 1}, {name: limit, type: integer, default: 10}]}, {path: '/users/:id', method: GET, auth: required, params: []}, {path: /users, method: POST, auth: required, body: {username: string, email: string, password: string}}], compact_types: [{string_val: hello, number_val: 42, float_val: 3.14, bool_val: true, null_val: null}, {string_val: world, number_val: 100, float_val: 2.71, bool_val: false, null_val: null}], minimal: [{a: 1}, {b: 2}, {c: 3}]} 318 318 319 319 Test collections_flow.yml - Flow style collections 320 320 ··· 515 515 Test collections_flow.yml with flow output 516 516 517 517 $ yamlcat --flow collections_flow.yml 518 - {simple_flow_sequence: [apple, banana, cherry, date]simple_flow_mapping, {name: John, age: 30, city: New York}, nested_flow_sequences: [[a, b, c], [1, 2, 3], [red, green, blue]]nested_flow_mappings, {person: {name: Alice, age: 25}contact, {email: alice@example.com, phone: 555-1234}}, flow_seq_with_maps: [{name: Alice, role: dev}, {name: Bob, role: ops}, {name: Charlie, role: qa}]flow_map_with_seqs, {colors: [red, green, blue]sizes, [S, M, L], numbers: [1, 2, 3]}, deep_flow_nesting: {level1: {level2: {level3: {level4: [a, b, c]}}}}empty_flow, {empty_seq: []empty_map, {}, both: [[], {}]}, flow_in_block: {sequence: [1, 2, 3, 4, 5]mapping, {a: 1, b: 2, c: 3}, nested: {items: [x, y, z]config, {timeout: 30, retries: 3}}}block_in_flow, {users: [{name: Alice, tags: [dev, senior]}, {name: Bob, tags: [ops, junior]}]}, mixed_structure: {services: [{name: api, ports: [8080, 8443]env, {DEBUG: true, LOG_LEVEL: info}}, {name: db, ports: [5432]env, {POSTGRES_DB: mydb, POSTGRES_USER: admin}}]config, {version: 1, enabled: true}}flow_types, {strings: [hello, world, foo, bar]numbers, [1, 2, 3, 42, 100], mixed: [string, 123, true, false, null]quoted, [with spaces, 'special:chars', commas, here]}, flow_map_types: {string: value, number: 42, boolean: true, null_value: null, float: 3.14}nested_mixed, [{id: 1, data: [a, b, c]meta, {type: first}}, {id: 2, data: [d, e, f]meta, {type: second}}, {id: 3, data: [g, h, i]meta, {type: third}}], multiline_flow: {long_sequence: [item1, item2, item3, item4]long_mapping, {key1: value1, key2: value2, key3: value3}}edge_cases, {single_item_seq: [alone]single_item_map, {only: one}, nested_empty: [[], [{}], [{}, []]]all_empty, [{}, [], {a: []}, {b: {}}]}} 518 + {simple_flow_sequence: [apple, banana, cherry, date], simple_flow_mapping: {name: John, age: 30, city: New York}, nested_flow_sequences: [[a, b, c], [1, 2, 3], [red, green, blue]], nested_flow_mappings: {person: {name: Alice, age: 25}, contact: {email: alice@example.com, phone: 555-1234}}, flow_seq_with_maps: [{name: Alice, role: dev}, {name: Bob, role: ops}, {name: Charlie, role: qa}], flow_map_with_seqs: {colors: [red, green, blue], sizes: [S, M, L], numbers: [1, 2, 3]}, deep_flow_nesting: {level1: {level2: {level3: {level4: [a, b, c]}}}}, empty_flow: {empty_seq: [], empty_map: {}, both: [[], {}]}, flow_in_block: {sequence: [1, 2, 3, 4, 5], mapping: {a: 1, b: 2, c: 3}, nested: {items: [x, y, z], config: {timeout: 30, retries: 3}}}, block_in_flow: {users: [{name: Alice, tags: [dev, senior]}, {name: Bob, tags: [ops, junior]}]}, mixed_structure: {services: [{name: api, ports: [8080, 8443], env: {DEBUG: true, LOG_LEVEL: info}}, {name: db, ports: [5432], env: {POSTGRES_DB: mydb, POSTGRES_USER: admin}}], config: {version: 1, enabled: true}}, flow_types: {strings: [hello, world, foo, bar], numbers: [1, 2, 3, 42, 100], mixed: [string, 123, true, false, null], quoted: [with spaces, 'special:chars', commas, here]}, flow_map_types: {string: value, number: 42, boolean: true, null_value: null, float: 3.14}, nested_mixed: [{id: 1, data: [a, b, c], meta: {type: first}}, {id: 2, data: [d, e, f], meta: {type: second}}, {id: 3, data: [g, h, i], meta: {type: third}}], multiline_flow: {long_sequence: [item1, item2, item3, item4], long_mapping: {key1: value1, key2: value2, key3: value3}}, edge_cases: {single_item_seq: [alone], single_item_map: {only: one}, nested_empty: [[], [{}], [{}, []]], all_empty: [{}, [], {a: []}, {b: {}}]}} 519 519 520 520 Inline test: Simple sequence 521 521 ··· 686 686 $ echo 'block_key: 687 687 > flow_seq: [1, 2, 3] 688 688 > flow_map: {a: 1, b: 2}' | yamlcat --flow 689 - {block_key: {flow_seq: [1, 2, 3]flow_map, {a: 1, b: 2}}} 689 + {block_key: {flow_seq: [1, 2, 3], flow_map: {a: 1, b: 2}}} 690 690 691 691 Inline test: Mixed block and flow (block in flow) 692 692 ··· 769 769 > tags: [x, y, z] 770 770 > config: 771 771 > enabled: false' | yamlcat --flow 772 - [{id: 1, tags: [a, b, c]config, {enabled: true}}, {id: 2, tags: [x, y, z]config, {enabled: false}}] 772 + [{id: 1, tags: [a, b, c], config: {enabled: true}}, {id: 2, tags: [x, y, z], config: {enabled: false}}] 773 773 774 774 Inline test: Empty collections 775 775 ··· 784 784 785 785 $ echo 'empty_seq: [] 786 786 > empty_map: {}' | yamlcat --flow 787 - {empty_seq: []empty_map, {}} 787 + {empty_seq: [], empty_map: {}} 788 788 789 789 Inline test: Sequence with mapping values 790 790 ··· 811 811 > - banana 812 812 > config: 813 813 > mode: fast' | yamlcat --flow 814 - {items: [apple, banana]config, {mode: fast}} 814 + {items: [apple, banana], config: {mode: fast}} 815 815 816 816 Inline test: Complex nested structure 817 817 ··· 850 850 > env: 851 851 > DEBUG: false 852 852 > MODE: prod' | yamlcat --flow 853 - {services: [{name: web, ports: [80, 443]env, {DEBUG: false, MODE: prod}}]} 853 + {services: [{name: web, ports: [80, 443], env: {DEBUG: false, MODE: prod}}]} 854 854 855 855 Inline test: Flow sequence with various types 856 856
+2
tests/cram/scalar_bool_vs_string.yml
··· 1 + unquoted_true: true 2 + quoted_true: "true"
+4
tests/cram/scalar_clip_folded.yml
··· 1 + text: > 2 + Folded with one 3 + trailing newline 4 +
+3
tests/cram/scalar_clip_literal.yml
··· 1 + text: | 2 + One trailing newline 3 +
+5
tests/cram/scalar_code_sample.yml
··· 1 + code: | 2 + def hello(): 3 + print("Hello") 4 + if True: 5 + return 42
+1
tests/cram/scalar_double_empty.yml
··· 1 + empty: ""
+1
tests/cram/scalar_double_quote.yml
··· 1 + text: "She said \"hello\""
+1
tests/cram/scalar_double_simple.yml
··· 1 + double: "hello world"
+1
tests/cram/scalar_empty_folded.yml
··· 1 + empty_folded: >
+1
tests/cram/scalar_empty_literal.yml
··· 1 + empty_literal: |
+4
tests/cram/scalar_folded_basic.yml
··· 1 + text: > 2 + This is a long paragraph 3 + that will be folded into 4 + a single line.
+4
tests/cram/scalar_folded_comment.yml
··· 1 + text: > 2 + Normal paragraph 3 + that continues. 4 + # This is part of the content
+8
tests/cram/scalar_folded_indent_preserve.yml
··· 1 + text: > 2 + Normal paragraph 3 + continues here. 4 + 5 + Indented block 6 + preserved. 7 + 8 + Back to normal.
+6
tests/cram/scalar_folded_para.yml
··· 1 + text: > 2 + First paragraph 3 + flows together. 4 + 5 + Second paragraph 6 + also flows.
+5
tests/cram/scalar_folded_strip.yml
··· 1 + text: >- 2 + Folded text 3 + with stripped 4 + trailing newlines 5 +
+4
tests/cram/scalar_indent2_folded.yml
··· 1 + text: >2 2 + Text with two space 3 + base indentation that 4 + will be folded.
+6
tests/cram/scalar_indent2_keep.yml
··· 1 + text: |2+ 2 + Indented by 2 3 + Keeps trailing newlines 4 + 5 + 6 +
+4
tests/cram/scalar_indent2_literal.yml
··· 1 + text: |2 2 + Two space base 3 + Second line 4 + Extra indent
+4
tests/cram/scalar_indent2_strip.yml
··· 1 + text: |2- 2 + Indented by 2 3 + No trailing newlines 4 +
+6
tests/cram/scalar_keep_folded.yml
··· 1 + text: >+ 2 + Folded text 3 + keeps trailing 4 + 5 + 6 +
+5
tests/cram/scalar_keep_literal.yml
··· 1 + text: |+ 2 + Keeps trailing newlines 3 + 4 + 5 +
+4
tests/cram/scalar_literal_basic.yml
··· 1 + text: | 2 + line one 3 + line two 4 + line three
+4
tests/cram/scalar_literal_blank.yml
··· 1 + text: | 2 + First paragraph 3 + 4 + Second paragraph
+4
tests/cram/scalar_literal_indent.yml
··· 1 + text: | 2 + First line 3 + Indented line 4 + Back to first
+8
tests/cram/scalar_nested_blocks.yml
··· 1 + outer: 2 + inner: 3 + description: > 4 + This is a folded 5 + description. 6 + code: | 7 + def test(): 8 + return True
+2
tests/cram/scalar_null_vs_string.yml
··· 1 + unquoted_null: null 2 + quoted_null: "null"
+3
tests/cram/scalar_plain_multi.yml
··· 1 + name: Alice 2 + age: 30 3 + active: true
+1
tests/cram/scalar_plain_simple.yml
··· 1 + key: value
+5
tests/cram/scalar_plain_types.yml
··· 1 + null_val: null 2 + bool_true: true 3 + bool_false: false 4 + number: 42 5 + float: 3.14
+7
tests/cram/scalar_seq_blocks.yml
··· 1 + items: 2 + - | 3 + First item 4 + multiline 5 + - > 6 + Second item 7 + folded
+1
tests/cram/scalar_single_dquote.yml
··· 1 + quote: 'He said "hello"'
+1
tests/cram/scalar_single_empty.yml
··· 1 + empty: ''
+1
tests/cram/scalar_single_escaped.yml
··· 1 + escaped: 'It''s a test'
+3
tests/cram/scalar_single_multiline.yml
··· 1 + text: 'This is a 2 + multi-line 3 + string'
+1
tests/cram/scalar_single_simple.yml
··· 1 + single: 'hello world'
+4
tests/cram/scalar_special_chars.yml
··· 1 + code: | 2 + Special: @#$%^&*() 3 + Symbols: <>?/\| 4 + Brackets: []{}
+3
tests/cram/scalar_strip_blank.yml
··· 1 + text: |- 2 + Text here 3 +
+2
tests/cram/scalar_strip_simple.yml
··· 1 + text: |- 2 + No trailing newline
+3
tests/cram/scalar_whitespace.yml
··· 1 + leading: " spaces" 2 + trailing: "spaces " 3 + both: " both "
+40 -136
tests/cram/scalars.t
··· 8 8 9 9 Simple plain scalars 10 10 11 - $ echo 'key: value' | yamlcat 11 + $ yamlcat scalar_plain_simple.yml 12 12 key: value 13 13 14 - $ echo 'name: Alice 15 - > age: 30 16 - > active: true' | yamlcat 14 + $ yamlcat scalar_plain_multi.yml 17 15 name: Alice 18 16 age: 30 19 17 active: true 20 18 21 19 Plain scalars with special values 22 20 23 - $ echo 'null_val: null 24 - > bool_true: true 25 - > bool_false: false 26 - > number: 42 27 - > float: 3.14' | yamlcat --json 21 + $ yamlcat --json scalar_plain_types.yml 28 22 {"null_val": null, "bool_true": true, "bool_false": false, "number": 42, "float": 3.14} 29 23 30 24 ================================================================================ ··· 33 27 34 28 Single-quoted strings preserve literal text 35 29 36 - $ echo "single: 'hello world'" | yamlcat 30 + $ yamlcat scalar_single_simple.yml 37 31 single: hello world 38 32 39 33 Single-quoted strings with embedded double quotes 40 34 41 - $ echo "quote: 'He said \"hello\"'" | yamlcat 35 + $ yamlcat scalar_single_dquote.yml 42 36 quote: "He said \"hello\"" 43 37 44 38 Single-quoted strings with escaped single quotes (doubled) 45 39 46 - $ echo "escaped: 'It''s a test'" | yamlcat 40 + $ yamlcat scalar_single_escaped.yml 47 41 escaped: It's a test 48 42 49 43 Single-quoted multiline (newlines become spaces) 50 44 51 - $ echo "text: 'This is a 52 - > multi-line 53 - > string'" | yamlcat --json 45 + $ yamlcat --json scalar_single_multiline.yml 54 46 {"text": "This is a multi-line string"} 55 47 56 48 Empty single-quoted string 57 49 58 - $ echo "empty: ''" | yamlcat 50 + $ yamlcat scalar_single_empty.yml 59 51 empty: '' 60 52 61 53 ================================================================================ ··· 64 56 65 57 Simple double-quoted strings 66 58 67 - $ echo 'double: "hello world"' | yamlcat 59 + $ yamlcat scalar_double_simple.yml 68 60 double: hello world 69 61 70 62 Double-quoted with escaped newline ··· 74 66 75 67 Double-quoted with escaped tab 76 68 77 - $ echo 'text: "Col1\tCol2\tCol3"' | yamlcat --json 69 + $ yamlcat --json tab_columns.yml 78 70 {"text": "Col1\tCol2\tCol3"} 79 71 80 72 Double-quoted with backslash escape (Windows path) ··· 86 78 87 79 Double-quoted with escaped quote 88 80 89 - $ echo 'text: "She said \"hello\""' | yamlcat --json 81 + $ yamlcat --json scalar_double_quote.yml 90 82 {"text": "She said \"hello\""} 91 83 92 84 Double-quoted with multiple escape sequences ··· 98 90 99 91 Empty double-quoted string 100 92 101 - $ echo 'empty: ""' | yamlcat 93 + $ yamlcat scalar_double_empty.yml 102 94 empty: '' 103 95 104 96 ================================================================================ ··· 107 99 108 100 Basic literal block scalar (preserves newlines) 109 101 110 - $ echo 'text: | 111 - > line one 112 - > line two 113 - > line three' | yamlcat --json 102 + $ yamlcat --json scalar_literal_basic.yml 114 103 {"text": "line one\nline two\nline three\n"} 115 104 116 105 Literal with indentation 117 106 118 - $ echo 'text: | 119 - > First line 120 - > Indented line 121 - > Back to first' | yamlcat --json 107 + $ yamlcat --json scalar_literal_indent.yml 122 108 {"text": "First line\n Indented line\nBack to first\n"} 123 109 124 110 Literal with blank lines 125 111 126 - $ echo 'text: | 127 - > First paragraph 128 - > 129 - > Second paragraph' | yamlcat --json 112 + $ yamlcat --json scalar_literal_blank.yml 130 113 {"text": "First paragraph\n\nSecond paragraph\n"} 131 114 132 115 ================================================================================ ··· 135 118 136 119 Basic folded block scalar (newlines become spaces) 137 120 138 - $ echo 'text: > 139 - > This is a long paragraph 140 - > that will be folded into 141 - > a single line.' | yamlcat --json 121 + $ yamlcat --json scalar_folded_basic.yml 142 122 {"text": "This is a long paragraph that will be folded into a single line.\n"} 143 123 144 124 Folded with paragraph separation (blank line preserved) 145 125 146 - $ echo 'text: > 147 - > First paragraph 148 - > flows together. 149 - > 150 - > Second paragraph 151 - > also flows.' | yamlcat --json 126 + $ yamlcat --json scalar_folded_para.yml 152 127 {"text": "First paragraph flows together.\nSecond paragraph also flows.\n"} 153 128 154 129 ================================================================================ ··· 157 132 158 133 Strip chomping (-) removes trailing newlines 159 134 160 - $ echo 'text: |- 161 - > No trailing newline' | yamlcat --json 135 + $ yamlcat --json scalar_strip_simple.yml 162 136 {"text": "No trailing newline"} 163 137 164 - $ echo 'text: |- 165 - > Text here 166 - > 167 - > ' | yamlcat --json 138 + $ yamlcat --json scalar_strip_blank.yml 168 139 {"text": "Text here"} 169 140 170 141 Folded with strip 171 142 172 - $ echo 'text: >- 173 - > Folded text 174 - > with stripped 175 - > trailing newlines 176 - > 177 - > ' | yamlcat --json 143 + $ yamlcat --json scalar_folded_strip.yml 178 144 {"text": "Folded text with stripped trailing newlines"} 179 145 180 146 Clip chomping (default) keeps single trailing newline 181 147 182 - $ echo 'text: | 183 - > One trailing newline 184 - > 185 - > ' | yamlcat --json 148 + $ yamlcat --json scalar_clip_literal.yml 186 149 {"text": "One trailing newline\n"} 187 150 188 - $ echo 'text: > 189 - > Folded with one 190 - > trailing newline 191 - > 192 - > ' | yamlcat --json 151 + $ yamlcat --json scalar_clip_folded.yml 193 152 {"text": "Folded with one trailing newline\n"} 194 153 195 154 Keep chomping (+) preserves all trailing newlines 196 155 197 - $ echo 'text: |+ 198 - > Keeps trailing newlines 199 - > 200 - > 201 - > ' | yamlcat --json 156 + $ yamlcat --json scalar_keep_literal.yml 202 157 {"text": "Keeps trailing newlines\n\n\n\n"} 203 158 204 - $ echo 'text: >+ 205 - > Folded text 206 - > keeps trailing 207 - > 208 - > 209 - > ' | yamlcat --json 159 + $ yamlcat --json scalar_keep_folded.yml 210 160 {"text": "Folded text keeps trailing\n\n\n\n"} 211 161 212 162 ================================================================================ ··· 215 165 216 166 Literal with explicit 2-space indentation 217 167 218 - $ echo 'text: |2 219 - > Two space base 220 - > Second line 221 - > Extra indent' | yamlcat --json 168 + $ yamlcat --json scalar_indent2_literal.yml 222 169 {"text": " Two space base\n Second line\n Extra indent\n"} 223 170 224 171 Folded with explicit indentation 225 172 226 - $ echo 'text: >2 227 - > Text with two space 228 - > base indentation that 229 - > will be folded.' | yamlcat --json 173 + $ yamlcat --json scalar_indent2_folded.yml 230 174 {"text": " Text with two space\n base indentation that\n will be folded.\n"} 231 175 232 176 Combined indentation and chomping indicators 233 177 234 - $ echo 'text: |2- 235 - > Indented by 2 236 - > No trailing newlines 237 - > 238 - > ' | yamlcat --json 178 + $ yamlcat --json scalar_indent2_strip.yml 239 179 {"text": " Indented by 2\n No trailing newlines"} 240 180 241 - $ echo 'text: |2+ 242 - > Indented by 2 243 - > Keeps trailing newlines 244 - > 245 - > 246 - > ' | yamlcat --json 181 + $ yamlcat --json scalar_indent2_keep.yml 247 182 {"text": " Indented by 2\n Keeps trailing newlines\n\n\n\n"} 248 183 249 184 ================================================================================ ··· 398 333 399 334 Empty block scalars 400 335 401 - $ echo 'empty_literal: |' | yamlcat --json 336 + $ yamlcat --json scalar_empty_literal.yml 402 337 {"empty_literal": ""} 403 338 404 - $ echo 'empty_folded: >' | yamlcat --json 339 + $ yamlcat --json scalar_empty_folded.yml 405 340 {"empty_folded": ""} 406 341 407 342 Block scalars with special characters (no escaping needed) 408 343 409 - $ echo 'code: | 410 - > Special: @#$%^&*() 411 - > Quotes: "double" '"'"'single'"'"' 412 - > Brackets: [array] {object}' | yamlcat --json 413 - {"code": "Special: @#$%^&*()\nQuotes: \"double\" 'single'\nBrackets: [array] {object}\n"} 344 + $ yamlcat --json scalar_special_chars.yml 345 + {"code": "Special: @#$%^&*()\nSymbols: <>?/\\|\nBrackets: []{}\n"} 414 346 415 347 Plain scalar vs quoted string for special values 416 348 417 - $ echo 'unquoted_true: true 418 - > quoted_true: "true"' | yamlcat --json 349 + $ yamlcat --json scalar_bool_vs_string.yml 419 350 {"unquoted_true": true, "quoted_true": "true"} 420 351 421 - $ echo 'unquoted_null: null 422 - > quoted_null: "null"' | yamlcat --json 352 + $ yamlcat --json scalar_null_vs_string.yml 423 353 {"unquoted_null": null, "quoted_null": "null"} 424 354 425 355 Strings that need quoting to preserve leading/trailing spaces 426 356 427 - $ echo 'leading: " spaces" 428 - > trailing: "spaces " 429 - > both: " spaces "' | yamlcat --json 430 - {"leading": " spaces", "trailing": "spaces ", "both": " spaces "} 357 + $ yamlcat --json scalar_whitespace.yml 358 + {"leading": " spaces", "trailing": "spaces ", "both": " both "} 431 359 432 360 Block scalars in sequences 433 361 434 - $ echo 'items: 435 - > - | 436 - > First item 437 - > multiline 438 - > - > 439 - > Second item 440 - > folded' | yamlcat --json 362 + $ yamlcat --json scalar_seq_blocks.yml 441 363 {"items": ["First item\nmultiline\n", "Second item folded\n"]} 442 364 443 365 Block scalars in nested mappings 444 366 445 - $ echo 'outer: 446 - > inner: 447 - > description: > 448 - > This is a folded 449 - > description. 450 - > code: | 451 - > def test(): 452 - > return True' | yamlcat --json 367 + $ yamlcat --json scalar_nested_blocks.yml 453 368 {"outer": {"inner": {"description": "This is a folded description.\n", "code": "def test():\n return True\n"}}} 454 369 455 370 Preserving indentation in literal blocks 456 371 457 - $ echo 'code: | 458 - > def hello(): 459 - > print("Hello") 460 - > if True: 461 - > return 42' | yamlcat --json 372 + $ yamlcat --json scalar_code_sample.yml 462 373 {"code": "def hello():\n print(\"Hello\")\n if True:\n return 42\n"} 463 374 464 375 Folded scalars preserve more-indented lines 465 376 466 - $ echo 'text: > 467 - > Normal paragraph 468 - > continues here. 469 - > 470 - > Indented block 471 - > preserved. 472 - > 473 - > Back to normal.' | yamlcat --json 377 + $ yamlcat --json scalar_folded_indent_preserve.yml 474 378 {"text": "Normal paragraph continues here.\n\n Indented block\n preserved.\n\nBack to normal.\n"}
+1
tests/cram/tab_columns.yml
··· 1 + text: "Col1\tCol2\tCol3"