libyay 1.0.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.
Files changed (3) hide show
  1. package/README.md +868 -0
  2. package/package.json +23 -0
  3. package/yay.js +2113 -0
package/README.md ADDED
@@ -0,0 +1,868 @@
1
+ # libyay
2
+
3
+ A parser for the [YAY](https://github.com/kriskowal/yay) data format, implemented in JavaScript (ES2024+).
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 22+ (for `Uint8Array.fromHex`)
8
+ - Or any JavaScript runtime with ES2024 support
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install libyay
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```js
19
+ import { parseYay } from 'libyay';
20
+
21
+ // Parse a YAY document
22
+ const result = parseYay('key: "value"');
23
+ // => { key: "value" }
24
+
25
+ // Parse with filename for error messages
26
+ const data = parseYay(source, 'config.yay');
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### `parseYay(source, filename?)`
32
+
33
+ Parses a YAY document string and returns the corresponding JavaScript value.
34
+
35
+ **Parameters:**
36
+
37
+ - `source` - A string containing the YAY document (UTF-8)
38
+ - `filename` - Optional filename for error messages
39
+
40
+ **Returns:** A JavaScript value representing the parsed document.
41
+
42
+ **Throws:** `Error` with line:column location if parsing fails.
43
+
44
+ ## Type Mapping
45
+
46
+ | YAY Type | JavaScript Type |
47
+ |----------|-----------------|
48
+ | `null` | `null` |
49
+ | big integer | `bigint` |
50
+ | float64 | `number` |
51
+ | boolean | `boolean` |
52
+ | string | `string` |
53
+ | array | `Array` |
54
+ | object | `Object` |
55
+ | bytes | `Uint8Array` |
56
+
57
+ # YAY Format
58
+
59
+ ## Null
60
+
61
+ The keyword `null` denotes a null value.
62
+
63
+ [null-literal.yay](https://github.com/kriskowal/yay/blob/main/test/yay/null-literal.yay)
64
+ ```yay
65
+ null
66
+ ```
67
+
68
+ [null-literal.js](https://github.com/kriskowal/yay/blob/main/test/js/null-literal.js)
69
+ ```js
70
+ null
71
+ ```
72
+
73
+ ## Booleans
74
+
75
+ The literals `true` and `false` denote booleans.
76
+
77
+ A true boolean value.
78
+
79
+ [boolean-true.yay](https://github.com/kriskowal/yay/blob/main/test/yay/boolean-true.yay)
80
+ ```yay
81
+ true
82
+ ```
83
+
84
+ [boolean-true.js](https://github.com/kriskowal/yay/blob/main/test/js/boolean-true.js)
85
+ ```js
86
+ true
87
+ ```
88
+
89
+ A false boolean value.
90
+
91
+ [boolean-false.yay](https://github.com/kriskowal/yay/blob/main/test/yay/boolean-false.yay)
92
+ ```yay
93
+ false
94
+ ```
95
+
96
+ [boolean-false.js](https://github.com/kriskowal/yay/blob/main/test/js/boolean-false.js)
97
+ ```js
98
+ false
99
+ ```
100
+
101
+ ## Big Integers
102
+
103
+ Unquoted decimal digit sequences are big integers (arbitrary precision).
104
+ A leading minus sign denotes a negative big integer; the minus must not be followed by a space.
105
+ Spaces may be used to group digits for readability; they do not change the value.
106
+
107
+ A basic positive integer.
108
+
109
+ [integer-big-basic.yay](https://github.com/kriskowal/yay/blob/main/test/yay/integer-big-basic.yay)
110
+ ```yay
111
+ 42
112
+ ```
113
+
114
+ [integer-big-basic.js](https://github.com/kriskowal/yay/blob/main/test/js/integer-big-basic.js)
115
+ ```js
116
+ 42n
117
+ ```
118
+
119
+ A negative integer.
120
+
121
+ [integer-big-negative.yay](https://github.com/kriskowal/yay/blob/main/test/yay/integer-big-negative.yay)
122
+ ```yay
123
+ -42
124
+ ```
125
+
126
+ [integer-big-negative.js](https://github.com/kriskowal/yay/blob/main/test/js/integer-big-negative.js)
127
+ ```js
128
+ -42n
129
+ ```
130
+
131
+ Spaces group digits for readability without changing the value.
132
+
133
+ [integer-big.yay](https://github.com/kriskowal/yay/blob/main/test/yay/integer-big.yay)
134
+ ```yay
135
+ 867 5309
136
+ ```
137
+
138
+ [integer-big.js](https://github.com/kriskowal/yay/blob/main/test/js/integer-big.js)
139
+ ```js
140
+ 8675309n
141
+ ```
142
+
143
+ ## Floating-Point (Float64)
144
+
145
+ A decimal point must be present to distinguish a float from a big integer.
146
+ Decimal literals with a decimal point, or the keywords `infinity`, `-infinity`, and `nan`, denote 64-bit floats.
147
+ A leading minus must not be followed by a space.
148
+ Spaces may group digits.
149
+
150
+ A basic floating-point number.
151
+
152
+ [number-float.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float.yay)
153
+ ```yay
154
+ 6.283185307179586
155
+ ```
156
+
157
+ [number-float.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float.js)
158
+ ```js
159
+ 6.283185307179586
160
+ ```
161
+
162
+ A float with a leading decimal point (no integer part).
163
+
164
+ [number-float-leading-dot.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-leading-dot.yay)
165
+ ```yay
166
+ .5
167
+ ```
168
+
169
+ [number-float-leading-dot.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-leading-dot.js)
170
+ ```js
171
+ 0.5
172
+ ```
173
+
174
+ A float with a trailing decimal point (no fractional part).
175
+
176
+ [number-float-trailing-dot.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-trailing-dot.yay)
177
+ ```yay
178
+ 1.
179
+ ```
180
+
181
+ [number-float-trailing-dot.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-trailing-dot.js)
182
+ ```js
183
+ 1
184
+ ```
185
+
186
+ Negative zero is distinct from positive zero.
187
+
188
+ [number-float-negative-zero.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-negative-zero.yay)
189
+ ```yay
190
+ -0.0
191
+ ```
192
+
193
+ [number-float-negative-zero.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-negative-zero.js)
194
+ ```js
195
+ -0
196
+ ```
197
+
198
+ Positive infinity.
199
+
200
+ [number-float-infinity.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-infinity.yay)
201
+ ```yay
202
+ infinity
203
+ ```
204
+
205
+ [number-float-infinity.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-infinity.js)
206
+ ```js
207
+ Infinity
208
+ ```
209
+
210
+ Negative infinity.
211
+
212
+ [number-float-negative-infinity.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-negative-infinity.yay)
213
+ ```yay
214
+ -infinity
215
+ ```
216
+
217
+ [number-float-negative-infinity.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-negative-infinity.js)
218
+ ```js
219
+ -Infinity
220
+ ```
221
+
222
+ Not-a-number (canonical NaN).
223
+
224
+ [number-float-nan.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-nan.yay)
225
+ ```yay
226
+ nan
227
+ ```
228
+
229
+ [number-float-nan.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-nan.js)
230
+ ```js
231
+ NaN
232
+ ```
233
+
234
+ Spaces group digits for readability in floats.
235
+
236
+ [number-float-grouped.yay](https://github.com/kriskowal/yay/blob/main/test/yay/number-float-grouped.yay)
237
+ ```yay
238
+ 6.283 185 307 179 586
239
+ ```
240
+
241
+ [number-float-grouped.js](https://github.com/kriskowal/yay/blob/main/test/js/number-float-grouped.js)
242
+ ```js
243
+ 6.283185307179586
244
+ ```
245
+
246
+ ## Block Strings
247
+
248
+ Block strings use the backtick (`` ` ``) introducer.
249
+ The body continues until the next line that is indented the same or less.
250
+ The first two spaces of each content line are stripped; any further indentation is preserved.
251
+ Empty lines are interpreted as newlines.
252
+ Trailing empty lines collapse to a single trailing newline.
253
+ Block strings do not support escape sequences—a backslash is just a backslash.
254
+ Comments are also not recognized inside block strings; `#` is literal content.
255
+
256
+ ### At Root Level
257
+
258
+ At root level or as an array item, content may appear on the same line after `` ` `` (backtick + space + content).
259
+ When the backtick is alone on a line, the result has an implicit leading newline.
260
+
261
+ Content on the same line as the backtick starts the string without a leading newline.
262
+
263
+ [string-block-root-same-line.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-root-same-line.yay)
264
+ ```yay
265
+ ` I think you ought to know I'm feeling very depressed.
266
+ This will all end in tears.
267
+ ```
268
+
269
+ [string-block-root-same-line.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-root-same-line.js)
270
+ ```js
271
+ "I think you ought to know I'm feeling very depressed.\nThis will all end in tears.\n"
272
+ ```
273
+
274
+ Backtick alone on its line produces a leading newline because content starts on the following line.
275
+
276
+ [string-block-root-next-line.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-root-next-line.yay)
277
+ ```yay
278
+ `
279
+ I've calculated your chance of survival,
280
+ but I don't think you'll like it.
281
+ ```
282
+
283
+ [string-block-root-next-line.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-root-next-line.js)
284
+ ```js
285
+ "\nI've calculated your chance of survival,\nbut I don't think you'll like it.\n"
286
+ ```
287
+
288
+ An empty line in the middle of a block string is preserved as a newline.
289
+
290
+ [string-block-empty-middle.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-empty-middle.yay)
291
+ ```yay
292
+ `
293
+ I'm getting better!
294
+
295
+ No you're not.
296
+ ```
297
+
298
+ [string-block-empty-middle.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-empty-middle.js)
299
+ ```js
300
+ "\nI'm getting better!\n\nNo you're not.\n"
301
+ ```
302
+
303
+ The `#` character inside a block string is literal content, not a comment.
304
+
305
+ [string-block-root-hash.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-root-hash.yay)
306
+ ```yay
307
+ ` # this is not a comment
308
+ it is content
309
+ ```
310
+
311
+ [string-block-root-hash.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-root-hash.js)
312
+ ```js
313
+ "# this is not a comment\nit is content\n"
314
+ ```
315
+
316
+ A block string may be deeply nested and the indentation prefix will be absent
317
+ in the value.
318
+ The string will end with a single newline regardless of any subsequent newlines
319
+ in the YAY text.
320
+
321
+ [string-block-nested-in-object-and-array.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-nested-in-object-and-array.yay)
322
+ ```yay
323
+ parrot:
324
+ condition: `
325
+ No, no, it's just resting!
326
+
327
+ remarks:
328
+ - ` Remarkable bird, the Norwegian Blue.
329
+ Beautiful plumage, innit?
330
+
331
+ - ` It's probably pining for the fjords.
332
+ Lovely plumage.
333
+ ```
334
+
335
+ [string-block-nested-in-object-and-array.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-nested-in-object-and-array.js)
336
+ ```js
337
+ ({
338
+ "parrot": {
339
+ "condition": "No, no, it's just resting!\n",
340
+ "remarks": [
341
+ "Remarkable bird, the Norwegian Blue.\nBeautiful plumage, innit?\n",
342
+ "It's probably pining for the fjords.\nLovely plumage.\n",
343
+ ],
344
+ },
345
+ })
346
+ ```
347
+
348
+ ### As Object Property
349
+
350
+ In property context, the backtick must be alone on the line (no content after it).
351
+ There is no implicit leading newline.
352
+ The first content line becomes the start of the string.
353
+
354
+ [string-block-property.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-property.yay)
355
+ ```yay
356
+ message: `
357
+ By Grabthar's hammer, we live to tell the tale.
358
+ ```
359
+
360
+ [string-block-property.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-property.js)
361
+ ```js
362
+ ({
363
+ "message": "By Grabthar's hammer, we live to tell the tale.\n",
364
+ })
365
+ ```
366
+
367
+ An empty line in the middle of a block string property is preserved.
368
+
369
+ [string-block-property-empty-middle.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-property-empty-middle.yay)
370
+ ```yay
371
+ message: `
372
+ It's not pining!
373
+
374
+ It's passed on! This parrot is no more!
375
+ ```
376
+
377
+ [string-block-property-empty-middle.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-property-empty-middle.js)
378
+ ```js
379
+ ({
380
+ "message": "It's not pining!\n\nIt's passed on! This parrot is no more!\n",
381
+ })
382
+ ```
383
+
384
+ A block string property followed by another property: the block ends when a line at the same or lesser indent appears.
385
+ Trailing empty lines collapse to a single trailing newline.
386
+
387
+ [string-block-property-trailing-empty.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-block-property-trailing-empty.yay)
388
+ ```yay
389
+ message: `
390
+ By Grabthar's hammer... what a savings.
391
+
392
+
393
+ next: 1
394
+ ```
395
+
396
+ [string-block-property-trailing-empty.js](https://github.com/kriskowal/yay/blob/main/test/js/string-block-property-trailing-empty.js)
397
+ ```js
398
+ ({
399
+ "message": "By Grabthar's hammer... what a savings.\n",
400
+ "next": 1n,
401
+ })
402
+ ```
403
+
404
+ ## Inline Strings
405
+
406
+ Strings may be quoted with double or single quotes.
407
+ Double-quoted strings support escape sequences: `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, `\t`, and `\u{XXXXXX}` for Unicode code points.
408
+ Single-quoted strings are literal (no escape sequences).
409
+
410
+ A double-quoted string.
411
+
412
+ [string-inline-doublequote-basic.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-inline-doublequote-basic.yay)
413
+ ```yay
414
+ "This will all end in tears."
415
+ ```
416
+
417
+ [string-inline-doublequote-basic.js](https://github.com/kriskowal/yay/blob/main/test/js/string-inline-doublequote-basic.js)
418
+ ```js
419
+ "This will all end in tears."
420
+ ```
421
+
422
+ A single-quoted string (literal, no escapes).
423
+
424
+ [string-inline-singlequote-basic.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-inline-singlequote-basic.yay)
425
+ ```yay
426
+ 'Are you suggesting coconuts migrate?'
427
+ ```
428
+
429
+ [string-inline-singlequote-basic.js](https://github.com/kriskowal/yay/blob/main/test/js/string-inline-singlequote-basic.js)
430
+ ```js
431
+ "Are you suggesting coconuts migrate?"
432
+ ```
433
+
434
+ A double-quoted string with escape sequences.
435
+
436
+ [string-inline-doublequote-escapes.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-inline-doublequote-escapes.yay)
437
+ ```yay
438
+ "\"\\\/\b\f\n\r\t\u{263A}"
439
+ ```
440
+
441
+ [string-inline-doublequote-escapes.js](https://github.com/kriskowal/yay/blob/main/test/js/string-inline-doublequote-escapes.js)
442
+ ```js
443
+ '"\\/\b\f\n\r\t☺'
444
+ ```
445
+
446
+ A double-quoted string with a Unicode emoji (literal UTF-8).
447
+
448
+ [string-inline-doublequote-unicode-emoji.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-inline-doublequote-unicode-emoji.yay)
449
+ ```yay
450
+ "😀"
451
+ ```
452
+
453
+ [string-inline-doublequote-unicode-emoji.js](https://github.com/kriskowal/yay/blob/main/test/js/string-inline-doublequote-unicode-emoji.js)
454
+ ```js
455
+ "😀"
456
+ ```
457
+
458
+ A Unicode code point escape for a character outside the BMP (U+1F600), which requires a surrogate pair in UTF-16.
459
+ The `\u{...}` escape accepts 1 to 6 hexadecimal digits representing a Unicode code point (e.g. `\u{41}` for "A", `\u{1F600}` for "😀").
460
+ Surrogate code points (U+D800 through U+DFFF) are forbidden in `\u{...}` escapes.
461
+ Unlike JSON, the four-digit `\uXXXX` form is not supported; use `\u{XXXX}` instead.
462
+
463
+ [string-inline-doublequote-unicode-surrogate-pair.yay](https://github.com/kriskowal/yay/blob/main/test/yay/string-inline-doublequote-unicode-surrogate-pair.yay)
464
+ ```yay
465
+ "\u{1F600}"
466
+ ```
467
+
468
+ [string-inline-doublequote-unicode-surrogate-pair.js](https://github.com/kriskowal/yay/blob/main/test/js/string-inline-doublequote-unicode-surrogate-pair.js)
469
+ ```js
470
+ "😀"
471
+ ```
472
+
473
+ ## Block Arrays
474
+
475
+ Arrays are written as a sequence of items, each introduced by `- ` (dash and space).
476
+ The two-character `- ` prefix is the list marker; the value follows immediately.
477
+ Items may be nested: a bullet line whose content starts with `- ` begins an inner list.
478
+ An array may be given a name as a key followed by `:`.
479
+
480
+ A basic block array with three integer items.
481
+
482
+ [array-multiline.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-multiline.yay)
483
+ ```yay
484
+ - 5
485
+ - 3
486
+ ```
487
+
488
+ [array-multiline.js](https://github.com/kriskowal/yay/blob/main/test/js/array-multiline.js)
489
+ ```js
490
+ [5n, 3n]
491
+ ```
492
+
493
+ Nested arrays where each top-level item contains an inner array.
494
+
495
+ [array-multiline-nested.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-multiline-nested.yay)
496
+ ```yay
497
+ - - "a"
498
+ - "b"
499
+ - - 1
500
+ - 2
501
+ ```
502
+
503
+ [array-multiline-nested.js](https://github.com/kriskowal/yay/blob/main/test/js/array-multiline-nested.js)
504
+ ```js
505
+ [["a", "b"], [1n, 2n]]
506
+ ```
507
+
508
+ An array as the value of an object property.
509
+
510
+ [array-multiline-named.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-multiline-named.yay)
511
+ ```yay
512
+ complaints:
513
+ - "I didn't vote for you."
514
+ - "Help, help, I'm being repressed!"
515
+ ```
516
+
517
+ [array-multiline-named.js](https://github.com/kriskowal/yay/blob/main/test/js/array-multiline-named.js)
518
+ ```js
519
+ ({
520
+ "complaints": [
521
+ "I didn't vote for you.",
522
+ "Help, help, I'm being repressed!",
523
+ ],
524
+ })
525
+ ```
526
+
527
+ ## Inline Arrays
528
+
529
+ Inline arrays use JSON-style bracket syntax with strict spacing rules: no space after `[`, no space before `]`, exactly one space after each `,`.
530
+
531
+ A simple inline array with string values.
532
+
533
+ [array-inline-doublequote.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-inline-doublequote.yay)
534
+ ```yay
535
+ ["And there was much rejoicing.", "yay."]
536
+ ```
537
+
538
+ [array-inline-doublequote.js](https://github.com/kriskowal/yay/blob/main/test/js/array-inline-doublequote.js)
539
+ ```js
540
+ ["And there was much rejoicing.", "yay."]
541
+ ```
542
+
543
+ An inline array containing big integers.
544
+
545
+ [array-inline-integers.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-inline-integers.yay)
546
+ ```yay
547
+ [42, 404, 418]
548
+ ```
549
+
550
+ [array-inline-integers.js](https://github.com/kriskowal/yay/blob/main/test/js/array-inline-integers.js)
551
+ ```js
552
+ [42n, 404n, 418n]
553
+ ```
554
+
555
+ An inline array containing byte array literals.
556
+
557
+ [array-inline-bytearray.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-inline-bytearray.yay)
558
+ ```yay
559
+ [<b0b5>, <cafe>]
560
+ ```
561
+
562
+ [array-inline-bytearray.js](https://github.com/kriskowal/yay/blob/main/test/js/array-inline-bytearray.js)
563
+ ```js
564
+ [
565
+ Uint8Array.from([0xb0, 0xb5]),
566
+ Uint8Array.from([0xca, 0xfe]),
567
+ ]
568
+ ```
569
+
570
+ Inline arrays nested within an inline array.
571
+
572
+ [array-inline-nested.yay](https://github.com/kriskowal/yay/blob/main/test/yay/array-inline-nested.yay)
573
+ ```yay
574
+ [["I feel happy!", "yay."], ["And there was much rejoicing.", "yay."]]
575
+ ```
576
+
577
+ [array-inline-nested.js](https://github.com/kriskowal/yay/blob/main/test/js/array-inline-nested.js)
578
+ ```js
579
+ [
580
+ ["I feel happy!", "yay."],
581
+ ["And there was much rejoicing.", "yay."],
582
+ ]
583
+ ```
584
+
585
+ ## Block Objects
586
+
587
+ Objects are key–value pairs.
588
+ A key is followed by `:` and then the value.
589
+ Object keys must be either alphanumeric (letters and digits) or quoted (double or single quotes, same rules as string values).
590
+ Nested objects are indented by two spaces.
591
+ Empty objects are written as `key: {}`.
592
+
593
+ A simple object with two key-value pairs at the root level.
594
+
595
+ [object-multiline.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-multiline.yay)
596
+ ```yay
597
+ answer: 42
598
+ error: 404
599
+ ```
600
+
601
+ [object-multiline.js](https://github.com/kriskowal/yay/blob/main/test/js/object-multiline.js)
602
+ ```js
603
+ ({ "answer": 42n, "error": 404n })
604
+ ```
605
+
606
+ An object nested within another object, demonstrating indentation.
607
+
608
+ [object-multiline-nested.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-multiline-nested.yay)
609
+ ```yay
610
+ parrot:
611
+ status: "pining for the fjords"
612
+ plumage: "beautiful"
613
+ ```
614
+
615
+ [object-multiline-nested.js](https://github.com/kriskowal/yay/blob/main/test/js/object-multiline-nested.js)
616
+ ```js
617
+ ({
618
+ "parrot": { "plumage": "beautiful", "status": "pining for the fjords" },
619
+ })
620
+ ```
621
+
622
+ Object keys containing spaces or special characters must be quoted.
623
+
624
+ [object-multiline-doublequote-key.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-multiline-doublequote-key.yay)
625
+ ```yay
626
+ "key name": 1
627
+ ```
628
+
629
+ [object-multiline-doublequote-key.js](https://github.com/kriskowal/yay/blob/main/test/js/object-multiline-doublequote-key.js)
630
+ ```js
631
+ ({ "key name": 1n })
632
+ ```
633
+
634
+ An empty object as a property value.
635
+
636
+ [object-inline-empty.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-inline-empty.yay)
637
+ ```yay
638
+ empty: {}
639
+ ```
640
+
641
+ [object-inline-empty.js](https://github.com/kriskowal/yay/blob/main/test/js/object-inline-empty.js)
642
+ ```js
643
+ ({ "empty": {} })
644
+ ```
645
+
646
+ ## Inline Objects
647
+
648
+ Inline objects use JSON-style brace syntax with strict spacing rules: no space after `{`, no space before `}`, exactly one space after each `,`.
649
+
650
+ A simple inline object with integer values.
651
+
652
+ [object-inline-integers.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-inline-integers.yay)
653
+ ```yay
654
+ {answer: 42, error: 404}
655
+ ```
656
+
657
+ [object-inline-integers.js](https://github.com/kriskowal/yay/blob/main/test/js/object-inline-integers.js)
658
+ ```js
659
+ ({ "answer": 42n, "error": 404n })
660
+ ```
661
+
662
+ An inline object with string and integer values.
663
+
664
+ [object-inline-mixed.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-inline-mixed.yay)
665
+ ```yay
666
+ {name: 'Marvin', mood: 'depressed'}
667
+ ```
668
+
669
+ [object-inline-mixed.js](https://github.com/kriskowal/yay/blob/main/test/js/object-inline-mixed.js)
670
+ ```js
671
+ ({ "mood": "depressed", "name": "Marvin" })
672
+ ```
673
+
674
+ An inline object containing both a nested object and an array.
675
+
676
+ [object-inline-nested.yay](https://github.com/kriskowal/yay/blob/main/test/yay/object-inline-nested.yay)
677
+ ```yay
678
+ {luggage: {combination: 12345}, air: ["canned", "Perri-Air"]}
679
+ ```
680
+
681
+ [object-inline-nested.js](https://github.com/kriskowal/yay/blob/main/test/js/object-inline-nested.js)
682
+ ```js
683
+ ({
684
+ "air": ["canned", "Perri-Air"],
685
+ "luggage": { "combination": 12345n },
686
+ })
687
+ ```
688
+
689
+ ## Block Byte Arrays
690
+
691
+ Block byte arrays use the `>` introducer (as opposed to `<...>` for inline).
692
+ Each line may hold hex chunks and comments (comments start with `#`).
693
+ Spaces within hex content are ignored.
694
+
695
+ ### At Root Level
696
+
697
+ At root level or as an array item, hex may appear on the same line after `> `.
698
+ The `> ` leader must have hex digits or a comment on the line—`>` alone is invalid.
699
+
700
+ A block byte array at root level with hex on the same line as the `>` introducer.
701
+
702
+ [bytearray-block-basic.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-block-basic.yay)
703
+ ```yay
704
+ > b0b5
705
+ c0ff
706
+ ```
707
+
708
+ [bytearray-block-basic.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-block-basic.js)
709
+ ```js
710
+ Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff])
711
+ ```
712
+
713
+ A block byte array with a comment on the first line instead of hex.
714
+
715
+ [bytearray-block-comment-only.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-block-comment-only.yay)
716
+ ```yay
717
+ > # header comment
718
+ b0b5 c0ff
719
+ ```
720
+
721
+ [bytearray-block-comment-only.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-block-comment-only.js)
722
+ ```js
723
+ Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff])
724
+ ```
725
+
726
+ Hex and comments on the same lines for inline documentation of byte sequences.
727
+
728
+ [bytearray-block-hex-and-comment.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-block-hex-and-comment.yay)
729
+ ```yay
730
+ > b0b5 # first chunk
731
+ c0ff # second chunk
732
+ ```
733
+
734
+ [bytearray-block-hex-and-comment.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-block-hex-and-comment.js)
735
+ ```js
736
+ Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff])
737
+ ```
738
+
739
+ ### As Object Property
740
+
741
+ In property context, the `>` must be alone on the line (optionally followed by a comment).
742
+ Hex content starts on the following lines, preserving column alignment.
743
+
744
+ [bytearray-block-property.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-block-property.yay)
745
+ ```yay
746
+ data: >
747
+ b0b5 c0ff
748
+ eefa cade
749
+ ```
750
+
751
+ [bytearray-block-property.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-block-property.js)
752
+ ```js
753
+ ({
754
+ "data": Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff, 0xee, 0xfa, 0xca, 0xde]),
755
+ })
756
+ ```
757
+
758
+ A block byte array property with a comment on the leader line.
759
+
760
+ [bytearray-block-property-comment.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-block-property-comment.yay)
761
+ ```yay
762
+ data: > # raw bytes
763
+ b0b5 c0ff
764
+ ```
765
+
766
+ [bytearray-block-property-comment.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-block-property-comment.js)
767
+ ```js
768
+ ({ "data": Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff]) })
769
+ ```
770
+
771
+ ## Inline Byte Arrays
772
+
773
+ Binary data is written as hexadecimal inside angle brackets.
774
+ Hexadecimal must be lowercase.
775
+ An odd number of hex digits is forbidden.
776
+ `<>` denotes an empty byte array.
777
+ Spaces inside the brackets are allowed for readability.
778
+
779
+ An empty byte array.
780
+
781
+ [bytearray-inline-empty.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-inline-empty.yay)
782
+ ```yay
783
+ <>
784
+ ```
785
+
786
+ [bytearray-inline-empty.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-inline-empty.js)
787
+ ```js
788
+ new Uint8Array(0)
789
+ ```
790
+
791
+ An inline byte array with hex content.
792
+
793
+ [bytearray-inline-even.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-inline-even.yay)
794
+ ```yay
795
+ <b0b5c0ffeefacade>
796
+ ```
797
+
798
+ [bytearray-inline-even.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-inline-even.js)
799
+ ```js
800
+ Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff, 0xee, 0xfa, 0xca, 0xde])
801
+ ```
802
+
803
+ An inline byte array as an object property value.
804
+
805
+ [bytearray-inline-named.yay](https://github.com/kriskowal/yay/blob/main/test/yay/bytearray-inline-named.yay)
806
+ ```yay
807
+ data: <b0b5c0ffeefacade>
808
+ ```
809
+
810
+ [bytearray-inline-named.js](https://github.com/kriskowal/yay/blob/main/test/js/bytearray-inline-named.js)
811
+ ```js
812
+ ({
813
+ "data": Uint8Array.from([0xb0, 0xb5, 0xc0, 0xff, 0xee, 0xfa, 0xca, 0xde]),
814
+ })
815
+ ```
816
+
817
+ ## Error Handling
818
+
819
+ Errors include line and column numbers for debugging:
820
+
821
+ ```js
822
+ try {
823
+ parseYay('invalid: [', 'config.yay');
824
+ } catch (e) {
825
+ console.error(e.message);
826
+ // "Unexpected newline in inline array at 1:11 of <config.yay>"
827
+ }
828
+ ```
829
+
830
+ ## Whitespace Rules
831
+
832
+ YAY has strict whitespace rules that the parser enforces:
833
+
834
+ - Two spaces for indentation (tabs are illegal)
835
+ - No trailing spaces on lines
836
+ - Exactly one space after `:` in key-value pairs
837
+ - Exactly one space after `,` in inline arrays/objects
838
+ - No spaces after `[` or `{`, or before `]` or `}`
839
+ - No space before `:` in keys
840
+
841
+ ## Running Tests
842
+
843
+ ```bash
844
+ cd js
845
+ node --test yay.test.js
846
+ ```
847
+
848
+ The test runner uses fixture files from `../test/`.
849
+ Files with `.yay` extension contain YAY input.
850
+ Files with `.js` extension contain expected JavaScript output.
851
+
852
+ ## References
853
+
854
+ Examples in this document pay homage to:
855
+
856
+ - The Hitchhiker's Guide to the Galaxy (Douglas Adams)
857
+ - Monty Python and the Holy Grail
858
+ - Monty Python's Flying Circus ("Dead Parrot" sketch)
859
+ - Galaxy Quest
860
+ - Spaceballs
861
+ - Tommy Tutone ("867-5309/Jenny")
862
+ - The Tau Manifesto
863
+
864
+ ## License
865
+
866
+ Apache 2.0
867
+
868
+ Copyright (C) 2026 Kris Kowal