yaml 2.0.0-4 → 2.0.0-8

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 (220) hide show
  1. package/README.md +5 -5
  2. package/browser/dist/compose/compose-collection.js +12 -9
  3. package/browser/dist/compose/compose-doc.js +23 -6
  4. package/browser/dist/compose/compose-node.js +27 -17
  5. package/browser/dist/compose/compose-scalar.js +21 -23
  6. package/browser/dist/compose/composer.js +108 -78
  7. package/browser/dist/compose/resolve-block-map.js +41 -29
  8. package/browser/dist/compose/resolve-block-scalar.js +14 -17
  9. package/browser/dist/compose/resolve-block-seq.js +21 -17
  10. package/browser/dist/compose/resolve-end.js +7 -8
  11. package/browser/dist/compose/resolve-flow-collection.js +158 -199
  12. package/browser/dist/compose/resolve-flow-scalar.js +62 -26
  13. package/browser/dist/compose/resolve-props.js +72 -37
  14. package/browser/dist/compose/util-contains-newline.js +15 -12
  15. package/browser/dist/compose/util-map-includes.js +17 -0
  16. package/browser/dist/doc/Document.js +74 -99
  17. package/browser/dist/doc/anchors.js +72 -0
  18. package/browser/dist/doc/createNode.js +35 -19
  19. package/browser/dist/doc/directives.js +5 -0
  20. package/browser/dist/errors.js +16 -12
  21. package/browser/dist/index.js +3 -3
  22. package/browser/dist/nodes/Alias.js +51 -28
  23. package/browser/dist/nodes/Collection.js +23 -92
  24. package/browser/dist/nodes/Node.js +9 -1
  25. package/browser/dist/nodes/Pair.js +16 -231
  26. package/browser/dist/nodes/YAMLMap.js +8 -4
  27. package/browser/dist/nodes/YAMLSeq.js +7 -4
  28. package/browser/dist/nodes/addPairToJSMap.js +103 -0
  29. package/browser/dist/nodes/toJS.js +12 -10
  30. package/browser/dist/options.js +1 -2
  31. package/browser/dist/parse/cst-scalar.js +219 -0
  32. package/browser/dist/parse/cst-stringify.js +61 -0
  33. package/browser/dist/parse/cst-visit.js +97 -0
  34. package/{dist/parse/tokens.js → browser/dist/parse/cst.js} +12 -7
  35. package/browser/dist/parse/lexer.js +149 -125
  36. package/browser/dist/parse/parser.js +272 -196
  37. package/browser/dist/public-api.js +11 -14
  38. package/browser/dist/schema/Schema.js +28 -0
  39. package/browser/dist/{tags/failsafe → schema/common}/map.js +0 -0
  40. package/browser/dist/schema/common/null.js +13 -0
  41. package/browser/dist/{tags/failsafe → schema/common}/seq.js +1 -1
  42. package/browser/dist/{tags/failsafe → schema/common}/string.js +0 -0
  43. package/browser/dist/schema/core/bool.js +19 -0
  44. package/browser/dist/schema/core/float.js +40 -0
  45. package/browser/dist/schema/core/int.js +38 -0
  46. package/browser/dist/schema/core/schema.js +23 -0
  47. package/browser/dist/{tags/json.js → schema/json/schema.js} +5 -6
  48. package/browser/dist/schema/tags.js +79 -0
  49. package/browser/dist/{tags → schema}/yaml-1.1/binary.js +0 -0
  50. package/browser/dist/schema/yaml-1.1/bool.js +26 -0
  51. package/browser/dist/schema/yaml-1.1/float.js +43 -0
  52. package/browser/dist/schema/yaml-1.1/int.js +71 -0
  53. package/browser/dist/{tags → schema}/yaml-1.1/omap.js +0 -0
  54. package/browser/dist/{tags → schema}/yaml-1.1/pairs.js +9 -6
  55. package/browser/dist/schema/yaml-1.1/schema.js +37 -0
  56. package/browser/dist/{tags → schema}/yaml-1.1/set.js +0 -0
  57. package/browser/dist/{tags → schema}/yaml-1.1/timestamp.js +0 -0
  58. package/browser/dist/stringify/stringify.js +8 -6
  59. package/browser/dist/stringify/stringifyCollection.js +122 -0
  60. package/browser/dist/stringify/stringifyComment.js +14 -0
  61. package/browser/dist/stringify/stringifyDocument.js +64 -0
  62. package/browser/dist/stringify/stringifyPair.js +111 -0
  63. package/browser/dist/stringify/stringifyString.js +53 -52
  64. package/browser/dist/visit.js +20 -1
  65. package/dist/compose/compose-collection.d.ts +4 -4
  66. package/dist/compose/compose-collection.js +12 -9
  67. package/dist/compose/compose-doc.d.ts +4 -3
  68. package/dist/compose/compose-doc.js +23 -6
  69. package/dist/compose/compose-node.d.ts +15 -7
  70. package/dist/compose/compose-node.js +27 -17
  71. package/dist/compose/compose-scalar.d.ts +4 -3
  72. package/dist/compose/compose-scalar.js +20 -22
  73. package/dist/compose/composer.d.ts +28 -23
  74. package/dist/compose/composer.js +109 -79
  75. package/dist/compose/resolve-block-map.d.ts +5 -4
  76. package/dist/compose/resolve-block-map.js +41 -29
  77. package/dist/compose/resolve-block-scalar.d.ts +5 -3
  78. package/dist/compose/resolve-block-scalar.js +14 -17
  79. package/dist/compose/resolve-block-seq.d.ts +4 -4
  80. package/dist/compose/resolve-block-seq.js +21 -17
  81. package/dist/compose/resolve-end.d.ts +3 -2
  82. package/dist/compose/resolve-end.js +7 -8
  83. package/dist/compose/resolve-flow-collection.d.ts +4 -5
  84. package/dist/compose/resolve-flow-collection.js +157 -198
  85. package/dist/compose/resolve-flow-scalar.d.ts +5 -3
  86. package/dist/compose/resolve-flow-scalar.js +62 -26
  87. package/dist/compose/resolve-props.d.ts +16 -10
  88. package/dist/compose/resolve-props.js +72 -37
  89. package/dist/compose/util-contains-newline.d.ts +1 -1
  90. package/dist/compose/util-contains-newline.js +15 -12
  91. package/dist/compose/util-empty-scalar-position.d.ts +1 -1
  92. package/dist/compose/util-map-includes.d.ts +4 -0
  93. package/dist/compose/util-map-includes.js +19 -0
  94. package/dist/doc/Document.d.ts +35 -15
  95. package/dist/doc/Document.js +72 -97
  96. package/dist/doc/anchors.d.ts +24 -0
  97. package/dist/doc/anchors.js +77 -0
  98. package/dist/doc/createNode.d.ts +10 -11
  99. package/dist/doc/createNode.js +34 -18
  100. package/dist/doc/directives.d.ts +1 -0
  101. package/dist/doc/directives.js +5 -0
  102. package/dist/errors.d.ts +11 -8
  103. package/dist/errors.js +16 -12
  104. package/dist/index.d.ts +5 -3
  105. package/dist/index.js +3 -3
  106. package/dist/nodes/Alias.d.ts +19 -9
  107. package/dist/nodes/Alias.js +51 -28
  108. package/dist/nodes/Collection.d.ts +9 -17
  109. package/dist/nodes/Collection.js +22 -91
  110. package/dist/nodes/Node.d.ts +10 -4
  111. package/dist/nodes/Node.js +9 -0
  112. package/dist/nodes/Pair.d.ts +10 -13
  113. package/dist/nodes/Pair.js +15 -230
  114. package/dist/nodes/Scalar.d.ts +6 -3
  115. package/dist/nodes/YAMLMap.d.ts +3 -3
  116. package/dist/nodes/YAMLMap.js +8 -4
  117. package/dist/nodes/YAMLSeq.d.ts +3 -3
  118. package/dist/nodes/YAMLSeq.js +7 -4
  119. package/dist/nodes/addPairToJSMap.d.ts +3 -0
  120. package/dist/nodes/addPairToJSMap.js +105 -0
  121. package/dist/nodes/toJS.d.ts +4 -5
  122. package/dist/nodes/toJS.js +12 -10
  123. package/dist/options.d.ts +41 -25
  124. package/dist/options.js +1 -2
  125. package/dist/parse/cst-scalar.d.ts +58 -0
  126. package/dist/parse/cst-scalar.js +223 -0
  127. package/dist/parse/cst-stringify.d.ts +8 -0
  128. package/dist/parse/cst-stringify.js +63 -0
  129. package/dist/parse/cst-visit.d.ts +39 -0
  130. package/dist/parse/cst-visit.js +99 -0
  131. package/dist/parse/{tokens.d.ts → cst.d.ts} +23 -7
  132. package/{browser/dist/parse/tokens.js → dist/parse/cst.js} +27 -1
  133. package/dist/parse/lexer.d.ts +7 -14
  134. package/dist/parse/lexer.js +150 -126
  135. package/dist/parse/parser.d.ts +31 -24
  136. package/dist/parse/parser.js +274 -198
  137. package/dist/public-api.d.ts +7 -7
  138. package/dist/public-api.js +11 -14
  139. package/dist/{doc → schema}/Schema.d.ts +6 -3
  140. package/dist/schema/Schema.js +30 -0
  141. package/dist/{tags/failsafe → schema/common}/map.d.ts +0 -0
  142. package/dist/{tags/failsafe → schema/common}/map.js +0 -0
  143. package/dist/schema/common/null.d.ts +4 -0
  144. package/dist/schema/common/null.js +15 -0
  145. package/dist/{tags/failsafe → schema/common}/seq.d.ts +0 -0
  146. package/dist/{tags/failsafe → schema/common}/seq.js +1 -1
  147. package/dist/{tags/failsafe → schema/common}/string.d.ts +0 -0
  148. package/dist/{tags/failsafe → schema/common}/string.js +0 -0
  149. package/dist/schema/core/bool.d.ts +4 -0
  150. package/dist/schema/core/bool.js +21 -0
  151. package/dist/schema/core/float.d.ts +4 -0
  152. package/dist/schema/core/float.js +44 -0
  153. package/dist/schema/core/int.d.ts +4 -0
  154. package/dist/schema/core/int.js +42 -0
  155. package/dist/schema/core/schema.d.ts +1 -0
  156. package/dist/schema/core/schema.js +25 -0
  157. package/dist/schema/json/schema.d.ts +2 -0
  158. package/dist/{tags/json.js → schema/json/schema.js} +5 -6
  159. package/dist/schema/tags.d.ts +41 -0
  160. package/dist/schema/tags.js +82 -0
  161. package/dist/{tags → schema}/types.d.ts +3 -7
  162. package/dist/{tags → schema}/yaml-1.1/binary.d.ts +0 -0
  163. package/dist/{tags → schema}/yaml-1.1/binary.js +0 -0
  164. package/dist/schema/yaml-1.1/bool.d.ts +7 -0
  165. package/dist/schema/yaml-1.1/bool.js +29 -0
  166. package/dist/schema/yaml-1.1/float.d.ts +4 -0
  167. package/dist/schema/yaml-1.1/float.js +47 -0
  168. package/dist/schema/yaml-1.1/int.d.ts +5 -0
  169. package/dist/schema/yaml-1.1/int.js +76 -0
  170. package/dist/{tags → schema}/yaml-1.1/omap.d.ts +0 -0
  171. package/dist/{tags → schema}/yaml-1.1/omap.js +0 -0
  172. package/dist/{tags → schema}/yaml-1.1/pairs.d.ts +3 -2
  173. package/dist/{tags → schema}/yaml-1.1/pairs.js +9 -6
  174. package/dist/schema/yaml-1.1/schema.d.ts +1 -0
  175. package/dist/schema/yaml-1.1/schema.js +39 -0
  176. package/dist/{tags → schema}/yaml-1.1/set.d.ts +1 -1
  177. package/dist/{tags → schema}/yaml-1.1/set.js +0 -0
  178. package/dist/{tags → schema}/yaml-1.1/timestamp.d.ts +0 -0
  179. package/dist/{tags → schema}/yaml-1.1/timestamp.js +0 -0
  180. package/dist/stringify/stringify.d.ts +1 -2
  181. package/dist/stringify/stringify.js +8 -6
  182. package/dist/stringify/stringifyCollection.d.ts +21 -0
  183. package/dist/stringify/stringifyCollection.js +124 -0
  184. package/dist/stringify/stringifyComment.d.ts +2 -0
  185. package/dist/stringify/stringifyComment.js +17 -0
  186. package/dist/stringify/stringifyDocument.d.ts +3 -0
  187. package/dist/stringify/stringifyDocument.js +66 -0
  188. package/dist/stringify/stringifyPair.d.ts +3 -0
  189. package/dist/stringify/stringifyPair.js +113 -0
  190. package/dist/stringify/stringifyString.js +53 -52
  191. package/dist/test-events.d.ts +1 -2
  192. package/dist/test-events.js +25 -12
  193. package/dist/util.d.ts +1 -1
  194. package/dist/visit.d.ts +10 -1
  195. package/dist/visit.js +20 -1
  196. package/package.json +9 -8
  197. package/browser/dist/doc/Anchors.js +0 -102
  198. package/browser/dist/doc/Schema.js +0 -27
  199. package/browser/dist/doc/getSchemaTags.js +0 -30
  200. package/browser/dist/stringify/addComment.js +0 -17
  201. package/browser/dist/tags/core.js +0 -109
  202. package/browser/dist/tags/failsafe/index.js +0 -7
  203. package/browser/dist/tags/index.js +0 -34
  204. package/browser/dist/tags/yaml-1.1/index.js +0 -152
  205. package/dist/doc/Anchors.d.ts +0 -36
  206. package/dist/doc/Anchors.js +0 -104
  207. package/dist/doc/Schema.js +0 -29
  208. package/dist/doc/getSchemaTags.d.ts +0 -3
  209. package/dist/doc/getSchemaTags.js +0 -32
  210. package/dist/stringify/addComment.d.ts +0 -2
  211. package/dist/stringify/addComment.js +0 -20
  212. package/dist/tags/core.d.ts +0 -14
  213. package/dist/tags/core.js +0 -119
  214. package/dist/tags/failsafe/index.d.ts +0 -1
  215. package/dist/tags/failsafe/index.js +0 -9
  216. package/dist/tags/index.d.ts +0 -31
  217. package/dist/tags/index.js +0 -37
  218. package/dist/tags/json.d.ts +0 -2
  219. package/dist/tags/yaml-1.1/index.d.ts +0 -2
  220. package/dist/tags/yaml-1.1/index.js +0 -154
