compose-node.js 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { Alias } from '../nodes/Alias.js';
  2. import { composeCollection } from './compose-collection.js';
  3. import { composeScalar } from './compose-scalar.js';
  4. import { resolveEnd } from './resolve-end.js';
  5. import { emptyScalarPosition } from './util-empty-scalar-position.js';
  6. const CN = { composeNode, composeEmptyNode };
  7. function composeNode(ctx, token, props, onError) {
  8. const { spaceBefore, comment, anchor, tag } = props;
  9. let node;
  10. let isSrcToken = true;
  11. switch (token.type) {
  12. case 'alias':
  13. node = composeAlias(ctx, token, onError);
  14. if (anchor || tag)
  15. onError(token, 'ALIAS_PROPS', 'An alias node must not specify any properties');
  16. break;
  17. case 'scalar':
  18. case 'single-quoted-scalar':
  19. case 'double-quoted-scalar':
  20. case 'block-scalar':
  21. node = composeScalar(ctx, token, tag, onError);
  22. if (anchor)
  23. node.anchor = anchor.source.substring(1);
  24. break;
  25. case 'block-map':
  26. case 'block-seq':
  27. case 'flow-collection':
  28. node = composeCollection(CN, ctx, token, tag, onError);
  29. if (anchor)
  30. node.anchor = anchor.source.substring(1);
  31. break;
  32. default: {
  33. const message = token.type === 'error'
  34. ? token.message
  35. : `Unsupported token (type: ${token.type})`;
  36. onError(token, 'UNEXPECTED_TOKEN', message);
  37. node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError);
  38. isSrcToken = false;
  39. }
  40. }
  41. if (anchor && node.anchor === '')
  42. onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
  43. if (spaceBefore)
  44. node.spaceBefore = true;
  45. if (comment) {
  46. if (token.type === 'scalar' && token.source === '')
  47. node.comment = comment;
  48. else
  49. node.commentBefore = comment;
  50. }
  51. // @ts-expect-error Type checking misses meaning of isSrcToken
  52. if (ctx.options.keepSourceTokens && isSrcToken)
  53. node.srcToken = token;
  54. return node;
  55. }
  56. function composeEmptyNode(ctx, offset, before, pos, { spaceBefore, comment, anchor, tag, end }, onError) {
  57. const token = {
  58. type: 'scalar',
  59. offset: emptyScalarPosition(offset, before, pos),
  60. indent: -1,
  61. source: ''
  62. };
  63. const node = composeScalar(ctx, token, tag, onError);
  64. if (anchor) {
  65. node.anchor = anchor.source.substring(1);
  66. if (node.anchor === '')
  67. onError(anchor, 'BAD_ALIAS', 'Anchor cannot be an empty string');
  68. }
  69. if (spaceBefore)
  70. node.spaceBefore = true;
  71. if (comment) {
  72. node.comment = comment;
  73. node.range[2] = end;
  74. }
  75. return node;
  76. }
  77. function composeAlias({ options }, { offset, source, end }, onError) {
  78. const alias = new Alias(source.substring(1));
  79. if (alias.source === '')
  80. onError(offset, 'BAD_ALIAS', 'Alias cannot be an empty string');
  81. if (alias.source.endsWith(':'))
  82. onError(offset + source.length - 1, 'BAD_ALIAS', 'Alias ending in : is ambiguous', true);
  83. const valueEnd = offset + source.length;
  84. const re = resolveEnd(end, valueEnd, options.strict, onError);
  85. alias.range = [offset, valueEnd, re.offset];
  86. if (re.comment)
  87. alias.comment = re.comment;
  88. return alias;
  89. }
  90. export { composeEmptyNode, composeNode };