yaml 2.0.0-8 → 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 (44) hide show
  1. package/browser/dist/compose/compose-node.js +2 -0
  2. package/browser/dist/compose/resolve-block-map.js +10 -3
  3. package/browser/dist/compose/resolve-block-scalar.js +1 -1
  4. package/browser/dist/compose/resolve-flow-collection.js +4 -1
  5. package/browser/dist/node_modules/tslib/tslib.es6.js +164 -0
  6. package/browser/dist/nodes/Collection.js +8 -4
  7. package/browser/dist/nodes/addPairToJSMap.js +2 -1
  8. package/browser/dist/options.js +1 -0
  9. package/browser/dist/parse/cst-scalar.js +2 -6
  10. package/browser/dist/parse/lexer.js +6 -3
  11. package/browser/dist/schema/tags.js +9 -5
  12. package/browser/dist/stringify/stringify.js +2 -1
  13. package/browser/dist/stringify/stringifyPair.js +2 -2
  14. package/browser/dist/stringify/stringifyString.js +35 -34
  15. package/browser/dist/util.js +3 -0
  16. package/dist/compose/compose-node.js +2 -0
  17. package/dist/compose/resolve-block-map.js +10 -3
  18. package/dist/compose/resolve-block-scalar.js +1 -1
  19. package/dist/compose/resolve-flow-collection.js +4 -1
  20. package/dist/index.d.ts +2 -2
  21. package/dist/node_modules/tslib/tslib.es6.js +76 -0
  22. package/dist/nodes/Alias.d.ts +7 -3
  23. package/dist/nodes/Collection.d.ts +4 -4
  24. package/dist/nodes/Collection.js +8 -4
  25. package/dist/nodes/Node.d.ts +3 -0
  26. package/dist/nodes/Pair.d.ts +3 -0
  27. package/dist/nodes/Scalar.d.ts +2 -0
  28. package/dist/nodes/YAMLMap.d.ts +2 -0
  29. package/dist/nodes/YAMLSeq.d.ts +2 -0
  30. package/dist/nodes/addPairToJSMap.js +1 -0
  31. package/dist/options.d.ts +18 -3
  32. package/dist/options.js +1 -0
  33. package/dist/parse/cst-scalar.d.ts +6 -0
  34. package/dist/parse/cst-scalar.js +2 -6
  35. package/dist/parse/lexer.js +6 -3
  36. package/dist/schema/tags.js +9 -5
  37. package/dist/stringify/stringify.js +2 -1
  38. package/dist/stringify/stringifyPair.js +2 -2
  39. package/dist/stringify/stringifyString.js +35 -34
  40. package/dist/test-events.d.ts +1 -1
  41. package/dist/util.d.ts +3 -0
  42. package/dist/util.js +6 -0
  43. package/package.json +4 -3
  44. package/util.d.ts +3 -0
@@ -43,6 +43,8 @@ function composeNode(ctx, token, props, onError) {
43
43
  else
44
44
  node.commentBefore = comment;
45
45
  }
46
+ if (ctx.options.keepSourceTokens)
47
+ node.srcToken = token;
46
48
  return node;
47
49
  }
