yaml 2.4.3 → 2.4.4

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.
@@ -7,6 +7,7 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
7
7
  let hasNewline = false;
8
8
  let hasNewlineAfterProp = false;
9
9
  let reqSpace = false;
10
+ let tab = null;
10
11
  let anchor = null;
11
12
  let tag = null;
12
13
  let comma = null;
@@ -20,6 +21,12 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
20
21
  onError(token.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
21
22
  reqSpace = false;
22
23
  }
24
+ if (tab) {
25
+ if (token.type !== 'comment') {
26
+ onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
27
+ }
28
+ tab = null;
29
+ }
23
30
  switch (token.type) {
24
31
  case 'space':
25
32
  // At the doc level, tabs at line start may be parsed
@@ -27,9 +34,10 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
27
34
  // In a flow collection, only the parser handles indent.
28
35
  if (!flow &&
29
36
  atNewline &&
30
- indicator !== 'doc-start' &&
31
- token.source[0] === '\t')
32
- onError(token, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
37
+ (indicator !== 'doc-start' || next?.type !== 'flow-collection') &&
38
+ token.source[0] === '\t') {
39
+ tab = token;
40
+ }
33
41
  hasSpace = true;
34
42
  break;
35
43
  case 'comment': {
@@ -115,8 +123,11 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
115
123
  next.type !== 'space' &&
116
124
  next.type !== 'newline' &&
117
125
  next.type !== 'comma' &&
118
- (next.type !== 'scalar' || next.source !== ''))
126
+ (next.type !== 'scalar' || next.source !== '')) {
119
127
  onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
128
+ }
129
+ if (tab)
130
+ onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
120
131
  return {
121
132
  comma,
122
133
  found,
@@ -79,11 +79,11 @@ function isEmpty(ch) {
79
79
  return false;
80
80
  }
81
81
  }
