Няма описание

Alias.js 3.1KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. 'use strict';
  2. var anchors = require('../doc/anchors.js');
  3. var visit = require('../visit.js');
  4. var Node = require('./Node.js');
  5. class Alias extends Node.NodeBase {
  6. constructor(source) {
  7. super(Node.ALIAS);
  8. this.source = source;
  9. Object.defineProperty(this, 'tag', {
  10. set() {
  11. throw new Error('Alias nodes cannot have tags');
  12. }
  13. });
  14. }
  15. /**
  16. * Resolve the value of this alias within `doc`, finding the last
  17. * instance of the `source` anchor before this node.
  18. */
  19. resolve(doc) {
  20. let found = undefined;
  21. visit.visit(doc, {
  22. Node: (_key, node) => {
  23. if (node === this)
  24. return visit.visit.BREAK;
  25. if (node.anchor === this.source)
  26. found = node;
  27. }
  28. });
  29. return found;
  30. }
  31. toJSON(_arg, ctx) {
  32. if (!ctx)
  33. return { source: this.source };
  34. const { anchors, doc, maxAliasCount } = ctx;
  35. const source = this.resolve(doc);
  36. if (!source) {
  37. const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
  38. throw new ReferenceError(msg);
  39. }
  40. const data = anchors.get(source);
  41. /* istanbul ignore if */
  42. if (!data || data.res === undefined) {
  43. const msg = 'This should not happen: Alias anchor was not resolved?';
  44. throw new ReferenceError(msg);
  45. }
  46. if (maxAliasCount >= 0) {
  47. data.count += 1;
  48. if (data.aliasCount === 0)
  49. data.aliasCount = getAliasCount(doc, source, anchors);
  50. if (data.count * data.aliasCount > maxAliasCount) {
  51. const msg = 'Excessive alias count indicates a resource exhaustion attack';
  52. throw new ReferenceError(msg);
  53. }
  54. }
  55. return data.res;
  56. }
  57. toString(ctx, _onComment, _onChompKeep) {
  58. const src = `*${this.source}`;
  59. if (ctx) {
  60. anchors.anchorIsValid(this.source);
  61. if (ctx.options.verifyAliasOrder && !ctx.anchors.has(this.source)) {
  62. const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
  63. throw new Error(msg);
  64. }
  65. if (ctx.implicitKey)
  66. return `${src} `;
  67. }
  68. return src;
  69. }
  70. }
  71. function getAliasCount(doc, node, anchors) {
  72. if (Node.isAlias(node)) {
  73. const source = node.resolve(doc);
  74. const anchor = anchors && source && anchors.get(source);
  75. return anchor ? anchor.count * anchor.aliasCount : 0;
  76. }
  77. else if (Node.isCollection(node)) {
  78. let count = 0;
  79. for (const item of node.items) {
  80. const c = getAliasCount(doc, item, anchors);
  81. if (c > count)
  82. count = c;
  83. }
  84. return count;
  85. }
  86. else if (Node.isPair(node)) {
  87. const kc = getAliasCount(doc, node.key, anchors);
  88. const vc = getAliasCount(doc, node.value, anchors);
  89. return Math.max(kc, vc);
  90. }
  91. return 1;
  92. }
  93. exports.Alias = Alias;