@tabnas/yaml 0.5.11 → 0.5.13
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/dist/yaml.d.ts +1 -1
- package/dist/yaml.js +378 -37
- package/dist/yaml.js.map +1 -1
- package/package.json +3 -2
- package/src/yaml.ts +323 -31
package/dist/yaml.d.ts
CHANGED
package/dist/yaml.js
CHANGED
|
@@ -51,8 +51,11 @@ const grammarText = `
|
|
|
51
51
|
rule: indent: open: [
|
|
52
52
|
# Key pair => map.
|
|
53
53
|
{ s: ['#KEY' '#CL'] p: map b: 2 g: yaml }
|
|
54
|
-
# Element marker => list
|
|
55
|
-
|
|
54
|
+
# Element marker => block sequence. yamlBlockList, not jsonic's list:
|
|
55
|
+
# list reads a '[' as its own opening bracket, so a flow sequence as the
|
|
56
|
+
# first item (k:\\n - [1, 2]) became the block sequence itself, or
|
|
57
|
+
# failed at the next item (tabnas/yaml#88).
|
|
58
|
+
{ s: '#EL' p: yamlBlockList g: yaml }
|
|
56
59
|
# Flow collection as a block-mapping value on the FOLLOWING line:
|
|
57
60
|
# required:
|
|
58
61
|
# [a, b, c]
|
|
@@ -221,6 +224,35 @@ const grammarText = `
|
|
|
221
224
|
}
|
|
222
225
|
`;
|
|
223
226
|
// --- END EMBEDDED yaml-grammar.jsonic ---
|
|
227
|
+
// The characters updateFlowState acts on, by char code: quotes, the escape
|
|
228
|
+
// backslash, the comment mark, flow brackets, and block scalar indicators.
|
|
229
|
+
// Every other character leaves its state unchanged, so it is skipped with
|
|
230
|
+
// one table read.
|
|
231
|
+
const FLOW_SCAN_CHARS = new Uint8Array(126);
|
|
232
|
+
for (const c of '"\'\\#{}[]|>')
|
|
233
|
+
FLOW_SCAN_CHARS[c.charCodeAt(0)] = 1;
|
|
234
|
+
// The value a `!!int` tag gives its text: YAML's core-schema hex (0x1f)
|
|
235
|
+
// and octal (0o17) forms, then a decimal parse. A text no form reads
|
|
236
|
+
// stays NaN, as before: the tag applies even when its value does not.
|
|
237
|
+
function yamlTagInt(raw) {
|
|
238
|
+
let m = raw.match(/^([-+]?)0x([0-9a-fA-F]+)$/) || raw.match(/^([-+]?)0o([0-7]+)$/);
|
|
239
|
+
if (m) {
|
|
240
|
+
let n = parseInt(m[2], raw.includes('0x') ? 16 : 8);
|
|
241
|
+
return '-' === m[1] ? -n : n;
|
|
242
|
+
}
|
|
243
|
+
return parseInt(raw, 10);
|
|
244
|
+
}
|
|
245
|
+
// The value a `!!float` tag gives its text: the core schema's infinities
|
|
246
|
+
// and not-a-number (.inf, -.inf, +.inf, .nan in three casings), then a
|
|
247
|
+
// decimal parse.
|
|
248
|
+
function yamlTagFloat(raw) {
|
|
249
|
+
let m = raw.match(/^([-+]?)\.(inf|Inf|INF)$/);
|
|
250
|
+
if (m)
|
|
251
|
+
return '-' === m[1] ? -Infinity : Infinity;
|
|
252
|
+
if (/^\.(nan|NaN|NAN)$/.test(raw))
|
|
253
|
+
return NaN;
|
|
254
|
+
return parseFloat(raw);
|
|
255
|
+
}
|
|
224
256
|
const Yaml = (tabnas, options) => {
|
|
225
257
|
// Install once per instance: a second use(Yaml) on the same instance
|
|
226
258
|
// returns here. options() does not re-run plugins, and make() builds a
|
|
@@ -277,19 +309,38 @@ const Yaml = (tabnas, options) => {
|
|
|
277
309
|
// Incremental flow-depth cache for text.check (avoids O(n²) rescan).
|
|
278
310
|
let _flowDepth = 0;
|
|
279
311
|
let _flowScanPos = 0;
|
|
312
|
+
let _flowScanUpTo = 0;
|
|
280
313
|
// Persistent quote state so multi-call scans handle quotes spanning slices.
|
|
281
314
|
let _inSingleQuote = false;
|
|
282
315
|
let _inDoubleQuote = false;
|
|
283
316
|
// Bring _flowDepth up to date with `upTo` by scanning lex.src incrementally.
|
|
284
|
-
//
|
|
317
|
+
//
|
|
318
|
+
// The scan has to read the source the way the lexer does, or text is
|
|
319
|
+
// counted as syntax. A quoted region is skipped, and so are the regions
|
|
320
|
+
// where a bracket or a quote is ordinary text (tabnas/yaml#89):
|
|
321
|
+
// - a comment (`#` at the start of a line or after whitespace);
|
|
322
|
+
// - a block scalar's content lines (`|` / `>`);
|
|
323
|
+
// - in block context, any `{` `[` `"` `'` that does not begin a node:
|
|
324
|
+
// the `{` in `f({` or the `"` in `say "hi` is inside a plain scalar.
|
|
325
|
+
// Counting those left the depth above zero, so the rest of the document
|
|
326
|
+
// was read as flow (a `{` failed the parse), or left a quote open, so a
|
|
327
|
+
// later `[1, 2]` was read as the one string "1, 2]".
|
|
328
|
+
// The scan may run past `upTo` (to the end of a comment or a block
|
|
329
|
+
// scalar), since the lexer never stops inside either.
|
|
285
330
|
function updateFlowState(src, upTo) {
|
|
286
|
-
if (upTo <
|
|
331
|
+
if (upTo < _flowScanUpTo) {
|
|
287
332
|
_flowDepth = 0;
|
|
288
333
|
_flowScanPos = 0;
|
|
289
334
|
_inSingleQuote = false;
|
|
290
335
|
_inDoubleQuote = false;
|
|
291
336
|
}
|
|
292
|
-
|
|
337
|
+
_flowScanUpTo = upTo;
|
|
338
|
+
let fi = _flowScanPos;
|
|
339
|
+
for (; fi < upTo; fi++) {
|
|
340
|
+
// Fast path: only these ten characters matter in any state.
|
|
341
|
+
let cc = src.charCodeAt(fi);
|
|
342
|
+
if (cc > 125 || 0 === FLOW_SCAN_CHARS[cc])
|
|
343
|
+
continue;
|
|
293
344
|
let fc = src[fi];
|
|
294
345
|
if (_inDoubleQuote) {
|
|
295
346
|
if (fc === '\\')
|
|
@@ -307,23 +358,274 @@ const Yaml = (tabnas, options) => {
|
|
|
307
358
|
}
|
|
308
359
|
continue;
|
|
309
360
|
}
|
|
310
|
-
if (fc === '
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
_flowDepth--;
|
|
361
|
+
if (fc === '#' && (fi === 0 || isYamlSpace(src[fi - 1]))) {
|
|
362
|
+
while (fi + 1 < src.length && src[fi + 1] !== '\n' && src[fi + 1] !== '\r')
|
|
363
|
+
fi++;
|
|
364
|
+
continue;
|
|
315
365
|
}
|
|
316
|
-
|
|
317
|
-
|
|
366
|
+
if (_flowDepth > 0) {
|
|
367
|
+
if (fc === '{' || fc === '[')
|
|
368
|
+
_flowDepth++;
|
|
369
|
+
else if (fc === '}' || fc === ']')
|
|
370
|
+
_flowDepth--;
|
|
371
|
+
else if (fc === '"')
|
|
372
|
+
_inDoubleQuote = true;
|
|
373
|
+
else if (fc === "'") {
|
|
374
|
+
let pc = fi > 0 ? src.charCodeAt(fi - 1) : 0;
|
|
375
|
+
if (!((pc >= 65 && pc <= 90) || (pc >= 97 && pc <= 122) || (pc >= 48 && pc <= 57))) {
|
|
376
|
+
_inSingleQuote = true;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
continue;
|
|
318
380
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
381
|
+
// Block context: only a node's first character opens anything.
|
|
382
|
+
if (fc === '{' || fc === '[' || fc === '"' || fc === "'" ||
|
|
383
|
+
fc === '|' || fc === '>') {
|
|
384
|
+
if (!startsYamlNode(src, fi)) {
|
|
385
|
+
// Inside a plain scalar, which nothing can open until it ends at
|
|
386
|
+
// `: `, ` #` or the end of the line: skip to there.
|
|
387
|
+
fi = plainScalarRest(src, fi) - 1;
|
|
388
|
+
}
|
|
389
|
+
else if (fc === '{' || fc === '[')
|
|
390
|
+
_flowDepth++;
|
|
391
|
+
else if (fc === '"')
|
|
392
|
+
_inDoubleQuote = true;
|
|
393
|
+
else if (fc === "'")
|
|
322
394
|
_inSingleQuote = true;
|
|
395
|
+
else {
|
|
396
|
+
let end = blockScalarEnd(src, fi);
|
|
397
|
+
if (end > fi)
|
|
398
|
+
fi = end - 1;
|
|
323
399
|
}
|
|
324
400
|
}
|
|
325
401
|
}
|
|
326
|
-
_flowScanPos =
|
|
402
|
+
_flowScanPos = fi;
|
|
403
|
+
}
|
|
404
|
+
// Whether a quoted scalar opens at `i` and is a block mapping key: its
|
|
405
|
+
// closing quote is followed, on the same line, by `:` and then whitespace
|
|
406
|
+
// or the end of the line.
|
|
407
|
+
function quotedKeyAt(src, i) {
|
|
408
|
+
let q = src[i];
|
|
409
|
+
let j = i + 1;
|
|
410
|
+
while (j < src.length && src[j] !== '\n' && src[j] !== '\r') {
|
|
411
|
+
if (q === '"' && src[j] === '\\') {
|
|
412
|
+
j += 2;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
if (src[j] === q) {
|
|
416
|
+
if (q === "'" && src[j + 1] === "'") {
|
|
417
|
+
j += 2;
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
j++;
|
|
423
|
+
}
|
|
424
|
+
if (src[j] !== q)
|
|
425
|
+
return false;
|
|
426
|
+
j++;
|
|
427
|
+
while (src[j] === ' ' || src[j] === '\t')
|
|
428
|
+
j++;
|
|
429
|
+
return src[j] === ':' && (j + 1 >= src.length || isYamlSpace(src[j + 1]));
|
|
430
|
+
}
|
|
431
|
+
// `text` with its quotes removed when the whole of it is one quoted
|
|
432
|
+
// scalar on one line; otherwise `text` unchanged. Double quotes take the
|
|
433
|
+
// common escapes; single quotes take '' for a quote.
|
|
434
|
+
function unquoteWholeScalar(text) {
|
|
435
|
+
let q = text[0];
|
|
436
|
+
if ((q !== '"' && q !== "'") || text.length < 2 || text[text.length - 1] !== q) {
|
|
437
|
+
return text;
|
|
438
|
+
}
|
|
439
|
+
let out = '';
|
|
440
|
+
for (let j = 1; j < text.length - 1; j++) {
|
|
441
|
+
let c = text[j];
|
|
442
|
+
if (q === "'" && c === "'") {
|
|
443
|
+
if (text[j + 1] !== "'" || j + 1 === text.length - 1)
|
|
444
|
+
return text;
|
|
445
|
+
out += "'";
|
|
446
|
+
j++;
|
|
447
|
+
}
|
|
448
|
+
else if (q === '"' && c === '"') {
|
|
449
|
+
return text;
|
|
450
|
+
}
|
|
451
|
+
else if (q === '"' && c === '\\') {
|
|
452
|
+
let e = text[++j];
|
|
453
|
+
let m = { n: '\n', t: '\t', r: '\r', '0': '\0', '"': '"', '\\': '\\', '/': '/', ' ': ' ' };
|
|
454
|
+
if (j >= text.length - 1 || !(e in m))
|
|
455
|
+
return text;
|
|
456
|
+
out += m[e];
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
out += c;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return out;
|
|
463
|
+
}
|
|
464
|
+
// Whether offset `i` begins a line: the source start, just after a line
|
|
465
|
+
// break, or just after the byte order mark that opens the stream.
|
|
466
|
+
function atLineStart(src, i) {
|
|
467
|
+
return 0 === i || src[i - 1] === '\n' || src[i - 1] === '\r' ||
|
|
468
|
+
(1 === i && 0xFEFF === src.charCodeAt(0));
|
|
469
|
+
}
|
|
470
|
+
function isYamlSpace(c) {
|
|
471
|
+
return c === ' ' || c === '\t' || c === '\n' || c === '\r';
|
|
472
|
+
}
|
|
473
|
+
// Whether the character at `i` (block context) is the first character of
|
|
474
|
+
// a node: first on its line, or after a `: ` / `- ` / `? ` indicator, a
|
|
475
|
+
// `---` marker, or a node property (`&anchor`, `!tag`) that itself starts
|
|
476
|
+
// a node. Anything else is inside a plain scalar.
|
|
477
|
+
function startsYamlNode(src, i) {
|
|
478
|
+
// Char codes throughout: this runs for every bracket and quote in block
|
|
479
|
+
// text, and indexing a string allocates a one-character string. A byte
|
|
480
|
+
// order mark opening the stream counts as a line start.
|
|
481
|
+
let p = i - 1;
|
|
482
|
+
let c = p >= 0 ? src.charCodeAt(p) : -1;
|
|
483
|
+
if (c === 10 || c === 13 || c < 0 || (0 === p && 0xFEFF === c))
|
|
484
|
+
return true;
|
|
485
|
+
if (c !== 32 && c !== 9)
|
|
486
|
+
return false;
|
|
487
|
+
while (c === 32 || c === 9)
|
|
488
|
+
c = --p >= 0 ? src.charCodeAt(p) : -1;
|
|
489
|
+
if (c === 10 || c === 13 || c < 0 || (0 === p && 0xFEFF === c))
|
|
490
|
+
return true;
|
|
491
|
+
if (c === 58)
|
|
492
|
+
return true; // `:`
|
|
493
|
+
if (c === 45 || c === 63) { // `-` / `?`
|
|
494
|
+
if (c === 45 && src.charCodeAt(p - 1) === 45 && src.charCodeAt(p - 2) === 45 &&
|
|
495
|
+
(p - 3 < 0 || src.charCodeAt(p - 3) === 10 || src.charCodeAt(p - 3) === 13))
|
|
496
|
+
return true;
|
|
497
|
+
return startsYamlNode(src, p);
|
|
498
|
+
}
|
|
499
|
+
let w = p;
|
|
500
|
+
while (w > 0 && !isYamlSpaceCode(src.charCodeAt(w - 1)))
|
|
501
|
+
w--;
|
|
502
|
+
c = src.charCodeAt(w);
|
|
503
|
+
if (c === 38 || c === 33)
|
|
504
|
+
return startsYamlNode(src, w); // `&` / `!`
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
// From `i` inside a block-context plain scalar, the offset where it can
|
|
508
|
+
// end: the next line break, a `:` followed by whitespace or the end, or a
|
|
509
|
+
// `#` after whitespace.
|
|
510
|
+
function plainScalarRest(src, i) {
|
|
511
|
+
let j = i + 1;
|
|
512
|
+
for (; j < src.length; j++) {
|
|
513
|
+
let c = src.charCodeAt(j);
|
|
514
|
+
if (c === 10 || c === 13)
|
|
515
|
+
break;
|
|
516
|
+
if (c === 58) { // `:`
|
|
517
|
+
let n = j + 1 < src.length ? src.charCodeAt(j + 1) : -1;
|
|
518
|
+
if (n < 0 || isYamlSpaceCode(n))
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
else if (c === 35) { // `#`
|
|
522
|
+
let b = src.charCodeAt(j - 1);
|
|
523
|
+
if (b === 32 || b === 9)
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return j;
|
|
528
|
+
}
|
|
529
|
+
function isYamlSpaceCode(c) {
|
|
530
|
+
return c === 32 || c === 9 || c === 10 || c === 13;
|
|
531
|
+
}
|
|
532
|
+
// A block scalar indicator (`|` or `>`, optional chomping/indentation
|
|
533
|
+
// indicators, then only a comment) at `i`: the offset just past its content
|
|
534
|
+
// lines, or `i` when it is not one. Content runs while lines are blank or
|
|
535
|
+
// indented at least as far as the first content line, which must be deeper
|
|
536
|
+
// than the indicator's line (column 0 is allowed for a document's root).
|
|
537
|
+
function blockScalarEnd(src, i) {
|
|
538
|
+
let j = i + 1;
|
|
539
|
+
let explicit = 0;
|
|
540
|
+
for (let k = 0; k < 2; k++) {
|
|
541
|
+
if (src[j] === '+' || src[j] === '-')
|
|
542
|
+
j++;
|
|
543
|
+
else if (src[j] >= '1' && src[j] <= '9') {
|
|
544
|
+
explicit = +src[j];
|
|
545
|
+
j++;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
while (src[j] === ' ' || src[j] === '\t')
|
|
549
|
+
j++;
|
|
550
|
+
if (src[j] === '#') {
|
|
551
|
+
while (j < src.length && src[j] !== '\n' && src[j] !== '\r')
|
|
552
|
+
j++;
|
|
553
|
+
}
|
|
554
|
+
if (j < src.length && src[j] !== '\n' && src[j] !== '\r')
|
|
555
|
+
return i;
|
|
556
|
+
let ls = i;
|
|
557
|
+
while (ls > 0 && src[ls - 1] !== '\n' && src[ls - 1] !== '\r')
|
|
558
|
+
ls--;
|
|
559
|
+
if (0 === ls && 0xFEFF === src.charCodeAt(0))
|
|
560
|
+
ls = 1;
|
|
561
|
+
let lineIndent = 0;
|
|
562
|
+
while (src[ls + lineIndent] === ' ')
|
|
563
|
+
lineIndent++;
|
|
564
|
+
let isRoot = ls + lineIndent === i ||
|
|
565
|
+
(src[ls] === '-' && src[ls + 1] === '-' && src[ls + 2] === '-');
|
|
566
|
+
let parentIndent = isRoot && lineIndent === 0 ? -1 : lineIndent;
|
|
567
|
+
let pos = j;
|
|
568
|
+
if (src[pos] === '\r')
|
|
569
|
+
pos++;
|
|
570
|
+
if (src[pos] === '\n')
|
|
571
|
+
pos++;
|
|
572
|
+
let blockIndent = -1;
|
|
573
|
+
if (explicit > 0) {
|
|
574
|
+
// As the block scalar handler does: after a key on the same line
|
|
575
|
+
// (`- a: |2`), the indent the indicator counts from includes each
|
|
576
|
+
// `- ` before the key, not only the line's leading spaces.
|
|
577
|
+
let base = Math.max(parentIndent, 0);
|
|
578
|
+
let hasColon = false;
|
|
579
|
+
for (let ci = ls + lineIndent; ci < i; ci++) {
|
|
580
|
+
if (src[ci] === ':' && (src[ci + 1] === ' ' || src[ci + 1] === '\t')) {
|
|
581
|
+
hasColon = true;
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (hasColon) {
|
|
586
|
+
let si = ls + lineIndent;
|
|
587
|
+
while (si < i && src[si] === '-' && (src[si + 1] === ' ' || src[si + 1] === '\t')) {
|
|
588
|
+
base += 2;
|
|
589
|
+
si += 2;
|
|
590
|
+
while (si < i && src[si] === ' ') {
|
|
591
|
+
base++;
|
|
592
|
+
si++;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
blockIndent = base + explicit;
|
|
597
|
+
}
|
|
598
|
+
let end = pos;
|
|
599
|
+
while (pos < src.length) {
|
|
600
|
+
let n = 0;
|
|
601
|
+
while (src[pos + n] === ' ')
|
|
602
|
+
n++;
|
|
603
|
+
let c = src[pos + n];
|
|
604
|
+
let lineEnd = pos + n;
|
|
605
|
+
while (lineEnd < src.length && src[lineEnd] !== '\n' && src[lineEnd] !== '\r')
|
|
606
|
+
lineEnd++;
|
|
607
|
+
let next = lineEnd;
|
|
608
|
+
if (src[next] === '\r')
|
|
609
|
+
next++;
|
|
610
|
+
if (src[next] === '\n')
|
|
611
|
+
next++;
|
|
612
|
+
if (c === undefined || c === '\n' || c === '\r') {
|
|
613
|
+
pos = next;
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
if (blockIndent < 0) {
|
|
617
|
+
if (n <= parentIndent)
|
|
618
|
+
break;
|
|
619
|
+
blockIndent = n;
|
|
620
|
+
}
|
|
621
|
+
if (n < blockIndent)
|
|
622
|
+
break;
|
|
623
|
+
if (n === 0 && (src.startsWith('---', pos) || src.startsWith('...', pos)))
|
|
624
|
+
break;
|
|
625
|
+
end = lineEnd;
|
|
626
|
+
pos = next;
|
|
627
|
+
}
|
|
628
|
+
return end;
|
|
327
629
|
}
|
|
328
630
|
tabnas.options({
|
|
329
631
|
fixed: {
|
|
@@ -434,6 +736,8 @@ const Yaml = (tabnas, options) => {
|
|
|
434
736
|
let li = pnt.sI;
|
|
435
737
|
while (li > 0 && lex.src[li - 1] !== '\n' && lex.src[li - 1] !== '\r')
|
|
436
738
|
li--;
|
|
739
|
+
if (0 === li && 0xFEFF === lex.src.charCodeAt(0))
|
|
740
|
+
li = 1;
|
|
437
741
|
let lineStart = li;
|
|
438
742
|
while (li < pnt.sI && lex.src[li] === ' ') {
|
|
439
743
|
containingIndent++;
|
|
@@ -759,7 +1063,11 @@ const Yaml = (tabnas, options) => {
|
|
|
759
1063
|
}
|
|
760
1064
|
else {
|
|
761
1065
|
// Unquoted value — to end of line, stopping at `: ` and ` #`.
|
|
1066
|
+
// A `#` straight after the tag's space starts a comment, so
|
|
1067
|
+
// the value is empty (`!!str #c` is "").
|
|
762
1068
|
while (valEnd < fwd.length && fwd[valEnd] !== '\n' && fwd[valEnd] !== '\r') {
|
|
1069
|
+
if (valEnd === valStart && valStart > tagEnd && fwd[valEnd] === '#')
|
|
1070
|
+
break;
|
|
763
1071
|
if (fwd[valEnd] === ':' && (fwd[valEnd + 1] === ' ' || fwd[valEnd + 1] === '\n' ||
|
|
764
1072
|
fwd[valEnd + 1] === '\r' || fwd[valEnd + 1] === undefined))
|
|
765
1073
|
break;
|
|
@@ -774,9 +1082,9 @@ const Yaml = (tabnas, options) => {
|
|
|
774
1082
|
if (tag === 'str')
|
|
775
1083
|
result = String(rawVal);
|
|
776
1084
|
else if (tag === 'int')
|
|
777
|
-
result =
|
|
1085
|
+
result = yamlTagInt(rawVal);
|
|
778
1086
|
else if (tag === 'float')
|
|
779
|
-
result =
|
|
1087
|
+
result = yamlTagFloat(rawVal);
|
|
780
1088
|
else if (tag === 'bool')
|
|
781
1089
|
result = rawVal === 'true' || rawVal === 'True' || rawVal === 'TRUE';
|
|
782
1090
|
else if (tag === 'null')
|
|
@@ -815,6 +1123,8 @@ const Yaml = (tabnas, options) => {
|
|
|
815
1123
|
let lineStart = pnt.sI;
|
|
816
1124
|
while (lineStart > 0 && lex.src[lineStart - 1] !== '\n' && lex.src[lineStart - 1] !== '\r')
|
|
817
1125
|
lineStart--;
|
|
1126
|
+
if (0 === lineStart && 0xFEFF === lex.src.charCodeAt(0))
|
|
1127
|
+
lineStart = 1;
|
|
818
1128
|
// Current line indent (indent of the line where text starts).
|
|
819
1129
|
let currentLineIndent = 0;
|
|
820
1130
|
{
|
|
@@ -1004,6 +1314,7 @@ const Yaml = (tabnas, options) => {
|
|
|
1004
1314
|
'on': true, 'On': true, 'ON': true,
|
|
1005
1315
|
'off': false, 'Off': false, 'OFF': false,
|
|
1006
1316
|
'.inf': Infinity, '.Inf': Infinity, '.INF': Infinity,
|
|
1317
|
+
'+.inf': Infinity, '+.Inf': Infinity, '+.INF': Infinity,
|
|
1007
1318
|
'-.inf': -Infinity, '-.Inf': -Infinity, '-.INF': -Infinity,
|
|
1008
1319
|
'.nan': NaN, '.NaN': NaN, '.NAN': NaN,
|
|
1009
1320
|
};
|
|
@@ -1085,6 +1396,7 @@ const Yaml = (tabnas, options) => {
|
|
|
1085
1396
|
yamlStreamCurMeta = null;
|
|
1086
1397
|
_flowDepth = 0;
|
|
1087
1398
|
_flowScanPos = 0;
|
|
1399
|
+
_flowScanUpTo = 0;
|
|
1088
1400
|
_inSingleQuote = false;
|
|
1089
1401
|
_inDoubleQuote = false;
|
|
1090
1402
|
// Empty / whitespace-only / comments-only source: emit one
|
|
@@ -1097,6 +1409,13 @@ const Yaml = (tabnas, options) => {
|
|
|
1097
1409
|
lex.pnt.sI = 0;
|
|
1098
1410
|
return tkn;
|
|
1099
1411
|
}
|
|
1412
|
+
// A byte order mark opening the stream is not content: step
|
|
1413
|
+
// over it without counting a column. atLineStart and the
|
|
1414
|
+
// flow scan treat the offset after it as a line start.
|
|
1415
|
+
if (0 === lex.pnt.sI && 0xFEFF === src.charCodeAt(0)) {
|
|
1416
|
+
lex.pnt.sI = 1;
|
|
1417
|
+
lex.refwd();
|
|
1418
|
+
}
|
|
1100
1419
|
}
|
|
1101
1420
|
// Drain any queued tokens first (from multi-token explicit keys).
|
|
1102
1421
|
if (pendingTokens.length > 0) {
|
|
@@ -1324,8 +1643,7 @@ const Yaml = (tabnas, options) => {
|
|
|
1324
1643
|
// #DR token whose val is the raw directive text. The stream rule
|
|
1325
1644
|
// applies the directive (e.g. %TAG handle registration) at parse
|
|
1326
1645
|
// time via the @apply-directive action.
|
|
1327
|
-
if (
|
|
1328
|
-
lex.src[pnt.sI - 1] === '\r') && fwd[0] === '%') {
|
|
1646
|
+
if (fwd[0] === '%' && atLineStart(lex.src, pnt.sI)) {
|
|
1329
1647
|
let pos = 0;
|
|
1330
1648
|
while (pos < fwd.length && fwd[pos] !== '\n' && fwd[pos] !== '\r')
|
|
1331
1649
|
pos++;
|
|
@@ -1519,9 +1837,9 @@ const Yaml = (tabnas, options) => {
|
|
|
1519
1837
|
let result = rawVal;
|
|
1520
1838
|
if (!tagHandles['!!']) {
|
|
1521
1839
|
if (tag === 'int')
|
|
1522
|
-
result =
|
|
1840
|
+
result = yamlTagInt(rawVal);
|
|
1523
1841
|
else if (tag === 'float')
|
|
1524
|
-
result =
|
|
1842
|
+
result = yamlTagFloat(rawVal);
|
|
1525
1843
|
else if (tag === 'bool')
|
|
1526
1844
|
result = rawVal === 'true' || rawVal === 'True' || rawVal === 'TRUE';
|
|
1527
1845
|
else if (tag === 'null')
|
|
@@ -1556,8 +1874,12 @@ const Yaml = (tabnas, options) => {
|
|
|
1556
1874
|
continue yamlMatchLoop;
|
|
1557
1875
|
}
|
|
1558
1876
|
// Unquoted: stop at `: `, ` #`, newline, flow indicators.
|
|
1877
|
+
// A `#` straight after the tag's space starts a comment, so
|
|
1878
|
+
// the value is empty (`!!str #c` is "").
|
|
1559
1879
|
while (valEnd < fwd.length && fwd[valEnd] !== '\n' && fwd[valEnd] !== '\r' &&
|
|
1560
1880
|
fwd[valEnd] !== ',' && fwd[valEnd] !== '}' && fwd[valEnd] !== ']') {
|
|
1881
|
+
if (valEnd === valStart && valStart > tagEnd && fwd[valEnd] === '#')
|
|
1882
|
+
break;
|
|
1561
1883
|
if (fwd[valEnd] === ':' && (fwd[valEnd + 1] === ' ' || fwd[valEnd + 1] === '\n' ||
|
|
1562
1884
|
fwd[valEnd + 1] === '\r' || fwd[valEnd + 1] === undefined))
|
|
1563
1885
|
break;
|
|
@@ -1574,9 +1896,9 @@ const Yaml = (tabnas, options) => {
|
|
|
1574
1896
|
if (tag === 'str')
|
|
1575
1897
|
result = String(rawVal);
|
|
1576
1898
|
else if (tag === 'int')
|
|
1577
|
-
result =
|
|
1899
|
+
result = yamlTagInt(rawVal);
|
|
1578
1900
|
else if (tag === 'float')
|
|
1579
|
-
result =
|
|
1901
|
+
result = yamlTagFloat(rawVal);
|
|
1580
1902
|
else if (tag === 'bool')
|
|
1581
1903
|
result = rawVal === 'true' || rawVal === 'True' || rawVal === 'TRUE';
|
|
1582
1904
|
else if (tag === 'null')
|
|
@@ -1631,6 +1953,9 @@ const Yaml = (tabnas, options) => {
|
|
|
1631
1953
|
explicitKeyTag = tagMatch[1];
|
|
1632
1954
|
key = tagMatch[2];
|
|
1633
1955
|
}
|
|
1956
|
+
// A quoted explicit key is the scalar inside the quotes, not
|
|
1957
|
+
// the quoted text (`? "k"` is the key k).
|
|
1958
|
+
key = unquoteWholeScalar(key);
|
|
1634
1959
|
let consumed = keyEnd;
|
|
1635
1960
|
// Track position before consuming newline (for !hasValue case).
|
|
1636
1961
|
let beforeNewline = consumed;
|
|
@@ -1853,14 +2178,13 @@ const Yaml = (tabnas, options) => {
|
|
|
1853
2178
|
// (no spurious #IN gets emitted between #DS and the content).
|
|
1854
2179
|
// Inline content on the same line as the marker (--- foo) is
|
|
1855
2180
|
// left in place for the next call.
|
|
1856
|
-
if ((
|
|
1857
|
-
|
|
1858
|
-
|
|
2181
|
+
if (((fwd[0] === '-' && fwd[1] === '-' && fwd[2] === '-' &&
|
|
2182
|
+
(fwd[3] === '\n' || fwd[3] === '\r' ||
|
|
2183
|
+
fwd[3] === ' ' || fwd[3] === '\t' || fwd[3] === undefined)) ||
|
|
2184
|
+
(fwd[0] === '.' && fwd[1] === '.' && fwd[2] === '.' &&
|
|
1859
2185
|
(fwd[3] === '\n' || fwd[3] === '\r' ||
|
|
1860
|
-
fwd[3] === ' ' || fwd[3] === '\t' || fwd[3] === undefined))
|
|
1861
|
-
|
|
1862
|
-
(fwd[3] === '\n' || fwd[3] === '\r' ||
|
|
1863
|
-
fwd[3] === ' ' || fwd[3] === '\t' || fwd[3] === undefined)))) {
|
|
2186
|
+
fwd[3] === ' ' || fwd[3] === '\t' || fwd[3] === undefined))) &&
|
|
2187
|
+
atLineStart(lex.src, pnt.sI)) {
|
|
1864
2188
|
let isEnd = fwd[0] === '.';
|
|
1865
2189
|
let pos = 3;
|
|
1866
2190
|
while (pos < fwd.length && (fwd[pos] === ' ' || fwd[pos] === '\t'))
|
|
@@ -2149,7 +2473,10 @@ const Yaml = (tabnas, options) => {
|
|
|
2149
2473
|
// trailing commas (e.g. 12,), or non-numeric text after a space
|
|
2150
2474
|
// (e.g. "64 characters, hexadecimal.") must be captured before
|
|
2151
2475
|
// jsonic's number matcher grabs just the digits.
|
|
2152
|
-
|
|
2476
|
+
// A sign before the digit counts too: `+190:20:30` is one plain
|
|
2477
|
+
// scalar, where the number matcher would take `+190`.
|
|
2478
|
+
if ((fwd[0] >= '0' && fwd[0] <= '9') ||
|
|
2479
|
+
((fwd[0] === '+' || fwd[0] === '-') && fwd[1] >= '0' && fwd[1] <= '9')) {
|
|
2153
2480
|
updateFlowState(lex.src, pnt.sI);
|
|
2154
2481
|
let inFlow = _flowDepth > 0;
|
|
2155
2482
|
let hasEmbeddedColon = false;
|
|
@@ -2157,10 +2484,16 @@ const Yaml = (tabnas, options) => {
|
|
|
2157
2484
|
let hasBlockComma = false;
|
|
2158
2485
|
let pi = 1;
|
|
2159
2486
|
while (pi < fwd.length && fwd[pi] !== '\n' && fwd[pi] !== '\r') {
|
|
2487
|
+
// An embedded colon (20:03:20) does not end the scan: the
|
|
2488
|
+
// scalar can go on past a space ("09:00 AM"), and only the
|
|
2489
|
+
// trailing-text branch below reads that as one scalar.
|
|
2490
|
+
// Stopping here took "09:00" and left "AM" to fail the
|
|
2491
|
+
// parse (tabnas/yaml#90).
|
|
2160
2492
|
if (fwd[pi] === ':' && fwd[pi + 1] !== ' ' && fwd[pi + 1] !== '\t' &&
|
|
2161
2493
|
fwd[pi + 1] !== '\n' && fwd[pi + 1] !== '\r' && fwd[pi + 1] !== undefined) {
|
|
2162
2494
|
hasEmbeddedColon = true;
|
|
2163
|
-
|
|
2495
|
+
pi++;
|
|
2496
|
+
continue;
|
|
2164
2497
|
}
|
|
2165
2498
|
// A COMMA IS NOT A SEPARATOR IN BLOCK CONTEXT.
|
|
2166
2499
|
//
|
|
@@ -2219,10 +2552,13 @@ const Yaml = (tabnas, options) => {
|
|
|
2219
2552
|
return null;
|
|
2220
2553
|
}
|
|
2221
2554
|
if (hasEmbeddedColon || hasBlockComma) {
|
|
2222
|
-
// Scan to end of plain scalar token (space, tab, newline,
|
|
2555
|
+
// Scan to end of plain scalar token (space, tab, newline,
|
|
2556
|
+
// eof, or in a flow collection its `,` `]` `}`: `[1, 12:30]`
|
|
2557
|
+
// holds "12:30", not "12:30,").
|
|
2223
2558
|
let end = 0;
|
|
2224
2559
|
while (end < fwd.length && fwd[end] !== ' ' && fwd[end] !== '\t' &&
|
|
2225
|
-
fwd[end] !== '\n' && fwd[end] !== '\r'
|
|
2560
|
+
fwd[end] !== '\n' && fwd[end] !== '\r' &&
|
|
2561
|
+
!(inFlow && (fwd[end] === ',' || fwd[end] === ']' || fwd[end] === '}')))
|
|
2226
2562
|
end++;
|
|
2227
2563
|
let text = fwd.substring(0, end);
|
|
2228
2564
|
let tkn = lex.token('#TX', text, text, lex.pnt);
|
|
@@ -2488,9 +2824,14 @@ const Yaml = (tabnas, options) => {
|
|
|
2488
2824
|
// Skip #IN when the next content is a flow indicator or quoted
|
|
2489
2825
|
// string at column 0 — there's no block to indent into. Match
|
|
2490
2826
|
// the previous behavior of the inline `--- foo` handler.
|
|
2827
|
+
// A quoted KEY at column 0 is different: it continues (or
|
|
2828
|
+
// closes back to) the root block mapping, so it needs its #IN
|
|
2829
|
+
// like a plain key does. Without it a block sequence ending
|
|
2830
|
+
// just before it swallowed the pair (tabnas/yaml#86).
|
|
2491
2831
|
if (spaces === 0 &&
|
|
2492
2832
|
(fwd[pos] === '{' || fwd[pos] === '[' ||
|
|
2493
|
-
fwd[pos] === '"' || fwd[pos] === "'")
|
|
2833
|
+
((fwd[pos] === '"' || fwd[pos] === "'") &&
|
|
2834
|
+
!quotedKeyAt(fwd, pos)))) {
|
|
2494
2835
|
pnt.sI += pos;
|
|
2495
2836
|
pnt.rI += rows;
|
|
2496
2837
|
pnt.cI = 0;
|
|
@@ -2858,6 +3199,6 @@ Yaml.defaults = {
|
|
|
2858
3199
|
// VERSION is this package's version. It MUST equal package.json "version":
|
|
2859
3200
|
// the release orchestrator rewrites both, and test/version.test.ts fails the
|
|
2860
3201
|
// build if they drift. Mirrors `const VERSION` in go/yaml.go.
|
|
2861
|
-
const VERSION = '0.5.
|
|
3202
|
+
const VERSION = '0.5.13';
|
|
2862
3203
|
exports.VERSION = VERSION;
|
|
2863
3204
|
//# sourceMappingURL=yaml.js.map
|