yaml 2.0.0-4 → 2.0.0-5

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 (210) 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 +20 -17
  5. package/browser/dist/compose/compose-scalar.js +20 -23
  6. package/browser/dist/compose/composer.js +105 -76
  7. package/browser/dist/compose/resolve-block-map.js +38 -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 +6 -7
  11. package/browser/dist/compose/resolve-flow-collection.js +153 -199
  12. package/browser/dist/compose/resolve-flow-scalar.js +49 -25
  13. package/browser/dist/compose/resolve-props.js +47 -35
  14. package/browser/dist/compose/util-contains-newline.js +15 -12
  15. package/browser/dist/doc/Document.js +50 -99
  16. package/browser/dist/doc/anchors.js +72 -0
  17. package/browser/dist/doc/createNode.js +27 -17
  18. package/browser/dist/errors.js +16 -12
  19. package/browser/dist/index.js +3 -3
  20. package/browser/dist/nodes/Alias.js +51 -28
  21. package/browser/dist/nodes/Collection.js +5 -83
  22. package/browser/dist/nodes/Node.js +2 -1
  23. package/browser/dist/nodes/Pair.js +9 -232
  24. package/browser/dist/nodes/YAMLMap.js +8 -4
  25. package/browser/dist/nodes/YAMLSeq.js +7 -4
  26. package/browser/dist/nodes/addPairToJSMap.js +103 -0
  27. package/browser/dist/nodes/toJS.js +12 -10
  28. package/browser/dist/options.js +0 -2
  29. package/browser/dist/parse/cst-scalar.js +219 -0
  30. package/browser/dist/parse/cst-stringify.js +61 -0
  31. package/browser/dist/parse/cst-visit.js +97 -0
  32. package/{dist/parse/tokens.js → browser/dist/parse/cst.js} +12 -7
  33. package/browser/dist/parse/lexer.js +99 -105
  34. package/browser/dist/parse/parser.js +219 -144
  35. package/browser/dist/public-api.js +11 -14
  36. package/browser/dist/schema/Schema.js +23 -0
  37. package/browser/dist/{tags/failsafe → schema/common}/map.js +0 -0
  38. package/browser/dist/schema/common/null.js +13 -0
  39. package/browser/dist/{tags/failsafe → schema/common}/seq.js +1 -1
  40. package/browser/dist/{tags/failsafe → schema/common}/string.js +0 -0
  41. package/browser/dist/schema/core/bool.js +19 -0
  42. package/browser/dist/schema/core/float.js +40 -0
  43. package/browser/dist/schema/core/int.js +38 -0
  44. package/browser/dist/schema/core/schema.js +23 -0
  45. package/browser/dist/{tags/json.js → schema/json/schema.js} +5 -6
  46. package/browser/dist/schema/tags.js +79 -0
  47. package/browser/dist/{tags → schema}/yaml-1.1/binary.js +0 -0
  48. package/browser/dist/schema/yaml-1.1/bool.js +26 -0
  49. package/browser/dist/schema/yaml-1.1/float.js +43 -0
  50. package/browser/dist/schema/yaml-1.1/int.js +71 -0
  51. package/browser/dist/{tags → schema}/yaml-1.1/omap.js +0 -0
  52. package/browser/dist/{tags → schema}/yaml-1.1/pairs.js +9 -6
  53. package/browser/dist/schema/yaml-1.1/schema.js +37 -0
  54. package/browser/dist/{tags → schema}/yaml-1.1/set.js +0 -0
  55. package/browser/dist/{tags → schema}/yaml-1.1/timestamp.js +0 -0
  56. package/browser/dist/stringify/addComment.js +1 -7
  57. package/browser/dist/stringify/stringify.js +8 -6
  58. package/browser/dist/stringify/stringifyCollection.js +108 -0
  59. package/browser/dist/stringify/stringifyDocument.js +61 -0
  60. package/browser/dist/stringify/stringifyPair.js +113 -0
  61. package/browser/dist/stringify/stringifyString.js +53 -52
  62. package/browser/dist/visit.js +20 -1
  63. package/dist/compose/compose-collection.d.ts +4 -4
  64. package/dist/compose/compose-collection.js +12 -9
  65. package/dist/compose/compose-doc.d.ts +4 -3
  66. package/dist/compose/compose-doc.js +23 -6
  67. package/dist/compose/compose-node.d.ts +15 -7
  68. package/dist/compose/compose-node.js +20 -17
  69. package/dist/compose/compose-scalar.d.ts +4 -3
  70. package/dist/compose/compose-scalar.js +19 -22
  71. package/dist/compose/composer.d.ts +28 -23
  72. package/dist/compose/composer.js +106 -77
  73. package/dist/compose/resolve-block-map.d.ts +4 -4
  74. package/dist/compose/resolve-block-map.js +38 -29
  75. package/dist/compose/resolve-block-scalar.d.ts +5 -3
  76. package/dist/compose/resolve-block-scalar.js +14 -17
  77. package/dist/compose/resolve-block-seq.d.ts +4 -4
  78. package/dist/compose/resolve-block-seq.js +21 -17
  79. package/dist/compose/resolve-end.d.ts +3 -2
  80. package/dist/compose/resolve-end.js +6 -7
  81. package/dist/compose/resolve-flow-collection.d.ts +4 -5
  82. package/dist/compose/resolve-flow-collection.js +152 -198
  83. package/dist/compose/resolve-flow-scalar.d.ts +5 -3
  84. package/dist/compose/resolve-flow-scalar.js +49 -25
  85. package/dist/compose/resolve-props.d.ts +17 -10
  86. package/dist/compose/resolve-props.js +47 -35
  87. package/dist/compose/util-contains-newline.d.ts +1 -1
  88. package/dist/compose/util-contains-newline.js +15 -12
  89. package/dist/compose/util-empty-scalar-position.d.ts +1 -1
  90. package/dist/doc/Document.d.ts +27 -15
  91. package/dist/doc/Document.js +48 -97
  92. package/dist/doc/anchors.d.ts +24 -0
  93. package/dist/doc/anchors.js +77 -0
  94. package/dist/doc/createNode.d.ts +8 -10
  95. package/dist/doc/createNode.js +26 -16
  96. package/dist/errors.d.ts +11 -8
  97. package/dist/errors.js +16 -12
  98. package/dist/index.d.ts +5 -3
  99. package/dist/index.js +3 -3
  100. package/dist/nodes/Alias.d.ts +19 -9
  101. package/dist/nodes/Alias.js +51 -28
  102. package/dist/nodes/Collection.d.ts +3 -17
  103. package/dist/nodes/Collection.js +4 -82
  104. package/dist/nodes/Node.d.ts +6 -4
  105. package/dist/nodes/Node.js +2 -0
  106. package/dist/nodes/Pair.d.ts +6 -11
  107. package/dist/nodes/Pair.js +8 -231
  108. package/dist/nodes/Scalar.d.ts +6 -3
  109. package/dist/nodes/YAMLMap.d.ts +3 -3
  110. package/dist/nodes/YAMLMap.js +8 -4
  111. package/dist/nodes/YAMLSeq.d.ts +3 -3
  112. package/dist/nodes/YAMLSeq.js +7 -4
  113. package/dist/nodes/addPairToJSMap.d.ts +3 -0
  114. package/dist/nodes/addPairToJSMap.js +105 -0
  115. package/dist/nodes/toJS.d.ts +4 -5
  116. package/dist/nodes/toJS.js +12 -10
  117. package/dist/options.d.ts +20 -26
  118. package/dist/options.js +0 -2
  119. package/dist/parse/cst-scalar.d.ts +58 -0
  120. package/dist/parse/cst-scalar.js +223 -0
  121. package/dist/parse/cst-stringify.d.ts +8 -0
  122. package/dist/parse/cst-stringify.js +63 -0
  123. package/dist/parse/cst-visit.d.ts +39 -0
  124. package/dist/parse/cst-visit.js +99 -0
  125. package/dist/parse/{tokens.d.ts → cst.d.ts} +23 -7
  126. package/{browser/dist/parse/tokens.js → dist/parse/cst.js} +27 -1
  127. package/dist/parse/lexer.d.ts +4 -13
  128. package/dist/parse/lexer.js +100 -106
  129. package/dist/parse/parser.d.ts +30 -24
  130. package/dist/parse/parser.js +221 -146
  131. package/dist/public-api.d.ts +7 -7
  132. package/dist/public-api.js +11 -14
  133. package/dist/{doc → schema}/Schema.d.ts +5 -3
  134. package/dist/schema/Schema.js +25 -0
  135. package/dist/{tags/failsafe → schema/common}/map.d.ts +0 -0
  136. package/dist/{tags/failsafe → schema/common}/map.js +0 -0
  137. package/dist/schema/common/null.d.ts +4 -0
  138. package/dist/schema/common/null.js +15 -0
  139. package/dist/{tags/failsafe → schema/common}/seq.d.ts +0 -0
  140. package/dist/{tags/failsafe → schema/common}/seq.js +1 -1
  141. package/dist/{tags/failsafe → schema/common}/string.d.ts +0 -0
  142. package/dist/{tags/failsafe → schema/common}/string.js +0 -0
  143. package/dist/schema/core/bool.d.ts +4 -0
  144. package/dist/schema/core/bool.js +21 -0
  145. package/dist/schema/core/float.d.ts +4 -0
  146. package/dist/schema/core/float.js +44 -0
  147. package/dist/schema/core/int.d.ts +4 -0
  148. package/dist/schema/core/int.js +42 -0
  149. package/dist/schema/core/schema.d.ts +1 -0
  150. package/dist/schema/core/schema.js +25 -0
  151. package/dist/schema/json/schema.d.ts +2 -0
  152. package/dist/{tags/json.js → schema/json/schema.js} +5 -6
  153. package/dist/schema/tags.d.ts +41 -0
  154. package/dist/schema/tags.js +82 -0
  155. package/dist/{tags → schema}/types.d.ts +3 -7
  156. package/dist/{tags → schema}/yaml-1.1/binary.d.ts +0 -0
  157. package/dist/{tags → schema}/yaml-1.1/binary.js +0 -0
  158. package/dist/schema/yaml-1.1/bool.d.ts +7 -0
  159. package/dist/schema/yaml-1.1/bool.js +29 -0
  160. package/dist/schema/yaml-1.1/float.d.ts +4 -0
  161. package/dist/schema/yaml-1.1/float.js +47 -0
  162. package/dist/schema/yaml-1.1/int.d.ts +5 -0
  163. package/dist/schema/yaml-1.1/int.js +76 -0
  164. package/dist/{tags → schema}/yaml-1.1/omap.d.ts +0 -0
  165. package/dist/{tags → schema}/yaml-1.1/omap.js +0 -0
  166. package/dist/{tags → schema}/yaml-1.1/pairs.d.ts +3 -2
  167. package/dist/{tags → schema}/yaml-1.1/pairs.js +9 -6
  168. package/dist/schema/yaml-1.1/schema.d.ts +1 -0
  169. package/dist/schema/yaml-1.1/schema.js +39 -0
  170. package/dist/{tags → schema}/yaml-1.1/set.d.ts +1 -1
  171. package/dist/{tags → schema}/yaml-1.1/set.js +0 -0
  172. package/dist/{tags → schema}/yaml-1.1/timestamp.d.ts +0 -0
  173. package/dist/{tags → schema}/yaml-1.1/timestamp.js +0 -0
  174. package/dist/stringify/addComment.js +0 -7
  175. package/dist/stringify/stringify.d.ts +1 -2
  176. package/dist/stringify/stringify.js +8 -6
  177. package/dist/stringify/stringifyCollection.d.ts +21 -0
  178. package/dist/stringify/stringifyCollection.js +110 -0
  179. package/dist/stringify/stringifyDocument.d.ts +3 -0
  180. package/dist/stringify/stringifyDocument.js +63 -0
  181. package/dist/stringify/stringifyPair.d.ts +3 -0
  182. package/dist/stringify/stringifyPair.js +115 -0
  183. package/dist/stringify/stringifyString.js +53 -52
  184. package/dist/test-events.d.ts +1 -2
  185. package/dist/test-events.js +25 -12
  186. package/dist/util.d.ts +1 -1
  187. package/dist/visit.d.ts +10 -1
  188. package/dist/visit.js +20 -1
  189. package/package.json +4 -3
  190. package/browser/dist/doc/Anchors.js +0 -102
  191. package/browser/dist/doc/Schema.js +0 -27
  192. package/browser/dist/doc/getSchemaTags.js +0 -30
  193. package/browser/dist/tags/core.js +0 -109
  194. package/browser/dist/tags/failsafe/index.js +0 -7
  195. package/browser/dist/tags/index.js +0 -34
  196. package/browser/dist/tags/yaml-1.1/index.js +0 -152
  197. package/dist/doc/Anchors.d.ts +0 -36
  198. package/dist/doc/Anchors.js +0 -104
  199. package/dist/doc/Schema.js +0 -29
  200. package/dist/doc/getSchemaTags.d.ts +0 -3
  201. package/dist/doc/getSchemaTags.js +0 -32
  202. package/dist/tags/core.d.ts +0 -14
  203. package/dist/tags/core.js +0 -119
  204. package/dist/tags/failsafe/index.d.ts +0 -1
  205. package/dist/tags/failsafe/index.js +0 -9
  206. package/dist/tags/index.d.ts +0 -31
  207. package/dist/tags/index.js +0 -37
  208. package/dist/tags/json.d.ts +0 -2
  209. package/dist/tags/yaml-1.1/index.d.ts +0 -2
  210. package/dist/tags/yaml-1.1/index.js +0 -154
