"use strict";
|
|
var __assign = (this && this.__assign) || function () {
|
|
__assign = Object.assign || function(t) {
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
s = arguments[i];
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
t[p] = s[p];
|
|
}
|
|
return t;
|
|
};
|
|
return __assign.apply(this, arguments);
|
|
};
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var assert_1 = __importDefault(require("assert"));
|
|
var source_map_1 = __importDefault(require("source-map"));
|
|
var options_1 = require("./options");
|
|
var util_1 = require("./util");
|
|
var mapping_1 = __importDefault(require("./mapping"));
|
|
var Lines = /** @class */ (function () {
|
|
function Lines(infos, sourceFileName) {
|
|
if (sourceFileName === void 0) { sourceFileName = null; }
|
|
this.infos = infos;
|
|
this.mappings = [];
|
|
this.cachedSourceMap = null;
|
|
this.cachedTabWidth = void 0;
|
|
assert_1.default.ok(infos.length > 0);
|
|
this.length = infos.length;
|
|
this.name = sourceFileName || null;
|
|
if (this.name) {
|
|
this.mappings.push(new mapping_1.default(this, {
|
|
start: this.firstPos(),
|
|
end: this.lastPos(),
|
|
}));
|
|
}
|
|
}
|
|
Lines.prototype.toString = function (options) {
|
|
return this.sliceString(this.firstPos(), this.lastPos(), options);
|
|
};
|
|
Lines.prototype.getSourceMap = function (sourceMapName, sourceRoot) {
|
|
if (!sourceMapName) {
|
|
// Although we could make up a name or generate an anonymous
|
|
// source map, instead we assume that any consumer who does not
|
|
// provide a name does not actually want a source map.
|
|
return null;
|
|
}
|
|
var targetLines = this;
|
|
function updateJSON(json) {
|
|
json = json || {};
|
|
json.file = sourceMapName;
|
|
if (sourceRoot) {
|
|
json.sourceRoot = sourceRoot;
|
|
}
|
|
return json;
|
|
}
|
|
if (targetLines.cachedSourceMap) {
|
|
// Since Lines objects are immutable, we can reuse any source map
|
|
// that was previously generated. Nevertheless, we return a new
|
|
// JSON object here to protect the cached source map from outside
|
|
// modification.
|
|
return updateJSON(targetLines.cachedSourceMap.toJSON());
|
|
}
|
|
var smg = new source_map_1.default.SourceMapGenerator(updateJSON());
|
|
var sourcesToContents = {};
|
|
targetLines.mappings.forEach(function (mapping) {
|
|
var sourceCursor = mapping.sourceLines.skipSpaces(mapping.sourceLoc.start) || mapping.sourceLines.lastPos();
|
|
var targetCursor = targetLines.skipSpaces(mapping.targetLoc.start) || targetLines.lastPos();
|
|
while (util_1.comparePos(sourceCursor, mapping.sourceLoc.end) < 0 &&
|
|
util_1.comparePos(targetCursor, mapping.targetLoc.end) < 0) {
|
|
var sourceChar = mapping.sourceLines.charAt(sourceCursor);
|
|
var targetChar = targetLines.charAt(targetCursor);
|
|
assert_1.default.strictEqual(sourceChar, targetChar);
|
|
var sourceName = mapping.sourceLines.name;
|
|
// Add mappings one character at a time for maximum resolution.
|
|
smg.addMapping({
|
|
source: sourceName,
|
|
original: { line: sourceCursor.line,
|
|
column: sourceCursor.column },
|
|
generated: { line: targetCursor.line,
|
|
column: targetCursor.column }
|
|
});
|
|
if (!hasOwn.call(sourcesToContents, sourceName)) {
|
|
var sourceContent = mapping.sourceLines.toString();
|
|
smg.setSourceContent(sourceName, sourceContent);
|
|
sourcesToContents[sourceName] = sourceContent;
|
|
}
|
|
targetLines.nextPos(targetCursor, true);
|
|
mapping.sourceLines.nextPos(sourceCursor, true);
|
|
}
|
|
});
|
|
targetLines.cachedSourceMap = smg;
|
|
return smg.toJSON();
|
|
};
|
|
Lines.prototype.bootstrapCharAt = function (pos) {
|
|
assert_1.default.strictEqual(typeof pos, "object");
|
|
assert_1.default.strictEqual(typeof pos.line, "number");
|
|
assert_1.default.strictEqual(typeof pos.column, "number");
|
|
var line = pos.line, column = pos.column, strings = this.toString().split(lineTerminatorSeqExp), string = strings[line - 1];
|
|
if (typeof string === "undefined")
|
|
return "";
|
|
if (column === string.length &&
|
|
line < strings.length)
|
|
return "\n";
|
|
if (column >= string.length)
|
|
return "";
|
|
return string.charAt(column);
|
|
};
|
|
Lines.prototype.charAt = function (pos) {
|
|
assert_1.default.strictEqual(typeof pos, "object");
|
|
assert_1.default.strictEqual(typeof pos.line, "number");
|
|
assert_1.default.strictEqual(typeof pos.column, "number");
|
|
var line = pos.line, column = pos.column, secret = this, infos = secret.infos, info = infos[line - 1], c = column;
|
|
if (typeof info === "undefined" || c < 0)
|
|
return "";
|
|
var indent = this.getIndentAt(line);
|
|
if (c < indent)
|
|
return " ";
|
|
c += info.sliceStart - indent;
|
|
if (c === info.sliceEnd &&
|
|
line < this.length)
|
|
return "\n";
|
|
if (c >= info.sliceEnd)
|
|
return "";
|
|
return info.line.charAt(c);
|
|
};
|
|
Lines.prototype.stripMargin = function (width, skipFirstLine) {
|
|
if (width === 0)
|
|
return this;
|
|
assert_1.default.ok(width > 0, "negative margin: " + width);
|
|
if (skipFirstLine && this.length === 1)
|
|
return this;
|
|
var lines = new Lines(this.infos.map(function (info, i) {
|
|
if (info.line && (i > 0 || !skipFirstLine)) {
|
|
info = __assign({}, info, { indent: Math.max(0, info.indent - width) });
|
|
}
|
|
return info;
|
|
}));
|
|
if (this.mappings.length > 0) {
|
|
var newMappings = lines.mappings;
|
|
assert_1.default.strictEqual(newMappings.length, 0);
|
|
this.mappings.forEach(function (mapping) {
|
|
newMappings.push(mapping.indent(width, skipFirstLine, true));
|
|
});
|
|
}
|
|
return lines;
|
|
};
|
|
Lines.prototype.indent = function (by) {
|
|
if (by === 0) {
|
|
return this;
|
|
}
|
|
var lines = new Lines(this.infos.map(function (info) {
|
|
if (info.line && !info.locked) {
|
|
info = __assign({}, info, { indent: info.indent + by });
|
|
}
|
|
return info;
|
|
}));
|
|
if (this.mappings.length > 0) {
|
|
var newMappings = lines.mappings;
|
|
assert_1.default.strictEqual(newMappings.length, 0);
|
|
this.mappings.forEach(function (mapping) {
|
|
newMappings.push(mapping.indent(by));
|
|
});
|
|
}
|
|
return lines;
|
|
};
|
|
Lines.prototype.indentTail = function (by) {
|
|
if (by === 0) {
|
|
return this;
|
|
}
|
|
if (this.length < 2) {
|
|
return this;
|
|
}
|
|
var lines = new Lines(this.infos.map(function (info, i) {
|
|
if (i > 0 && info.line && !info.locked) {
|
|
info = __assign({}, info, { indent: info.indent + by });
|
|
}
|
|
return info;
|
|
}));
|
|
if (this.mappings.length > 0) {
|
|
var newMappings = lines.mappings;
|
|
assert_1.default.strictEqual(newMappings.length, 0);
|
|
this.mappings.forEach(function (mapping) {
|
|
newMappings.push(mapping.indent(by, true));
|
|
});
|
|
}
|
|
return lines;
|
|
};
|
|
Lines.prototype.lockIndentTail = function () {
|
|
if (this.length < 2) {
|
|
return this;
|
|
}
|
|
return new Lines(this.infos.map(function (info, i) {
|
|
return __assign({}, info, { locked: i > 0 });
|
|
}));
|
|
};
|
|
Lines.prototype.getIndentAt = function (line) {
|
|
assert_1.default.ok(line >= 1, "no line " + line + " (line numbers start from 1)");
|
|
return Math.max(this.infos[line - 1].indent, 0);
|
|
};
|
|
Lines.prototype.guessTabWidth = function () {
|
|
if (typeof this.cachedTabWidth === "number") {
|
|
return this.cachedTabWidth;
|
|
}
|
|
var counts = []; // Sparse array.
|
|
var lastIndent = 0;
|
|
for (var line = 1, last = this.length; line <= last; ++line) {
|
|
var info = this.infos[line - 1];
|
|
var sliced = info.line.slice(info.sliceStart, info.sliceEnd);
|
|
// Whitespace-only lines don't tell us much about the likely tab
|
|
// width of this code.
|
|
if (isOnlyWhitespace(sliced)) {
|
|
continue;
|
|
}
|
|
var diff = Math.abs(info.indent - lastIndent);
|
|
counts[diff] = ~~counts[diff] + 1;
|
|
lastIndent = info.indent;
|
|
}
|
|
var maxCount = -1;
|
|
var result = 2;
|
|
for (var tabWidth = 1; tabWidth < counts.length; tabWidth += 1) {
|
|
if (hasOwn.call(counts, tabWidth) &&
|
|
counts[tabWidth] > maxCount) {
|
|
maxCount = counts[tabWidth];
|
|
result = tabWidth;
|
|
}
|
|
}
|
|
return this.cachedTabWidth = result;
|
|
};
|
|
// Determine if the list of lines has a first line that starts with a //
|
|
// or /* comment. If this is the case, the code may need to be wrapped in
|
|
// parens to avoid ASI issues.
|
|
Lines.prototype.startsWithComment = function () {
|
|
if (this.infos.length === 0) {
|
|
return false;
|
|
}
|
|
var firstLineInfo = this.infos[0], sliceStart = firstLineInfo.sliceStart, sliceEnd = firstLineInfo.sliceEnd, firstLine = firstLineInfo.line.slice(sliceStart, sliceEnd).trim();
|
|
return firstLine.length === 0 ||
|
|
firstLine.slice(0, 2) === "//" ||
|
|
firstLine.slice(0, 2) === "/*";
|
|
};
|
|
Lines.prototype.isOnlyWhitespace = function () {
|
|
return isOnlyWhitespace(this.toString());
|
|
};
|
|
Lines.prototype.isPrecededOnlyByWhitespace = function (pos) {
|
|
var info = this.infos[pos.line - 1];
|
|
var indent = Math.max(info.indent, 0);
|
|
var diff = pos.column - indent;
|
|
if (diff <= 0) {
|
|
// If pos.column does not exceed the indentation amount, then
|
|
// there must be only whitespace before it.
|
|
return true;
|
|
}
|
|
var start = info.sliceStart;
|
|
var end = Math.min(start + diff, info.sliceEnd);
|
|
var prefix = info.line.slice(start, end);
|
|
return isOnlyWhitespace(prefix);
|
|
};
|
|
Lines.prototype.getLineLength = function (line) {
|
|
var info = this.infos[line - 1];
|
|
return this.getIndentAt(line) + info.sliceEnd - info.sliceStart;
|
|
};
|
|
Lines.prototype.nextPos = function (pos, skipSpaces) {
|
|
if (skipSpaces === void 0) { skipSpaces = false; }
|
|
var l = Math.max(pos.line, 0), c = Math.max(pos.column, 0);
|
|
if (c < this.getLineLength(l)) {
|
|
pos.column += 1;
|
|
return skipSpaces
|
|
? !!this.skipSpaces(pos, false, true)
|
|
: true;
|
|
}
|
|
if (l < this.length) {
|
|
pos.line += 1;
|
|
pos.column = 0;
|
|
return skipSpaces
|
|
? !!this.skipSpaces(pos, false, true)
|
|
: true;
|
|
}
|
|
return false;
|
|
};
|
|
Lines.prototype.prevPos = function (pos, skipSpaces) {
|
|
if (skipSpaces === void 0) { skipSpaces = false; }
|
|
var l = pos.line, c = pos.column;
|
|
if (c < 1) {
|
|
l -= 1;
|
|
if (l < 1)
|
|
return false;
|
|
c = this.getLineLength(l);
|
|
}
|
|
else {
|
|
c = Math.min(c - 1, this.getLineLength(l));
|
|
}
|
|
pos.line = l;
|
|
pos.column = c;
|
|
return skipSpaces
|
|
? !!this.skipSpaces(pos, true, true)
|
|
: true;
|
|
};
|
|
Lines.prototype.firstPos = function () {
|
|
// Trivial, but provided for completeness.
|
|
return { line: 1, column: 0 };
|
|
};
|
|
Lines.prototype.lastPos = function () {
|
|
return {
|
|
line: this.length,
|
|
column: this.getLineLength(this.length)
|
|
};
|
|
};
|
|
Lines.prototype.skipSpaces = function (pos, backward, modifyInPlace) {
|
|
if (backward === void 0) { backward = false; }
|
|
if (modifyInPlace === void 0) { modifyInPlace = false; }
|
|
if (pos) {
|
|
pos = modifyInPlace ? pos : {
|
|
line: pos.line,
|
|
column: pos.column
|
|
};
|
|
}
|
|
else if (backward) {
|
|
pos = this.lastPos();
|
|
}
|
|
else {
|
|
pos = this.firstPos();
|
|
}
|
|
if (backward) {
|
|
while (this.prevPos(pos)) {
|
|
if (!isOnlyWhitespace(this.charAt(pos)) &&
|
|
this.nextPos(pos)) {
|
|
return pos;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
else {
|
|
while (isOnlyWhitespace(this.charAt(pos))) {
|
|
if (!this.nextPos(pos)) {
|
|
return null;
|
|
}
|
|
}
|
|
return pos;
|
|
}
|
|
};
|
|
Lines.prototype.trimLeft = function () {
|
|
var pos = this.skipSpaces(this.firstPos(), false, true);
|
|
return pos ? this.slice(pos) : emptyLines;
|
|
};
|
|
Lines.prototype.trimRight = function () {
|
|
var pos = this.skipSpaces(this.lastPos(), true, true);
|
|
return pos ? this.slice(this.firstPos(), pos) : emptyLines;
|
|
};
|
|
Lines.prototype.trim = function () {
|
|
var start = this.skipSpaces(this.firstPos(), false, true);
|
|
if (start === null) {
|
|
return emptyLines;
|
|
}
|
|
var end = this.skipSpaces(this.lastPos(), true, true);
|
|
if (end === null) {
|
|
return emptyLines;
|
|
}
|
|
return this.slice(start, end);
|
|
};
|
|
Lines.prototype.eachPos = function (callback, startPos, skipSpaces) {
|
|
if (startPos === void 0) { startPos = this.firstPos(); }
|
|
if (skipSpaces === void 0) { skipSpaces = false; }
|
|
var pos = this.firstPos();
|
|
if (startPos) {
|
|
pos.line = startPos.line,
|
|
pos.column = startPos.column;
|
|
}
|
|
if (skipSpaces && !this.skipSpaces(pos, false, true)) {
|
|
return; // Encountered nothing but spaces.
|
|
}
|
|
do
|
|
callback.call(this, pos);
|
|
while (this.nextPos(pos, skipSpaces));
|
|
};
|
|
Lines.prototype.bootstrapSlice = function (start, end) {
|
|
var strings = this.toString().split(lineTerminatorSeqExp).slice(start.line - 1, end.line);
|
|
if (strings.length > 0) {
|
|
strings.push(strings.pop().slice(0, end.column));
|
|
strings[0] = strings[0].slice(start.column);
|
|
}
|
|
return fromString(strings.join("\n"));
|
|
};
|
|
Lines.prototype.slice = function (start, end) {
|
|
if (!end) {
|
|
if (!start) {
|
|
// The client seems to want a copy of this Lines object, but
|
|
// Lines objects are immutable, so it's perfectly adequate to
|
|
// return the same object.
|
|
return this;
|
|
}
|
|
// Slice to the end if no end position was provided.
|
|
end = this.lastPos();
|
|
}
|
|
if (!start) {
|
|
throw new Error("cannot slice with end but not start");
|
|
}
|
|
var sliced = this.infos.slice(start.line - 1, end.line);
|
|
if (start.line === end.line) {
|
|
sliced[0] = sliceInfo(sliced[0], start.column, end.column);
|
|
}
|
|
else {
|
|
assert_1.default.ok(start.line < end.line);
|
|
sliced[0] = sliceInfo(sliced[0], start.column);
|
|
sliced.push(sliceInfo(sliced.pop(), 0, end.column));
|
|
}
|
|
var lines = new Lines(sliced);
|
|
if (this.mappings.length > 0) {
|
|
var newMappings = lines.mappings;
|
|
assert_1.default.strictEqual(newMappings.length, 0);
|
|
this.mappings.forEach(function (mapping) {
|
|
var sliced = mapping.slice(this, start, end);
|
|
if (sliced) {
|
|
newMappings.push(sliced);
|
|
}
|
|
}, this);
|
|
}
|
|
return lines;
|
|
};
|
|
Lines.prototype.bootstrapSliceString = function (start, end, options) {
|
|
return this.slice(start, end).toString(options);
|
|
};
|
|
Lines.prototype.sliceString = function (start, end, options) {
|
|
if (start === void 0) { start = this.firstPos(); }
|
|
if (end === void 0) { end = this.lastPos(); }
|
|
options = options_1.normalize(options);
|
|
var parts = [];
|
|
var _a = options.tabWidth, tabWidth = _a === void 0 ? 2 : _a;
|
|
for (var line = start.line; line <= end.line; ++line) {
|
|
var info = this.infos[line - 1];
|
|
if (line === start.line) {
|
|
if (line === end.line) {
|
|
info = sliceInfo(info, start.column, end.column);
|
|
}
|
|
else {
|
|
info = sliceInfo(info, start.column);
|
|
}
|
|
}
|
|
else if (line === end.line) {
|
|
info = sliceInfo(info, 0, end.column);
|
|
}
|
|
var indent = Math.max(info.indent, 0);
|
|
var before = info.line.slice(0, info.sliceStart);
|
|
if (options.reuseWhitespace &&
|
|
isOnlyWhitespace(before) &&
|
|
countSpaces(before, options.tabWidth) === indent) {
|
|
// Reuse original spaces if the indentation is correct.
|
|
parts.push(info.line.slice(0, info.sliceEnd));
|
|
continue;
|
|
}
|
|
var tabs = 0;
|
|
var spaces = indent;
|
|
if (options.useTabs) {
|
|
tabs = Math.floor(indent / tabWidth);
|
|
spaces -= tabs * tabWidth;
|
|
}
|
|
var result = "";
|
|
if (tabs > 0) {
|
|
result += new Array(tabs + 1).join("\t");
|
|
}
|
|
if (spaces > 0) {
|
|
result += new Array(spaces + 1).join(" ");
|
|
}
|
|
result += info.line.slice(info.sliceStart, info.sliceEnd);
|
|
parts.push(result);
|
|
}
|
|
return parts.join(options.lineTerminator);
|
|
};
|
|
Lines.prototype.isEmpty = function () {
|
|
return this.length < 2 && this.getLineLength(1) < 1;
|
|
};
|
|
Lines.prototype.join = function (elements) {
|
|
var separator = this;
|
|
var infos = [];
|
|
var mappings = [];
|
|
var prevInfo;
|
|
function appendLines(linesOrNull) {
|
|
if (linesOrNull === null) {
|
|
return;
|
|
}
|
|
if (prevInfo) {
|
|
var info = linesOrNull.infos[0];
|
|
var indent = new Array(info.indent + 1).join(" ");
|
|
var prevLine = infos.length;
|
|
var prevColumn = Math.max(prevInfo.indent, 0) +
|
|
prevInfo.sliceEnd - prevInfo.sliceStart;
|
|
prevInfo.line = prevInfo.line.slice(0, prevInfo.sliceEnd) + indent + info.line.slice(info.sliceStart, info.sliceEnd);
|
|
// If any part of a line is indentation-locked, the whole line
|
|
// will be indentation-locked.
|
|
prevInfo.locked = prevInfo.locked || info.locked;
|
|
prevInfo.sliceEnd = prevInfo.line.length;
|
|
if (linesOrNull.mappings.length > 0) {
|
|
linesOrNull.mappings.forEach(function (mapping) {
|
|
mappings.push(mapping.add(prevLine, prevColumn));
|
|
});
|
|
}
|
|
}
|
|
else if (linesOrNull.mappings.length > 0) {
|
|
mappings.push.apply(mappings, linesOrNull.mappings);
|
|
}
|
|
linesOrNull.infos.forEach(function (info, i) {
|
|
if (!prevInfo || i > 0) {
|
|
prevInfo = __assign({}, info);
|
|
infos.push(prevInfo);
|
|
}
|
|
});
|
|
}
|
|
function appendWithSeparator(linesOrNull, i) {
|
|
if (i > 0)
|
|
appendLines(separator);
|
|
appendLines(linesOrNull);
|
|
}
|
|
elements.map(function (elem) {
|
|
var lines = fromString(elem);
|
|
if (lines.isEmpty())
|
|
return null;
|
|
return lines;
|
|
}).forEach(function (linesOrNull, i) {
|
|
if (separator.isEmpty()) {
|
|
appendLines(linesOrNull);
|
|
}
|
|
else {
|
|
appendWithSeparator(linesOrNull, i);
|
|
}
|
|
});
|
|
if (infos.length < 1)
|
|
return emptyLines;
|
|
var lines = new Lines(infos);
|
|
lines.mappings = mappings;
|
|
return lines;
|
|
};
|
|
Lines.prototype.concat = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var list = [this];
|
|
list.push.apply(list, args);
|
|
assert_1.default.strictEqual(list.length, args.length + 1);
|
|
return emptyLines.join(list);
|
|
};
|
|
return Lines;
|
|
}());
|
|
exports.Lines = Lines;
|
|
var fromStringCache = {};
|
|
var hasOwn = fromStringCache.hasOwnProperty;
|
|
var maxCacheKeyLen = 10;
|
|
function countSpaces(spaces, tabWidth) {
|
|
var count = 0;
|
|
var len = spaces.length;
|
|
for (var i = 0; i < len; ++i) {
|
|
switch (spaces.charCodeAt(i)) {
|
|
case 9: // '\t'
|
|
assert_1.default.strictEqual(typeof tabWidth, "number");
|
|
assert_1.default.ok(tabWidth > 0);
|
|
var next = Math.ceil(count / tabWidth) * tabWidth;
|
|
if (next === count) {
|
|
count += tabWidth;
|
|
}
|
|
else {
|
|
count = next;
|
|
}
|
|
break;
|
|
case 11: // '\v'
|
|
case 12: // '\f'
|
|
case 13: // '\r'
|
|
case 0xfeff: // zero-width non-breaking space
|
|
// These characters contribute nothing to indentation.
|
|
break;
|
|
case 32: // ' '
|
|
default: // Treat all other whitespace like ' '.
|
|
count += 1;
|
|
break;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
exports.countSpaces = countSpaces;
|
|
var leadingSpaceExp = /^\s*/;
|
|
// As specified here: http://www.ecma-international.org/ecma-262/6.0/#sec-line-terminators
|
|
var lineTerminatorSeqExp = /\u000D\u000A|\u000D(?!\u000A)|\u000A|\u2028|\u2029/;
|
|
/**
|
|
* @param {Object} options - Options object that configures printing.
|
|
*/
|
|
function fromString(string, options) {
|
|
if (string instanceof Lines)
|
|
return string;
|
|
string += "";
|
|
var tabWidth = options && options.tabWidth;
|
|
var tabless = string.indexOf("\t") < 0;
|
|
var cacheable = !options && tabless && (string.length <= maxCacheKeyLen);
|
|
assert_1.default.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string);
|
|
if (cacheable && hasOwn.call(fromStringCache, string))
|
|
return fromStringCache[string];
|
|
var lines = new Lines(string.split(lineTerminatorSeqExp).map(function (line) {
|
|
// TODO: handle null exec result
|
|
var spaces = leadingSpaceExp.exec(line)[0];
|
|
return {
|
|
line: line,
|
|
indent: countSpaces(spaces, tabWidth),
|
|
// Boolean indicating whether this line can be reindented.
|
|
locked: false,
|
|
sliceStart: spaces.length,
|
|
sliceEnd: line.length
|
|
};
|
|
}), options_1.normalize(options).sourceFileName);
|
|
if (cacheable)
|
|
fromStringCache[string] = lines;
|
|
return lines;
|
|
}
|
|
exports.fromString = fromString;
|
|
function isOnlyWhitespace(string) {
|
|
return !/\S/.test(string);
|
|
}
|
|
function sliceInfo(info, startCol, endCol) {
|
|
var sliceStart = info.sliceStart;
|
|
var sliceEnd = info.sliceEnd;
|
|
var indent = Math.max(info.indent, 0);
|
|
var lineLength = indent + sliceEnd - sliceStart;
|
|
if (typeof endCol === "undefined") {
|
|
endCol = lineLength;
|
|
}
|
|
startCol = Math.max(startCol, 0);
|
|
endCol = Math.min(endCol, lineLength);
|
|
endCol = Math.max(endCol, startCol);
|
|
if (endCol < indent) {
|
|
indent = endCol;
|
|
sliceEnd = sliceStart;
|
|
}
|
|
else {
|
|
sliceEnd -= lineLength - endCol;
|
|
}
|
|
lineLength = endCol;
|
|
lineLength -= startCol;
|
|
if (startCol < indent) {
|
|
indent -= startCol;
|
|
}
|
|
else {
|
|
startCol -= indent;
|
|
indent = 0;
|
|
sliceStart += startCol;
|
|
}
|
|
assert_1.default.ok(indent >= 0);
|
|
assert_1.default.ok(sliceStart <= sliceEnd);
|
|
assert_1.default.strictEqual(lineLength, indent + sliceEnd - sliceStart);
|
|
if (info.indent === indent &&
|
|
info.sliceStart === sliceStart &&
|
|
info.sliceEnd === sliceEnd) {
|
|
return info;
|
|
}
|
|
return {
|
|
line: info.line,
|
|
indent: indent,
|
|
// A destructive slice always unlocks indentation.
|
|
locked: false,
|
|
sliceStart: sliceStart,
|
|
sliceEnd: sliceEnd
|
|
};
|
|
}
|
|
function concat(elements) {
|
|
return emptyLines.join(elements);
|
|
}
|
|
exports.concat = concat;
|
|
;
|
|
// The emptyLines object needs to be created all the way down here so that
|
|
// Lines.prototype will be fully populated.
|
|
var emptyLines = fromString("");
|