Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Collection.js 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.grabCollectionEndComments = grabCollectionEndComments;
  6. exports.default = void 0;
  7. var _constants = require("../constants");
  8. var _BlankLine = _interopRequireDefault(require("./BlankLine"));
  9. var _CollectionItem = _interopRequireDefault(require("./CollectionItem"));
  10. var _Comment = _interopRequireDefault(require("./Comment"));
  11. var _Node = _interopRequireDefault(require("./Node"));
  12. var _Range = _interopRequireDefault(require("./Range"));
  13. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  14. function grabCollectionEndComments(node) {
  15. let cnode = node;
  16. while (cnode instanceof _CollectionItem.default) cnode = cnode.node;
  17. if (!(cnode instanceof Collection)) return null;
  18. const len = cnode.items.length;
  19. let ci = -1;
  20. for (let i = len - 1; i >= 0; --i) {
  21. const n = cnode.items[i];
  22. if (n.type === _constants.Type.COMMENT) {
  23. // Keep sufficiently indented comments with preceding node
  24. const {
  25. indent,
  26. lineStart
  27. } = n.context;
  28. if (indent > 0 && n.range.start >= lineStart + indent) break;
  29. ci = i;
  30. } else if (n.type === _constants.Type.BLANK_LINE) ci = i;else break;
  31. }
  32. if (ci === -1) return null;
  33. const ca = cnode.items.splice(ci, len - ci);
  34. const prevEnd = ca[0].range.start;
  35. while (true) {
  36. cnode.range.end = prevEnd;
  37. if (cnode.valueRange && cnode.valueRange.end > prevEnd) cnode.valueRange.end = prevEnd;
  38. if (cnode === node) break;
  39. cnode = cnode.context.parent;
  40. }
  41. return ca;
  42. }
  43. class Collection extends _Node.default {
  44. static nextContentHasIndent(src, offset, indent) {
  45. const lineStart = _Node.default.endOfLine(src, offset) + 1;
  46. offset = _Node.default.endOfWhiteSpace(src, lineStart);
  47. const ch = src[offset];
  48. if (!ch) return false;
  49. if (offset >= lineStart + indent) return true;
  50. if (ch !== '#' && ch !== '\n') return false;
  51. return Collection.nextContentHasIndent(src, offset, indent);
  52. }
  53. constructor(firstItem) {
  54. super(firstItem.type === _constants.Type.SEQ_ITEM ? _constants.Type.SEQ : _constants.Type.MAP);
  55. for (let i = firstItem.props.length - 1; i >= 0; --i) {
  56. if (firstItem.props[i].start < firstItem.context.lineStart) {
  57. // props on previous line are assumed by the collection
  58. this.props = firstItem.props.slice(0, i + 1);
  59. firstItem.props = firstItem.props.slice(i + 1);
  60. const itemRange = firstItem.props[0] || firstItem.valueRange;
  61. firstItem.range.start = itemRange.start;
  62. break;
  63. }
  64. }
  65. this.items = [firstItem];
  66. const ec = grabCollectionEndComments(firstItem);
  67. if (ec) Array.prototype.push.apply(this.items, ec);
  68. }
  69. get includesTrailingLines() {
  70. return this.items.length > 0;
  71. }
  72. /**
  73. * @param {ParseContext} context
  74. * @param {number} start - Index of first character
  75. * @returns {number} - Index of the character after this
  76. */
  77. parse(context, start) {
  78. this.context = context;
  79. const {
  80. parseNode,
  81. src
  82. } = context; // It's easier to recalculate lineStart here rather than tracking down the
  83. // last context from which to read it -- eemeli/yaml#2
  84. let lineStart = _Node.default.startOfLine(src, start);
  85. const firstItem = this.items[0]; // First-item context needs to be correct for later comment handling
  86. // -- eemeli/yaml#17
  87. firstItem.context.parent = this;
  88. this.valueRange = _Range.default.copy(firstItem.valueRange);
  89. const indent = firstItem.range.start - firstItem.context.lineStart;
  90. let offset = start;
  91. offset = _Node.default.normalizeOffset(src, offset);
  92. let ch = src[offset];
  93. let atLineStart = _Node.default.endOfWhiteSpace(src, lineStart) === offset;
  94. let prevIncludesTrailingLines = false;
  95. while (ch) {
  96. while (ch === '\n' || ch === '#') {
  97. if (atLineStart && ch === '\n' && !prevIncludesTrailingLines) {
  98. const blankLine = new _BlankLine.default();
  99. offset = blankLine.parse({
  100. src
  101. }, offset);
  102. this.valueRange.end = offset;
  103. if (offset >= src.length) {
  104. ch = null;
  105. break;
  106. }
  107. this.items.push(blankLine);
  108. offset -= 1; // blankLine.parse() consumes terminal newline
  109. } else if (ch === '#') {
  110. if (offset < lineStart + indent && !Collection.nextContentHasIndent(src, offset, indent)) {
  111. return offset;
  112. }
  113. const comment = new _Comment.default();
  114. offset = comment.parse({
  115. indent,
  116. lineStart,
  117. src
  118. }, offset);
  119. this.items.push(comment);
  120. this.valueRange.end = offset;
  121. if (offset >= src.length) {
  122. ch = null;
  123. break;
  124. }
  125. }
  126. lineStart = offset + 1;
  127. offset = _Node.default.endOfIndent(src, lineStart);
  128. if (_Node.default.atBlank(src, offset)) {
  129. const wsEnd = _Node.default.endOfWhiteSpace(src, offset);
  130. const next = src[wsEnd];
  131. if (!next || next === '\n' || next === '#') {
  132. offset = wsEnd;
  133. }
  134. }
  135. ch = src[offset];
  136. atLineStart = true;
  137. }
  138. if (!ch) {
  139. break;
  140. }
  141. if (offset !== lineStart + indent && (atLineStart || ch !== ':')) {
  142. if (lineStart > start) offset = lineStart;
  143. break;
  144. }
  145. if (firstItem.type === _constants.Type.SEQ_ITEM !== (ch === '-')) {
  146. let typeswitch = true;
  147. if (ch === '-') {
  148. // map key may start with -, as long as it's followed by a non-whitespace char
  149. const next = src[offset + 1];
  150. typeswitch = !next || next === '\n' || next === '\t' || next === ' ';
  151. }
  152. if (typeswitch) {
  153. if (lineStart > start) offset = lineStart;
  154. break;
  155. }
  156. }
  157. const node = parseNode({
  158. atLineStart,
  159. inCollection: true,
  160. indent,
  161. lineStart,
  162. parent: this
  163. }, offset);
  164. if (!node) return offset; // at next document start
  165. this.items.push(node);
  166. this.valueRange.end = node.valueRange.end;
  167. offset = _Node.default.normalizeOffset(src, node.range.end);
  168. ch = src[offset];
  169. atLineStart = false;
  170. prevIncludesTrailingLines = node.includesTrailingLines; // Need to reset lineStart and atLineStart here if preceding node's range
  171. // has advanced to check the current line's indentation level
  172. // -- eemeli/yaml#10 & eemeli/yaml#38
  173. if (ch) {
  174. let ls = offset - 1;
  175. let prev = src[ls];
  176. while (prev === ' ' || prev === '\t') prev = src[--ls];
  177. if (prev === '\n') {
  178. lineStart = ls + 1;
  179. atLineStart = true;
  180. }
  181. }
  182. const ec = grabCollectionEndComments(node);
  183. if (ec) Array.prototype.push.apply(this.items, ec);
  184. }
  185. return offset;
  186. }
  187. setOrigRanges(cr, offset) {
  188. offset = super.setOrigRanges(cr, offset);
  189. this.items.forEach(node => {
  190. offset = node.setOrigRanges(cr, offset);
  191. });
  192. return offset;
  193. }
  194. toString() {
  195. const {
  196. context: {
  197. src
  198. },
  199. items,
  200. range,
  201. value
  202. } = this;
  203. if (value != null) return value;
  204. let str = src.slice(range.start, items[0].range.start) + String(items[0]);
  205. for (let i = 1; i < items.length; ++i) {
  206. const item = items[i];
  207. const {
  208. atLineStart,
  209. indent
  210. } = item.context;
  211. if (atLineStart) for (let i = 0; i < indent; ++i) str += ' ';
  212. str += String(item);
  213. }
  214. return _Node.default.addStringTerminator(src, range.end, str);
  215. }
  216. }
  217. exports.default = Collection;