package/README.md CHANGED
@@ -19,7 +19,7 @@ For more information, see the project's documentation site: [**eemeli.org/yaml**
19
19
  To install:
20
20
 
21
21
  ```sh
22
- npm install yaml@next
22
+ npm install --save-exact yaml@next
23
23
  ```
24
24
 
25
25
  **Note:** These docs are for `yaml@2`. For v1, see the [v1.10.0 tag](https://github.com/eemeli/yaml/tree/v1.10.0) for the source and [eemeli.org/yaml/v1](https://eemeli.org/yaml/v1/) for the documentation.
@@ -67,16 +67,16 @@ const YAML = require('yaml')
67
67
  - [`new Scalar(value)`](https://eemeli.org/yaml/#scalar-values)
68
68
  - [`new YAMLMap()`](https://eemeli.org/yaml/#collections)
69
69
  - [`new YAMLSeq()`](https://eemeli.org/yaml/#collections)
70
- - [`doc.anchors.createAlias(node, name?): Alias`](https://eemeli.org/yaml/#working-with-anchors)
70
+ - [`doc.createAlias(node, name?): Alias`](https://eemeli.org/yaml/#working-with-anchors)
71
71
  - [`doc.createNode(value, options?): Node`](https://eemeli.org/yaml/#creating-nodes)
72
72
  - [`doc.createPair(key, value): Pair`](https://eemeli.org/yaml/#creating-nodes)
73
73
  - [`visit(node, visitor)`](https://eemeli.org/yaml/#modifying-nodes)
74
74
 
75
75
  ### Parsing YAML
76
76
 
77
- - [`new Lexer(push)`](https://eemeli.org/yaml/#lexer)
78
- - [`new Parser(push, onNewLine?)`](https://eemeli.org/yaml/#parser)
79
- - [`new Composer(push, options?)`](https://eemeli.org/yaml/#composer)
77
+ - [`new Lexer().lex(src)`](https://eemeli.org/yaml/#lexer)
78
+ - [`new Parser(onNewLine?).parse(src)`](https://eemeli.org/yaml/#parser)
79
+ - [`new Composer(options?).compose(tokens)`](https://eemeli.org/yaml/#composer)
80
80
 
81
81
  ## YAML.parse
82
82
 
@@ -4,22 +4,25 @@ import { resolveBlockMap } from './resolve-block-map.js';
4
4
  import { resolveBlockSeq } from './resolve-block-seq.js';
5
5
  import { resolveFlowCollection } from './resolve-flow-collection.js';
6
6
 
7
- function composeCollection(CN, doc, token, anchor, tagName, onError) {
7
+ function composeCollection(CN, ctx, token, tagToken, onError) {
8
8
  let coll;
9
9
  switch (token.type) {
10
10
  case 'block-map': {
11
- coll = resolveBlockMap(CN, doc, token, anchor, onError);
11
+ coll = resolveBlockMap(CN, ctx, token, onError);
12
12
  break;
13
13
  }
14
14
  case 'block-seq': {
15
- coll = resolveBlockSeq(CN, doc, token, anchor, onError);
15
+ coll = resolveBlockSeq(CN, ctx, token, onError);
16
16
  break;
17
17
  }
18
18
  case 'flow-collection': {
19
- coll = resolveFlowCollection(CN, doc, token, anchor, onError);
19
+ coll = resolveFlowCollection(CN, ctx, token, onError);
20
20
  break;
21
21
  }
22
22
  }
23
+ if (!tagToken)
24
+ return coll;
25
+ const tagName = ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg));
23
26
  if (!tagName)
24
27
  return coll;
25
28
  // Cast needed due to: https://github.com/Microsoft/TypeScript/issues/3841
@@ -29,20 +32,20 @@ function composeCollection(CN, doc, token, anchor, tagName, onError) {
29
32
  return coll;
30
33
  }
31
34
  const expType = isMap(coll) ? 'map' : 'seq';
32
- let tag = doc.schema.tags.find(t => t.collection === expType && t.tag === tagName);
35
+ let tag = ctx.schema.tags.find(t => t.collection === expType && t.tag === tagName);
33
36
  if (!tag) {
34
- const kt = doc.schema.knownTags[tagName];
37
+ const kt = ctx.schema.knownTags[tagName];
35
38
  if (kt && kt.collection === expType) {
36
- doc.schema.tags.push(Object.assign({}, kt, { default: false }));
39
+ ctx.schema.tags.push(Object.assign({}, kt, { default: false }));
37
40
  tag = kt;
38
41
  }
39
42
  else {
40
- onError(coll.range[0], `Unresolved tag: ${tagName}`, true);
43
+ onError(tagToken, 'TAG_RESOLVE_FAILED', `Unresolved tag: ${tagName}`, true);
41
44
  coll.tag = tagName;
42
45
  return coll;
43
46
  }
44
47
  }
45
- const res = tag.resolve(coll, msg => onError(coll.range[0], msg), doc.options);
48
+ const res = tag.resolve(coll, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg), ctx.options);
46
49
  const node = isNode(res)
47
50
  ? res
48
51
  : new Scalar(res);
@@ -6,16 +6,33 @@ import { resolveProps } from './resolve-props.js';
6
6
  function composeDoc(options, directives, { offset, start, value, end }, onError) {
7
7
  const opts = Object.assign({ directives }, options);
8
8
  const doc = new Document(undefined, opts);
9
- const props = resolveProps(doc, start, true, 'doc-start', offset, onError);
10
- if (props.found)
9
+ const ctx = {
10
+ directives: doc.directives,
11
+ options: doc.options,
12
+ schema: doc.schema
13
+ };
14
+ const props = resolveProps(start, {
15
+ ctx,
16
+ indicator: 'doc-start',
17
+ offset,
18
+ onError,
19
+ startOnNewline: true
20
+ });
21
+ if (props.found) {
11
22
  doc.directives.marker = true;
23
+ if (value &&
24
+ (value.type === 'block-map' || value.type === 'block-seq') &&
25
+ !props.hasNewline)
26
+ onError(props.end, 'MISSING_CHAR', 'Block collection cannot start on same line with directives-end marker');
27
+ }
12
28
  doc.contents = value
13
- ? composeNode(doc, value, props, onError)
14
- : composeEmptyNode(doc, offset + props.length, start, null, props, onError);
15
- const re = resolveEnd(end, doc.contents.range[1], false, onError);
29
+ ? composeNode(ctx, value, props, onError)
30
+ : composeEmptyNode(ctx, props.end, start, null, props, onError);
31
+ const contentEnd = doc.contents.range[2];
32
+ const re = resolveEnd(end, contentEnd, false, onError);
16
33
  if (re.comment)
17
34
  doc.comment = re.comment;
18
- doc.range = [offset, re.offset];
35
+ doc.range = [offset, contentEnd, re.offset];
19
36
  return doc;
20
37
  }
21
38
 
@@ -5,25 +5,29 @@ import { resolveEnd } from './resolve-end.js';
5
5
  import { emptyScalarPosition } from './util-empty-scalar-position.js';
6
6
 
7
7
  const CN = { composeNode, composeEmptyNode };
8
- function composeNode(doc, token, props, onError) {
9
- const { spaceBefore, comment, anchor, tagName } = props;
8
+ function composeNode(ctx, token, props, onError) {
9
+ const { spaceBefore, comment, anchor, tag } = props;
10
10
  let node;
11
11
  switch (token.type) {
12
12
  case 'alias':
13
- node = composeAlias(doc, token, onError);
14
- if (anchor || tagName)
15
- onError(token.offset, 'An alias node must not specify any properties');
13
+ node = composeAlias(ctx, token, onError);
14
+ if (anchor || tag)
15
+ onError(token, 'ALIAS_PROPS', 'An alias node must not specify any properties');
16
16
  break;
17
17
  case 'scalar':
18
18
  case 'single-quoted-scalar':
19
19
  case 'double-quoted-scalar':
20
20
  case 'block-scalar':
21
- node = composeScalar(doc, token, anchor, tagName, onError);
21
+ node = composeScalar(ctx, token, tag, onError);
22
+ if (anchor)
23
+ node.anchor = anchor.source.substring(1);
22
24
  break;
23
25
  case 'block-map':
24
26
  case 'block-seq':
25
27
  case 'flow-collection':
26
- node = composeCollection(CN, doc, token, anchor, tagName, onError);
28
+ node = composeCollection(CN, ctx, token, tag, onError);
29
+ if (anchor)
30
+ node.anchor = anchor.source.substring(1);
27
31
  break;
28
32
  default:
29
33
  console.log(token);
@@ -39,28 +43,27 @@ function composeNode(doc, token, props, onError) {
39
43
  }
40
44
  return node;
41
45
  }
42
- function composeEmptyNode(doc, offset, before, pos, { spaceBefore, comment, anchor, tagName }, onError) {
46
+ function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag }, onError) {
43
47
  const token = {
44
48
  type: 'scalar',
45
49
  offset: emptyScalarPosition(offset, before, pos),
46
50
  indent: -1,
47
51
  source: ''
48
52
  };
49
- const node = composeScalar(doc, token, anchor, tagName, onError);
53
+ const node = composeScalar(ctx, token, tag, onError);
54
+ if (anchor)
55
+ node.anchor = anchor.source.substring(1);
50
56
  if (spaceBefore)
51
57
  node.spaceBefore = true;
52
58
  if (comment)
53
59
  node.comment = comment;
54
60
  return node;
55
61
  }
56
- function composeAlias(doc, { offset, source, end }, onError) {
57
- const name = source.substring(1);
58
- const src = doc.anchors.getNode(name);
59
- if (!src)
60
- onError(offset, `Aliased anchor not found: ${name}`);
61
- const alias = new Alias(src);
62
- const re = resolveEnd(end, offset + source.length, doc.options.strict, onError);
63
- alias.range = [offset, re.offset];
62
+ function composeAlias({ options }, { offset, source, end }, onError) {
63
+ const alias = new Alias(source.substring(1));
64
+ const valueEnd = offset + source.length;
65
+ const re = resolveEnd(end, valueEnd, options.strict, onError);
66
+ alias.range = [offset, valueEnd, re.offset];
64
67
  if (re.comment)
65
68
  alias.comment = re.comment;
66
69
  return alias;
@@ -1,46 +1,43 @@
1
- import { isScalar } from '../nodes/Node.js';
1
+ import { isScalar, SCALAR } from '../nodes/Node.js';
2
2
  import { Scalar } from '../nodes/Scalar.js';
3
3
  import { resolveBlockScalar } from './resolve-block-scalar.js';
4
4
  import { resolveFlowScalar } from './resolve-flow-scalar.js';
5
5
 
6
- function composeScalar(doc, token, anchor, tagName, onError) {
7
- const { offset } = token;
8
- const { value, type, comment, length } = token.type === 'block-scalar'
9
- ? resolveBlockScalar(token, doc.options.strict, onError)
10
- : resolveFlowScalar(token, doc.options.strict, onError);
11
- const tag = tagName
12
- ? findScalarTagByName(doc.schema, value, tagName, onError)
13
- : findScalarTagByTest(doc.schema, value, token.type === 'scalar');
6
+ function composeScalar(ctx, token, tagToken, onError) {
7
+ const { value, type, comment, range } = token.type === 'block-scalar'
8
+ ? resolveBlockScalar(token, ctx.options.strict, onError)
9
+ : resolveFlowScalar(token, ctx.options.strict, onError);
10
+ const tagName = tagToken
11
+ ? ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg))
12
+ : null;
13
+ const tag = tagToken && tagName
14
+ ? findScalarTagByName(ctx.schema, value, tagName, tagToken, onError)
15
+ : findScalarTagByTest(ctx.schema, value, token.type === 'scalar');
14
16
  let scalar;
15
17
  try {
16
- const res = tag
17
- ? tag.resolve(value, msg => onError(offset, msg), doc.options)
18
- : value;
18
+ const res = tag.resolve(value, msg => onError(tagToken || token, 'TAG_RESOLVE_FAILED', msg), ctx.options);
19
19
  scalar = isScalar(res) ? res : new Scalar(res);
20
20
  }
21
21
  catch (error) {
22
- onError(offset, error.message);
22
+ onError(tagToken || token, 'TAG_RESOLVE_FAILED', error.message);
23
23
  scalar = new Scalar(value);
24
24
  }
25
- scalar.range = [offset, offset + length];
25
+ scalar.range = range;
26
26
  scalar.source = value;
27
27
  if (type)
28
28
  scalar.type = type;
29
29
  if (tagName)
30
30
  scalar.tag = tagName;
31
- if (tag === null || tag === void 0 ? void 0 : tag.format)
31
+ if (tag.format)
32
32
  scalar.format = tag.format;
33
33
  if (comment)
34
34
  scalar.comment = comment;
35
- if (anchor)
36
- doc.anchors.setAnchor(scalar, anchor);
37
35
  return scalar;
38
36
  }
39
- const defaultScalarTag = (schema) => schema.tags.find(tag => !tag.collection && tag.tag === 'tag:yaml.org,2002:str');
40
- function findScalarTagByName(schema, value, tagName, onError) {
37
+ function findScalarTagByName(schema, value, tagName, tagToken, onError) {
41
38
  var _a;
42
39
  if (tagName === '!')
43
- return defaultScalarTag(schema); // non-specific tag
40
+ return schema[SCALAR]; // non-specific tag
44
41
  const matchWithTest = [];
45
42
  for (const tag of schema.tags) {
46
43
  if (!tag.collection && tag.tag === tagName) {
@@ -60,8 +57,8 @@ function findScalarTagByName(schema, value, tagName, onError) {
60
57
  schema.tags.push(Object.assign({}, kt, { default: false, test: undefined }));
61
58
  return kt;
62
59
  }
63
- onError(0, `Unresolved tag: ${tagName}`, tagName !== 'tag:yaml.org,2002:str');
64
- return defaultScalarTag(schema);
60
+ onError(tagToken, 'TAG_RESOLVE_FAILED', `Unresolved tag: ${tagName}`, tagName !== 'tag:yaml.org,2002:str');
61
+ return schema[SCALAR];
65
62
  }
66
63
  function findScalarTagByTest(schema, value, apply) {
67
64
  var _a;
@@ -71,7 +68,7 @@ function findScalarTagByTest(schema, value, apply) {
71
68
  return tag;
72
69
  }
73
70
  }
74
- return defaultScalarTag(schema);
71
+ return schema[SCALAR];
75
72
  }
76
73
 
77
74
  export { composeScalar };
@@ -1,11 +1,19 @@
1
1
  import { Directives } from '../doc/directives.js';
2
2
  import { Document } from '../doc/Document.js';
3
3
  import { YAMLWarning, YAMLParseError } from '../errors.js';
4
- import { isCollection } from '../nodes/Node.js';
4
+ import { isCollection, isPair } from '../nodes/Node.js';
5
5
  import { defaultOptions } from '../options.js';
6
6
  import { composeDoc } from './compose-doc.js';
7
7
  import { resolveEnd } from './resolve-end.js';
8
8
 
9
+ function getErrorPos(src) {
10
+ if (typeof src === 'number')
11
+ return [src, src + 1];
12
+ if (Array.isArray(src))
13
+ return src.length === 2 ? src : [src[0], src[1]];
14
+ const { offset, source } = src;
15
+ return [offset, offset + (typeof source === 'string' ? source.length : 1)];
16
+ }
9
17
  function parsePrelude(prelude) {
10
18
  let comment = '';
11
19
  let atComment = false;
@@ -38,88 +46,30 @@ function parsePrelude(prelude) {
38
46
  * Compose a stream of CST nodes into a stream of YAML Documents.
39
47
  *
40
48
  * ```ts
41
- * const options: Options = { ... }
42
- * const docs: Document.Parsed[] = []
43
- * const composer = new Composer(doc => docs.push(doc), options)
44
- * const parser = new Parser(composer.next)
45
- * parser.parse(source)
46
- * composer.end()
49
+ * import { Composer, Parser } from 'yaml'
50
+ *
51
+ * const src: string = ...
52
+ * const tokens = new Parser().parse(src)
53
+ * const docs = new Composer().compose(tokens)
47
54
  * ```
48
55
  */
49
56
  class Composer {
50
- constructor(onDocument, options = {}) {
57
+ constructor(options = {}) {
51
58
  this.doc = null;
52
59
  this.atDirectives = false;
53
60
  this.prelude = [];
54
61
  this.errors = [];
55
62
  this.warnings = [];
56
- this.onError = (offset, message, warning) => {
63
+ this.onError = (source, code, message, warning) => {
64
+ const pos = getErrorPos(source);
57
65
  if (warning)
58
- this.warnings.push(new YAMLWarning(offset, message));
66
+ this.warnings.push(new YAMLWarning(pos, code, message));
59
67
  else
60
- this.errors.push(new YAMLParseError(offset, message));
61
- };
62
- /**
63
- * Advance the composed by one CST token. Bound to the Composer
64
- * instance, so may be used directly as a callback function.
65
- */
66
- this.next = (token) => {
67
- switch (token.type) {
68
- case 'directive':
69
- this.directives.add(token.source, this.onError);
70
- this.prelude.push(token.source);
71
- this.atDirectives = true;
72
- break;
73
- case 'document': {
74
- const doc = composeDoc(this.options, this.directives, token, this.onError);
75
- this.decorate(doc, false);
76
- if (this.doc)
77
- this.onDocument(this.doc);
78
- this.doc = doc;
79
- this.atDirectives = false;
80
- break;
81
- }
82
- case 'byte-order-mark':
83
- case 'space':
84
- break;
85
- case 'comment':
86
- case 'newline':
87
- this.prelude.push(token.source);
88
- break;
89
- case 'error': {
90
- const msg = token.source
91
- ? `${token.message}: ${JSON.stringify(token.source)}`
92
- : token.message;
93
- const error = new YAMLParseError(-1, msg);
94
- if (this.atDirectives || !this.doc)
95
- this.errors.push(error);
96
- else
97
- this.doc.errors.push(error);
98
- break;
99
- }
100
- case 'doc-end': {
101
- if (!this.doc) {
102
- const msg = 'Unexpected doc-end without preceding document';
103
- this.errors.push(new YAMLParseError(token.offset, msg));
104
- break;
105
- }
106
- const end = resolveEnd(token.end, token.offset + token.source.length, this.doc.options.strict, this.onError);
107
- this.decorate(this.doc, true);
108
- if (end.comment) {
109
- const dc = this.doc.comment;
110
- this.doc.comment = dc ? `${dc}\n${end.comment}` : end.comment;
111
- }
112
- this.doc.range[1] = end.offset;
113
- break;
114
- }
115
- default:
116
- this.errors.push(new YAMLParseError(-1, `Unsupported token ${token.type}`));
117
- }
68
+ this.errors.push(new YAMLParseError(pos, code, message));
118
69
  };
119
70
  this.directives = new Directives({
120
- version: (options === null || options === void 0 ? void 0 : options.version) || defaultOptions.version
71
+ version: options.version || defaultOptions.version
121
72
  });
122
- this.onDocument = onDocument;
123
73
  this.options = options;
124
74
  }
125
75
  decorate(doc, afterDoc) {
@@ -134,7 +84,9 @@ class Composer {
134
84
  doc.commentBefore = comment;
135
85
  }
136
86
  else if (isCollection(dc) && !dc.flow && dc.items.length > 0) {
137
- const it = dc.items[0];
87
+ let it = dc.items[0];
88
+ if (isPair(it))
89
+ it = it.key;
138
90
  const cb = it.commentBefore;
139
91
  it.commentBefore = cb ? `${comment}\n${cb}` : comment;
140
92
  }
@@ -168,20 +120,97 @@ class Composer {
168
120
  warnings: this.warnings
169
121
  };
170
122
  }
171
- end(forceDoc = false, offset = -1) {
123
+ /**
124
+ * Compose tokens into documents.
125
+ *
126
+ * @param forceDoc - If the stream contains no document, still emit a final document including any comments and directives that would be applied to a subsequent document.
127
+ * @param endOffset - Should be set if `forceDoc` is also set, to set the document range end and to indicate errors correctly.
128
+ */
129
+ *compose(tokens, forceDoc = false, endOffset = -1) {
130
+ for (const token of tokens)
131
+ yield* this.next(token);
132
+ yield* this.end(forceDoc, endOffset);
133
+ }
134
+ /** Advance the composer by one CST token. */
135
+ *next(token) {
136
+ switch (token.type) {
137
+ case 'directive':
138
+ this.directives.add(token.source, (offset, message, warning) => {
139
+ const pos = getErrorPos(token);
140
+ pos[0] += offset;
141
+ this.onError(pos, 'BAD_DIRECTIVE', message, warning);
142
+ });
143
+ this.prelude.push(token.source);
144
+ this.atDirectives = true;
145
+ break;
146
+ case 'document': {
147
+ const doc = composeDoc(this.options, this.directives, token, this.onError);
148
+ if (this.atDirectives && !doc.directives.marker)
149
+ this.onError(token, 'MISSING_CHAR', 'Missing directives-end indicator line');
150
+ this.decorate(doc, false);
151
+ if (this.doc)
152
+ yield this.doc;
153
+ this.doc = doc;
154
+ this.atDirectives = false;
155
+ break;
156
+ }
157
+ case 'byte-order-mark':
158
+ case 'space':
159
+ break;
160
+ case 'comment':
161
+ case 'newline':
162
+ this.prelude.push(token.source);
163
+ break;
164
+ case 'error': {
165
+ const msg = token.source
166
+ ? `${token.message}: ${JSON.stringify(token.source)}`
167
+ : token.message;
168
+ const error = new YAMLParseError(getErrorPos(token), 'UNEXPECTED_TOKEN', msg);
169
+ if (this.atDirectives || !this.doc)
170
+ this.errors.push(error);
171
+ else
172
+ this.doc.errors.push(error);
173
+ break;
174
+ }
175
+ case 'doc-end': {
176
+ if (!this.doc) {
177
+ const msg = 'Unexpected doc-end without preceding document';
178
+ this.errors.push(new YAMLParseError(getErrorPos(token), 'UNEXPECTED_TOKEN', msg));
179
+ break;
180
+ }
181
+ const end = resolveEnd(token.end, token.offset + token.source.length, this.doc.options.strict, this.onError);
182
+ this.decorate(this.doc, true);
183
+ if (end.comment) {
184
+ const dc = this.doc.comment;
185
+ this.doc.comment = dc ? `${dc}\n${end.comment}` : end.comment;
186
+ }
187
+ this.doc.range[2] = end.offset;
188
+ break;
189
+ }
190
+ default:
191
+ this.errors.push(new YAMLParseError(getErrorPos(token), 'UNEXPECTED_TOKEN', `Unsupported token ${token.type}`));
192
+ }
193
+ }
194
+ /**
195
+ * Call at end of input to yield any remaining document.
196
+ *
197
+ * @param forceDoc - If the stream contains no document, still emit a final document including any comments and directives that would be applied to a subsequent document.
198
+ * @param endOffset - Should be set if `forceDoc` is also set, to set the document range end and to indicate errors correctly.
199
+ */
200
+ *end(forceDoc = false, endOffset = -1) {
172
201
  if (this.doc) {
173
202
  this.decorate(this.doc, true);
174
- this.onDocument(this.doc);
203
+ yield this.doc;
175
204
  this.doc = null;
176
205
  }
177
206
  else if (forceDoc) {
178
207
  const opts = Object.assign({ directives: this.directives }, this.options);
179
208
  const doc = new Document(undefined, opts);
180
209
  if (this.atDirectives)
181
- this.onError(offset, 'Missing directives-end indicator line');
182
- doc.range = [0, offset];
210
+ this.onError(endOffset, 'MISSING_CHAR', 'Missing directives-end indicator line');
211
+ doc.range = [0, endOffset, endOffset];
183
212
  this.decorate(doc, false);
184
- this.onDocument(doc);
213
+ yield doc;
185
214
  }
186
215
  }
187
216
  }
@@ -4,24 +4,28 @@ import { resolveProps } from './resolve-props.js';
4
4
  import { containsNewline } from './util-contains-newline.js';
5
5
 
6
6
  const startColMsg = 'All mapping items must start at the same column';
7
- function resolveBlockMap({ composeNode, composeEmptyNode }, doc, { indent, items, offset }, anchor, onError) {
7
+ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError) {
8
8
  var _a;
9
- const start = offset;
10
- const map = new YAMLMap(doc.schema);
11
- if (anchor)
12
- doc.anchors.setAnchor(map, anchor);
13
- for (const { start, key, sep, value } of items) {
9
+ const map = new YAMLMap(ctx.schema);
10
+ let offset = bm.offset;
11
+ for (const { start, key, sep, value } of bm.items) {
14
12
  // key properties
15
- const keyProps = resolveProps(doc, start, true, 'explicit-key-ind', offset, onError);
13
+ const keyProps = resolveProps(start, {
14
+ ctx,
15
+ indicator: 'explicit-key-ind',
16
+ offset,
17
+ onError,
18
+ startOnNewline: true
19
+ });
16
20
  const implicitKey = !keyProps.found;
17
21
  if (implicitKey) {
18
22
  if (key) {
19
23
  if (key.type === 'block-seq')
20
- onError(offset, 'A block sequence may not be used as an implicit map key');
21
- else if ('indent' in key && key.indent !== indent)
22
- onError(offset, startColMsg);
24
+ onError(offset, 'BLOCK_AS_IMPLICIT_KEY', 'A block sequence may not be used as an implicit map key');
25
+ else if ('indent' in key && key.indent !== bm.indent)
26
+ onError(offset, 'BAD_INDENT', startColMsg);
23
27
  }
24
- if (!keyProps.anchor && !keyProps.tagName && !sep) {
28
+ if (!keyProps.anchor && !keyProps.tag && !sep) {
25
29
  // TODO: assert being at last item?
26
30
  if (keyProps.comment) {
27
31
  if (map.comment)
@@ -32,39 +36,44 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, doc, { indent, items
32
36
  continue;
33
37
  }
34
38
  }
35
- else if (((_a = keyProps.found) === null || _a === void 0 ? void 0 : _a.indent) !== indent)
36
- onError(offset, startColMsg);
37
- offset += keyProps.length;
39
+ else if (((_a = keyProps.found) === null || _a === void 0 ? void 0 : _a.indent) !== bm.indent)
40
+ onError(offset, 'BAD_INDENT', startColMsg);
38
41
  if (implicitKey && containsNewline(key))
39
- onError(offset, 'Implicit keys need to be on a single line');
42
+ onError(key, // checked by containsNewline()
43
+ 'MULTILINE_IMPLICIT_KEY', 'Implicit keys need to be on a single line');
40
44
  // key value
41
- const keyStart = offset;
45
+ const keyStart = keyProps.end;
42
46
  const keyNode = key
43
- ? composeNode(doc, key, keyProps, onError)
44
- : composeEmptyNode(doc, offset, start, null, keyProps, onError);
45
- offset = keyNode.range[1];
47
+ ? composeNode(ctx, key, keyProps, onError)
48
+ : composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
46
49
  // value properties
47
- const valueProps = resolveProps(doc, sep || [], !key || key.type === 'block-scalar', 'map-value-ind', offset, onError);
48
- offset += valueProps.length;
50
+ const valueProps = resolveProps(sep || [], {
51
+ ctx,
52
+ indicator: 'map-value-ind',
53
+ offset: keyNode.range[2],
54
+ onError,
55
+ startOnNewline: !key || key.type === 'block-scalar'
56
+ });
57
+ offset = valueProps.end;
49
58
  if (valueProps.found) {
50
59
  if (implicitKey) {
51
60
  if ((value === null || value === void 0 ? void 0 : value.type) === 'block-map' && !valueProps.hasNewline)
52
- onError(offset, 'Nested mappings are not allowed in compact mappings');
53
- if (doc.options.strict &&
61
+ onError(offset, 'BLOCK_AS_IMPLICIT_KEY', 'Nested mappings are not allowed in compact mappings');
62
+ if (ctx.options.strict &&
54
63
  keyProps.start < valueProps.found.offset - 1024)
55
- onError(offset, 'The : indicator must be at most 1024 chars after the start of an implicit block mapping key');
64
+ onError(keyNode.range, 'KEY_OVER_1024_CHARS', 'The : indicator must be at most 1024 chars after the start of an implicit block mapping key');
56
65
  }
57
66
  // value value
58
67
  const valueNode = value
59
- ? composeNode(doc, value, valueProps, onError)
60
- : composeEmptyNode(doc, offset, sep, null, valueProps, onError);
61
- offset = valueNode.range[1];
68
+ ? composeNode(ctx, value, valueProps, onError)
69
+ : composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
70
+ offset = valueNode.range[2];
62
71
  map.items.push(new Pair(keyNode, valueNode));
63
72
  }
64
73
  else {
65
74
  // key with no value
66
75
  if (implicitKey)
67
- onError(keyStart, 'Implicit map keys need to be followed by map values');
76
+ onError(keyNode.range, 'MISSING_CHAR', 'Implicit map keys need to be followed by map values');
68
77
  if (valueProps.comment) {
69
78
  if (keyNode.comment)
70
79
  keyNode.comment += '\n' + valueProps.comment;
@@ -74,7 +83,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, doc, { indent, items
74
83
  map.items.push(new Pair(keyNode));
75
84
  }
76
85
  }
77
- map.range = [start, offset];
86
+ map.range = [bm.offset, offset, offset];
78
87
  return map;
79
88
  }
80
89