compose-collection.js 3.1 KB

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