yaml 2.0.0-5 → 2.0.0-9

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 (94) hide show
  1. package/browser/dist/compose/compose-doc.js +1 -1
  2. package/browser/dist/compose/compose-node.js +10 -1
  3. package/browser/dist/compose/compose-scalar.js +2 -1
  4. package/browser/dist/compose/composer.js +3 -2
  5. package/browser/dist/compose/resolve-block-map.js +15 -5
  6. package/browser/dist/compose/resolve-block-scalar.js +2 -2
  7. package/browser/dist/compose/resolve-block-seq.js +1 -1
  8. package/browser/dist/compose/resolve-end.js +2 -2
  9. package/browser/dist/compose/resolve-flow-collection.js +14 -6
  10. package/browser/dist/compose/resolve-flow-scalar.js +19 -7
  11. package/browser/dist/compose/resolve-props.js +30 -7
  12. package/browser/dist/compose/util-map-includes.js +17 -0
  13. package/browser/dist/doc/Document.js +26 -2
  14. package/browser/dist/doc/createNode.js +11 -5
  15. package/browser/dist/doc/directives.js +5 -0
  16. package/browser/dist/node_modules/tslib/tslib.es6.js +164 -0
  17. package/browser/dist/nodes/Collection.js +28 -15
  18. package/browser/dist/nodes/Node.js +7 -0
  19. package/browser/dist/nodes/Pair.js +9 -1
  20. package/browser/dist/nodes/addPairToJSMap.js +4 -3
  21. package/browser/dist/options.js +2 -0
  22. package/browser/dist/parse/cst-scalar.js +2 -6
  23. package/browser/dist/parse/lexer.js +64 -31
  24. package/browser/dist/parse/parser.js +53 -52
  25. package/browser/dist/schema/Schema.js +5 -0
  26. package/browser/dist/schema/tags.js +9 -5
  27. package/browser/dist/stringify/stringify.js +2 -1
  28. package/browser/dist/stringify/stringifyCollection.js +23 -9
  29. package/browser/dist/stringify/stringifyComment.js +14 -0
  30. package/browser/dist/stringify/stringifyDocument.js +8 -5
  31. package/browser/dist/stringify/stringifyPair.js +5 -7
  32. package/browser/dist/stringify/stringifyString.js +35 -34
  33. package/browser/dist/util.js +3 -0
  34. package/dist/compose/compose-doc.js +1 -1
  35. package/dist/compose/compose-node.js +10 -1
  36. package/dist/compose/compose-scalar.js +2 -1
  37. package/dist/compose/composer.js +3 -2
  38. package/dist/compose/resolve-block-map.d.ts +2 -1
  39. package/dist/compose/resolve-block-map.js +15 -5
  40. package/dist/compose/resolve-block-scalar.js +2 -2
  41. package/dist/compose/resolve-block-seq.js +1 -1
  42. package/dist/compose/resolve-end.js +2 -2
  43. package/dist/compose/resolve-flow-collection.js +14 -6
  44. package/dist/compose/resolve-flow-scalar.js +19 -7
  45. package/dist/compose/resolve-props.d.ts +3 -4
  46. package/dist/compose/resolve-props.js +30 -7
  47. package/dist/compose/util-map-includes.d.ts +4 -0
  48. package/dist/compose/util-map-includes.js +19 -0
  49. package/dist/doc/Document.d.ts +10 -2
  50. package/dist/doc/Document.js +25 -1
  51. package/dist/doc/createNode.d.ts +2 -1
  52. package/dist/doc/createNode.js +10 -4
  53. package/dist/doc/directives.d.ts +1 -0
  54. package/dist/doc/directives.js +5 -0
  55. package/dist/errors.d.ts +1 -1
  56. package/dist/index.d.ts +2 -2
  57. package/dist/node_modules/tslib/tslib.es6.js +76 -0
  58. package/dist/nodes/Alias.d.ts +7 -3
  59. package/dist/nodes/Collection.d.ts +10 -4
  60. package/dist/nodes/Collection.js +27 -14
  61. package/dist/nodes/Node.d.ts +10 -3
  62. package/dist/nodes/Node.js +7 -0
  63. package/dist/nodes/Pair.d.ts +7 -2
  64. package/dist/nodes/Pair.js +8 -0
  65. package/dist/nodes/Scalar.d.ts +2 -0
  66. package/dist/nodes/YAMLMap.d.ts +2 -0
  67. package/dist/nodes/YAMLSeq.d.ts +2 -0
  68. package/dist/nodes/addPairToJSMap.js +3 -2
  69. package/dist/options.d.ts +40 -3
  70. package/dist/options.js +2 -0
  71. package/dist/parse/cst-scalar.d.ts +6 -0
  72. package/dist/parse/cst-scalar.js +2 -6
  73. package/dist/parse/lexer.d.ts +3 -1
  74. package/dist/parse/lexer.js +64 -31
  75. package/dist/parse/parser.d.ts +1 -0
  76. package/dist/parse/parser.js +53 -52
  77. package/dist/schema/Schema.d.ts +1 -0
  78. package/dist/schema/Schema.js +5 -0
  79. package/dist/schema/tags.js +9 -5
  80. package/dist/stringify/stringify.js +2 -1
  81. package/dist/stringify/stringifyCollection.d.ts +1 -1
  82. package/dist/stringify/stringifyCollection.js +24 -10
  83. package/dist/stringify/stringifyComment.d.ts +2 -0
  84. package/dist/stringify/{addComment.js → stringifyComment.js} +5 -1
  85. package/dist/stringify/stringifyDocument.js +9 -6
  86. package/dist/stringify/stringifyPair.js +9 -11
  87. package/dist/stringify/stringifyString.js +35 -34
  88. package/dist/test-events.d.ts +1 -1
  89. package/dist/util.d.ts +3 -0
  90. package/dist/util.js +6 -0
  91. package/package.json +9 -8
  92. package/util.d.ts +3 -0
  93. package/browser/dist/stringify/addComment.js +0 -11
  94. package/dist/stringify/addComment.d.ts +0 -2