48
50
  function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag }, onError) {
@@ -9,7 +9,8 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
9
9
  var _a;
10
10
  const map = new YAMLMap(ctx.schema);
11
11
  let offset = bm.offset;
12
- for (const { start, key, sep, value } of bm.items) {
12
+ for (const collItem of bm.items) {
13
+ const { start, key, sep, value } = collItem;
13
14
  // key properties
14
15
  const keyProps = resolveProps(start, {
15
16
  indicator: 'explicit-key-ind',
@@ -71,7 +72,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
71
72
  ? composeNode(ctx, value, valueProps, onError)
72
73
  : composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
73
74
  offset = valueNode.range[2];
74
- map.items.push(new Pair(keyNode, valueNode));
75
+ const pair = new Pair(keyNode, valueNode);
76
+ if (ctx.options.keepSourceTokens)
77
+ pair.srcToken = collItem;
78
+ map.items.push(pair);
75
79
  }
76
80
  else {
77
81
  // key with no value
@@ -83,7 +87,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
83
87
  else
84
88
  keyNode.comment = valueProps.comment;
85
89
  }
86
- map.items.push(new Pair(keyNode));
90
+ const pair = new Pair(keyNode);
91
+ if (ctx.options.keepSourceTokens)
92
+ pair.srcToken = collItem;
93
+ map.items.push(pair);
87
94
  }
88
95
  }
89
96
  map.range = [bm.offset, offset, offset];
@@ -18,7 +18,7 @@ function resolveBlockScalar(scalar, strict, onError) {
18
18
  }
19
19
  // shortcut for empty contents
20
20
  if (!scalar.source || chompStart === 0) {
21
- const value = header.chomp === '+' ? lines.map(line => line[0]).join('\n') : '';
21
+ const value = header.chomp === '+' ? '\n'.repeat(Math.max(0, lines.length - 1)) : '';
22
22
  let end = start + header.length;
23
23
  if (scalar.source)
24
24
  end += scalar.source.length;
@@ -18,7 +18,8 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
18
18
  coll.flow = true;
19
19
  let offset = fc.offset;
20
20
  for (let i = 0; i < fc.items.length; ++i) {
21
- const { start, key, sep, value } = fc.items[i];
21
+ const collItem = fc.items[i];
22
+ const { start, key, sep, value } = collItem;
22
23
  const props = resolveProps(start, {
23
24
  flow: fcName,
24
25
  indicator: 'explicit-key-ind',
@@ -145,6 +146,8 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
145
146
  keyNode.comment = valueProps.comment;
146
147
  }
147
148
  const pair = new Pair(keyNode, valueNode);
149
+ if (ctx.options.keepSourceTokens)
150
+ pair.srcToken = collItem;
148
151
  if (isMap) {
149
152
  const map = coll;
150
153
  if (mapIncludes(ctx, map.items, keyNode))
@@ -0,0 +1,164 @@
1
+ /*! *****************************************************************************
2
+ Copyright (c) Microsoft Corporation.
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any
5
+ purpose with or without fee is hereby granted.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
14
+ ***************************************************************************** */
15
+
16
+ /* global Reflect, Promise */
17
+ var extendStatics = function (d, b) {
18
+ extendStatics = Object.setPrototypeOf || {
19
+ __proto__: []
20
+ } instanceof Array && function (d, b) {
21
+ d.__proto__ = b;
22
+ } || function (d, b) {
23
+ for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
24
+ };
25
+
26
+ return extendStatics(d, b);
27
+ };
28
+
29
+ function __extends(d, b) {
30
+ if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
31
+ extendStatics(d, b);
32
+
33
+ function __() {
34
+ this.constructor = d;
35
+ }
36
+
37
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
38
+ }
39
+ function __generator(thisArg, body) {
40
+ var _ = {
41
+ label: 0,
42
+ sent: function () {
43
+ if (t[0] & 1) throw t[1];
44
+ return t[1];
45
+ },
46
+ trys: [],
47
+ ops: []
48
+ },
49
+ f,
50
+ y,
51
+ t,
52
+ g;
53
+ return g = {
54
+ next: verb(0),
55
+ "throw": verb(1),
56
+ "return": verb(2)
57
+ }, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
58
+ return this;
59
+ }), g;
60
+
61
+ function verb(n) {
62
+ return function (v) {
63
+ return step([n, v]);
64
+ };
65
+ }
66
+
67
+ function step(op) {
68
+ if (f) throw new TypeError("Generator is already executing.");
69
+
70
+ while (_) try {
71
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
72
+ if (y = 0, t) op = [op[0] & 2, t.value];
73
+
74
+ switch (op[0]) {
75
+ case 0:
76
+ case 1:
77
+ t = op;
78
+ break;
79
+
80
+ case 4:
81
+ _.label++;
82
+ return {
83
+ value: op[1],
84
+ done: false
85
+ };
86
+
87
+ case 5:
88
+ _.label++;
89
+ y = op[1];
90
+ op = [0];
91
+ continue;
92
+
93
+ case 7:
94
+ op = _.ops.pop();
95
+
96
+ _.trys.pop();
97
+
98
+ continue;
99
+
100
+ default:
101
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
102
+ _ = 0;
103
+ continue;
104
+ }
105
+
106
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
107
+ _.label = op[1];
108
+ break;
109
+ }
110
+
111
+ if (op[0] === 6 && _.label < t[1]) {
112
+ _.label = t[1];
113
+ t = op;
114
+ break;
115
+ }
116
+
117
+ if (t && _.label < t[2]) {
118
+ _.label = t[2];
119
+
120
+ _.ops.push(op);
121
+
122
+ break;
123
+ }
124
+
125
+ if (t[2]) _.ops.pop();
126
+
127
+ _.trys.pop();
128
+
129
+ continue;
130
+ }
131
+
132
+ op = body.call(thisArg, _);
133
+ } catch (e) {
134
+ op = [6, e];
135
+ y = 0;
136
+ } finally {
137
+ f = t = 0;
138
+ }
139
+
140
+ if (op[0] & 5) throw op[1];
141
+ return {
142
+ value: op[0] ? op[1] : void 0,
143
+ done: true
144
+ };
145
+ }
146
+ }
147
+ function __values(o) {
148
+ var s = typeof Symbol === "function" && Symbol.iterator,
149
+ m = s && o[s],
150
+ i = 0;
151
+ if (m) return m.call(o);
152
+ if (o && typeof o.length === "number") return {
153
+ next: function () {
154
+ if (o && i >= o.length) o = void 0;
155
+ return {
156
+ value: o && o[i++],
157
+ done: !o
158
+ };
159
+ }
160
+ };
161
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
162
+ }
163
+
164
+ export { __extends, __generator, __values };
@@ -74,7 +74,8 @@ class Collection extends NodeBase {
74
74
  * Removes a value from the collection.
75
75
  * @returns `true` if the item was found and removed.
76
76
  */
77
- deleteIn([key, ...rest]) {
77
+ deleteIn(path) {
78
+ const [key, ...rest] = path;
78
79
  if (rest.length === 0)
79
80
  return this.delete(key);
80
81
  const node = this.get(key, true);
@@ -88,7 +89,8 @@ class Collection extends NodeBase {
88
89
  * scalar values from their surrounding node; to disable set `keepScalar` to
89
90
  * `true` (collections are always returned intact).
90
91
  */
91
- getIn([key, ...rest], keepScalar) {
92
+ getIn(path, keepScalar) {
93
+ const [key, ...rest] = path;
92
94
  const node = this.get(key, true);
93
95
  if (rest.length === 0)
94
96
  return !keepScalar && isScalar(node) ? node.value : node;
@@ -112,7 +114,8 @@ class Collection extends NodeBase {
112
114
  /**
113
115
  * Checks if the collection includes a value with the key `key`.
114
116
  */
115
- hasIn([key, ...rest]) {
117
+ hasIn(path) {
118
+ const [key, ...rest] = path;
116
119
  if (rest.length === 0)
117
120
  return this.has(key);
118
121
  const node = this.get(key, true);
@@ -122,7 +125,8 @@ class Collection extends NodeBase {
122
125
  * Sets a value in this collection. For `!!set`, `value` needs to be a
123
126
  * boolean to add/remove the item from the set.
124
127
  */
125
- setIn([key, ...rest], value) {
128
+ setIn(path, value) {
129
+ const [key, ...rest] = path;
126
130
  if (rest.length === 0) {
127
131
  this.set(key, value);
128
132
  }
@@ -1,12 +1,13 @@
1
1
  import { warn } from '../log.js';
2
2
  import { createStringifyContext } from '../stringify/stringify.js';
3
- import { isSeq, isScalar, isAlias, isMap, isNode } from './Node.js';
3
+ import { isAlias, isSeq, isScalar, isMap, isNode } from './Node.js';
4
4
  import { Scalar } from './Scalar.js';
5
5
  import { toJS } from './toJS.js';
6
6
 
7
7
  const MERGE_KEY = '<<';
8
8
  function addPairToJSMap(ctx, map, { key, value }) {
9
9
  if (ctx && ctx.doc.schema.merge && isMergeKey(key)) {
10
+ value = isAlias(value) ? value.resolve(ctx.doc) : value;
10
11
  if (isSeq(value))
11
12
  for (const it of value.items)
12
13
  mergeToJSMap(ctx, map, it);
@@ -7,6 +7,7 @@
7
7
  */
8
8
  const defaultOptions = {
9
9
  intAsBigInt: false,
10
+ keepSourceTokens: false,
10
11
  logLevel: 'warn',
11
12
  prettyErrors: true,
12
13
  strict: true,
@@ -3,10 +3,6 @@ import { resolveFlowScalar } from '../compose/resolve-flow-scalar.js';
3
3
  import { YAMLParseError } from '../errors.js';
4
4
  import { stringifyString } from '../stringify/stringifyString.js';
5
5
 
6
- /**
7
- * If `token` is a CST flow or block scalar, determine its string value and a few other attributes.
8
- * Otherwise, return `null`.
9
- */
10
6
  function resolveAsScalar(token, strict = true, onError) {
11
7
  if (token) {
12
8
  const _onError = (pos, code, message) => {
@@ -48,7 +44,7 @@ function createScalarToken(value, context) {
48
44
  implicitKey,
49
45
  indent: indent > 0 ? ' '.repeat(indent) : '',
50
46
  inFlow,
51
- options: { lineWidth: -1 }
47
+ options: { blockQuote: true, lineWidth: -1 }
52
48
  });
53
49
  const end = (_a = context.end) !== null && _a !== void 0 ? _a : [
54
50
  { type: 'newline', offset: -1, indent, source: '\n' }
@@ -117,7 +113,7 @@ function setScalarValue(token, value, context = {}) {
117
113
  implicitKey: implicitKey || indent === null,
118
114
  indent: indent !== null && indent > 0 ? ' '.repeat(indent) : '',
119
115
  inFlow,
120
- options: { lineWidth: -1 }
116
+ options: { blockQuote: true, lineWidth: -1 }
121
117
  });
122
118
  switch (source[0]) {
123
119
  case '|':
@@ -364,7 +364,7 @@ class Lexer {
364
364
  const line = this.getLine();
365
365
  if (line === null)
366
366
  return this.setNext('flow');
367
- if ((indent !== -1 && indent < this.indentNext) ||
367
+ if ((indent !== -1 && indent < this.indentNext && line[0] !== '#') ||
368
368
  (indent === 0 &&
369
369
  (line.startsWith('---') || line.startsWith('...')) &&
370
370
  isEmpty(line[3]))) {
@@ -382,8 +382,11 @@ class Lexer {
382
382
  }
383
383
  }
384
384
  let n = 0;
385
- while (line[n] === ',')
386
- n += (yield* this.pushCount(1)) + (yield* this.pushSpaces(true));
385
+ while (line[n] === ',') {
386
+ n += yield* this.pushCount(1);
387
+ n += yield* this.pushSpaces(true);
388
+ this.flowKey = false;
389
+ }
387
390
  n += yield* this.pushIndicators();
388
391
  switch (line[n]) {
389
392
  case undefined:
@@ -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)
@@ -85,14 +85,14 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
85
85
  const valueStr = stringify(value, ctx, () => (valueCommentDone = true), () => (chompKeep = true));
86
86
  let ws = ' ';
87
87
  if (vcb || keyComment) {
88
- ws = `${vcb}\n${ctx.indent}`;
88
+ ws = valueStr === '' && !ctx.inFlow ? vcb : `${vcb}\n${ctx.indent}`;
89
89
  }
90
90
  else if (!explicitKey && isCollection(value)) {
91
91
  const flow = valueStr[0] === '[' || valueStr[0] === '{';
92
92
  if (!flow || valueStr.includes('\n'))
93
93
  ws = `\n${ctx.indent}`;
94
94
  }
95
- else if (valueStr[0] === '\n')
95
+ else if (valueStr === '' || valueStr[0] === '\n')
96
96
  ws = '';
97
97
  if (ctx.inFlow) {
98
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';
@@ -45,6 +45,8 @@ function composeNode(ctx, token, props, onError) {
45
45
  else
46
46
  node.commentBefore = comment;
47
47
  }
48
+ if (ctx.options.keepSourceTokens)
49
+ node.srcToken = token;
48
50
  return node;
49
51
  }
50
52
  function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag }, onError) {
@@ -11,7 +11,8 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
11
11
  var _a;
12
12
  const map = new YAMLMap.YAMLMap(ctx.schema);
13
13
  let offset = bm.offset;
14
- for (const { start, key, sep, value } of bm.items) {
14
+ for (const collItem of bm.items) {
15
+ const { start, key, sep, value } = collItem;
15
16
  // key properties
16
17
  const keyProps = resolveProps.resolveProps(start, {
17
18
  indicator: 'explicit-key-ind',
@@ -73,7 +74,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
73
74
  ? composeNode(ctx, value, valueProps, onError)
74
75
  : composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
75
76
  offset = valueNode.range[2];
76
- 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);
77
81
  }
78
82
  else {
79
83
  // key with no value
@@ -85,7 +89,10 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
85
89
  else
86
90
  keyNode.comment = valueProps.comment;
87
91
  }
88
- 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);
89
96
  }
90
97
  }
91
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;
@@ -20,7 +20,8 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
20
20
  coll.flow = true;
21
21
  let offset = fc.offset;
22
22
  for (let i = 0; i < fc.items.length; ++i) {
23
- const { start, key, sep, value } = fc.items[i];
23
+ const collItem = fc.items[i];
24
+ const { start, key, sep, value } = collItem;
24
25
  const props = resolveProps.resolveProps(start, {
25
26
  flow: fcName,
26
27
  indicator: 'explicit-key-ind',
@@ -147,6 +148,8 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
147
148
  keyNode.comment = valueProps.comment;
148
149
  }
149
150
  const pair = new Pair.Pair(keyNode, valueNode);
151
+ if (ctx.options.keepSourceTokens)
152
+ pair.srcToken = collItem;
150
153
  if (isMap) {
151
154
  const map = coll;
152
155
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export { Composer } from './compose/composer.js';
2
2
  export { Document } from './doc/Document.js';
3
3
  export { Schema } from './schema/Schema.js';
4
- export { YAMLError, YAMLParseError, YAMLWarning } from './errors.js';
4
+ export { ErrorCode, YAMLError, YAMLParseError, YAMLWarning } from './errors.js';
5
5
  export { Alias } from './nodes/Alias.js';
6
- export { isAlias, isCollection, isDocument, isMap, isNode, isPair, isScalar, isSeq, Node, ParsedNode } from './nodes/Node.js';
6
+ export { isAlias, isCollection, isDocument, isMap, isNode, isPair, isScalar, isSeq, Node, ParsedNode, Range } from './nodes/Node.js';
7
7
  export { Pair } from './nodes/Pair.js';
8
8
  export { Scalar } from './nodes/Scalar.js';
9
9
  export { YAMLMap } from './nodes/YAMLMap.js';
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ /*! *****************************************************************************
4
+ Copyright (c) Microsoft Corporation.
5
+
6
+ Permission to use, copy, modify, and/or distribute this software for any
7
+ purpose with or without fee is hereby granted.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
16
+ ***************************************************************************** */
17
+ /* global Reflect, Promise */
18
+
19
+ var extendStatics = function(d, b) {
20
+ extendStatics = Object.setPrototypeOf ||
21
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
22
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
23
+ return extendStatics(d, b);
24
+ };
25
+
26
+ function __extends(d, b) {
27
+ if (typeof b !== "function" && b !== null)
28
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
29
+ extendStatics(d, b);
30
+ function __() { this.constructor = d; }
31
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
32
+ }
33
+
34
+ function __generator(thisArg, body) {
35
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
36
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
37
+ function verb(n) { return function (v) { return step([n, v]); }; }
38
+ function step(op) {
39
+ if (f) throw new TypeError("Generator is already executing.");
40
+ while (_) try {
41
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
42
+ if (y = 0, t) op = [op[0] & 2, t.value];
43
+ switch (op[0]) {
44
+ case 0: case 1: t = op; break;
45
+ case 4: _.label++; return { value: op[1], done: false };
46
+ case 5: _.label++; y = op[1]; op = [0]; continue;
47
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
48
+ default:
49
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
50
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
51
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
52
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
53
+ if (t[2]) _.ops.pop();
54
+ _.trys.pop(); continue;
55
+ }
56
+ op = body.call(thisArg, _);
57
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
58
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
+ }
60
+ }
61
+
62
+ function __values(o) {
63
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
64
+ if (m) return m.call(o);
65
+ if (o && typeof o.length === "number") return {
66
+ next: function () {
67
+ if (o && i >= o.length) o = void 0;
68
+ return { value: o && o[i++], done: !o };
69
+ }
70
+ };
71
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
72
+ }
73
+
74
+ exports.__extends = __extends;
75
+ exports.__generator = __generator;
76
+ exports.__values = __values;
@@ -1,13 +1,17 @@
1
- import type { Document } from '../doc/Document';
1
+ import type { Document } from '../doc/Document.js';
2
+ import type { FlowScalar } from '../parse/cst.js';
2
3
  import type { StringifyContext } from '../stringify/stringify.js';
3
4
  import { NodeBase, Range } from './Node.js';
4
5
  import type { Scalar } from './Scalar';
5
6
  import type { ToJSContext } from './toJS.js';
6
- import type { YAMLMap } from './YAMLMap';
7
- import type { YAMLSeq } from './YAMLSeq';
7
+ import type { YAMLMap } from './YAMLMap.js';
8
+ import type { YAMLSeq } from './YAMLSeq.js';
8
9
  export declare namespace Alias {
9
10
  interface Parsed extends Alias {
10
11
  range: Range;
12
+ srcToken?: FlowScalar & {
13
+ type: 'alias';
14
+ };
11
15
  }
12
16
  }
13
17
  export declare class Alias extends NodeBase {
@@ -53,21 +53,21 @@ export declare abstract class Collection extends NodeBase {
53
53
  * Removes a value from the collection.
54
54
  * @returns `true` if the item was found and removed.
55
55
  */
56
- deleteIn([key, ...rest]: Iterable<unknown>): boolean;
56
+ deleteIn(path: Iterable<unknown>): boolean;
57
57
  /**
58
58
  * Returns item at `key`, or `undefined` if not found. By default unwraps
59
59
  * scalar values from their surrounding node; to disable set `keepScalar` to
60
60
  * `true` (collections are always returned intact).
61
61
  */
62
- getIn([key, ...rest]: Iterable<unknown>, keepScalar?: boolean): unknown;
62
+ getIn(path: Iterable<unknown>, keepScalar?: boolean): unknown;
63
63
  hasAllNullValues(allowScalar?: boolean): boolean;
64
64
  /**
65
65
  * Checks if the collection includes a value with the key `key`.
66
66
  */
67
- hasIn([key, ...rest]: Iterable<unknown>): boolean;
67
+ hasIn(path: Iterable<unknown>): boolean;
68
68
  /**
69
69
  * Sets a value in this collection. For `!!set`, `value` needs to be a
70
70
  * boolean to add/remove the item from the set.
71
71
  */
72
- setIn([key, ...rest]: Iterable<unknown>, value: unknown): void;
72
+ setIn(path: Iterable<unknown>, value: unknown): void;
73
73
  }
@@ -76,7 +76,8 @@ class Collection extends Node.NodeBase {
76
76
  * Removes a value from the collection.
77
77
  * @returns `true` if the item was found and removed.
78
78
  */
79
- deleteIn([key, ...rest]) {
79
+ deleteIn(path) {
80
+ const [key, ...rest] = path;
80
81
  if (rest.length === 0)
81
82
  return this.delete(key);
82
83
  const node = this.get(key, true);
@@ -90,7 +91,8 @@ class Collection extends Node.NodeBase {
90
91
  * scalar values from their surrounding node; to disable set `keepScalar` to
91
92
  * `true` (collections are always returned intact).
92
93
  */
93
- getIn([key, ...rest], keepScalar) {
94
+ getIn(path, keepScalar) {
95
+ const [key, ...rest] = path;
94
96
  const node = this.get(key, true);
95
97
  if (rest.length === 0)
96
98
  return !keepScalar && Node.isScalar(node) ? node.value : node;
@@ -114,7 +116,8 @@ class Collection extends Node.NodeBase {
114
116
  /**
115
117
  * Checks if the collection includes a value with the key `key`.
116
118
  */
117
- hasIn([key, ...rest]) {
119
+ hasIn(path) {
120
+ const [key, ...rest] = path;
118
121
  if (rest.length === 0)
119
122
  return this.has(key);
120
123
  const node = this.get(key, true);
@@ -124,7 +127,8 @@ class Collection extends Node.NodeBase {
124
127
  * Sets a value in this collection. For `!!set`, `value` needs to be a
125
128
  * boolean to add/remove the item from the set.
126
129
  */
127
- setIn([key, ...rest], value) {
130
+ setIn(path, value) {
131
+ const [key, ...rest] = path;
128
132
  if (rest.length === 0) {
129
133
  this.set(key, value);
130
134
  }
@@ -1,4 +1,5 @@
1
1
  import type { Document } from '../doc/Document.js';
2
+ import { Token } from '../parse/cst.js';
2
3
  import type { StringifyContext } from '../stringify/stringify.js';
3
4
  import type { Alias } from './Alias.js';
4
5
  import type { Pair } from './Pair.js';
@@ -39,6 +40,8 @@ export declare abstract class NodeBase {
39
40
  range?: Range | null;
40
41
  /** A blank line before this node and its commentBefore */
41
42
  spaceBefore?: boolean;
43
+ /** The CST token that was composed into this node. */
44
+ srcToken?: Token;
42
45
  /** A fully qualified tag, if required */
43
46
  tag?: string;
44
47
  /** A plain JS representation of this node */
@@ -1,4 +1,5 @@
1
1
  import { CreateNodeContext } from '../doc/createNode.js';
2
+ import type { CollectionItem } from '../parse/cst.js';
2
3
  import type { Schema } from '../schema/Schema.js';
3
4
  import type { StringifyContext } from '../stringify/stringify.js';
4
5
  import { addPairToJSMap } from './addPairToJSMap.js';
@@ -11,6 +12,8 @@ export declare class Pair<K = unknown, V = unknown> {
11
12
  key: K;
12
13
  /** Always Node or null when parsed, but can be set to anything. */
13
14
  value: V | null;
15
+ /** The CST token that was composed into this pair. */
16
+ srcToken?: CollectionItem;
14
17
  constructor(key: K, value?: V | null);
15
18
  clone(schema?: Schema): Pair<K, V>;
16
19
  toJSON(_?: unknown, ctx?: ToJSContext): ReturnType<typeof addPairToJSMap>;
@@ -1,3 +1,4 @@
1
+ import type { BlockScalar, FlowScalar } from '../parse/cst.js';
1
2
  import { NodeBase, Range } from './Node.js';
2
3
  import { ToJSContext } from './toJS.js';
3
4
  export declare const isScalarValue: (value: unknown) => boolean;
@@ -5,6 +6,7 @@ export declare namespace Scalar {
5
6
  interface Parsed extends Scalar {
6
7
  range: Range;
7
8
  source: string;
9
+ srcToken?: FlowScalar | BlockScalar;
8
10
  }
9
11
  type BLOCK_FOLDED = 'BLOCK_FOLDED';
10
12
  type BLOCK_LITERAL = 'BLOCK_LITERAL';
@@ -1,3 +1,4 @@
1
+ import type { BlockMap, FlowCollection } from '../parse/cst.js';
1
2
  import type { Schema } from '../schema/Schema.js';
2
3
  import type { StringifyContext } from '../stringify/stringify.js';
3
4
  import { Collection } from './Collection.js';
@@ -9,6 +10,7 @@ export declare namespace YAMLMap {
9
10
  interface Parsed<K extends ParsedNode = ParsedNode, V extends ParsedNode | null = ParsedNode | null> extends YAMLMap<K, V> {
10
11
  items: Pair<K, V>[];
11
12
  range: Range;
13
+ srcToken?: BlockMap | FlowCollection;
12
14
  }
13
15
  }
14
16
  export declare class YAMLMap<K = unknown, V = unknown> extends Collection {
@@ -1,3 +1,4 @@
1
+ import type { BlockSequence, FlowCollection } from '../parse/cst.js';
1
2
  import type { Schema } from '../schema/Schema.js';
2
3
  import type { StringifyContext } from '../stringify/stringify.js';
3
4
  import { Collection } from './Collection.js';
@@ -8,6 +9,7 @@ export declare namespace YAMLSeq {
8
9
  interface Parsed<T extends ParsedNode | Pair<ParsedNode, ParsedNode | null> = ParsedNode> extends YAMLSeq<T> {
9
10
  items: T[];
10
11
  range: Range;
12
+ srcToken?: BlockSequence | FlowCollection;
11
13
  }
12
14
  }
13
15
  export declare class YAMLSeq<T = unknown> extends Collection {
@@ -9,6 +9,7 @@ var toJS = require('./toJS.js');
9
9
  const MERGE_KEY = '<<';
10
10
  function addPairToJSMap(ctx, map, { key, value }) {
11
11
  if (ctx && ctx.doc.schema.merge && isMergeKey(key)) {
12
+ value = Node.isAlias(value) ? value.resolve(ctx.doc) : value;
12
13
  if (Node.isSeq(value))
13
14
  for (const it of value.items)
14
15
  mergeToJSMap(ctx, map, it);
package/dist/options.d.ts CHANGED
@@ -17,6 +17,13 @@ export declare type ParseOptions = {
17
17
  * https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/BigInt
18
18
  */
19
19
  intAsBigInt?: boolean;
20
+ /**
21
+ * Include a `srcToken` value on each parsed `Node`, containing the CST token
22
+ * that was composed into this node.
23
+ *
24
+ * Default: `false`
25
+ */
26
+ keepSourceTokens?: boolean;
20
27
  /**
21
28
  * If set, newlines will be tracked, to allow for `lineCounter.linePos(offset)`
22
29
  * to provide the `{ line, col }` positions within the input.
@@ -161,6 +168,13 @@ export declare type ToJSOptions = {
161
168
  reviver?: Reviver;
162
169
  };
163
170
  export declare type ToStringOptions = {
171
+ /**
172
+ * Use block quote styles for scalar values where applicable.
173
+ * Set to `false` to disable block quotes completely.
174
+ *
175
+ * Default: `true`
176
+ */
177
+ blockQuote?: boolean | 'folded' | 'literal';
164
178
  /**
165
179
  * The default type of string literal used to stringify implicit key values.
166
180
  * Output may use other types if required to fully represent the value.
@@ -254,11 +268,12 @@ export declare type ToStringOptions = {
254
268
  */
255
269
  simpleKeys?: boolean;
256
270
  /**
257
- * Prefer 'single quote' rather than "double quote" where applicable.
271
+ * Use 'single quote' rather than "double quote" where applicable.
272
+ * Set to `false` to disable single quotes completely.
258
273
  *
259
- * Default: `false`
274
+ * Default: `null`
260
275
  */
261
- singleQuote?: boolean;
276
+ singleQuote?: boolean | null;
262
277
  /**
263
278
  * String representation for `true`.
264
279
  * With the core schema, use `'true'`, `'True'`, or `'TRUE'`.
package/dist/options.js CHANGED
@@ -9,6 +9,7 @@
9
9
  */
10
10
  const defaultOptions = {
11
11
  intAsBigInt: false,
12
+ keepSourceTokens: false,
12
13
  logLevel: 'warn',
13
14
  prettyErrors: true,
14
15
  strict: true,
@@ -6,6 +6,12 @@ import type { BlockScalar, FlowScalar, SourceToken, Token } from './cst.js';
6
6
  * If `token` is a CST flow or block scalar, determine its string value and a few other attributes.
7
7
  * Otherwise, return `null`.
8
8
  */
9
+ export declare function resolveAsScalar(token: FlowScalar | BlockScalar, strict?: boolean, onError?: (offset: number, code: ErrorCode, message: string) => void): {
10
+ value: string;
11
+ type: Scalar.Type | null;
12
+ comment: string;
13
+ range: Range;
14
+ };
9
15
  export declare function resolveAsScalar(token: Token | null | undefined, strict?: boolean, onError?: (offset: number, code: ErrorCode, message: string) => void): {
10
16
  value: string;
11
17
  type: Scalar.Type | null;
@@ -5,10 +5,6 @@ var resolveFlowScalar = require('../compose/resolve-flow-scalar.js');
5
5
  var errors = require('../errors.js');
6
6
  var stringifyString = require('../stringify/stringifyString.js');
7
7
 
8
- /**
9
- * If `token` is a CST flow or block scalar, determine its string value and a few other attributes.
10
- * Otherwise, return `null`.
11
- */
12
8
  function resolveAsScalar(token, strict = true, onError) {
13
9
  if (token) {
14
10
  const _onError = (pos, code, message) => {
@@ -50,7 +46,7 @@ function createScalarToken(value, context) {
50
46
  implicitKey,
51
47
  indent: indent > 0 ? ' '.repeat(indent) : '',
52
48
  inFlow,
53
- options: { lineWidth: -1 }
49
+ options: { blockQuote: true, lineWidth: -1 }
54
50
  });
55
51
  const end = (_a = context.end) !== null && _a !== void 0 ? _a : [
56
52
  { type: 'newline', offset: -1, indent, source: '\n' }
@@ -119,7 +115,7 @@ function setScalarValue(token, value, context = {}) {
119
115
  implicitKey: implicitKey || indent === null,
120
116
  indent: indent !== null && indent > 0 ? ' '.repeat(indent) : '',
121
117
  inFlow,
122
- options: { lineWidth: -1 }
118
+ options: { blockQuote: true, lineWidth: -1 }
123
119
  });
124
120
  switch (source[0]) {
125
121
  case '|':
@@ -366,7 +366,7 @@ class Lexer {
366
366
  const line = this.getLine();
367
367
  if (line === null)
368
368
  return this.setNext('flow');
369
- if ((indent !== -1 && indent < this.indentNext) ||
369
+ if ((indent !== -1 && indent < this.indentNext && line[0] !== '#') ||
370
370
  (indent === 0 &&
371
371
  (line.startsWith('---') || line.startsWith('...')) &&
372
372
  isEmpty(line[3]))) {
@@ -384,8 +384,11 @@ class Lexer {
384
384
  }
385
385
  }
386
386
  let n = 0;
387
- while (line[n] === ',')
388
- n += (yield* this.pushCount(1)) + (yield* this.pushSpaces(true));
387
+ while (line[n] === ',') {
388
+ n += yield* this.pushCount(1);
389
+ n += yield* this.pushSpaces(true);
390
+ this.flowKey = false;
391
+ }
389
392
  n += yield* this.pushIndicators();
390
393
  switch (line[n]) {
391
394
  case undefined:
@@ -52,11 +52,15 @@ const coreKnownTags = {
52
52
  function getTags(customTags, schemaName) {
53
53
  let tags = schemas[schemaName];
54
54
  if (!tags) {
55
- const keys = Object.keys(schemas)
56
- .filter(key => key !== 'yaml11')
57
- .map(key => JSON.stringify(key))
58
- .join(', ');
59
- throw new Error(`Unknown schema "${schemaName}"; use one of ${keys}`);
55
+ if (Array.isArray(customTags))
56
+ tags = [];
57
+ else {
58
+ const keys = Object.keys(schemas)
59
+ .filter(key => key !== 'yaml11')
60
+ .map(key => JSON.stringify(key))
61
+ .join(', ');
62
+ throw new Error(`Unknown schema "${schemaName}"; use one of ${keys} or define customTags array`);
63
+ }
60
64
  }
61
65
  if (Array.isArray(customTags)) {
62
66
  for (const tag of customTags)
@@ -10,6 +10,7 @@ const createStringifyContext = (doc, options) => ({
10
10
  indent: '',
11
11
  indentStep: typeof options.indent === 'number' ? ' '.repeat(options.indent) : ' ',
12
12
  options: Object.assign({
13
+ blockQuote: true,
13
14
  defaultKeyType: null,
14
15
  defaultStringType: 'PLAIN',
15
16
  directives: null,
@@ -21,7 +22,7 @@ const createStringifyContext = (doc, options) => ({
21
22
  minContentWidth: 20,
22
23
  nullStr: 'null',
23
24
  simpleKeys: false,
24
- singleQuote: false,
25
+ singleQuote: null,
25
26
  trueStr: 'true',
26
27
  verifyAliasOrder: true
27
28
  }, options)
@@ -87,14 +87,14 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
87
87
  const valueStr = stringify.stringify(value, ctx, () => (valueCommentDone = true), () => (chompKeep = true));
88
88
  let ws = ' ';
89
89
  if (vcb || keyComment) {
90
- ws = `${vcb}\n${ctx.indent}`;
90
+ ws = valueStr === '' && !ctx.inFlow ? vcb : `${vcb}\n${ctx.indent}`;
91
91
  }
92
92
  else if (!explicitKey && Node.isCollection(value)) {
93
93
  const flow = valueStr[0] === '[' || valueStr[0] === '{';
94
94
  if (!flow || valueStr.includes('\n'))
95
95
  ws = `\n${ctx.indent}`;
96
96
  }
97
- else if (valueStr[0] === '\n')
97
+ else if (valueStr === '' || valueStr[0] === '\n')
98
98
  ws = '';
99
99
  if (ctx.inFlow) {
100
100
  if (valueCommentDone && onComment)
@@ -120,34 +120,50 @@ function doubleQuotedString(value, ctx) {
120
120
  : foldFlowLines.foldFlowLines(str, indent, foldFlowLines.FOLD_QUOTED, getFoldOptions(ctx));
121
121
  }
122
122
  function singleQuotedString(value, ctx) {
123
- if (ctx.implicitKey) {
124
- if (/\n/.test(value))
125
- return doubleQuotedString(value, ctx);
126
- }
127
- else {
128
- // single quoted string can't have leading or trailing whitespace around newline
129
- if (/[ \t]\n|\n[ \t]/.test(value))
130
- return doubleQuotedString(value, ctx);
131
- }
123
+ if (ctx.options.singleQuote === false ||
124
+ (ctx.implicitKey && value.includes('\n')) ||
125
+ /[ \t]\n|\n[ \t]/.test(value) // single quoted string can't have leading or trailing whitespace around newline
126
+ )
127
+ return doubleQuotedString(value, ctx);
132
128
  const indent = ctx.indent || (containsDocumentMarker(value) ? ' ' : '');
133
129
  const res = "'" + value.replace(/'/g, "''").replace(/\n+/g, `$&\n${indent}`) + "'";
134
130
  return ctx.implicitKey
135
131
  ? res
136
132
  : foldFlowLines.foldFlowLines(res, indent, foldFlowLines.FOLD_FLOW, getFoldOptions(ctx));
137
133
  }
134
+ function quotedString(value, ctx) {
135
+ const { singleQuote } = ctx.options;
136
+ let qs;
137
+ if (singleQuote === false)
138
+ qs = doubleQuotedString;
139
+ else {
140
+ const hasDouble = value.includes('"');
141
+ const hasSingle = value.includes("'");
142
+ if (hasDouble && !hasSingle)
143
+ qs = singleQuotedString;
144
+ else if (hasSingle && !hasDouble)
145
+ qs = doubleQuotedString;
146
+ else
147
+ qs = singleQuote ? singleQuotedString : doubleQuotedString;
148
+ }
149
+ return qs(value, ctx);
150
+ }
138
151
  function blockString({ comment, type, value }, ctx, onComment, onChompKeep) {
152
+ const { lineWidth, blockQuote } = ctx.options;
139
153
  // 1. Block can't end in whitespace unless the last line is non-empty.
140
154
  // 2. Strings consisting of only whitespace are best rendered explicitly.
141
- if (/\n[\t ]+$/.test(value) || /^\s*$/.test(value)) {
142
- return doubleQuotedString(value, ctx);
155
+ if (!blockQuote || /\n[\t ]+$/.test(value) || /^\s*$/.test(value)) {
156
+ return quotedString(value, ctx);
143
157
  }
144
158
  const indent = ctx.indent ||
145
159
  (ctx.forceBlockIndent || containsDocumentMarker(value) ? ' ' : '');
146
- const literal = type === Scalar.Scalar.BLOCK_FOLDED
147
- ? false
148
- : type === Scalar.Scalar.BLOCK_LITERAL
149
- ? true
150
- : !lineLengthOverLimit(value, ctx.options.lineWidth, indent.length);
160
+ const literal = blockQuote === 'literal'
161
+ ? true
162
+ : blockQuote === 'folded' || type === Scalar.Scalar.BLOCK_FOLDED
163
+ ? false
164
+ : type === Scalar.Scalar.BLOCK_LITERAL
165
+ ? true
166
+ : !lineLengthOverLimit(value, lineWidth, indent.length);
151
167
  if (!value)
152
168
  return literal ? '|\n' : '>\n';
153
169
  // determine chomping from whitespace at value end
@@ -220,25 +236,10 @@ function plainString(item, ctx, onComment, onChompKeep) {
220
236
  const { actualString, implicitKey, indent, inFlow } = ctx;
221
237
  if ((implicitKey && /[\n[\]{},]/.test(value)) ||
222
238
  (inFlow && /[[\]{},]/.test(value))) {
223
- return doubleQuotedString(value, ctx);
239
+ return quotedString(value, ctx);
224
240
  }
225
241
  if (!value ||
226
242
  /^[\n\t ,[\]{}#&*!|>'"%@`]|^[?-]$|^[?-][ \t]|[\n:][ \t]|[ \t]\n|[\n\t ]#|[\n\t :]$/.test(value)) {
227
- const hasDouble = value.indexOf('"') !== -1;
228
- const hasSingle = value.indexOf("'") !== -1;
229
- let quotedString;
230
- if (hasDouble && !hasSingle) {
231
- quotedString = singleQuotedString;
232
- }
233
- else if (hasSingle && !hasDouble) {
234
- quotedString = doubleQuotedString;
235
- }
236
- else if (ctx.options.singleQuote) {
237
- quotedString = singleQuotedString;
238
- }
239
- else {
240
- quotedString = doubleQuotedString;
241
- }
242
243
  // not allowed:
243
244
  // - empty string, '-' or '?'
244
245
  // - start with an indicator character (except [?:-]) or /[?-] /
@@ -269,7 +270,7 @@ function plainString(item, ctx, onComment, onChompKeep) {
269
270
  if (tag.default &&
270
271
  tag.tag !== 'tag:yaml.org,2002:str' &&
271
272
  ((_a = tag.test) === null || _a === void 0 ? void 0 : _a.test(str)))
272
- return doubleQuotedString(value, ctx);
273
+ return quotedString(value, ctx);
273
274
  }
274
275
  }
275
276
  return implicitKey
@@ -292,7 +293,7 @@ function stringifyString(item, ctx, onComment, onChompKeep) {
292
293
  case Scalar.Scalar.BLOCK_FOLDED:
293
294
  case Scalar.Scalar.BLOCK_LITERAL:
294
295
  return implicitKey || inFlow
295
- ? doubleQuotedString(ss.value, ctx) // blocks are not valid inside flow containers
296
+ ? quotedString(ss.value, ctx) // blocks are not valid inside flow containers
296
297
  : blockString(ss, ctx, onComment, onChompKeep);
297
298
  case Scalar.Scalar.QUOTE_DOUBLE:
298
299
  return doubleQuotedString(ss.value, ctx);
@@ -1,4 +1,4 @@
1
1
  export declare function testEvents(src: string): {
2
2
  events: string[];
3
- error: any;
3
+ error: unknown;
4
4
  };
package/dist/util.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export { debug, LogLevelId, warn } from './log.js';
2
2
  export { findPair } from './nodes/YAMLMap.js';
3
3
  export { toJS, ToJSContext } 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';
5
8
  export { stringifyNumber } from './stringify/stringifyNumber.js';
6
9
  export { stringifyString } from './stringify/stringifyString.js';
package/dist/util.js CHANGED
@@ -3,6 +3,9 @@
3
3
  var log = require('./log.js');
4
4
  var YAMLMap = require('./nodes/YAMLMap.js');
5
5
  var toJS = require('./nodes/toJS.js');
6
+ var map = require('./schema/common/map.js');
7
+ var seq = require('./schema/common/seq.js');
8
+ var string = require('./schema/common/string.js');
6
9
  var foldFlowLines = require('./stringify/foldFlowLines.js');
7
10
  var stringifyNumber = require('./stringify/stringifyNumber.js');
8
11
  var stringifyString = require('./stringify/stringifyString.js');
@@ -13,6 +16,9 @@ exports.debug = log.debug;
13
16
  exports.warn = log.warn;
14
17
  exports.findPair = YAMLMap.findPair;
15
18
  exports.toJS = toJS.toJS;
19
+ exports.mapTag = map.map;
20
+ exports.seqTag = seq.seq;
21
+ exports.stringTag = string.string;
16
22
  exports.foldFlowLines = foldFlowLines.foldFlowLines;
17
23
  exports.stringifyNumber = stringifyNumber.stringifyNumber;
18
24
  exports.stringifyString = stringifyString.stringifyString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaml",
3
- "version": "2.0.0-8",
3
+ "version": "2.0.0-9",
4
4
  "license": "ISC",
5
5
  "author": "Eemeli Aro <eemeli@gmail.com>",
6
6
  "repository": "github:eemeli/yaml",
@@ -14,6 +14,7 @@
14
14
  "files": [
15
15
  "browser/",
16
16
  "dist/",
17
+ "util.d.ts",
17
18
  "util.js"
18
19
  ],
19
20
  "type": "commonjs",
@@ -68,10 +69,10 @@
68
69
  "@babel/plugin-transform-typescript": "^7.12.17",
69
70
  "@babel/preset-env": "^7.12.11",
70
71
  "@rollup/plugin-babel": "^5.2.3",
71
- "@rollup/plugin-replace": "^2.3.4",
72
+ "@rollup/plugin-replace": "^3.0.0",
72
73
  "@rollup/plugin-typescript": "^8.1.1",
73
74
  "@types/jest": "^27.0.1",
74
- "@types/node": "^15.6.1",
75
+ "@types/node": "^16.9.1",
75
76
  "@typescript-eslint/eslint-plugin": "^4.15.2",
76
77
  "@typescript-eslint/parser": "^4.15.2",
77
78
  "babel-jest": "^27.0.1",
package/util.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ // Workaround for incomplete exports support in TypeScript
2
+ // https://github.com/microsoft/TypeScript/issues/33079
3
+ export * from './dist/util.js'