compose-scalar.js 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. 'use strict';
  2. var identity = require('../nodes/identity.js');
  3. var Scalar = require('../nodes/Scalar.js');
  4. var resolveBlockScalar = require('./resolve-block-scalar.js');
  5. var resolveFlowScalar = require('./resolve-flow-scalar.js');
  6. function composeScalar(ctx, token, tagToken, onError) {
  7. const { value, type, comment, range } = token.type === 'block-scalar'
  8. ? resolveBlockScalar.resolveBlockScalar(token, ctx.options.strict, onError)
  9. : resolveFlowScalar.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. : token.type === 'scalar'
  16. ? findScalarTagByTest(ctx, value, token, onError)
  17. : ctx.schema[identity.SCALAR];
  18. let scalar;
  19. try {
  20. const res = tag.resolve(value, msg => onError(tagToken ?? token, 'TAG_RESOLVE_FAILED', msg), ctx.options);
  21. scalar = identity.isScalar(res) ? res : new Scalar.Scalar(res);
  22. }
  23. catch (error) {
  24. const msg = error instanceof Error ? error.message : String(error);
  25. onError(tagToken ?? token, 'TAG_RESOLVE_FAILED', msg);
  26. scalar = new Scalar.Scalar(value);
  27. }
  28. scalar.range = range;
  29. scalar.source = value;
  30. if (type)
  31. scalar.type = type;
  32. if (tagName)
  33. scalar.tag = tagName;
  34. if (tag.format)
  35. scalar.format = tag.format;
  36. if (comment)
  37. scalar.comment = comment;
  38. return scalar;
  39. }
  40. function findScalarTagByName(schema, value, tagName, tagToken, onError) {
  41. if (tagName === '!')
  42. return schema[identity.SCALAR]; // non-specific tag
  43. const matchWithTest = [];
  44. for (const tag of schema.tags) {
  45. if (!tag.collection && tag.tag === tagName) {
  46. if (tag.default && tag.test)
  47. matchWithTest.push(tag);
  48. else
  49. return tag;
  50. }
  51. }
  52. for (const tag of matchWithTest)
  53. if (tag.test?.test(value))
  54. return tag;
  55. const kt = schema.knownTags[tagName];
  56. if (kt && !kt.collection) {
  57. // Ensure that the known tag is available for stringifying,
  58. // but does not get used by default.
  59. schema.tags.push(Object.assign({}, kt, { default: false, test: undefined }));
  60. return kt;
  61. }
  62. onError(tagToken, 'TAG_RESOLVE_FAILED', `Unresolved tag: ${tagName}`, tagName !== 'tag:yaml.org,2002:str');
  63. return schema[identity.SCALAR];
  64. }
  65. function findScalarTagByTest({ directives, schema }, value, token, onError) {
  66. const tag = schema.tags.find(tag => tag.default && tag.test?.test(value)) || schema[identity.SCALAR];
  67. if (schema.compat) {
  68. const compat = schema.compat.find(tag => tag.default && tag.test?.test(value)) ??
  69. schema[identity.SCALAR];
  70. if (tag.tag !== compat.tag) {
  71. const ts = directives.tagString(tag.tag);
  72. const cs = directives.tagString(compat.tag);
  73. const msg = `Value may be parsed as either ${ts} or ${cs}`;
  74. onError(token, 'TAG_RESOLVE_FAILED', msg, true);
  75. }
  76. }
  77. return tag;
  78. }
  79. exports.composeScalar = composeScalar;