82
- const hexDigits = '0123456789ABCDEFabcdef'.split('');
83
- const tagChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-#;/?:@&=+$_.!~*'()".split('');
84
- const invalidFlowScalarChars = ',[]{}'.split('');
85
- const invalidAnchorChars = ' ,[]{}\n\r\t'.split('');
86
- const isNotAnchorChar = (ch) => !ch || invalidAnchorChars.includes(ch);
82
+ const hexDigits = new Set('0123456789ABCDEFabcdef');
83
+ const tagChars = new Set("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-#;/?:@&=+$_.!~*'()");
84
+ const flowIndicatorChars = new Set(',[]{}');
85
+ const invalidAnchorChars = new Set(' ,[]{}\n\r\t');
86
+ const isNotAnchorChar = (ch) => !ch || invalidAnchorChars.has(ch);
87
87
  /**
88
88
  * Splits an input string into lexical tokens, i.e. smaller strings that are
89
89
  * easily identifiable by `tokens.tokenType()`.
@@ -525,8 +525,10 @@ class Lexer {
525
525
  if (indent >= this.indentNext) {
526
526
  if (this.blockScalarIndent === -1)
527
527
  this.indentNext = indent;
528
- else
529
- this.indentNext += this.blockScalarIndent;
528
+ else {
529
+ this.indentNext =
530
+ this.blockScalarIndent + (this.indentNext === 0 ? 1 : this.indentNext);
531
+ }
530
532
  do {
531
533
  const cs = this.continueScalar(nl + 1);
532
534
  if (cs === -1)
@@ -566,7 +568,7 @@ class Lexer {
566
568
  while ((ch = this.buffer[++i])) {
567
569
  if (ch === ':') {
568
570
  const next = this.buffer[i + 1];
569
- if (isEmpty(next) || (inFlow && next === ','))
571
+ if (isEmpty(next) || (inFlow && flowIndicatorChars.has(next)))
570
572
  break;
571
573
  end = i;
572
574
  }
@@ -581,7 +583,7 @@ class Lexer {
581
583
  else
582
584
  end = i;
583
585
  }
584
- if (next === '#' || (inFlow && invalidFlowScalarChars.includes(next)))
586
+ if (next === '#' || (inFlow && flowIndicatorChars.has(next)))
585
587
  break;
586
588
  if (ch === '\n') {
587
589
  const cs = this.continueScalar(i + 1);
@@ -591,7 +593,7 @@ class Lexer {
591
593
  }
592
594
  }
593
595
  else {
594
- if (inFlow && invalidFlowScalarChars.includes(ch))
596
+ if (inFlow && flowIndicatorChars.has(ch))
595
597
  break;
596
598
  end = i;
597
599
  }
@@ -636,7 +638,7 @@ class Lexer {
636
638
  case ':': {
637
639
  const inFlow = this.flowLevel > 0;
638
640
  const ch1 = this.charAt(1);
639
- if (isEmpty(ch1) || (inFlow && invalidFlowScalarChars.includes(ch1))) {
641
+ if (isEmpty(ch1) || (inFlow && flowIndicatorChars.has(ch1))) {
640
642
  if (!inFlow)
641
643
  this.indentNext = this.indentValue + 1;
642
644
  else if (this.flowKey)
@@ -661,11 +663,11 @@ class Lexer {
661
663
  let i = this.pos + 1;
662
664
  let ch = this.buffer[i];
663
665
  while (ch) {
664
- if (tagChars.includes(ch))
666
+ if (tagChars.has(ch))
665
667
  ch = this.buffer[++i];
666
668
  else if (ch === '%' &&
667
- hexDigits.includes(this.buffer[i + 1]) &&
668
- hexDigits.includes(this.buffer[i + 2])) {
669
+ hexDigits.has(this.buffer[i + 1]) &&
670
+ hexDigits.has(this.buffer[i + 2])) {
669
671
  ch = this.buffer[(i += 3)];
670
672
  }
671
673
  else
@@ -304,7 +304,7 @@ class Parser {
304
304
  }
305
305
  else {
306
306
  Object.assign(it, { key: token, sep: [] });
307
- this.onKeyLine = !includesToken(it.start, 'explicit-key-ind');
307
+ this.onKeyLine = !it.explicitKey;
308
308
  return;
309
309
  }
310
310
  break;
@@ -513,9 +513,9 @@ class Parser {
513
513
  return;
514
514
  }
515
515
  if (this.indent >= map.indent) {
516
- const atNextItem = !this.onKeyLine &&
517
- this.indent === map.indent &&
518
- it.sep &&
516
+ const atMapIndent = !this.onKeyLine && this.indent === map.indent;
517
+ const atNextItem = atMapIndent &&
518
+ (it.sep || it.explicitKey) &&
519
519
  this.type !== 'seq-item-ind';
520
520
  // For empty nodes, assign newline-separated not indented empty tokens to following node
521
521
  let start = [];
@@ -556,25 +556,26 @@ class Parser {
556
556
  }
557
557
  return;
558
558
  case 'explicit-key-ind':
559
- if (!it.sep && !includesToken(it.start, 'explicit-key-ind')) {
559
+ if (!it.sep && !it.explicitKey) {
560
560
  it.start.push(this.sourceToken);
561
+ it.explicitKey = true;
561
562
  }
562
563
  else if (atNextItem || it.value) {
563
564
  start.push(this.sourceToken);
564
- map.items.push({ start });
565
+ map.items.push({ start, explicitKey: true });
565
566
  }
566
567
  else {
567
568
  this.stack.push({
568
569
  type: 'block-map',
569
570
  offset: this.offset,
570
571
  indent: this.indent,
571
- items: [{ start: [this.sourceToken] }]
572
+ items: [{ start: [this.sourceToken], explicitKey: true }]
572
573
  });
573
574
  }
574
575
  this.onKeyLine = true;
575
576
  return;
576
577
  case 'map-value-ind':
577
- if (includesToken(it.start, 'explicit-key-ind')) {
578
+ if (it.explicitKey) {
578
579
  if (!it.sep) {
579
580
  if (includesToken(it.start, 'newline')) {
580
581
  Object.assign(it, { key: null, sep: [this.sourceToken] });
@@ -665,9 +666,7 @@ class Parser {
665
666
  default: {
666
667
  const bv = this.startBlockValue(map);
667
668
  if (bv) {
668
- if (atNextItem &&
669
- bv.type !== 'block-seq' &&
670
- includesToken(it.start, 'explicit-key-ind')) {
669
+ if (atMapIndent && bv.type !== 'block-seq') {
671
670
  map.items.push({ start });
672
671
  }
673
672
  this.stack.push(bv);
@@ -888,7 +887,7 @@ class Parser {
888
887
  type: 'block-map',
889
888
  offset: this.offset,
890
889
  indent: this.indent,
891
- items: [{ start }]
890
+ items: [{ start, explicitKey: true }]
892
891
  };
893
892
  }
894
893
  case 'map-value-ind': {
@@ -9,6 +9,7 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
9
9
  let hasNewline = false;
10
10
  let hasNewlineAfterProp = false;
11
11
  let reqSpace = false;
12
+ let tab = null;
12
13
  let anchor = null;
13
14
  let tag = null;
14
15
  let comma = null;
@@ -22,6 +23,12 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
22
23
  onError(token.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
23
24
  reqSpace = false;
24
25
  }
26
+ if (tab) {
27
+ if (token.type !== 'comment') {
28
+ onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
29
+ }
30
+ tab = null;
31
+ }
25
32
  switch (token.type) {
26
33
  case 'space':
27
34
  // At the doc level, tabs at line start may be parsed
@@ -29,9 +36,10 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
29
36
  // In a flow collection, only the parser handles indent.
30
37
  if (!flow &&
31
38
  atNewline &&
32
- indicator !== 'doc-start' &&
33
- token.source[0] === '\t')
34
- onError(token, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
39
+ (indicator !== 'doc-start' || next?.type !== 'flow-collection') &&
40
+ token.source[0] === '\t') {
41
+ tab = token;
42
+ }
35
43
  hasSpace = true;
36
44
  break;
37
45
  case 'comment': {
@@ -117,8 +125,11 @@ function resolveProps(tokens, { flow, indicator, next, offset, onError, startOnN
117
125
  next.type !== 'space' &&
118
126
  next.type !== 'newline' &&
119
127
  next.type !== 'comma' &&
120
- (next.type !== 'scalar' || next.source !== ''))
128
+ (next.type !== 'scalar' || next.source !== '')) {
121
129
  onError(next.offset, 'MISSING_CHAR', 'Tags and anchors must be separated from the next token by white space');
130
+ }
131
+ if (tab)
132
+ onError(tab, 'TAB_AS_INDENT', 'Tabs are not allowed as indentation');
122
133
  return {
123
134
  comma,
124
135
  found,
@@ -51,11 +51,13 @@ export interface BlockMap {
51
51
  indent: number;
52
52
  items: Array<{
53
53
  start: SourceToken[];
54
+ explicitKey?: true;
54
55
  key?: never;
55
56
  sep?: never;
56
57
  value?: never;
57
58
  } | {
58
59
  start: SourceToken[];
60
+ explicitKey?: true;
59
61
  key: Token | null;
60
62
  sep: SourceToken[];
61
63
  value?: Token;
@@ -81,11 +81,11 @@ function isEmpty(ch) {
81
81
  return false;
82
82
  }
83
83
  }
84
- const hexDigits = '0123456789ABCDEFabcdef'.split('');
85
- const tagChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-#;/?:@&=+$_.!~*'()".split('');
86
- const invalidFlowScalarChars = ',[]{}'.split('');
87
- const invalidAnchorChars = ' ,[]{}\n\r\t'.split('');
88
- const isNotAnchorChar = (ch) => !ch || invalidAnchorChars.includes(ch);
84
+ const hexDigits = new Set('0123456789ABCDEFabcdef');
85
+ const tagChars = new Set("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-#;/?:@&=+$_.!~*'()");
86
+ const flowIndicatorChars = new Set(',[]{}');
87
+ const invalidAnchorChars = new Set(' ,[]{}\n\r\t');
88
+ const isNotAnchorChar = (ch) => !ch || invalidAnchorChars.has(ch);
89
89
  /**
90
90
  * Splits an input string into lexical tokens, i.e. smaller strings that are
91
91
  * easily identifiable by `tokens.tokenType()`.
@@ -527,8 +527,10 @@ class Lexer {
527
527
  if (indent >= this.indentNext) {
528
528
  if (this.blockScalarIndent === -1)
529
529
  this.indentNext = indent;
530
- else
531
- this.indentNext += this.blockScalarIndent;
530
+ else {
531
+ this.indentNext =
532
+ this.blockScalarIndent + (this.indentNext === 0 ? 1 : this.indentNext);
533
+ }
532
534
  do {
533
535
  const cs = this.continueScalar(nl + 1);
534
536
  if (cs === -1)
@@ -568,7 +570,7 @@ class Lexer {
568
570
  while ((ch = this.buffer[++i])) {
569
571
  if (ch === ':') {
570
572
  const next = this.buffer[i + 1];
571
- if (isEmpty(next) || (inFlow && next === ','))
573
+ if (isEmpty(next) || (inFlow && flowIndicatorChars.has(next)))
572
574
  break;
573
575
  end = i;
574
576
  }
@@ -583,7 +585,7 @@ class Lexer {
583
585
  else
584
586
  end = i;
585
587
  }
586
- if (next === '#' || (inFlow && invalidFlowScalarChars.includes(next)))
588
+ if (next === '#' || (inFlow && flowIndicatorChars.has(next)))
587
589
  break;
588
590
  if (ch === '\n') {
589
591
  const cs = this.continueScalar(i + 1);
@@ -593,7 +595,7 @@ class Lexer {
593
595
  }
594
596
  }
595
597
  else {
596
- if (inFlow && invalidFlowScalarChars.includes(ch))
598
+ if (inFlow && flowIndicatorChars.has(ch))
597
599
  break;
598
600
  end = i;
599
601
  }
@@ -638,7 +640,7 @@ class Lexer {
638
640
  case ':': {
639
641
  const inFlow = this.flowLevel > 0;
640
642
  const ch1 = this.charAt(1);
641
- if (isEmpty(ch1) || (inFlow && invalidFlowScalarChars.includes(ch1))) {
643
+ if (isEmpty(ch1) || (inFlow && flowIndicatorChars.has(ch1))) {
642
644
  if (!inFlow)
643
645
  this.indentNext = this.indentValue + 1;
644
646
  else if (this.flowKey)
@@ -663,11 +665,11 @@ class Lexer {
663
665
  let i = this.pos + 1;
664
666
  let ch = this.buffer[i];
665
667
  while (ch) {
666
- if (tagChars.includes(ch))
668
+ if (tagChars.has(ch))
667
669
  ch = this.buffer[++i];
668
670
  else if (ch === '%' &&
669
- hexDigits.includes(this.buffer[i + 1]) &&
670
- hexDigits.includes(this.buffer[i + 2])) {
671
+ hexDigits.has(this.buffer[i + 1]) &&
672
+ hexDigits.has(this.buffer[i + 2])) {
671
673
  ch = this.buffer[(i += 3)];
672
674
  }
673
675
  else
@@ -308,7 +308,7 @@ class Parser {
308
308
  }
309
309
  else {
310
310
  Object.assign(it, { key: token, sep: [] });
311
- this.onKeyLine = !includesToken(it.start, 'explicit-key-ind');
311
+ this.onKeyLine = !it.explicitKey;
312
312
  return;
313
313
  }
314
314
  break;
@@ -517,9 +517,9 @@ class Parser {
517
517
  return;
518
518
  }
519
519
  if (this.indent >= map.indent) {
520
- const atNextItem = !this.onKeyLine &&
521
- this.indent === map.indent &&
522
- it.sep &&
520
+ const atMapIndent = !this.onKeyLine && this.indent === map.indent;
521
+ const atNextItem = atMapIndent &&
522
+ (it.sep || it.explicitKey) &&
523
523
  this.type !== 'seq-item-ind';
524
524
  // For empty nodes, assign newline-separated not indented empty tokens to following node
525
525
  let start = [];
@@ -560,25 +560,26 @@ class Parser {
560
560
  }
561
561
  return;
562
562
  case 'explicit-key-ind':
563
- if (!it.sep && !includesToken(it.start, 'explicit-key-ind')) {
563
+ if (!it.sep && !it.explicitKey) {
564
564
  it.start.push(this.sourceToken);
565
+ it.explicitKey = true;
565
566
  }
566
567
  else if (atNextItem || it.value) {
567
568
  start.push(this.sourceToken);
568
- map.items.push({ start });
569
+ map.items.push({ start, explicitKey: true });
569
570
  }
570
571
  else {
571
572
  this.stack.push({
572
573
  type: 'block-map',
573
574
  offset: this.offset,
574
575
  indent: this.indent,
575
- items: [{ start: [this.sourceToken] }]
576
+ items: [{ start: [this.sourceToken], explicitKey: true }]
576
577
  });
577
578
  }
578
579
  this.onKeyLine = true;
579
580
  return;
580
581
  case 'map-value-ind':
581
- if (includesToken(it.start, 'explicit-key-ind')) {
582
+ if (it.explicitKey) {
582
583
  if (!it.sep) {
583
584
  if (includesToken(it.start, 'newline')) {
584
585
  Object.assign(it, { key: null, sep: [this.sourceToken] });
@@ -669,9 +670,7 @@ class Parser {
669
670
  default: {
670
671
  const bv = this.startBlockValue(map);
671
672
  if (bv) {
672
- if (atNextItem &&
673
- bv.type !== 'block-seq' &&
674
- includesToken(it.start, 'explicit-key-ind')) {
673
+ if (atMapIndent && bv.type !== 'block-seq') {
675
674
  map.items.push({ start });
676
675
  }
677
676
  this.stack.push(bv);
@@ -892,7 +891,7 @@ class Parser {
892
891
  type: 'block-map',
893
892
  offset: this.offset,
894
893
  indent: this.indent,
895
- items: [{ start }]
894
+ items: [{ start, explicitKey: true }]
896
895
  };
897
896
  }
898
897
  case 'map-value-ind': {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaml",
3
- "version": "2.4.3",
3
+ "version": "2.4.4",
4
4
  "license": "ISC",
5
5
  "author": "Eemeli Aro <eemeli@gmail.com>",
6
6
  "repository": "github:eemeli/yaml",
@@ -44,8 +44,8 @@
44
44
  "clean": "git clean -fdxe node_modules",
45
45
  "lint": "eslint src/",
46
46
  "prettier": "prettier --write .",
47
- "prestart": "npm run build:node",
48
- "start": "node -i -e 'YAML=require(\"./dist/index.js\")'",
47
+ "prestart": "rollup --sourcemap -c config/rollup.node-config.mjs",
48
+ "start": "node --enable-source-maps -i -e 'YAML=require(\"./dist/index.js\");const{parse,parseDocument,parseAllDocuments}=YAML'",
49
49
  "test": "jest --config config/jest.config.js",
50
50
  "test:all": "npm test && npm run test:types && npm run test:dist && npm run test:dist:types",
51
51
  "test:browsers": "cd playground && npm test",