YAMLSeq.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { createNode } from '../doc/createNode.js';
  2. import { stringifyCollection } from '../stringify/stringifyCollection.js';
  3. import { Collection } from './Collection.js';
  4. import { SEQ, isScalar } from './identity.js';
  5. import { isScalarValue } from './Scalar.js';
  6. import { toJS } from './toJS.js';
  7. class YAMLSeq extends Collection {
  8. static get tagName() {
  9. return 'tag:yaml.org,2002:seq';
  10. }
  11. constructor(schema) {
  12. super(SEQ, schema);
  13. this.items = [];
  14. }
  15. add(value) {
  16. this.items.push(value);
  17. }
  18. /**
  19. * Removes a value from the collection.
  20. *
  21. * `key` must contain a representation of an integer for this to succeed.
  22. * It may be wrapped in a `Scalar`.
  23. *
  24. * @returns `true` if the item was found and removed.
  25. */
  26. delete(key) {
  27. const idx = asItemIndex(key);
  28. if (typeof idx !== 'number')
  29. return false;
  30. const del = this.items.splice(idx, 1);
  31. return del.length > 0;
  32. }
  33. get(key, keepScalar) {
  34. const idx = asItemIndex(key);
  35. if (typeof idx !== 'number')
  36. return undefined;
  37. const it = this.items[idx];
  38. return !keepScalar && isScalar(it) ? it.value : it;
  39. }
  40. /**
  41. * Checks if the collection includes a value with the key `key`.
  42. *
  43. * `key` must contain a representation of an integer for this to succeed.
  44. * It may be wrapped in a `Scalar`.
  45. */
  46. has(key) {
  47. const idx = asItemIndex(key);
  48. return typeof idx === 'number' && idx < this.items.length;
  49. }
  50. /**
  51. * Sets a value in this collection. For `!!set`, `value` needs to be a
  52. * boolean to add/remove the item from the set.
  53. *
  54. * If `key` does not contain a representation of an integer, this will throw.
  55. * It may be wrapped in a `Scalar`.
  56. */
  57. set(key, value) {
  58. const idx = asItemIndex(key);
  59. if (typeof idx !== 'number')
  60. throw new Error(`Expected a valid index, not ${key}.`);
  61. const prev = this.items[idx];
  62. if (isScalar(prev) && isScalarValue(value))
  63. prev.value = value;
  64. else
  65. this.items[idx] = value;
  66. }
  67. toJSON(_, ctx) {
  68. const seq = [];
  69. if (ctx?.onCreate)
  70. ctx.onCreate(seq);
  71. let i = 0;
  72. for (const item of this.items)
  73. seq.push(toJS(item, String(i++), ctx));
  74. return seq;
  75. }
  76. toString(ctx, onComment, onChompKeep) {
  77. if (!ctx)
  78. return JSON.stringify(this);
  79. return stringifyCollection(this, ctx, {
  80. blockItemPrefix: '- ',
  81. flowChars: { start: '[', end: ']' },
  82. itemIndent: (ctx.indent || '') + ' ',
  83. onChompKeep,
  84. onComment
  85. });
  86. }
  87. static from(schema, obj, ctx) {
  88. const { replacer } = ctx;
  89. const seq = new this(schema);
  90. if (obj && Symbol.iterator in Object(obj)) {
  91. let i = 0;
  92. for (let it of obj) {
  93. if (typeof replacer === 'function') {
  94. const key = obj instanceof Set ? it : String(i++);
  95. it = replacer.call(obj, key, it);
  96. }
  97. seq.items.push(createNode(it, undefined, ctx));
  98. }
  99. }
  100. return seq;
  101. }
  102. }
  103. function asItemIndex(key) {
  104. let idx = isScalar(key) ? key.value : key;
  105. if (idx && typeof idx === 'string')
  106. idx = Number(idx);
  107. return typeof idx === 'number' && Number.isInteger(idx) && idx >= 0
  108. ? idx
  109. : null;
  110. }
  111. export { YAMLSeq };