lines.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.concat = exports.fromString = exports.countSpaces = exports.Lines = void 0;
  4. var tslib_1 = require("tslib");
  5. var assert_1 = tslib_1.__importDefault(require("assert"));
  6. var source_map_1 = tslib_1.__importDefault(require("source-map"));
  7. var options_1 = require("./options");
  8. var util_1 = require("./util");
  9. var mapping_1 = tslib_1.__importDefault(require("./mapping"));
  10. var Lines = /** @class */ (function () {
  11. function Lines(infos, sourceFileName) {
  12. if (sourceFileName === void 0) { sourceFileName = null; }
  13. this.infos = infos;
  14. this.mappings = [];
  15. this.cachedSourceMap = null;
  16. this.cachedTabWidth = void 0;
  17. assert_1.default.ok(infos.length > 0);
  18. this.length = infos.length;
  19. this.name = sourceFileName || null;
  20. if (this.name) {
  21. this.mappings.push(new mapping_1.default(this, {
  22. start: this.firstPos(),
  23. end: this.lastPos(),
  24. }));
  25. }
  26. }
  27. Lines.prototype.toString = function (options) {
  28. return this.sliceString(this.firstPos(), this.lastPos(), options);
  29. };
  30. Lines.prototype.getSourceMap = function (sourceMapName, sourceRoot) {
  31. if (!sourceMapName) {
  32. // Although we could make up a name or generate an anonymous
  33. // source map, instead we assume that any consumer who does not
  34. // provide a name does not actually want a source map.
  35. return null;
  36. }
  37. var targetLines = this;
  38. function updateJSON(json) {
  39. json = json || {};
  40. json.file = sourceMapName;
  41. if (sourceRoot) {
  42. json.sourceRoot = sourceRoot;
  43. }
  44. return json;
  45. }
  46. if (targetLines.cachedSourceMap) {
  47. // Since Lines objects are immutable, we can reuse any source map
  48. // that was previously generated. Nevertheless, we return a new
  49. // JSON object here to protect the cached source map from outside
  50. // modification.
  51. return updateJSON(targetLines.cachedSourceMap.toJSON());
  52. }
  53. var smg = new source_map_1.default.SourceMapGenerator(updateJSON());
  54. var sourcesToContents = {};
  55. targetLines.mappings.forEach(function (mapping) {
  56. var sourceCursor = mapping.sourceLines.skipSpaces(mapping.sourceLoc.start) ||
  57. mapping.sourceLines.lastPos();
  58. var targetCursor = targetLines.skipSpaces(mapping.targetLoc.start) ||
  59. targetLines.lastPos();
  60. while ((0, util_1.comparePos)(sourceCursor, mapping.sourceLoc.end) < 0 &&
  61. (0, util_1.comparePos)(targetCursor, mapping.targetLoc.end) < 0) {
  62. var sourceChar = mapping.sourceLines.charAt(sourceCursor);
  63. var targetChar = targetLines.charAt(targetCursor);
  64. assert_1.default.strictEqual(sourceChar, targetChar);
  65. var sourceName = mapping.sourceLines.name;
  66. // Add mappings one character at a time for maximum resolution.
  67. smg.addMapping({
  68. source: sourceName,
  69. original: { line: sourceCursor.line, column: sourceCursor.column },
  70. generated: { line: targetCursor.line, column: targetCursor.column },
  71. });
  72. if (!hasOwn.call(sourcesToContents, sourceName)) {
  73. var sourceContent = mapping.sourceLines.toString();
  74. smg.setSourceContent(sourceName, sourceContent);
  75. sourcesToContents[sourceName] = sourceContent;
  76. }
  77. targetLines.nextPos(targetCursor, true);
  78. mapping.sourceLines.nextPos(sourceCursor, true);
  79. }
  80. });
  81. targetLines.cachedSourceMap = smg;
  82. return smg.toJSON();
  83. };
  84. Lines.prototype.bootstrapCharAt = function (pos) {
  85. assert_1.default.strictEqual(typeof pos, "object");
  86. assert_1.default.strictEqual(typeof pos.line, "number");
  87. assert_1.default.strictEqual(typeof pos.column, "number");
  88. var line = pos.line, column = pos.column, strings = this.toString().split(lineTerminatorSeqExp), string = strings[line - 1];
  89. if (typeof string === "undefined")
  90. return "";
  91. if (column === string.length && line < strings.length)
  92. return "\n";
  93. if (column >= string.length)
  94. return "";
  95. return string.charAt(column);
  96. };
  97. Lines.prototype.charAt = function (pos) {
  98. assert_1.default.strictEqual(typeof pos, "object");
  99. assert_1.default.strictEqual(typeof pos.line, "number");
  100. assert_1.default.strictEqual(typeof pos.column, "number");
  101. var line = pos.line, column = pos.column, secret = this, infos = secret.infos, info = infos[line - 1], c = column;
  102. if (typeof info === "undefined" || c < 0)
  103. return "";
  104. var indent = this.getIndentAt(line);
  105. if (c < indent)
  106. return " ";
  107. c += info.sliceStart - indent;
  108. if (c === info.sliceEnd && line < this.length)
  109. return "\n";
  110. if (c >= info.sliceEnd)
  111. return "";
  112. return info.line.charAt(c);
  113. };
  114. Lines.prototype.stripMargin = function (width, skipFirstLine) {
  115. if (width === 0)
  116. return this;
  117. assert_1.default.ok(width > 0, "negative margin: " + width);
  118. if (skipFirstLine && this.length === 1)
  119. return this;
  120. var lines = new Lines(this.infos.map(function (info, i) {
  121. if (info.line && (i > 0 || !skipFirstLine)) {
  122. info = tslib_1.__assign(tslib_1.__assign({}, info), { indent: Math.max(0, info.indent - width) });
  123. }
  124. return info;
  125. }));
  126. if (this.mappings.length > 0) {
  127. var newMappings_1 = lines.mappings;
  128. assert_1.default.strictEqual(newMappings_1.length, 0);
  129. this.mappings.forEach(function (mapping) {
  130. newMappings_1.push(mapping.indent(width, skipFirstLine, true));
  131. });
  132. }
  133. return lines;
  134. };
  135. Lines.prototype.indent = function (by) {
  136. if (by === 0) {
  137. return this;
  138. }
  139. var lines = new Lines(this.infos.map(function (info) {
  140. if (info.line && !info.locked) {
  141. info = tslib_1.__assign(tslib_1.__assign({}, info), { indent: info.indent + by });
  142. }
  143. return info;
  144. }));
  145. if (this.mappings.length > 0) {
  146. var newMappings_2 = lines.mappings;
  147. assert_1.default.strictEqual(newMappings_2.length, 0);
  148. this.mappings.forEach(function (mapping) {
  149. newMappings_2.push(mapping.indent(by));
  150. });
  151. }
  152. return lines;
  153. };
  154. Lines.prototype.indentTail = function (by) {
  155. if (by === 0) {
  156. return this;
  157. }
  158. if (this.length < 2) {
  159. return this;
  160. }
  161. var lines = new Lines(this.infos.map(function (info, i) {
  162. if (i > 0 && info.line && !info.locked) {
  163. info = tslib_1.__assign(tslib_1.__assign({}, info), { indent: info.indent + by });
  164. }
  165. return info;
  166. }));
  167. if (this.mappings.length > 0) {
  168. var newMappings_3 = lines.mappings;
  169. assert_1.default.strictEqual(newMappings_3.length, 0);
  170. this.mappings.forEach(function (mapping) {
  171. newMappings_3.push(mapping.indent(by, true));
  172. });
  173. }
  174. return lines;
  175. };
  176. Lines.prototype.lockIndentTail = function () {
  177. if (this.length < 2) {
  178. return this;
  179. }
  180. return new Lines(this.infos.map(function (info, i) { return (tslib_1.__assign(tslib_1.__assign({}, info), { locked: i > 0 })); }));
  181. };
  182. Lines.prototype.getIndentAt = function (line) {
  183. assert_1.default.ok(line >= 1, "no line " + line + " (line numbers start from 1)");
  184. return Math.max(this.infos[line - 1].indent, 0);
  185. };
  186. Lines.prototype.guessTabWidth = function () {
  187. if (typeof this.cachedTabWidth === "number") {
  188. return this.cachedTabWidth;
  189. }
  190. var counts = []; // Sparse array.
  191. var lastIndent = 0;
  192. for (var line = 1, last = this.length; line <= last; ++line) {
  193. var info = this.infos[line - 1];
  194. var sliced = info.line.slice(info.sliceStart, info.sliceEnd);
  195. // Whitespace-only lines don't tell us much about the likely tab
  196. // width of this code.
  197. if (isOnlyWhitespace(sliced)) {
  198. continue;
  199. }
  200. var diff = Math.abs(info.indent - lastIndent);
  201. counts[diff] = ~~counts[diff] + 1;
  202. lastIndent = info.indent;
  203. }
  204. var maxCount = -1;
  205. var result = 2;
  206. for (var tabWidth = 1; tabWidth < counts.length; tabWidth += 1) {
  207. if (hasOwn.call(counts, tabWidth) && counts[tabWidth] > maxCount) {
  208. maxCount = counts[tabWidth];
  209. result = tabWidth;
  210. }
  211. }
  212. return (this.cachedTabWidth = result);
  213. };
  214. // Determine if the list of lines has a first line that starts with a //
  215. // or /* comment. If this is the case, the code may need to be wrapped in
  216. // parens to avoid ASI issues.
  217. Lines.prototype.startsWithComment = function () {
  218. if (this.infos.length === 0) {
  219. return false;
  220. }
  221. var firstLineInfo = this.infos[0], sliceStart = firstLineInfo.sliceStart, sliceEnd = firstLineInfo.sliceEnd, firstLine = firstLineInfo.line.slice(sliceStart, sliceEnd).trim();
  222. return (firstLine.length === 0 ||
  223. firstLine.slice(0, 2) === "//" ||
  224. firstLine.slice(0, 2) === "/*");
  225. };
  226. Lines.prototype.isOnlyWhitespace = function () {
  227. return isOnlyWhitespace(this.toString());
  228. };
  229. Lines.prototype.isPrecededOnlyByWhitespace = function (pos) {
  230. var info = this.infos[pos.line - 1];
  231. var indent = Math.max(info.indent, 0);
  232. var diff = pos.column - indent;
  233. if (diff <= 0) {
  234. // If pos.column does not exceed the indentation amount, then
  235. // there must be only whitespace before it.
  236. return true;
  237. }
  238. var start = info.sliceStart;
  239. var end = Math.min(start + diff, info.sliceEnd);
  240. var prefix = info.line.slice(start, end);
  241. return isOnlyWhitespace(prefix);
  242. };
  243. Lines.prototype.getLineLength = function (line) {
  244. var info = this.infos[line - 1];
  245. return this.getIndentAt(line) + info.sliceEnd - info.sliceStart;
  246. };
  247. Lines.prototype.nextPos = function (pos, skipSpaces) {
  248. if (skipSpaces === void 0) { skipSpaces = false; }
  249. var l = Math.max(pos.line, 0), c = Math.max(pos.column, 0);
  250. if (c < this.getLineLength(l)) {
  251. pos.column += 1;
  252. return skipSpaces ? !!this.skipSpaces(pos, false, true) : true;
  253. }
  254. if (l < this.length) {
  255. pos.line += 1;
  256. pos.column = 0;
  257. return skipSpaces ? !!this.skipSpaces(pos, false, true) : true;
  258. }
  259. return false;
  260. };
  261. Lines.prototype.prevPos = function (pos, skipSpaces) {
  262. if (skipSpaces === void 0) { skipSpaces = false; }
  263. var l = pos.line, c = pos.column;
  264. if (c < 1) {
  265. l -= 1;
  266. if (l < 1)
  267. return false;
  268. c = this.getLineLength(l);
  269. }
  270. else {
  271. c = Math.min(c - 1, this.getLineLength(l));
  272. }
  273. pos.line = l;
  274. pos.column = c;
  275. return skipSpaces ? !!this.skipSpaces(pos, true, true) : true;
  276. };
  277. Lines.prototype.firstPos = function () {
  278. // Trivial, but provided for completeness.
  279. return { line: 1, column: 0 };
  280. };
  281. Lines.prototype.lastPos = function () {
  282. return {
  283. line: this.length,
  284. column: this.getLineLength(this.length),
  285. };
  286. };
  287. Lines.prototype.skipSpaces = function (pos, backward, modifyInPlace) {
  288. if (backward === void 0) { backward = false; }
  289. if (modifyInPlace === void 0) { modifyInPlace = false; }
  290. if (pos) {
  291. pos = modifyInPlace
  292. ? pos
  293. : {
  294. line: pos.line,
  295. column: pos.column,
  296. };
  297. }
  298. else if (backward) {
  299. pos = this.lastPos();
  300. }
  301. else {
  302. pos = this.firstPos();
  303. }
  304. if (backward) {
  305. while (this.prevPos(pos)) {
  306. if (!isOnlyWhitespace(this.charAt(pos)) && this.nextPos(pos)) {
  307. return pos;
  308. }
  309. }
  310. return null;
  311. }
  312. else {
  313. while (isOnlyWhitespace(this.charAt(pos))) {
  314. if (!this.nextPos(pos)) {
  315. return null;
  316. }
  317. }
  318. return pos;
  319. }
  320. };
  321. Lines.prototype.trimLeft = function () {
  322. var pos = this.skipSpaces(this.firstPos(), false, true);
  323. return pos ? this.slice(pos) : emptyLines;
  324. };
  325. Lines.prototype.trimRight = function () {
  326. var pos = this.skipSpaces(this.lastPos(), true, true);
  327. return pos ? this.slice(this.firstPos(), pos) : emptyLines;
  328. };
  329. Lines.prototype.trim = function () {
  330. var start = this.skipSpaces(this.firstPos(), false, true);
  331. if (start === null) {
  332. return emptyLines;
  333. }
  334. var end = this.skipSpaces(this.lastPos(), true, true);
  335. if (end === null) {
  336. return emptyLines;
  337. }
  338. return this.slice(start, end);
  339. };
  340. Lines.prototype.eachPos = function (callback, startPos, skipSpaces) {
  341. if (startPos === void 0) { startPos = this.firstPos(); }
  342. if (skipSpaces === void 0) { skipSpaces = false; }
  343. var pos = this.firstPos();
  344. if (startPos) {
  345. (pos.line = startPos.line), (pos.column = startPos.column);
  346. }
  347. if (skipSpaces && !this.skipSpaces(pos, false, true)) {
  348. return; // Encountered nothing but spaces.
  349. }
  350. do
  351. callback.call(this, pos);
  352. while (this.nextPos(pos, skipSpaces));
  353. };
  354. Lines.prototype.bootstrapSlice = function (start, end) {
  355. var strings = this.toString()
  356. .split(lineTerminatorSeqExp)
  357. .slice(start.line - 1, end.line);
  358. if (strings.length > 0) {
  359. strings.push(strings.pop().slice(0, end.column));
  360. strings[0] = strings[0].slice(start.column);
  361. }
  362. return fromString(strings.join("\n"));
  363. };
  364. Lines.prototype.slice = function (start, end) {
  365. if (!end) {
  366. if (!start) {
  367. // The client seems to want a copy of this Lines object, but
  368. // Lines objects are immutable, so it's perfectly adequate to
  369. // return the same object.
  370. return this;
  371. }
  372. // Slice to the end if no end position was provided.
  373. end = this.lastPos();
  374. }
  375. if (!start) {
  376. throw new Error("cannot slice with end but not start");
  377. }
  378. var sliced = this.infos.slice(start.line - 1, end.line);
  379. if (start.line === end.line) {
  380. sliced[0] = sliceInfo(sliced[0], start.column, end.column);
  381. }
  382. else {
  383. assert_1.default.ok(start.line < end.line);
  384. sliced[0] = sliceInfo(sliced[0], start.column);
  385. sliced.push(sliceInfo(sliced.pop(), 0, end.column));
  386. }
  387. var lines = new Lines(sliced);
  388. if (this.mappings.length > 0) {
  389. var newMappings_4 = lines.mappings;
  390. assert_1.default.strictEqual(newMappings_4.length, 0);
  391. this.mappings.forEach(function (mapping) {
  392. var sliced = mapping.slice(this, start, end);
  393. if (sliced) {
  394. newMappings_4.push(sliced);
  395. }
  396. }, this);
  397. }
  398. return lines;
  399. };
  400. Lines.prototype.bootstrapSliceString = function (start, end, options) {
  401. return this.slice(start, end).toString(options);
  402. };
  403. Lines.prototype.sliceString = function (start, end, options) {
  404. if (start === void 0) { start = this.firstPos(); }
  405. if (end === void 0) { end = this.lastPos(); }
  406. var _a = (0, options_1.normalize)(options), tabWidth = _a.tabWidth, useTabs = _a.useTabs, reuseWhitespace = _a.reuseWhitespace, lineTerminator = _a.lineTerminator;
  407. var parts = [];
  408. for (var line = start.line; line <= end.line; ++line) {
  409. var info = this.infos[line - 1];
  410. if (line === start.line) {
  411. if (line === end.line) {
  412. info = sliceInfo(info, start.column, end.column);
  413. }
  414. else {
  415. info = sliceInfo(info, start.column);
  416. }
  417. }
  418. else if (line === end.line) {
  419. info = sliceInfo(info, 0, end.column);
  420. }
  421. var indent = Math.max(info.indent, 0);
  422. var before_1 = info.line.slice(0, info.sliceStart);
  423. if (reuseWhitespace &&
  424. isOnlyWhitespace(before_1) &&
  425. countSpaces(before_1, tabWidth) === indent) {
  426. // Reuse original spaces if the indentation is correct.
  427. parts.push(info.line.slice(0, info.sliceEnd));
  428. continue;
  429. }
  430. var tabs = 0;
  431. var spaces = indent;
  432. if (useTabs) {
  433. tabs = Math.floor(indent / tabWidth);
  434. spaces -= tabs * tabWidth;
  435. }
  436. var result = "";
  437. if (tabs > 0) {
  438. result += new Array(tabs + 1).join("\t");
  439. }
  440. if (spaces > 0) {
  441. result += new Array(spaces + 1).join(" ");
  442. }
  443. result += info.line.slice(info.sliceStart, info.sliceEnd);
  444. parts.push(result);
  445. }
  446. return parts.join(lineTerminator);
  447. };
  448. Lines.prototype.isEmpty = function () {
  449. return this.length < 2 && this.getLineLength(1) < 1;
  450. };
  451. Lines.prototype.join = function (elements) {
  452. var separator = this;
  453. var infos = [];
  454. var mappings = [];
  455. var prevInfo;
  456. function appendLines(linesOrNull) {
  457. if (linesOrNull === null) {
  458. return;
  459. }
  460. if (prevInfo) {
  461. var info = linesOrNull.infos[0];
  462. var indent = new Array(info.indent + 1).join(" ");
  463. var prevLine_1 = infos.length;
  464. var prevColumn_1 = Math.max(prevInfo.indent, 0) +
  465. prevInfo.sliceEnd -
  466. prevInfo.sliceStart;
  467. prevInfo.line =
  468. prevInfo.line.slice(0, prevInfo.sliceEnd) +
  469. indent +
  470. info.line.slice(info.sliceStart, info.sliceEnd);
  471. // If any part of a line is indentation-locked, the whole line
  472. // will be indentation-locked.
  473. prevInfo.locked = prevInfo.locked || info.locked;
  474. prevInfo.sliceEnd = prevInfo.line.length;
  475. if (linesOrNull.mappings.length > 0) {
  476. linesOrNull.mappings.forEach(function (mapping) {
  477. mappings.push(mapping.add(prevLine_1, prevColumn_1));
  478. });
  479. }
  480. }
  481. else if (linesOrNull.mappings.length > 0) {
  482. mappings.push.apply(mappings, linesOrNull.mappings);
  483. }
  484. linesOrNull.infos.forEach(function (info, i) {
  485. if (!prevInfo || i > 0) {
  486. prevInfo = tslib_1.__assign({}, info);
  487. infos.push(prevInfo);
  488. }
  489. });
  490. }
  491. function appendWithSeparator(linesOrNull, i) {
  492. if (i > 0)
  493. appendLines(separator);
  494. appendLines(linesOrNull);
  495. }
  496. elements
  497. .map(function (elem) {
  498. var lines = fromString(elem);
  499. if (lines.isEmpty())
  500. return null;
  501. return lines;
  502. })
  503. .forEach(function (linesOrNull, i) {
  504. if (separator.isEmpty()) {
  505. appendLines(linesOrNull);
  506. }
  507. else {
  508. appendWithSeparator(linesOrNull, i);
  509. }
  510. });
  511. if (infos.length < 1)
  512. return emptyLines;
  513. var lines = new Lines(infos);
  514. lines.mappings = mappings;
  515. return lines;
  516. };
  517. Lines.prototype.concat = function () {
  518. var args = [];
  519. for (var _i = 0; _i < arguments.length; _i++) {
  520. args[_i] = arguments[_i];
  521. }
  522. var list = [this];
  523. list.push.apply(list, args);
  524. assert_1.default.strictEqual(list.length, args.length + 1);
  525. return emptyLines.join(list);
  526. };
  527. return Lines;
  528. }());
  529. exports.Lines = Lines;
  530. var fromStringCache = {};
  531. var hasOwn = fromStringCache.hasOwnProperty;
  532. var maxCacheKeyLen = 10;
  533. function countSpaces(spaces, tabWidth) {
  534. var count = 0;
  535. var len = spaces.length;
  536. for (var i = 0; i < len; ++i) {
  537. switch (spaces.charCodeAt(i)) {
  538. case 9: {
  539. // '\t'
  540. assert_1.default.strictEqual(typeof tabWidth, "number");
  541. assert_1.default.ok(tabWidth > 0);
  542. var next = Math.ceil(count / tabWidth) * tabWidth;
  543. if (next === count) {
  544. count += tabWidth;
  545. }
  546. else {
  547. count = next;
  548. }
  549. break;
  550. }
  551. case 11: // '\v'
  552. case 12: // '\f'
  553. case 13: // '\r'
  554. case 0xfeff: // zero-width non-breaking space
  555. // These characters contribute nothing to indentation.
  556. break;
  557. case 32: // ' '
  558. default:
  559. // Treat all other whitespace like ' '.
  560. count += 1;
  561. break;
  562. }
  563. }
  564. return count;
  565. }
  566. exports.countSpaces = countSpaces;
  567. var leadingSpaceExp = /^\s*/;
  568. // As specified here: http://www.ecma-international.org/ecma-262/6.0/#sec-line-terminators
  569. var lineTerminatorSeqExp = /\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/;
  570. /**
  571. * @param {Object} options - Options object that configures printing.
  572. */
  573. function fromString(string, options) {
  574. if (string instanceof Lines)
  575. return string;
  576. string += "";
  577. var tabWidth = options && options.tabWidth;
  578. var tabless = string.indexOf("\t") < 0;
  579. var cacheable = !options && tabless && string.length <= maxCacheKeyLen;
  580. assert_1.default.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string);
  581. if (cacheable && hasOwn.call(fromStringCache, string))
  582. return fromStringCache[string];
  583. var lines = new Lines(string.split(lineTerminatorSeqExp).map(function (line) {
  584. // TODO: handle null exec result
  585. var spaces = leadingSpaceExp.exec(line)[0];
  586. return {
  587. line: line,
  588. indent: countSpaces(spaces, tabWidth),
  589. // Boolean indicating whether this line can be reindented.
  590. locked: false,
  591. sliceStart: spaces.length,
  592. sliceEnd: line.length,
  593. };
  594. }), (0, options_1.normalize)(options).sourceFileName);
  595. if (cacheable)
  596. fromStringCache[string] = lines;
  597. return lines;
  598. }
  599. exports.fromString = fromString;
  600. function isOnlyWhitespace(string) {
  601. return !/\S/.test(string);
  602. }
  603. function sliceInfo(info, startCol, endCol) {
  604. var sliceStart = info.sliceStart;
  605. var sliceEnd = info.sliceEnd;
  606. var indent = Math.max(info.indent, 0);
  607. var lineLength = indent + sliceEnd - sliceStart;
  608. if (typeof endCol === "undefined") {
  609. endCol = lineLength;
  610. }
  611. startCol = Math.max(startCol, 0);
  612. endCol = Math.min(endCol, lineLength);
  613. endCol = Math.max(endCol, startCol);
  614. if (endCol < indent) {
  615. indent = endCol;
  616. sliceEnd = sliceStart;
  617. }
  618. else {
  619. sliceEnd -= lineLength - endCol;
  620. }
  621. lineLength = endCol;
  622. lineLength -= startCol;
  623. if (startCol < indent) {
  624. indent -= startCol;
  625. }
  626. else {
  627. startCol -= indent;
  628. indent = 0;
  629. sliceStart += startCol;
  630. }
  631. assert_1.default.ok(indent >= 0);
  632. assert_1.default.ok(sliceStart <= sliceEnd);
  633. assert_1.default.strictEqual(lineLength, indent + sliceEnd - sliceStart);
  634. if (info.indent === indent &&
  635. info.sliceStart === sliceStart &&
  636. info.sliceEnd === sliceEnd) {
  637. return info;
  638. }
  639. return {
  640. line: info.line,
  641. indent: indent,
  642. // A destructive slice always unlocks indentation.
  643. locked: false,
  644. sliceStart: sliceStart,
  645. sliceEnd: sliceEnd,
  646. };
  647. }
  648. function concat(elements) {
  649. return emptyLines.join(elements);
  650. }
  651. exports.concat = concat;
  652. // The emptyLines object needs to be created all the way down here so that
  653. // Lines.prototype will be fully populated.
  654. var emptyLines = fromString("");