Comparing version 0.17.1 to 0.17.2
@@ -234,3 +234,3 @@ "use strict"; | ||
else if (lines instanceof lines_1.Lines) { | ||
var trailingSpace = lines.slice(loc.end, lines.skipSpaces(loc.end)); | ||
var trailingSpace = lines.slice(loc.end, lines.skipSpaces(loc.end) || lines.lastPos()); | ||
if (trailingSpace.length === 1) { | ||
@@ -237,0 +237,0 @@ // If the trailing space contains no newlines, then we want to |
@@ -1,44 +0,55 @@ | ||
export declare type Pos = { | ||
line: number; | ||
column: number; | ||
import { Options } from "./options"; | ||
import { Position as Pos } from "./types"; | ||
declare type LineInfo = { | ||
readonly line: string; | ||
readonly indent: number; | ||
readonly locked: boolean; | ||
readonly sliceStart: number; | ||
readonly sliceEnd: number; | ||
}; | ||
export interface LinesType { | ||
length: any; | ||
name: any; | ||
toString(options?: any): any; | ||
getSourceMap(sourceMapName: any, sourceRoot: any): any; | ||
bootstrapCharAt(pos: any): any; | ||
charAt(pos: any): any; | ||
stripMargin(width: any, skipFirstLine: any): any; | ||
indent(by: number): any; | ||
indentTail(by: any): any; | ||
lockIndentTail(): any; | ||
getIndentAt(line: any): any; | ||
guessTabWidth(): any; | ||
startsWithComment(): any; | ||
isOnlyWhitespace(): any; | ||
isPrecededOnlyByWhitespace(pos: any): any; | ||
getLineLength(line: any): any; | ||
nextPos(pos: any, skipSpaces?: any): any; | ||
prevPos(pos: any, skipSpaces?: any): any; | ||
firstPos(): Pos; | ||
lastPos(): Pos; | ||
skipSpaces(pos: any, backward?: any, modifyInPlace?: any): any; | ||
trimLeft(): any; | ||
trimRight(): any; | ||
trim(): any; | ||
eachPos(callback: (pos: Pos) => any, startPos?: any, skipSpaces?: any): any; | ||
bootstrapSlice(start: any, end: any): any; | ||
slice(start?: Pos, end?: Pos): LinesType; | ||
bootstrapSliceString(start: any, end: any, options: any): any; | ||
sliceString(start: any, end: any, options?: any): any; | ||
isEmpty(): any; | ||
join(elements: any): any; | ||
concat(...args: any[]): any; | ||
export declare class Lines { | ||
private infos; | ||
readonly length: number; | ||
readonly name: string | null; | ||
private mappings; | ||
private cachedSourceMap; | ||
private cachedTabWidth; | ||
constructor(infos: LineInfo[], sourceFileName?: string | null); | ||
toString(options?: Options): string; | ||
getSourceMap(sourceMapName: string, sourceRoot?: string): any; | ||
bootstrapCharAt(pos: Pos): string; | ||
charAt(pos: Pos): string; | ||
stripMargin(width: number, skipFirstLine: boolean): Lines; | ||
indent(by: number): Lines; | ||
indentTail(by: number): Lines; | ||
lockIndentTail(): Lines; | ||
getIndentAt(line: number): number; | ||
guessTabWidth(): number; | ||
startsWithComment(): boolean; | ||
isOnlyWhitespace(): boolean; | ||
isPrecededOnlyByWhitespace(pos: Pos): boolean; | ||
getLineLength(line: number): number; | ||
nextPos(pos: Pos, skipSpaces?: boolean): boolean; | ||
prevPos(pos: Pos, skipSpaces?: boolean): boolean; | ||
firstPos(): { | ||
line: number; | ||
column: number; | ||
}; | ||
lastPos(): { | ||
line: number; | ||
column: number; | ||
}; | ||
skipSpaces(pos: Pos, backward?: boolean, modifyInPlace?: boolean): Pos | null; | ||
trimLeft(): Lines; | ||
trimRight(): Lines; | ||
trim(): Lines; | ||
eachPos(callback: (pos: Pos) => any, startPos?: Pos, skipSpaces?: boolean): void; | ||
bootstrapSlice(start: Pos, end: Pos): Lines; | ||
slice(start?: Pos, end?: Pos): Lines; | ||
bootstrapSliceString(start: Pos, end: Pos, options?: Options): string; | ||
sliceString(start?: Pos, end?: Pos, options?: Options): string; | ||
isEmpty(): boolean; | ||
join(elements: (string | Lines)[]): Lines; | ||
concat(...args: (string | Lines)[]): Lines; | ||
} | ||
interface LinesConstructor { | ||
new (infos: any, sourceFileName?: any): LinesType; | ||
} | ||
declare const Lines: LinesConstructor; | ||
export { Lines }; | ||
export declare function countSpaces(spaces: any, tabWidth?: number): number; | ||
@@ -48,3 +59,4 @@ /** | ||
*/ | ||
export declare function fromString(string: string | LinesType, options?: any): LinesType; | ||
export declare function concat(elements: any): any; | ||
export declare function fromString(string: string | Lines, options?: Options): Lines; | ||
export declare function concat(elements: any): Lines; | ||
export {}; |
1109
lib/lines.js
"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) { | ||
@@ -9,70 +20,528 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
var options_1 = require("./options"); | ||
var private_1 = require("private"); | ||
var secretKey = private_1.makeUniqueKey(); | ||
var types_1 = __importDefault(require("./types")); | ||
var isString = types_1.default.builtInTypes.string; | ||
var util_1 = require("./util"); | ||
var mapping_1 = __importDefault(require("./mapping")); | ||
// Goals: | ||
// 1. Minimize new string creation. | ||
// 2. Keep (de)identation O(lines) time. | ||
// 3. Permit negative indentations. | ||
// 4. Enforce immutability. | ||
// 5. No newline characters. | ||
var useSymbol = typeof Symbol === "function"; | ||
// @ts-ignore Subsequent variable declarations must have the same type. | ||
var secretKey = "recastLinesSecret"; | ||
if (useSymbol) { | ||
secretKey = Symbol.for(secretKey); | ||
} | ||
function getSecret(lines) { | ||
return lines[secretKey]; | ||
} | ||
var Lines = function Lines(infos, sourceFileName) { | ||
assert_1.default.ok(this instanceof Lines); | ||
assert_1.default.ok(infos.length > 0); | ||
if (sourceFileName) { | ||
isString.assert(sourceFileName); | ||
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(), | ||
})); | ||
} | ||
} | ||
else { | ||
sourceFileName = null; | ||
} | ||
setSymbolOrKey(this, secretKey, { | ||
infos: infos, | ||
mappings: [], | ||
name: sourceFileName, | ||
cachedSourceMap: null | ||
}); | ||
this.length = infos.length; | ||
this.name = sourceFileName; | ||
if (sourceFileName) { | ||
getSecret(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; | ||
function setSymbolOrKey(obj, key, value) { | ||
if (useSymbol) { | ||
return obj[key] = value; | ||
} | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: false, | ||
writable: false, | ||
configurable: true | ||
}); | ||
return value; | ||
} | ||
var Lp = Lines.prototype; | ||
function copyLineInfo(info) { | ||
return { | ||
line: info.line, | ||
indent: info.indent, | ||
locked: info.locked, | ||
sliceStart: info.sliceStart, | ||
sliceEnd: info.sliceEnd | ||
}; | ||
} | ||
var fromStringCache = {}; | ||
@@ -124,3 +593,2 @@ var hasOwn = fromStringCache.hasOwnProperty; | ||
var tabless = string.indexOf("\t") < 0; | ||
var locked = !!(options && options.locked); | ||
var cacheable = !options && tabless && (string.length <= maxCacheKeyLen); | ||
@@ -137,3 +605,3 @@ assert_1.default.ok(tabWidth || tabless, "No tab width specified but encountered tabs in string\n" + string); | ||
// Boolean indicating whether this line can be reindented. | ||
locked: locked, | ||
locked: false, | ||
sliceStart: spaces.length, | ||
@@ -151,387 +619,2 @@ sliceEnd: line.length | ||
} | ||
Lp.toString = function (options) { | ||
return this.sliceString(this.firstPos(), this.lastPos(), options); | ||
}; | ||
Lp.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 || {}; | ||
isString.assert(sourceMapName); | ||
json.file = sourceMapName; | ||
if (sourceRoot) { | ||
isString.assert(sourceRoot); | ||
json.sourceRoot = sourceRoot; | ||
} | ||
return json; | ||
} | ||
var secret = getSecret(targetLines); | ||
if (secret.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(secret.cachedSourceMap.toJSON()); | ||
} | ||
var smg = new source_map_1.default.SourceMapGenerator(updateJSON()); | ||
var sourcesToContents = {}; | ||
secret.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); | ||
} | ||
}); | ||
secret.cachedSourceMap = smg; | ||
return smg.toJSON(); | ||
}; | ||
Lp.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); | ||
}; | ||
Lp.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 = getSecret(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); | ||
}; | ||
Lp.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 secret = getSecret(this); | ||
var lines = new Lines(secret.infos.map(function (info, i) { | ||
if (info.line && (i > 0 || !skipFirstLine)) { | ||
info = copyLineInfo(info); | ||
info.indent = Math.max(0, info.indent - width); | ||
} | ||
return info; | ||
})); | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert_1.default.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function (mapping) { | ||
newMappings.push(mapping.indent(width, skipFirstLine, true)); | ||
}); | ||
} | ||
return lines; | ||
}; | ||
Lp.indent = function (by) { | ||
if (by === 0) | ||
return this; | ||
var secret = getSecret(this); | ||
var lines = new Lines(secret.infos.map(function (info) { | ||
if (info.line && !info.locked) { | ||
info = copyLineInfo(info); | ||
info.indent += by; | ||
} | ||
return info; | ||
})); | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert_1.default.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function (mapping) { | ||
newMappings.push(mapping.indent(by)); | ||
}); | ||
} | ||
return lines; | ||
}; | ||
Lp.indentTail = function (by) { | ||
if (by === 0) | ||
return this; | ||
if (this.length < 2) | ||
return this; | ||
var secret = getSecret(this); | ||
var lines = new Lines(secret.infos.map(function (info, i) { | ||
if (i > 0 && info.line && !info.locked) { | ||
info = copyLineInfo(info); | ||
info.indent += by; | ||
} | ||
return info; | ||
})); | ||
if (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert_1.default.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function (mapping) { | ||
newMappings.push(mapping.indent(by, true)); | ||
}); | ||
} | ||
return lines; | ||
}; | ||
Lp.lockIndentTail = function () { | ||
if (this.length < 2) { | ||
return this; | ||
} | ||
var infos = getSecret(this).infos; | ||
return new Lines(infos.map(function (info, i) { | ||
info = copyLineInfo(info); | ||
info.locked = i > 0; | ||
return info; | ||
})); | ||
}; | ||
Lp.getIndentAt = function (line) { | ||
assert_1.default.ok(line >= 1, "no line " + line + " (line numbers start from 1)"); | ||
var secret = getSecret(this), info = secret.infos[line - 1]; | ||
return Math.max(info.indent, 0); | ||
}; | ||
Lp.guessTabWidth = function () { | ||
var secret = getSecret(this); | ||
if (hasOwn.call(secret, "cachedTabWidth")) { | ||
return secret.cachedTabWidth; | ||
} | ||
var counts = []; // Sparse array. | ||
var lastIndent = 0; | ||
for (var line = 1, last = this.length; line <= last; ++line) { | ||
var info = secret.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 secret.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. | ||
Lp.startsWithComment = function () { | ||
var secret = getSecret(this); | ||
if (secret.infos.length === 0) { | ||
return false; | ||
} | ||
var firstLineInfo = secret.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) === "/*"; | ||
}; | ||
Lp.isOnlyWhitespace = function () { | ||
return isOnlyWhitespace(this.toString()); | ||
}; | ||
Lp.isPrecededOnlyByWhitespace = function (pos) { | ||
var secret = getSecret(this); | ||
var info = secret.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); | ||
}; | ||
Lp.getLineLength = function (line) { | ||
var secret = getSecret(this), info = secret.infos[line - 1]; | ||
return this.getIndentAt(line) + info.sliceEnd - info.sliceStart; | ||
}; | ||
Lp.nextPos = function (pos, skipSpaces) { | ||
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; | ||
}; | ||
Lp.prevPos = function (pos, skipSpaces) { | ||
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; | ||
}; | ||
Lp.firstPos = function () { | ||
// Trivial, but provided for completeness. | ||
return { line: 1, column: 0 }; | ||
}; | ||
Lp.lastPos = function () { | ||
return { | ||
line: this.length, | ||
column: this.getLineLength(this.length) | ||
}; | ||
}; | ||
Lp.skipSpaces = function (pos, backward, modifyInPlace) { | ||
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; | ||
} | ||
}; | ||
Lp.trimLeft = function () { | ||
var pos = this.skipSpaces(this.firstPos(), false, true); | ||
return pos ? this.slice(pos) : emptyLines; | ||
}; | ||
Lp.trimRight = function () { | ||
var pos = this.skipSpaces(this.lastPos(), true, true); | ||
return pos ? this.slice(this.firstPos(), pos) : emptyLines; | ||
}; | ||
Lp.trim = function () { | ||
var start = this.skipSpaces(this.firstPos(), false, true); | ||
if (start === null) | ||
return emptyLines; | ||
var end = this.skipSpaces(this.lastPos(), true, true); | ||
assert_1.default.notStrictEqual(end, null); | ||
return this.slice(start, end); | ||
}; | ||
Lp.eachPos = function (callback, startPos, skipSpaces) { | ||
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)); | ||
}; | ||
Lp.bootstrapSlice = function (start, end) { | ||
var strings = this.toString().split(lineTerminatorSeqExp).slice(start.line - 1, end.line); | ||
strings.push(strings.pop().slice(0, end.column)); | ||
strings[0] = strings[0].slice(start.column); | ||
return fromString(strings.join("\n")); | ||
}; | ||
Lp.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 secret = getSecret(this); | ||
var sliced = secret.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 (secret.mappings.length > 0) { | ||
var newMappings = getSecret(lines).mappings; | ||
assert_1.default.strictEqual(newMappings.length, 0); | ||
secret.mappings.forEach(function (mapping) { | ||
var sliced = mapping.slice(this, start, end); | ||
if (sliced) { | ||
newMappings.push(sliced); | ||
} | ||
}, this); | ||
} | ||
return lines; | ||
}; | ||
function sliceInfo(info, startCol, endCol) { | ||
@@ -582,118 +665,2 @@ var sliceStart = info.sliceStart; | ||
} | ||
Lp.bootstrapSliceString = function (start, end, options) { | ||
return this.slice(start, end).toString(options); | ||
}; | ||
Lp.sliceString = function (start, end, options) { | ||
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(); | ||
} | ||
options = options_1.normalize(options); | ||
var infos = getSecret(this).infos; | ||
var parts = []; | ||
var tabWidth = options.tabWidth; | ||
for (var line = start.line; line <= end.line; ++line) { | ||
var info = 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); | ||
}; | ||
Lp.isEmpty = function () { | ||
return this.length < 2 && this.getLineLength(1) < 1; | ||
}; | ||
Lp.join = function (elements) { | ||
var separator = this; | ||
var separatorSecret = getSecret(separator); | ||
var infos = []; | ||
var mappings = []; | ||
var prevInfo; | ||
function appendSecret(secret) { | ||
if (secret === null) | ||
return; | ||
if (prevInfo) { | ||
var info = secret.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 (secret.mappings.length > 0) { | ||
secret.mappings.forEach(function (mapping) { | ||
mappings.push(mapping.add(prevLine, prevColumn)); | ||
}); | ||
} | ||
} | ||
else if (secret.mappings.length > 0) { | ||
mappings.push.apply(mappings, secret.mappings); | ||
} | ||
secret.infos.forEach(function (info, i) { | ||
if (!prevInfo || i > 0) { | ||
prevInfo = copyLineInfo(info); | ||
infos.push(prevInfo); | ||
} | ||
}); | ||
} | ||
function appendWithSeparator(secret, i) { | ||
if (i > 0) | ||
appendSecret(separatorSecret); | ||
appendSecret(secret); | ||
} | ||
elements.map(function (elem) { | ||
var lines = fromString(elem); | ||
if (lines.isEmpty()) | ||
return null; | ||
return getSecret(lines); | ||
}).forEach(separator.isEmpty() | ||
? appendSecret | ||
: appendWithSeparator); | ||
if (infos.length < 1) | ||
return emptyLines; | ||
var lines = new Lines(infos); | ||
getSecret(lines).mappings = mappings; | ||
return lines; | ||
}; | ||
function concat(elements) { | ||
@@ -704,14 +671,4 @@ return emptyLines.join(elements); | ||
; | ||
Lp.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); | ||
}; | ||
// The emptyLines object needs to be created all the way down here so that | ||
// Lines.prototype will be fully populated. | ||
var emptyLines = fromString(""); |
@@ -1,14 +0,12 @@ | ||
interface MappingType { | ||
sourceLines: any; | ||
sourceLoc: any; | ||
targetLoc: any; | ||
slice(lines: any, start: any, end: any): MappingType | null; | ||
add(line: number, column: number): MappingType; | ||
subtract(line: number, column: number): MappingType; | ||
indent(by: any, skipFirstLine: any, noNegativeColumns: any): MappingType; | ||
import { SourceLocation as Loc, Position as Pos } from "./types"; | ||
import { Lines } from "./lines"; | ||
export default class Mapping { | ||
sourceLines: Lines; | ||
sourceLoc: Loc; | ||
targetLoc: Loc; | ||
constructor(sourceLines: Lines, sourceLoc: Loc, targetLoc?: Loc); | ||
slice(lines: Lines, start: Pos, end?: Pos): Mapping | null; | ||
add(line: number, column: number): Mapping; | ||
subtract(line: number, column: number): Mapping; | ||
indent(by: number, skipFirstLine?: boolean, noNegativeColumns?: boolean): Mapping; | ||
} | ||
interface MappingConstructor { | ||
new (sourceLines: any, sourceLoc: any, targetLoc?: any): MappingType; | ||
} | ||
declare const Mapping: MappingConstructor; | ||
export default Mapping; |
@@ -5,124 +5,132 @@ "use strict";; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var assert_1 = __importDefault(require("assert")); | ||
var types_1 = __importDefault(require("./types")); | ||
var isNumber = types_1.default.builtInTypes.number; | ||
var SourceLocation = types_1.default.namedTypes.SourceLocation; | ||
var Position = types_1.default.namedTypes.Position; | ||
var linesModule = __importStar(require("./lines")); | ||
var util_1 = require("./util"); | ||
var Mapping = function Mapping(sourceLines, sourceLoc, targetLoc) { | ||
assert_1.default.ok(this instanceof Mapping); | ||
assert_1.default.ok(sourceLines instanceof linesModule.Lines); | ||
SourceLocation.assert(sourceLoc); | ||
if (targetLoc) { | ||
// In certain cases it's possible for targetLoc.{start,end}.column | ||
// values to be negative, which technically makes them no longer | ||
// valid SourceLocation nodes, so we need to be more forgiving. | ||
assert_1.default.ok(isNumber.check(targetLoc.start.line) && | ||
isNumber.check(targetLoc.start.column) && | ||
isNumber.check(targetLoc.end.line) && | ||
isNumber.check(targetLoc.end.column)); | ||
var Mapping = /** @class */ (function () { | ||
function Mapping(sourceLines, sourceLoc, targetLoc) { | ||
if (targetLoc === void 0) { targetLoc = sourceLoc; } | ||
this.sourceLines = sourceLines; | ||
this.sourceLoc = sourceLoc; | ||
this.targetLoc = targetLoc; | ||
} | ||
else { | ||
// Assume identity mapping if no targetLoc specified. | ||
targetLoc = sourceLoc; | ||
} | ||
Object.defineProperties(this, { | ||
sourceLines: { value: sourceLines }, | ||
sourceLoc: { value: sourceLoc }, | ||
targetLoc: { value: targetLoc } | ||
}); | ||
}; | ||
var Mp = Mapping.prototype; | ||
exports.default = Mapping; | ||
Mp.slice = function (lines, start, end) { | ||
assert_1.default.ok(lines instanceof linesModule.Lines); | ||
Position.assert(start); | ||
if (end) { | ||
Position.assert(end); | ||
} | ||
else { | ||
end = lines.lastPos(); | ||
} | ||
var sourceLines = this.sourceLines; | ||
var sourceLoc = this.sourceLoc; | ||
var targetLoc = this.targetLoc; | ||
function skip(name) { | ||
var sourceFromPos = sourceLoc[name]; | ||
var targetFromPos = targetLoc[name]; | ||
var targetToPos = start; | ||
if (name === "end") { | ||
targetToPos = end; | ||
Mapping.prototype.slice = function (lines, start, end) { | ||
if (end === void 0) { end = lines.lastPos(); } | ||
var sourceLines = this.sourceLines; | ||
var sourceLoc = this.sourceLoc; | ||
var targetLoc = this.targetLoc; | ||
function skip(name) { | ||
var sourceFromPos = sourceLoc[name]; | ||
var targetFromPos = targetLoc[name]; | ||
var targetToPos = start; | ||
if (name === "end") { | ||
targetToPos = end; | ||
} | ||
else { | ||
assert_1.default.strictEqual(name, "start"); | ||
} | ||
return skipChars(sourceLines, sourceFromPos, lines, targetFromPos, targetToPos); | ||
} | ||
if (util_1.comparePos(start, targetLoc.start) <= 0) { | ||
if (util_1.comparePos(targetLoc.end, end) <= 0) { | ||
targetLoc = { | ||
start: subtractPos(targetLoc.start, start.line, start.column), | ||
end: subtractPos(targetLoc.end, start.line, start.column) | ||
}; | ||
// The sourceLoc can stay the same because the contents of the | ||
// targetLoc have not changed. | ||
} | ||
else if (util_1.comparePos(end, targetLoc.start) <= 0) { | ||
return null; | ||
} | ||
else { | ||
sourceLoc = { | ||
start: sourceLoc.start, | ||
end: skip("end") | ||
}; | ||
targetLoc = { | ||
start: subtractPos(targetLoc.start, start.line, start.column), | ||
end: subtractPos(end, start.line, start.column) | ||
}; | ||
} | ||
} | ||
else { | ||
assert_1.default.strictEqual(name, "start"); | ||
if (util_1.comparePos(targetLoc.end, start) <= 0) { | ||
return null; | ||
} | ||
if (util_1.comparePos(targetLoc.end, end) <= 0) { | ||
sourceLoc = { | ||
start: skip("start"), | ||
end: sourceLoc.end | ||
}; | ||
targetLoc = { | ||
// Same as subtractPos(start, start.line, start.column): | ||
start: { line: 1, column: 0 }, | ||
end: subtractPos(targetLoc.end, start.line, start.column) | ||
}; | ||
} | ||
else { | ||
sourceLoc = { | ||
start: skip("start"), | ||
end: skip("end") | ||
}; | ||
targetLoc = { | ||
// Same as subtractPos(start, start.line, start.column): | ||
start: { line: 1, column: 0 }, | ||
end: subtractPos(end, start.line, start.column) | ||
}; | ||
} | ||
} | ||
return skipChars(sourceLines, sourceFromPos, lines, targetFromPos, targetToPos); | ||
} | ||
if (util_1.comparePos(start, targetLoc.start) <= 0) { | ||
if (util_1.comparePos(targetLoc.end, end) <= 0) { | ||
targetLoc = { | ||
start: subtractPos(targetLoc.start, start.line, start.column), | ||
end: subtractPos(targetLoc.end, start.line, start.column) | ||
}; | ||
// The sourceLoc can stay the same because the contents of the | ||
// targetLoc have not changed. | ||
return new Mapping(this.sourceLines, sourceLoc, targetLoc); | ||
}; | ||
Mapping.prototype.add = function (line, column) { | ||
return new Mapping(this.sourceLines, this.sourceLoc, { | ||
start: addPos(this.targetLoc.start, line, column), | ||
end: addPos(this.targetLoc.end, line, column) | ||
}); | ||
}; | ||
Mapping.prototype.subtract = function (line, column) { | ||
return new Mapping(this.sourceLines, this.sourceLoc, { | ||
start: subtractPos(this.targetLoc.start, line, column), | ||
end: subtractPos(this.targetLoc.end, line, column) | ||
}); | ||
}; | ||
Mapping.prototype.indent = function (by, skipFirstLine, noNegativeColumns) { | ||
if (skipFirstLine === void 0) { skipFirstLine = false; } | ||
if (noNegativeColumns === void 0) { noNegativeColumns = false; } | ||
if (by === 0) { | ||
return this; | ||
} | ||
else if (util_1.comparePos(end, targetLoc.start) <= 0) { | ||
return null; | ||
var targetLoc = this.targetLoc; | ||
var startLine = targetLoc.start.line; | ||
var endLine = targetLoc.end.line; | ||
if (skipFirstLine && startLine === 1 && endLine === 1) { | ||
return this; | ||
} | ||
else { | ||
sourceLoc = { | ||
start: sourceLoc.start, | ||
end: skip("end") | ||
targetLoc = { | ||
start: targetLoc.start, | ||
end: targetLoc.end | ||
}; | ||
if (!skipFirstLine || startLine > 1) { | ||
var startColumn = targetLoc.start.column + by; | ||
targetLoc.start = { | ||
line: startLine, | ||
column: noNegativeColumns | ||
? Math.max(0, startColumn) | ||
: startColumn | ||
}; | ||
targetLoc = { | ||
start: subtractPos(targetLoc.start, start.line, start.column), | ||
end: subtractPos(end, start.line, start.column) | ||
}; | ||
} | ||
} | ||
else { | ||
if (util_1.comparePos(targetLoc.end, start) <= 0) { | ||
return null; | ||
} | ||
if (util_1.comparePos(targetLoc.end, end) <= 0) { | ||
sourceLoc = { | ||
start: skip("start"), | ||
end: sourceLoc.end | ||
if (!skipFirstLine || endLine > 1) { | ||
var endColumn = targetLoc.end.column + by; | ||
targetLoc.end = { | ||
line: endLine, | ||
column: noNegativeColumns | ||
? Math.max(0, endColumn) | ||
: endColumn | ||
}; | ||
targetLoc = { | ||
// Same as subtractPos(start, start.line, start.column): | ||
start: { line: 1, column: 0 }, | ||
end: subtractPos(targetLoc.end, start.line, start.column) | ||
}; | ||
} | ||
else { | ||
sourceLoc = { | ||
start: skip("start"), | ||
end: skip("end") | ||
}; | ||
targetLoc = { | ||
// Same as subtractPos(start, start.line, start.column): | ||
start: { line: 1, column: 0 }, | ||
end: subtractPos(end, start.line, start.column) | ||
}; | ||
} | ||
} | ||
return new Mapping(this.sourceLines, sourceLoc, targetLoc); | ||
}; | ||
Mp.add = function (line, column) { | ||
return new Mapping(this.sourceLines, this.sourceLoc, { | ||
start: addPos(this.targetLoc.start, line, column), | ||
end: addPos(this.targetLoc.end, line, column) | ||
}); | ||
}; | ||
return new Mapping(this.sourceLines, this.sourceLoc, targetLoc); | ||
}; | ||
return Mapping; | ||
}()); | ||
exports.default = Mapping; | ||
function addPos(toPos, line, column) { | ||
@@ -136,8 +144,2 @@ return { | ||
} | ||
Mp.subtract = function (line, column) { | ||
return new Mapping(this.sourceLines, this.sourceLoc, { | ||
start: subtractPos(this.targetLoc.start, line, column), | ||
end: subtractPos(this.targetLoc.end, line, column) | ||
}); | ||
}; | ||
function subtractPos(fromPos, line, column) { | ||
@@ -151,42 +153,3 @@ return { | ||
} | ||
Mp.indent = function (by, skipFirstLine, noNegativeColumns) { | ||
if (by === 0) { | ||
return this; | ||
} | ||
var targetLoc = this.targetLoc; | ||
var startLine = targetLoc.start.line; | ||
var endLine = targetLoc.end.line; | ||
if (skipFirstLine && startLine === 1 && endLine === 1) { | ||
return this; | ||
} | ||
targetLoc = { | ||
start: targetLoc.start, | ||
end: targetLoc.end | ||
}; | ||
if (!skipFirstLine || startLine > 1) { | ||
var startColumn = targetLoc.start.column + by; | ||
targetLoc.start = { | ||
line: startLine, | ||
column: noNegativeColumns | ||
? Math.max(0, startColumn) | ||
: startColumn | ||
}; | ||
} | ||
if (!skipFirstLine || endLine > 1) { | ||
var endColumn = targetLoc.end.column + by; | ||
targetLoc.end = { | ||
line: endLine, | ||
column: noNegativeColumns | ||
? Math.max(0, endColumn) | ||
: endColumn | ||
}; | ||
} | ||
return new Mapping(this.sourceLines, this.sourceLoc, targetLoc); | ||
}; | ||
function skipChars(sourceLines, sourceFromPos, targetLines, targetFromPos, targetToPos) { | ||
assert_1.default.ok(sourceLines instanceof linesModule.Lines); | ||
assert_1.default.ok(targetLines instanceof linesModule.Lines); | ||
Position.assert(sourceFromPos); | ||
Position.assert(targetFromPos); | ||
Position.assert(targetToPos); | ||
var targetComparison = util_1.comparePos(targetFromPos, targetToPos); | ||
@@ -199,4 +162,4 @@ if (targetComparison === 0) { | ||
// Skipping forward. | ||
var sourceCursor = sourceLines.skipSpaces(sourceFromPos); | ||
var targetCursor = targetLines.skipSpaces(targetFromPos); | ||
var sourceCursor = sourceLines.skipSpaces(sourceFromPos) || sourceLines.lastPos(); | ||
var targetCursor = targetLines.skipSpaces(targetFromPos) || targetLines.lastPos(); | ||
var lineDiff = targetToPos.line - targetCursor.line; | ||
@@ -222,4 +185,4 @@ sourceCursor.line += lineDiff; | ||
// Skipping backward. | ||
var sourceCursor = sourceLines.skipSpaces(sourceFromPos, true); | ||
var targetCursor = targetLines.skipSpaces(targetFromPos, true); | ||
var sourceCursor = sourceLines.skipSpaces(sourceFromPos, true) || sourceLines.firstPos(); | ||
var targetCursor = targetLines.skipSpaces(targetFromPos, true) || targetLines.firstPos(); | ||
var lineDiff = targetToPos.line - targetCursor.line; | ||
@@ -226,0 +189,0 @@ sourceCursor.line += lineDiff; |
import astTypes from "ast-types"; | ||
export default astTypes; | ||
export * from "ast-types"; | ||
export declare type Position = { | ||
line: number; | ||
column: number; | ||
}; | ||
export declare type SourceLocation = { | ||
source?: string | null; | ||
start: Position; | ||
end: Position; | ||
}; |
{ | ||
"author": "Ben Newman <bn@cs.stanford.edu>", | ||
"name": "recast", | ||
"version": "0.17.1", | ||
"version": "0.17.2", | ||
"description": "JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
230915
5619