compose-collection.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { isNode } from '../nodes/identity.js';
  2. import { Scalar } from '../nodes/Scalar.js';
  3. import { YAMLMap } from '../nodes/YAMLMap.js';
  4. import { YAMLSeq } from '../nodes/YAMLSeq.js';
  5. import { resolveBlockMap } from './resolve-block-map.js';
  6. import { resolveBlockSeq } from './resolve-block-seq.js';
  7. import { resolveFlowCollection } from './resolve-flow-collection.js';
  8. function resolveCollection(CN, ctx, token, onError, tagName, tag) {
  9. const coll = token.type === 'block-map'
  10. ? resolveBlockMap(CN, ctx, token, onError, tag)
  11. : token.type === 'block-seq'
  12. ? resolveBlockSeq(CN, ctx, token, onError, tag)
  13. : resolveFlowCollection(CN, ctx, token, onError, tag);
  14. const Coll = coll.constructor;
  15. // If we got a tagName matching the class, or the tag name is '!',
  16. // then use the tagName from the node class used to create it.
  17. if (tagName === '!' || tagName === Coll.tagName) {
  18. coll.tag = Coll.tagName;
  19. return coll;
  20. }
  21. if (tagName)
  22. coll.tag = tagName;
  23. return coll;
  24. }
  25. function composeCollection(CN, ctx, token, tagToken, onError) {
  26. const tagName = !tagToken
  27. ? null
  28. : ctx.directives.tagName(tagToken.source, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg));
  29. const expType = token.type === 'block-map'
  30. ? 'map'
  31. : token.type === 'block-seq'
  32. ? 'seq'
  33. : token.start.source === '{'
  34. ? 'map'
  35. : 'seq';
  36. // shortcut: check if it's a generic YAMLMap or YAMLSeq
  37. // before jumping into the custom tag logic.
  38. if (!tagToken ||
  39. !tagName ||
  40. tagName === '!' ||
  41. (tagName === YAMLMap.tagName && expType === 'map') ||
  42. (tagName === YAMLSeq.tagName && expType === 'seq') ||
  43. !expType) {
  44. return resolveCollection(CN, ctx, token, onError, tagName);
  45. }
  46. let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
  47. if (!tag) {
  48. const kt = ctx.schema.knownTags[tagName];
  49. if (kt && kt.collection === expType) {
  50. ctx.schema.tags.push(Object.assign({}, kt, { default: false }));
  51. tag = kt;
  52. }
  53. else {
  54. if (kt?.collection) {
  55. onError(tagToken, 'BAD_COLLECTION_TYPE', `${kt.tag} used for ${expType} collection, but expects ${kt.collection}`, true);
  56. }
  57. else {
  58. onError(tagToken, 'TAG_RESOLVE_FAILED', `Unresolved tag: ${tagName}`, true);
  59. }
  60. return resolveCollection(CN, ctx, token, onError, tagName);
  61. }
  62. }
  63. const coll = resolveCollection(CN, ctx, token, onError, tagName, tag);
  64. const res = tag.resolve?.(coll, msg => onError(tagToken, 'TAG_RESOLVE_FAILED', msg), ctx.options) ?? coll;
  65. const node = isNode(res)
  66. ? res
  67. : new Scalar(res);
  68. node.range = coll.range;
  69. node.tag = tagName;
  70. if (tag?.format)
  71. node.format = tag.format;
  72. return node;
  73. }
  74. export { composeCollection };