@@ -1,229 +1,188 @@
1
- import { isNode, isPair } from '../nodes/Node.js';
1
+ import { isPair } from '../nodes/Node.js';
2
2
  import { Pair } from '../nodes/Pair.js';
3
3
  import { YAMLMap } from '../nodes/YAMLMap.js';
4
4
  import { YAMLSeq } from '../nodes/YAMLSeq.js';
5
5
  import { resolveEnd } from './resolve-end.js';
6
+ import { resolveProps } from './resolve-props.js';
6
7
  import { containsNewline } from './util-contains-newline.js';
8
+ import { mapIncludes } from './util-map-includes.js';
7
9
 
8
- function resolveFlowCollection({ composeNode, composeEmptyNode }, doc, fc, _anchor, onError) {
10
+ const blockMsg = 'Block collections are not allowed within flow collections';
11
+ const isBlock = (token) => token && (token.type === 'block-map' || token.type === 'block-seq');
12
+ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onError) {
9
13
  const isMap = fc.start.source === '{';
10
- const coll = isMap ? new YAMLMap(doc.schema) : new YAMLSeq(doc.schema);
14
+ const fcName = isMap ? 'flow map' : 'flow sequence';
15
+ const coll = isMap
16
+ ? new YAMLMap(ctx.schema)
17
+ : new YAMLSeq(ctx.schema);
11
18
  coll.flow = true;
12
- if (_anchor)
13
- doc.anchors.setAnchor(coll, _anchor);
14
- let key = null;
15
- let value = null;
16
- let spaceBefore = false;
17
- let comment = '';
18
- let hasSpace = false;
19
- let hasComment = false;
20
- let newlines = '';
21
- let anchor = '';
22
- let tagName = '';
23
- let offset = fc.offset + 1;
24
- let atLineStart = false;
25
- let atExplicitKey = false;
26
- let atValueEnd = false;
27
- let nlAfterValueInSeq = false;
28
- let seqKeyToken = null;
29
- function getProps() {
30
- const props = { spaceBefore, comment, anchor, tagName };
31
- spaceBefore = false;
32
- comment = '';
33
- hasComment = false;
34
- newlines = '';
35
- anchor = '';
36
- tagName = '';
37
- return props;
38
- }
39
- function addItem(pos) {
40
- if (value) {
41
- if (hasComment)
42
- value.comment = comment;
43
- }
44
- else {
45
- value = composeEmptyNode(doc, offset, fc.items, pos, getProps(), onError);
19
+ let offset = fc.offset;
20
+ for (let i = 0; i < fc.items.length; ++i) {
21
+ const { start, key, sep, value } = fc.items[i];
22
+ const props = resolveProps(start, {
23
+ flow: fcName,
24
+ indicator: 'explicit-key-ind',
25
+ next: key || (sep === null || sep === void 0 ? void 0 : sep[0]),
26
+ offset,
27
+ onError,
28
+ startOnNewline: false
29
+ });
30
+ if (!props.found) {
31
+ if (!props.anchor && !props.tag && !sep && !value) {
32
+ if (i === 0 && props.comma)
33
+ onError(props.comma, 'UNEXPECTED_TOKEN', `Unexpected , in ${fcName}`);
34
+ else if (i < fc.items.length - 1)
35
+ onError(props.start, 'UNEXPECTED_TOKEN', `Unexpected empty item in ${fcName}`);
36
+ if (props.comment) {
37
+ if (coll.comment)
38
+ coll.comment += '\n' + props.comment;
39
+ else
40
+ coll.comment = props.comment;
41
+ }
42
+ continue;
43
+ }
44
+ if (!isMap && ctx.options.strict && containsNewline(key))
45
+ onError(key, // checked by containsNewline()
46
+ 'MULTILINE_IMPLICIT_KEY', 'Implicit keys of flow sequence pairs need to be on a single line');
46
47
  }
47
- if (isMap || atExplicitKey) {
48
- coll.items.push(key ? new Pair(key, value) : new Pair(value));
48
+ if (i === 0) {
49
+ if (props.comma)
50
+ onError(props.comma, 'UNEXPECTED_TOKEN', `Unexpected , in ${fcName}`);
49
51
  }
50
52
  else {
51
- const seq = coll;
52
- if (key) {
53
- const map = new YAMLMap(doc.schema);
54
- map.flow = true;
55
- map.items.push(new Pair(key, value));
56
- seq.items.push(map);
57
- }
58
- else
59
- seq.items.push(value);
60
- }
61
- }
62
- for (let i = 0; i < fc.items.length; ++i) {
63
- const token = fc.items[i];
64
- let isSourceToken = true;
65
- switch (token.type) {
66
- case 'space':
67
- hasSpace = true;
68
- break;
69
- case 'comment': {
70
- if (doc.options.strict && !hasSpace)
71
- onError(offset, 'Comments must be separated from other tokens by white space characters');
72
- const cb = token.source.substring(1);
73
- if (!hasComment)
74
- comment = cb;
75
- else
76
- comment += newlines + cb;
77
- atLineStart = false;
78
- hasComment = true;
79
- newlines = '';
80
- break;
81
- }
82
- case 'newline':
83
- if (atLineStart && !hasComment)
84
- spaceBefore = true;
85
- if (atValueEnd) {
86
- if (hasComment) {
87
- let node = coll.items[coll.items.length - 1];
88
- if (isPair(node))
89
- node = node.value || node.key;
90
- /* istanbul ignore else should not happen */
91
- if (isNode(node))
92
- node.comment = comment;
93
- else
94
- onError(offset, 'Error adding trailing comment to node');
95
- comment = '';
96
- hasComment = false;
53
+ if (!props.comma)
54
+ onError(props.start, 'MISSING_CHAR', `Missing , between ${fcName} items`);
55
+ if (props.comment) {
56
+ let prevItemComment = '';
57
+ loop: for (const st of start) {
58
+ switch (st.type) {
59
+ case 'comma':
60
+ case 'space':
61
+ break;
62
+ case 'comment':
63
+ prevItemComment = st.source.substring(1);
64
+ break loop;
65
+ default:
66
+ break loop;
97
67
  }
98
- atValueEnd = false;
99
68
  }
100
- else {
101
- newlines += token.source;
102
- if (!isMap && !key && value)
103
- nlAfterValueInSeq = true;
69
+ if (prevItemComment) {
70
+ let prev = coll.items[coll.items.length - 1];
71
+ if (isPair(prev))
72
+ prev = prev.value || prev.key;
73
+ if (prev.comment)
74
+ prev.comment += '\n' + prevItemComment;
75
+ else
76
+ prev.comment = prevItemComment;
77
+ props.comment = props.comment.substring(prevItemComment.length + 1);
104
78
  }
105
- atLineStart = true;
106
- hasSpace = true;
107
- break;
108
- case 'anchor':
109
- if (anchor)
110
- onError(offset, 'A node can have at most one anchor');
111
- anchor = token.source.substring(1);
112
- atLineStart = false;
113
- atValueEnd = false;
114
- hasSpace = false;
115
- break;
116
- case 'tag': {
117
- if (tagName)
118
- onError(offset, 'A node can have at most one tag');
119
- const tn = doc.directives.tagName(token.source, m => onError(offset, m));
120
- if (tn)
121
- tagName = tn;
122
- atLineStart = false;
123
- atValueEnd = false;
124
- hasSpace = false;
125
- break;
126
79
  }
127
- case 'explicit-key-ind':
128
- if (anchor || tagName)
129
- onError(offset, 'Anchors and tags must be after the ? indicator');
130
- atExplicitKey = true;
131
- atLineStart = false;
132
- atValueEnd = false;
133
- hasSpace = false;
134
- break;
135
- case 'map-value-ind': {
136
- if (key) {
137
- if (value) {
138
- onError(offset, 'Missing {} around pair used as mapping key');
139
- const map = new YAMLMap(doc.schema);
140
- map.flow = true;
141
- map.items.push(new Pair(key, value));
142
- map.range = [key.range[0], value.range[1]];
143
- key = map;
144
- value = null;
145
- } // else explicit key
146
- }
147
- else if (value) {
148
- if (doc.options.strict) {
149
- const slMsg = 'Implicit keys of flow sequence pairs need to be on a single line';
150
- if (nlAfterValueInSeq)
151
- onError(offset, slMsg);
152
- else if (seqKeyToken) {
153
- if (containsNewline(seqKeyToken))
154
- onError(offset, slMsg);
155
- const start = 'offset' in seqKeyToken && seqKeyToken.offset;
156
- if (typeof start === 'number' && start < offset - 1024)
157
- onError(offset, 'The : indicator must be at most 1024 chars after the start of an implicit flow sequence key');
158
- seqKeyToken = null;
80
+ }
81
+ if (!isMap && !sep && !props.found) {
82
+ // item is a value in a seq
83
+ // → key & sep are empty, start does not include ? or :
84
+ const valueNode = value
85
+ ? composeNode(ctx, value, props, onError)
86
+ : composeEmptyNode(ctx, props.end, sep, null, props, onError);
87
+ coll.items.push(valueNode);
88
+ offset = valueNode.range[2];
89
+ if (isBlock(value))
90
+ onError(valueNode.range, 'BLOCK_IN_FLOW', blockMsg);
91
+ }
92
+ else {
93
+ // item is a key+value pair
94
+ // key value
95
+ const keyStart = props.end;
96
+ const keyNode = key
97
+ ? composeNode(ctx, key, props, onError)
98
+ : composeEmptyNode(ctx, keyStart, start, null, props, onError);
99
+ if (isBlock(key))
100
+ onError(keyNode.range, 'BLOCK_IN_FLOW', blockMsg);
101
+ // value properties
102
+ const valueProps = resolveProps(sep || [], {
103
+ flow: fcName,
104
+ indicator: 'map-value-ind',
105
+ next: value,
106
+ offset: keyNode.range[2],
107
+ onError,
108
+ startOnNewline: false
109
+ });
110
+ if (valueProps.found) {
111
+ if (!isMap && !props.found && ctx.options.strict) {
112
+ if (sep)
113
+ for (const st of sep) {
114
+ if (st === valueProps.found)
115
+ break;
116
+ if (st.type === 'newline') {
117
+ onError(st, 'MULTILINE_IMPLICIT_KEY', 'Implicit keys of flow sequence pairs need to be on a single line');
118
+ break;
119
+ }
159
120
  }
160
- }
161
- key = value;
162
- value = null;
121
+ if (props.start < valueProps.found.offset - 1024)
122
+ onError(valueProps.found, 'KEY_OVER_1024_CHARS', 'The : indicator must be at most 1024 chars after the start of an implicit flow sequence key');
163
123
  }
164
- else {
165
- key = composeEmptyNode(doc, offset, fc.items, i, getProps(), onError);
166
- }
167
- if (hasComment) {
168
- key.comment = comment;
169
- comment = '';
170
- hasComment = false;
171
- }
172
- atExplicitKey = false;
173
- atValueEnd = false;
174
- hasSpace = false;
175
- break;
176
124
  }
177
- case 'comma':
178
- if (key || value || anchor || tagName || atExplicitKey)
179
- addItem(i);
125
+ else if (value) {
126
+ if ('source' in value && value.source && value.source[0] === ':')
127
+ onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`);
180
128
  else
181
- onError(offset, `Unexpected , in flow ${isMap ? 'map' : 'sequence'}`);
182
- key = null;
183
- value = null;
184
- atExplicitKey = false;
185
- atValueEnd = true;
186
- hasSpace = false;
187
- nlAfterValueInSeq = false;
188
- seqKeyToken = null;
189
- break;
190
- case 'block-map':
191
- case 'block-seq':
192
- onError(offset, 'Block collections are not allowed within flow collections');
193
- // fallthrough
194
- default: {
195
- if (value)
196
- onError(offset, 'Missing , between flow collection items');
197
- if (!isMap && !key && !atExplicitKey)
198
- seqKeyToken = token;
199
- value = composeNode(doc, token, getProps(), onError);
200
- offset = value.range[1];
201
- atLineStart = false;
202
- isSourceToken = false;
203
- atValueEnd = false;
204
- hasSpace = false;
129
+ onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`);
205
130
  }
131
+ // value value
132
+ const valueNode = value
133
+ ? composeNode(ctx, value, valueProps, onError)
134
+ : valueProps.found
135
+ ? composeEmptyNode(ctx, valueProps.end, sep, null, valueProps, onError)
136
+ : null;
137
+ if (valueNode) {
138
+ if (isBlock(value))
139
+ onError(valueNode.range, 'BLOCK_IN_FLOW', blockMsg);
140
+ }
141
+ else if (valueProps.comment) {
142
+ if (keyNode.comment)
143
+ keyNode.comment += '\n' + valueProps.comment;
144
+ else
145
+ keyNode.comment = valueProps.comment;
146
+ }
147
+ const pair = new Pair(keyNode, valueNode);
148
+ if (isMap) {
149
+ const map = coll;
150
+ if (mapIncludes(ctx, map.items, keyNode))
151
+ onError(keyStart, 'DUPLICATE_KEY', 'Map keys must be unique');
152
+ map.items.push(pair);
153
+ }
154
+ else {
155
+ const map = new YAMLMap(ctx.schema);
156
+ map.flow = true;
157
+ map.items.push(pair);
158
+ coll.items.push(map);
159
+ }
160
+ offset = valueNode ? valueNode.range[2] : valueProps.end;
206
161
  }
207
- if (isSourceToken)
208
- offset += token.source.length;
209
162
  }
210
- if (key || value || anchor || tagName || atExplicitKey)
211
- addItem(fc.items.length);
212
163
  const expectedEnd = isMap ? '}' : ']';
213
164
  const [ce, ...ee] = fc.end;
214
- if (!ce || ce.source !== expectedEnd) {
215
- const cs = isMap ? 'map' : 'sequence';
216
- onError(offset, `Expected flow ${cs} to end with ${expectedEnd}`);
165
+ let cePos = offset;
166
+ if (ce && ce.source === expectedEnd)
167
+ cePos = ce.offset + ce.source.length;
168
+ else {
169
+ onError(offset + 1, 'MISSING_CHAR', `Expected ${fcName} to end with ${expectedEnd}`);
170
+ if (ce && ce.source.length !== 1)
171
+ ee.unshift(ce);
217
172
  }
218
- if (ce)
219
- offset += ce.source.length;
220
173
  if (ee.length > 0) {
221
- const end = resolveEnd(ee, offset, doc.options.strict, onError);
222
- if (end.comment)
223
- coll.comment = comment;
224
- offset = end.offset;
174
+ const end = resolveEnd(ee, cePos, ctx.options.strict, onError);
175
+ if (end.comment) {
176
+ if (coll.comment)
177
+ coll.comment += '\n' + end.comment;
178
+ else
179
+ coll.comment = end.comment;
180
+ }
181
+ coll.range = [fc.offset, cePos, end.offset];
182
+ }
183
+ else {
184
+ coll.range = [fc.offset, cePos, cePos];
225
185
  }
226
- coll.range = [fc.offset, offset];
227
186
  return coll;
228
187
  }
229
188
 
@@ -1,10 +1,11 @@
1
1
  import { Scalar } from '../nodes/Scalar.js';
2
2
  import { resolveEnd } from './resolve-end.js';
3
3
 
4
- function resolveFlowScalar({ offset, type, source, end }, strict, onError) {
4
+ function resolveFlowScalar(scalar, strict, onError) {
5
+ const { offset, type, source, end } = scalar;
5
6
  let _type;
6
7
  let value;
7
- const _onError = (rel, msg) => onError(offset + rel, msg);
8
+ const _onError = (rel, code, msg) => onError(offset + rel, code, msg);
8
9
  switch (type) {
9
10
  case 'scalar':
10
11
  _type = Scalar.PLAIN;
@@ -20,68 +21,97 @@ function resolveFlowScalar({ offset, type, source, end }, strict, onError) {
20
21
  break;
21
22
  /* istanbul ignore next should not happen */
22
23
  default:
23
- onError(offset, `Expected a flow scalar value, but found: ${type}`);
24
+ onError(scalar, 'UNEXPECTED_TOKEN', `Expected a flow scalar value, but found: ${type}`);
24
25
  return {
25
26
  value: '',
26
27
  type: null,
27
28
  comment: '',
28
- length: source.length
29
+ range: [offset, offset + source.length, offset + source.length]
29
30
  };
30
31
  }
31
- const re = resolveEnd(end, 0, strict, _onError);
32
+ const valueEnd = offset + source.length;
33
+ const re = resolveEnd(end, valueEnd, strict, onError);
32
34
  return {
33
35
  value,
34
36
  type: _type,
35
37
  comment: re.comment,
36
- length: source.length + re.offset
38
+ range: [offset, valueEnd, re.offset]
37
39
  };
38
40
  }
39
41
  function plainValue(source, onError) {
42
+ let badChar = '';
40
43
  switch (source[0]) {
41
44
  /* istanbul ignore next should not happen */
42
45
  case '\t':
43
- onError(0, 'Plain value cannot start with a tab character');
46
+ badChar = 'a tab character';
47
+ break;
48
+ case ',':
49
+ badChar = 'flow indicator character ,';
50
+ break;
51
+ case '%':
52
+ badChar = 'directive indicator character %';
44
53
  break;
45
54
  case '|':
46
55
  case '>': {
47
- const message = `Plain value cannot start with block scalar indicator ${source[0]}`;
48
- onError(0, message);
56
+ badChar = `block scalar indicator ${source[0]}`;
49
57
  break;
50
58
  }
51
59
  case '@':
52
60
  case '`': {
53
- const message = `Plain value cannot start with reserved character ${source[0]}`;
54
- onError(0, message);
61
+ badChar = `reserved character ${source[0]}`;
55
62
  break;
56
63
  }
57
64
  }
58
- return foldLines(source.trim());
65
+ if (badChar)
66
+ onError(0, 'BAD_SCALAR_START', `Plain value cannot start with ${badChar}`);
67
+ return foldLines(source);
59
68
  }
60
69
  function singleQuotedValue(source, onError) {
61
70
  if (source[source.length - 1] !== "'" || source.length === 1)
62
- onError(source.length, "Missing closing 'quote");
71
+ onError(source.length, 'MISSING_CHAR', "Missing closing 'quote");
63
72
  return foldLines(source.slice(1, -1)).replace(/''/g, "'");
64
73
  }
65
74
  function foldLines(source) {
66
- const lines = source.split(/[ \t]*\r?\n[ \t]*/);
67
- let res = lines[0];
75
+ /**
76
+ * The negative lookbehind here and in the `re` RegExp is to
77
+ * prevent causing a polynomial search time in certain cases.
78
+ *
79
+ * The try-catch is for Safari, which doesn't support this yet:
80
+ * https://caniuse.com/js-regexp-lookbehind
81
+ */
82
+ let first, line;
83
+ try {
84
+ first = new RegExp('(.*?)(?<![ \t])[ \t]*\r?\n', 'sy');
85
+ line = new RegExp('[ \t]*(.*?)(?:(?<![ \t])[ \t]*)?\r?\n', 'sy');
86
+ }
87
+ catch (_) {
88
+ first = /(.*?)[ \t]*\r?\n/sy;
89
+ line = /[ \t]*(.*?)[ \t]*\r?\n/sy;
90
+ }
91
+ let match = first.exec(source);
92
+ if (!match)
93
+ return source;
94
+ let res = match[1];
68
95
  let sep = ' ';
69
- for (let i = 1; i < lines.length - 1; ++i) {
70
- const line = lines[i];
71
- if (line === '') {
96
+ let pos = first.lastIndex;
97
+ line.lastIndex = pos;
98
+ while ((match = line.exec(source))) {
99
+ if (match[1] === '') {
72
100
  if (sep === '\n')
73
101
  res += sep;
74
102
  else
75
103
  sep = '\n';
76
104
  }
77
105
  else {
78
- res += sep + line;
106
+ res += sep + match[1];
79
107
  sep = ' ';
80
108
  }
109
+ pos = line.lastIndex;
81
110
  }
82
- if (lines.length > 1)
83
- res += sep + lines[lines.length - 1];
84
- return res;
111
+ const last = /[ \t]*(.*)/sy;
112
+ last.lastIndex = pos;
113
+ match = last.exec(source);
114
+ return res + sep + ((match && match[1]) || '');
85
115
  }
86
116
  function doubleQuotedValue(source, onError) {
87
117
  let res = '';
@@ -105,6 +135,12 @@ function doubleQuotedValue(source, onError) {
105
135
  while (next === ' ' || next === '\t')
106
136
  next = source[++i + 1];
107
137
  }
138
+ else if (next === '\r' && source[i + 1] === '\n') {
139
+ // skip escaped CRLF newlines, but still trim the following line
140
+ next = source[++i + 1];
141
+ while (next === ' ' || next === '\t')
142
+ next = source[++i + 1];
143
+ }
108
144
  else if (next === 'x' || next === 'u' || next === 'U') {
109
145
  const length = { x: 2, u: 4, U: 8 }[next];
110
146
  res += parseCharCode(source, i + 1, length, onError);
@@ -112,7 +148,7 @@ function doubleQuotedValue(source, onError) {
112
148
  }
113
149
  else {
114
150
  const raw = source.substr(i - 1, 2);
115
- onError(i - 1, `Invalid escape sequence ${raw}`);
151
+ onError(i - 1, 'BAD_DQ_ESCAPE', `Invalid escape sequence ${raw}`);
116
152
  res += raw;
117
153
  }
118
154
  }
@@ -122,7 +158,7 @@ function doubleQuotedValue(source, onError) {
122
158
  let next = source[i + 1];
123
159
  while (next === ' ' || next === '\t')
124
160
  next = source[++i + 1];
125
- if (next !== '\n')
161
+ if (next !== '\n' && !(next === '\r' && source[i + 2] === '\n'))
126
162
  res += i > wsStart ? source.slice(wsStart, i + 1) : ch;
127
163
  }
128
164
  else {
@@ -130,7 +166,7 @@ function doubleQuotedValue(source, onError) {
130
166
  }
131
167
  }
132
168
  if (source[source.length - 1] !== '"' || source.length === 1)
133
- onError(source.length, 'Missing closing "quote');
169
+ onError(source.length, 'MISSING_CHAR', 'Missing closing "quote');
134
170
  return res;
135
171
  }
136
172
  /**
@@ -178,7 +214,7 @@ function parseCharCode(source, offset, length, onError) {
178
214
  const code = ok ? parseInt(cc, 16) : NaN;
179
215
  if (isNaN(code)) {
180
216
  const raw = source.substr(offset - 2, length + 2);
181
- onError(offset - 2, `Invalid escape sequence ${raw}`);
217
+ onError(offset - 2, 'BAD_DQ_ESCAPE', `Invalid escape sequence ${raw}`);
182
218
  return raw;
183
219
  }
184
220
  return String.fromCodePoint(code);