github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/gen/includes/for-loop-json-tips.inc.md (about) 1 ### Tips when writing JSON inside for loops 2 3 One of the drawbacks (or maybe advantages, depending on your perspective) of 4 JSON is that parsers generally expect a complete file for processing in that 5 the JSON specification requires closing tags for every opening tag. This means 6 it's not always suitable for streaming. For example 7 8 ``` 9 » ja [1..3] -> foreach i { out ({ "$i": $i }) } 10 { "1": 1 } 11 { "2": 2 } 12 { "3": 3 } 13 ``` 14 15 **What does this even mean and how can you build a JSON file up sequentially?** 16 17 One answer if to write the output in a streaming file format and convert back 18 to JSON 19 20 ``` 21 » ja [1..3] -> foreach i { out (- "$i": $i) } 22 - "1": 1 23 - "2": 2 24 - "3": 3 25 26 » ja [1..3] -> foreach i { out (- "$i": $i) } -> cast yaml -> format json 27 [ 28 { 29 "1": 1 30 }, 31 { 32 "2": 2 33 }, 34 { 35 "3": 3 36 } 37 ] 38 ``` 39 40 **What if I'm returning an object rather than writing one?** 41 42 The problem with building JSON structures from existing structures is that you 43 can quickly end up with invalid JSON due to the specifications strict use of 44 commas. 45 46 For example in the code below, each item block is it's own object and there are 47 no `[ ... ]` encapsulating them to denote it is an array of objects, nor are 48 the objects terminated by a comma. 49 50 ``` 51 » config -> [ shell ] -> formap k v { $v -> alter /Foo Bar } 52 { 53 "Data-Type": "bool", 54 "Default": true, 55 "Description": "Display the interactive shell's hint text helper. Please note, even when this is disabled, it will still appear when used for regexp searches and other readline-specific functions", 56 "Dynamic": false, 57 "Foo": "Bar", 58 "Global": true, 59 "Value": true 60 } 61 { 62 "Data-Type": "block", 63 "Default": "{ progress $PID }", 64 "Description": "Murex function to execute when an `exec` process is stopped", 65 "Dynamic": false, 66 "Foo": "Bar", 67 "Global": true, 68 "Value": "{ progress $PID }" 69 } 70 { 71 "Data-Type": "bool", 72 "Default": true, 73 "Description": "ANSI escape sequences in Murex builtins to highlight syntax errors, history completions, {SGR} variables, etc", 74 "Dynamic": false, 75 "Foo": "Bar", 76 "Global": true, 77 "Value": true 78 } 79 ... 80 ``` 81 82 Luckily JSON also has it's own streaming format: JSON lines (`jsonl`). We can 83 `cast` this output as `jsonl` then `format` it back into valid JSON: 84 85 ``` 86 » config -> [ shell ] -> formap k v { $v -> alter /Foo Bar } -> cast jsonl -> format json 87 [ 88 { 89 "Data-Type": "bool", 90 "Default": true, 91 "Description": "Write shell history (interactive shell) to disk", 92 "Dynamic": false, 93 "Foo": "Bar", 94 "Global": true, 95 "Value": true 96 }, 97 { 98 "Data-Type": "int", 99 "Default": 4, 100 "Description": "Maximum number of lines with auto-completion suggestions to display", 101 "Dynamic": false, 102 "Foo": "Bar", 103 "Global": true, 104 "Value": "6" 105 }, 106 { 107 "Data-Type": "bool", 108 "Default": true, 109 "Description": "Display some status information about the stop process when ctrl+z is pressed (conceptually similar to ctrl+t / SIGINFO on some BSDs)", 110 "Dynamic": false, 111 "Foo": "Bar", 112 "Global": true, 113 "Value": true 114 }, 115 ... 116 ``` 117 118 #### `foreach` will automatically cast it's output as `jsonl` _if_ it's STDIN type is `json` 119 120 ``` 121 » ja [Tom,Dick,Sally] -> foreach name { out Hello $name } 122 Hello Tom 123 Hello Dick 124 Hello Sally 125 126 » ja [Tom,Dick,Sally] -> foreach name { out Hello $name } -> debug -> [[ /Data-Type/Murex ]] 127 jsonl 128 129 » ja [Tom,Dick,Sally] -> foreach name { out Hello $name } -> format json 130 [ 131 "Hello Tom", 132 "Hello Dick", 133 "Hello Sally" 134 ] 135 ```