@@ -20,38 +20,6 @@ function includesNonEmpty(list) {
20
20
  }
21
21
  return false;
22
22
  }
23
- function atFirstEmptyLineAfterComments(start) {
24
- let hasComment = false;
25
- for (let i = 0; i < start.length; ++i) {
26
- switch (start[i].type) {
27
- case 'space':
28
- break;
29
- case 'comment':
30
- hasComment = true;
31
- break;
32
- case 'newline':
33
- if (!hasComment)
34
- return false;
35
- break;
36
- default:
37
- return false;
38
- }
39
- }
40
- if (hasComment) {
41
- for (let i = start.length - 1; i >= 0; --i) {
42
- switch (start[i].type) {
43
- /* istanbul ignore next */
44
- case 'space':
45
- break;
46
- case 'newline':
47
- return true;
48
- default:
49
- return false;
50
- }
51
- }
52
- }
53
- return false;
54
- }
55
23
  function isFlowToken(token) {
56
24
  switch (token === null || token === void 0 ? void 0 : token.type) {
57
25
  case 'alias':
@@ -502,24 +470,38 @@ class Parser {
502
470
  switch (this.type) {
503
471
  case 'newline':
504
472
  this.onKeyLine = false;
505
- if (!it.sep && atFirstEmptyLineAfterComments(it.start)) {
506
- const prev = map.items[map.items.length - 2];
507
- const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end;
508
- if (Array.isArray(end)) {
509
- Array.prototype.push.apply(end, it.start);
510
- it.start = [this.sourceToken];
511
- return;
512
- }
473
+ if (it.value) {
474
+ const end = 'end' in it.value ? it.value.end : undefined;
475
+ const last = Array.isArray(end) ? end[end.length - 1] : undefined;
476
+ if ((last === null || last === void 0 ? void 0 : last.type) === 'comment')
477
+ end === null || end === void 0 ? void 0 : end.push(this.sourceToken);
478
+ else
479
+ map.items.push({ start: [this.sourceToken] });
513
480
  }
514
- // fallthrough
481
+ else if (it.sep)
482
+ it.sep.push(this.sourceToken);
483
+ else
484
+ it.start.push(this.sourceToken);
485
+ return;
515
486
  case 'space':
516
487
  case 'comment':
517
488
  if (it.value)
518
489
  map.items.push({ start: [this.sourceToken] });
519
490
  else if (it.sep)
520
491
  it.sep.push(this.sourceToken);
521
- else
492
+ else {
493
+ if (this.atIndentedComment(it.start, map.indent)) {
494
+ const prev = map.items[map.items.length - 2];
495
+ const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end;
496
+ if (Array.isArray(end)) {
497
+ Array.prototype.push.apply(end, it.start);
498
+ end.push(this.sourceToken);
499
+ map.items.pop();
500
+ return;
501
+ }
502
+ }
522
503
  it.start.push(this.sourceToken);
504
+ }
523
505
  return;
524
506
  }
525
507
  if (this.indent >= map.indent) {
@@ -624,22 +606,34 @@ class Parser {
624
606
  const it = seq.items[seq.items.length - 1];
625
607
  switch (this.type) {
626
608
  case 'newline':
627
- if (!it.value && atFirstEmptyLineAfterComments(it.start)) {
628
- const prev = seq.items[seq.items.length - 2];
629
- const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end;
630
- if (Array.isArray(end)) {
631
- Array.prototype.push.apply(end, it.start);
632
- it.start = [this.sourceToken];
633
- return;
634
- }
609
+ if (it.value) {
610
+ const end = 'end' in it.value ? it.value.end : undefined;
611
+ const last = Array.isArray(end) ? end[end.length - 1] : undefined;
612
+ if ((last === null || last === void 0 ? void 0 : last.type) === 'comment')
613
+ end === null || end === void 0 ? void 0 : end.push(this.sourceToken);
614
+ else
615
+ seq.items.push({ start: [this.sourceToken] });
635
616
  }
636
- // fallthrough
617
+ else
618
+ it.start.push(this.sourceToken);
619
+ return;
637
620
  case 'space':
638
621
  case 'comment':
639
622
  if (it.value)
640
623
  seq.items.push({ start: [this.sourceToken] });
641
- else
624
+ else {
625
+ if (this.atIndentedComment(it.start, seq.indent)) {
626
+ const prev = seq.items[seq.items.length - 2];
627
+ const end = (_a = prev === null || prev === void 0 ? void 0 : prev.value) === null || _a === void 0 ? void 0 : _a.end;
628
+ if (Array.isArray(end)) {
629
+ Array.prototype.push.apply(end, it.start);
630
+ end.push(this.sourceToken);
631
+ seq.items.pop();
632
+ return;
633
+ }
634
+ }
642
635
  it.start.push(this.sourceToken);
636
+ }
643
637
  return;
644
638
  case 'anchor':
645
639
  case 'tag':
@@ -834,6 +828,13 @@ class Parser {
834
828
  }
835
829
  return null;
836
830
  }
831
+ atIndentedComment(start, indent) {
832
+ if (this.type !== 'comment')
833
+ return false;
834
+ if (this.indent <= indent)
835
+ return false;
836
+ return start.every(st => st.type === 'newline' || st.type === 'space');
837
+ }
837
838
  *documentEnd(docEnd) {
838
839
  if (this.type !== 'doc-mode') {
839
840
  if (docEnd.end)
@@ -18,6 +18,11 @@ class Schema {
18
18
  this.sortMapEntries =
19
19
  sortMapEntries === true ? sortMapEntriesByKey : sortMapEntries || null;
20
20
  }
21
+ clone() {
22
+ const copy = Object.create(Schema.prototype, Object.getOwnPropertyDescriptors(this));
23
+ copy.tags = this.tags.slice();
24
+ return copy;
25
+ }
21
26
  }
22
27
 
23
28
  export { Schema };
@@ -50,11 +50,15 @@ const coreKnownTags = {
50
50
  function getTags(customTags, schemaName) {
51
51
  let tags = schemas[schemaName];
52
52
  if (!tags) {
53
- const keys = Object.keys(schemas)
54
- .filter(key => key !== 'yaml11')
55
- .map(key => JSON.stringify(key))
56
- .join(', ');
57
- throw new Error(`Unknown schema "${schemaName}"; use one of ${keys}`);
53
+ if (Array.isArray(customTags))
54
+ tags = [];
55
+ else {
56
+ const keys = Object.keys(schemas)
57
+ .filter(key => key !== 'yaml11')
58
+ .map(key => JSON.stringify(key))
59
+ .join(', ');
60
+ throw new Error(`Unknown schema "${schemaName}"; use one of ${keys} or define customTags array`);
61
+ }
58
62
  }
59
63
  if (Array.isArray(customTags)) {
60
64
  for (const tag of customTags)
@@ -8,6 +8,7 @@ const createStringifyContext = (doc, options) => ({
8
8
  indent: '',
9
9
  indentStep: typeof options.indent === 'number' ? ' '.repeat(options.indent) : ' ',
10
10
  options: Object.assign({
11
+ blockQuote: true,
11
12
  defaultKeyType: null,
12
13
  defaultStringType: 'PLAIN',
13
14
  directives: null,
@@ -19,7 +20,7 @@ const createStringifyContext = (doc, options) => ({
19
20
  minContentWidth: 20,
20
21
  nullStr: 'null',
21
22
  simpleKeys: false,
22
- singleQuote: false,
23
+ singleQuote: null,
23
24
  trueStr: 'true',
24
25
  verifyAliasOrder: true
25
26
  }, options)
@@ -1,7 +1,7 @@
1
1
  import { Collection } from '../nodes/Collection.js';
2
- import { addComment } from './addComment.js';
3
- import { stringify } from './stringify.js';
4
2
  import { isNode, isPair } from '../nodes/Node.js';
3
+ import { stringify } from './stringify.js';
4
+ import { addComment, stringifyComment } from './stringifyComment.js';
5
5
 
6
6
  function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowChars, itemIndent, onChompKeep, onComment }) {
7
7
  const { indent, indentStep } = ctx;
@@ -16,10 +16,17 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowCha
16
16
  if (isNode(item)) {
17
17
  if (!chompKeep && item.spaceBefore)
18
18
  nodes.push({ comment: true, str: '' });
19
- if (item.commentBefore) {
19
+ let cb = item.commentBefore;
20
+ if (cb && chompKeep)
21
+ cb = cb.replace(/^\n+/, '');
22
+ if (cb) {
23
+ if (/^\n+$/.test(cb))
24
+ cb = cb.substring(1);
20
25
  // This match will always succeed on a non-empty string
21
- for (const line of item.commentBefore.match(/^.*$/gm))
22
- nodes.push({ comment: true, str: `#${line}` });
26
+ for (const line of cb.match(/^.*$/gm)) {
27
+ const str = line === ' ' ? '#' : line ? `#${line}` : '';
28
+ nodes.push({ comment: true, str });
29
+ }
23
30
  }
24
31
  if (item.comment) {
25
32
  comment = item.comment;
@@ -31,10 +38,17 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowCha
31
38
  if (ik) {
32
39
  if (!chompKeep && ik.spaceBefore)
33
40
  nodes.push({ comment: true, str: '' });
34
- if (ik.commentBefore) {
41
+ let cb = ik.commentBefore;
42
+ if (cb && chompKeep)
43
+ cb = cb.replace(/^\n+/, '');
44
+ if (cb) {
45
+ if (/^\n+$/.test(cb))
46
+ cb = cb.substring(1);
35
47
  // This match will always succeed on a non-empty string
36
- for (const line of ik.commentBefore.match(/^.*$/gm))
37
- nodes.push({ comment: true, str: `#${line}` });
48
+ for (const line of cb.match(/^.*$/gm)) {
49
+ const str = line === ' ' ? '#' : line ? `#${line}` : '';
50
+ nodes.push({ comment: true, str });
51
+ }
38
52
  }
39
53
  if (ik.comment)
40
54
  singleLineOutput = false;
@@ -96,7 +110,7 @@ function stringifyCollection({ comment, flow, items }, ctx, { blockItem, flowCha
96
110
  str += s ? `\n${indent}${s}` : '\n';
97
111
  }
98
112
  if (comment) {
99
- str += '\n' + comment.replace(/^/gm, `${indent}#`);
113
+ str += '\n' + stringifyComment(comment, indent);
100
114
  if (onComment)
101
115
  onComment();
102
116
  }
@@ -0,0 +1,14 @@
1
+ const stringifyComment = (comment, indent) => /^\n+$/.test(comment)
2
+ ? comment.substring(1)
3
+ : comment.replace(/^(?!$)(?: $)?/gm, `${indent}#`);
4
+ function addComment(str, indent, comment) {
5
+ return !comment
6
+ ? str
7
+ : comment.includes('\n')
8
+ ? `${str}\n` + stringifyComment(comment, indent)
9
+ : str.endsWith(' ')
10
+ ? `${str}#${comment}`
11
+ : `${str} #${comment}`;
12
+ }
13
+
14
+ export { addComment, stringifyComment };
@@ -1,6 +1,6 @@
1
1
  import { isNode } from '../nodes/Node.js';
2
- import { addComment } from './addComment.js';
3
2
  import { createStringifyContext, stringify } from './stringify.js';
3
+ import { stringifyComment, addComment } from './stringifyComment.js';
4
4
 
5
5
  function stringifyDocument(doc, options) {
6
6
  const lines = [];
@@ -19,7 +19,7 @@ function stringifyDocument(doc, options) {
19
19
  if (doc.commentBefore) {
20
20
  if (lines.length !== 1)
21
21
  lines.unshift('');
22
- lines.unshift(doc.commentBefore.replace(/^/gm, '#'));
22
+ lines.unshift(stringifyComment(doc.commentBefore, ''));
23
23
  }
24
24
  const ctx = createStringifyContext(doc, options);
25
25
  let chompKeep = false;
@@ -29,7 +29,7 @@ function stringifyDocument(doc, options) {
29
29
  if (doc.contents.spaceBefore && hasDirectives)
30
30
  lines.push('');
31
31
  if (doc.contents.commentBefore)
32
- lines.push(doc.contents.commentBefore.replace(/^/gm, '#'));
32
+ lines.push(stringifyComment(doc.contents.commentBefore, ''));
33
33
  // top-level block scalars need to be indented if followed by a comment
34
34
  ctx.forceBlockIndent = !!doc.comment;
35
35
  contentComment = doc.contents.comment;
@@ -50,10 +50,13 @@ function stringifyDocument(doc, options) {
50
50
  else {
51
51
  lines.push(stringify(doc.contents, ctx));
52
52
  }
53
- if (doc.comment) {
53
+ let dc = doc.comment;
54
+ if (dc && chompKeep)
55
+ dc = dc.replace(/^\n+/, '');
56
+ if (dc) {
54
57
  if ((!chompKeep || contentComment) && lines[lines.length - 1] !== '')
55
58
  lines.push('');
56
- lines.push(doc.comment.replace(/^/gm, '#'));
59
+ lines.push(stringifyComment(dc, ''));
57
60
  }
58
61
  return lines.join('\n') + '\n';
59
62
  }
@@ -1,7 +1,7 @@
1
1
  import { isCollection, isNode, isScalar, isSeq } from '../nodes/Node.js';
2
2
  import { Scalar } from '../nodes/Scalar.js';
3
- import { addComment } from './addComment.js';
4
3
  import { stringify } from './stringify.js';
4
+ import { addComment, stringifyComment } from './stringifyComment.js';
5
5
 
6
6
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
7
7
  const { allNullValues, doc, indent, indentStep, options: { indentSeq, simpleKeys } } = ctx;
@@ -59,10 +59,8 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
59
59
  if (isNode(value)) {
60
60
  if (value.spaceBefore)
61
61
  vcb = '\n';
62
- if (value.commentBefore) {
63
- const cs = value.commentBefore.replace(/^/gm, `${ctx.indent}#`);
64
- vcb += `\n${cs}`;
65
- }
62
+ if (value.commentBefore)
63
+ vcb += `\n${stringifyComment(value.commentBefore, ctx.indent)}`;
66
64
  valueComment = value.comment;
67
65
  }
68
66
  else if (value && typeof value === 'object') {
@@ -87,14 +85,14 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
87
85
  const valueStr = stringify(value, ctx, () => (valueCommentDone = true), () => (chompKeep = true));
88
86
  let ws = ' ';
89
87
  if (vcb || keyComment) {
90
- ws = `${vcb}\n${ctx.indent}`;
88
+ ws = valueStr === '' && !ctx.inFlow ? vcb : `${vcb}\n${ctx.indent}`;
91
89
  }
92
90
  else if (!explicitKey && isCollection(value)) {
93
91
  const flow = valueStr[0] === '[' || valueStr[0] === '{';
94
92
  if (!flow || valueStr.includes('\n'))
95
93
  ws = `\n${ctx.indent}`;
96
94
  }
97
- else if (valueStr[0] === '\n')
95
+ else if (valueStr === '' || valueStr[0] === '\n')
98
96
  ws = '';
99
97
  if (ctx.inFlow) {
100
98
  if (valueCommentDone && onComment)
@@ -118,34 +118,50 @@ function doubleQuotedString(value, ctx) {
118
118
  : foldFlowLines(str, indent, FOLD_QUOTED, getFoldOptions(ctx));
119
119
  }
120
120
  function singleQuotedString(value, ctx) {
121
- if (ctx.implicitKey) {
122
- if (/\n/.test(value))
123
- return doubleQuotedString(value, ctx);
124
- }
125
- else {
126
- // single quoted string can't have leading or trailing whitespace around newline
127
- if (/[ \t]\n|\n[ \t]/.test(value))
128
- return doubleQuotedString(value, ctx);
129
- }
121
+ if (ctx.options.singleQuote === false ||
122
+ (ctx.implicitKey && value.includes('\n')) ||
123
+ /[ \t]\n|\n[ \t]/.test(value) // single quoted string can't have leading or trailing whitespace around newline
124
+ )
125
+ return doubleQuotedString(value, ctx);
130
126
  const indent = ctx.indent || (containsDocumentMarker(value) ? ' ' : '');
131
127
  const res = "'" + value.replace(/'/g, "''").replace(/\n+/g, `$&\n${indent}`) + "'";
132
128
  return ctx.implicitKey
133
129
  ? res
134
130
  : foldFlowLines(res, indent, FOLD_FLOW, getFoldOptions(ctx));
135
131
  }
132
+ function quotedString(value, ctx) {
133
+ const { singleQuote } = ctx.options;
134
+ let qs;
135
+ if (singleQuote === false)
136
+ qs = doubleQuotedString;
137
+ else {
138
+ const hasDouble = value.includes('"');
139
+ const hasSingle = value.includes("'");
140
+ if (hasDouble && !hasSingle)
141
+ qs = singleQuotedString;
142
+ else if (hasSingle && !hasDouble)
143
+ qs = doubleQuotedString;
144
+ else
145
+ qs = singleQuote ? singleQuotedString : doubleQuotedString;
146
+ }
147
+ return qs(value, ctx);
148
+ }
136
149
  function blockString({ comment, type, value }, ctx, onComment, onChompKeep) {
150
+ const { lineWidth, blockQuote } = ctx.options;
137
151
  // 1. Block can't end in whitespace unless the last line is non-empty.
138
152
  // 2. Strings consisting of only whitespace are best rendered explicitly.
139
- if (/\n[\t ]+$/.test(value) || /^\s*$/.test(value)) {
140
- return doubleQuotedString(value, ctx);
153
+ if (!blockQuote || /\n[\t ]+$/.test(value) || /^\s*$/.test(value)) {
154
+ return quotedString(value, ctx);
141
155
  }
142
156
  const indent = ctx.indent ||
143
157
  (ctx.forceBlockIndent || containsDocumentMarker(value) ? ' ' : '');
144
- const literal = type === Scalar.BLOCK_FOLDED
145
- ? false
146
- : type === Scalar.BLOCK_LITERAL
147
- ? true
148
- : !lineLengthOverLimit(value, ctx.options.lineWidth, indent.length);
158
+ const literal = blockQuote === 'literal'
159
+ ? true
160
+ : blockQuote === 'folded' || type === Scalar.BLOCK_FOLDED
161
+ ? false
162
+ : type === Scalar.BLOCK_LITERAL
163
+ ? true
164
+ : !lineLengthOverLimit(value, lineWidth, indent.length);
149
165
  if (!value)
150
166
  return literal ? '|\n' : '>\n';
151
167
  // determine chomping from whitespace at value end
@@ -218,25 +234,10 @@ function plainString(item, ctx, onComment, onChompKeep) {
218
234
  const { actualString, implicitKey, indent, inFlow } = ctx;
219
235
  if ((implicitKey && /[\n[\]{},]/.test(value)) ||
220
236
  (inFlow && /[[\]{},]/.test(value))) {
221
- return doubleQuotedString(value, ctx);
237
+ return quotedString(value, ctx);
222
238
  }
223
239
  if (!value ||
224
240
  /^[\n\t ,[\]{}#&*!|>'"%@`]|^[?-]$|^[?-][ \t]|[\n:][ \t]|[ \t]\n|[\n\t ]#|[\n\t :]$/.test(value)) {
225
- const hasDouble = value.indexOf('"') !== -1;
226
- const hasSingle = value.indexOf("'") !== -1;
227
- let quotedString;
228
- if (hasDouble && !hasSingle) {
229
- quotedString = singleQuotedString;
230
- }
231
- else if (hasSingle && !hasDouble) {
232
- quotedString = doubleQuotedString;
233
- }
234
- else if (ctx.options.singleQuote) {
235
- quotedString = singleQuotedString;
236
- }
237
- else {
238
- quotedString = doubleQuotedString;
239
- }
240
241
  // not allowed:
241
242
  // - empty string, '-' or '?'
242
243
  // - start with an indicator character (except [?:-]) or /[?-] /
@@ -267,7 +268,7 @@ function plainString(item, ctx, onComment, onChompKeep) {
267
268
  if (tag.default &&
268
269
  tag.tag !== 'tag:yaml.org,2002:str' &&
269
270
  ((_a = tag.test) === null || _a === void 0 ? void 0 : _a.test(str)))
270
- return doubleQuotedString(value, ctx);
271
+ return quotedString(value, ctx);
271
272
  }
272
273
  }
273
274
  return implicitKey
@@ -290,7 +291,7 @@ function stringifyString(item, ctx, onComment, onChompKeep) {
290
291
  case Scalar.BLOCK_FOLDED:
291
292
  case Scalar.BLOCK_LITERAL:
292
293
  return implicitKey || inFlow
293
- ? doubleQuotedString(ss.value, ctx) // blocks are not valid inside flow containers
294
+ ? quotedString(ss.value, ctx) // blocks are not valid inside flow containers
294
295
  : blockString(ss, ctx, onComment, onChompKeep);
295
296
  case Scalar.QUOTE_DOUBLE:
296
297
  return doubleQuotedString(ss.value, ctx);
@@ -1,6 +1,9 @@
1
1
  export { debug, warn } from './log.js';
2
2
  export { findPair } from './nodes/YAMLMap.js';
3
3
  export { toJS } from './nodes/toJS.js';
4
+ export { map as mapTag } from './schema/common/map.js';
5
+ export { seq as seqTag } from './schema/common/seq.js';
6
+ export { string as stringTag } from './schema/common/string.js';
4
7
  export { foldFlowLines } from './stringify/foldFlowLines.js';
5
8
  export { stringifyNumber } from './stringify/stringifyNumber.js';
6
9
  export { stringifyString } from './stringify/stringifyString.js';
@@ -14,8 +14,8 @@ function composeDoc(options, directives, { offset, start, value, end }, onError)
14
14
  schema: doc.schema
15
15
  };
16
16
  const props = resolveProps.resolveProps(start, {
17
- ctx,
18
17
  indicator: 'doc-start',
18
+ next: value || (end === null || end === void 0 ? void 0 : end[0]),
19
19
  offset,
20
20
  onError,
21
21
  startOnNewline: true
@@ -35,6 +35,8 @@ function composeNode(ctx, token, props, onError) {
35
35
  console.log(token);
36
36
  throw new Error(`Unsupporten token type: ${token.type}`);
37
37
  }
38
+ if (anchor && node.anchor === '')
39
+ onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
38
40
  if (spaceBefore)
39
41
  node.spaceBefore = true;
40
42
  if (comment) {
@@ -43,6 +45,8 @@ function composeNode(ctx, token, props, onError) {
43
45
  else
44
46
  node.commentBefore = comment;
45
47
  }
48
+ if (ctx.options.keepSourceTokens)
49
+ node.srcToken = token;
46
50
  return node;
47
51
  }
48
52
  function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag }, onError) {
@@ -53,8 +57,11 @@ function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anch
53
57
  source: ''
54
58
  };
55
59
  const node = composeScalar.composeScalar(ctx, token, tag, onError);
56
- if (anchor)
60
+ if (anchor) {
57
61
  node.anchor = anchor.source.substring(1);
62
+ if (node.anchor === '')
63
+ onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
64
+ }
58
65
  if (spaceBefore)
59
66
  node.spaceBefore = true;
60
67
  if (comment)
@@ -63,6 +70,8 @@ function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anch
63
70
  }
64
71
  function composeAlias({ options }, { offset, source, end }, onError) {
65
72
  const alias = new Alias.Alias(source.substring(1));
73
+ if (alias.source === '')
74
+ onError(offset, 'BAD_ALIAS', 'Alias cannot be an empty string');
66
75
  const valueEnd = offset + source.length;
67
76
  const re = resolveEnd.resolveEnd(end, valueEnd, options.strict, onError);
68
77
  alias.range = [offset, valueEnd, re.offset];
@@ -21,7 +21,8 @@ function composeScalar(ctx, token, tagToken, onError) {
21
21
  scalar = Node.isScalar(res) ? res : new Scalar.Scalar(res);
22
22
  }
23
23
  catch (error) {
24
- onError(tagToken || token, 'TAG_RESOLVE_FAILED', error.message);
24
+ const msg = error instanceof Error ? error.message : String(error);
25
+ onError(tagToken || token, 'TAG_RESOLVE_FAILED', msg);
25
26
  scalar = new Scalar.Scalar(value);
26
27
  }
27
28
  scalar.range = range;
@@ -17,6 +17,7 @@ function getErrorPos(src) {
17
17
  return [offset, offset + (typeof source === 'string' ? source.length : 1)];
18
18
  }
19
19
  function parsePrelude(prelude) {
20
+ var _a;
20
21
  let comment = '';
21
22
  let atComment = false;
22
23
  let afterEmptyLine = false;
@@ -26,12 +27,12 @@ function parsePrelude(prelude) {
26
27
  case '#':
27
28
  comment +=
28
29
  (comment === '' ? '' : afterEmptyLine ? '\n\n' : '\n') +
29
- source.substring(1);
30
+ (source.substring(1) || ' ');
30
31
  atComment = true;
31
32
  afterEmptyLine = false;
32
33
  break;
33
34
  case '%':
34
- if (prelude[i + 1][0] !== '#')
35
+ if (((_a = prelude[i + 1]) === null || _a === void 0 ? void 0 : _a[0]) !== '#')
35
36
  i += 1;
36
37
  atComment = false;
37
38
  break;
@@ -1,5 +1,6 @@
1
+ import type { ParsedNode } from '../nodes/Node.js';
1
2
  import { YAMLMap } from '../nodes/YAMLMap.js';
2
3
  import type { BlockMap } from '../parse/cst.js';
3
4
  import type { ComposeContext, ComposeNode } from './compose-node.js';
4
5
  import type { ComposeErrorHandler } from './composer.js';
5
- export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler): YAMLMap.Parsed<import("../index.js").ParsedNode, import("../index.js").ParsedNode | null>;
6
+ export declare function resolveBlockMap({ composeNode, composeEmptyNode }: ComposeNode, ctx: ComposeContext, bm: BlockMap, onError: ComposeErrorHandler): YAMLMap.Parsed<ParsedNode, ParsedNode | null>;
@@ -4,17 +4,19 @@ var Pair = require('../nodes/Pair.js');
4
4
  var YAMLMap = require('../nodes/YAMLMap.js');
5
5
  var resolveProps = require('./resolve-props.js');
6
6
  var utilContainsNewline = require('./util-contains-newline.js');
7
+ var utilMapIncludes = require('./util-map-includes.js');
7
8
 
8
9
  const startColMsg = 'All mapping items must start at the same column';
9
10
  function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
10
11
  var _a;
11
12
  const map = new YAMLMap.YAMLMap(ctx.schema);
12
13
  let offset = bm.offset;
13
- for (const { start, key, sep, value } of bm.items) {
14
+ for (const collItem of bm.items) {
15
+ const { start, key, sep, value } = collItem;
14
16
  // key properties
15
17
  const keyProps = resolveProps.resolveProps(start, {
16
- ctx,
17
18
  indicator: 'explicit-key-ind',
19
+ next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
18
20
  offset,
19
21
  onError,
20
22
  startOnNewline: true
@@ -48,10 +50,12 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
48
50
  const keyNode = key
49
51
  ? composeNode(ctx, key, keyProps, onError)
50
52
  : composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
53
+ if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
54
+ onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
51
55
  // value properties
52
56
  const valueProps = resolveProps.resolveProps(sep || [], {
53
- ctx,
54
57
  indicator: 'map-value-ind',
58
+ next: value,
55
59
  offset: keyNode.range[2],
56
60
  onError,
57
61
  startOnNewline: !key || key.type === 'block-scalar'
@@ -70,7 +74,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
70
74
  ? composeNode(ctx, value, valueProps, onError)
71
75
  : composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
72
76
  offset = valueNode.range[2];
73
- map.items.push(new Pair.Pair(keyNode, valueNode));
77
+ const pair = new Pair.Pair(keyNode, valueNode);
78
+ if (ctx.options.keepSourceTokens)
79
+ pair.srcToken = collItem;
80
+ map.items.push(pair);
74
81
  }
75
82
  else {
76
83
  // key with no value
@@ -82,7 +89,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
82
89
  else
83
90
  keyNode.comment = valueProps.comment;
84
91
  }
85
- map.items.push(new Pair.Pair(keyNode));
92
+ const pair = new Pair.Pair(keyNode);
93
+ if (ctx.options.keepSourceTokens)
94
+ pair.srcToken = collItem;
95
+ map.items.push(pair);
86
96
  }
87
97
  }
88
98
  map.range = [bm.offset, offset, offset];
@@ -20,7 +20,7 @@ function resolveBlockScalar(scalar, strict, onError) {
20
20
  }
21
21
  // shortcut for empty contents
22
22
  if (!scalar.source || chompStart === 0) {
23
- const value = header.chomp === '+' ? lines.map(line => line[0]).join('\n') : '';
23
+ const value = header.chomp === '+' ? '\n'.repeat(Math.max(0, lines.length - 1)) : '';
24
24
  let end = start + header.length;
25
25
  if (scalar.source)
26
26
  end += scalar.source.length;
@@ -151,7 +151,7 @@ function parseBlockScalarHeader({ offset, props }, strict, onError) {
151
151
  case 'comment':
152
152
  if (strict && !hasSpace) {
153
153
  const message = 'Comments must be separated from other tokens by white space characters';
154
- onError(token, 'COMMENT_SPACE', message);
154
+ onError(token, 'MISSING_CHAR', message);
155
155
  }
156
156
  length += token.source.length;
157
157
  comment = token.source.substring(1);