mirror of https://gitee.com/antv-l7/antv-l7
278 lines
8.1 KiB
JavaScript
278 lines
8.1 KiB
JavaScript
var assert = require("assert");
|
|
var types = require("./types");
|
|
var isString = types.builtInTypes.string;
|
|
var isNumber = types.builtInTypes.number;
|
|
var SourceLocation = types.namedTypes.SourceLocation;
|
|
var Position = types.namedTypes.Position;
|
|
var linesModule = require("./lines");
|
|
var comparePos = require("./util").comparePos;
|
|
|
|
function Mapping(sourceLines, sourceLoc, targetLoc) {
|
|
assert.ok(this instanceof Mapping);
|
|
assert.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.ok(
|
|
isNumber.check(targetLoc.start.line) &&
|
|
isNumber.check(targetLoc.start.column) &&
|
|
isNumber.check(targetLoc.end.line) &&
|
|
isNumber.check(targetLoc.end.column)
|
|
);
|
|
} 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;
|
|
module.exports = Mapping;
|
|
|
|
Mp.slice = function(lines, start, end) {
|
|
assert.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;
|
|
} else {
|
|
assert.strictEqual(name, "start");
|
|
}
|
|
|
|
return skipChars(
|
|
sourceLines, sourceFromPos,
|
|
lines, targetFromPos, targetToPos
|
|
);
|
|
}
|
|
|
|
if (comparePos(start, targetLoc.start) <= 0) {
|
|
if (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 (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 {
|
|
if (comparePos(targetLoc.end, start) <= 0) {
|
|
return null;
|
|
}
|
|
|
|
if (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 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)
|
|
});
|
|
};
|
|
|
|
function addPos(toPos, line, column) {
|
|
return {
|
|
line: toPos.line + line - 1,
|
|
column: (toPos.line === 1)
|
|
? toPos.column + column
|
|
: toPos.column
|
|
};
|
|
}
|
|
|
|
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) {
|
|
return {
|
|
line: fromPos.line - line + 1,
|
|
column: (fromPos.line === line)
|
|
? fromPos.column - column
|
|
: fromPos.column
|
|
};
|
|
}
|
|
|
|
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.ok(sourceLines instanceof linesModule.Lines);
|
|
assert.ok(targetLines instanceof linesModule.Lines);
|
|
Position.assert(sourceFromPos);
|
|
Position.assert(targetFromPos);
|
|
Position.assert(targetToPos);
|
|
|
|
var targetComparison = comparePos(targetFromPos, targetToPos);
|
|
if (targetComparison === 0) {
|
|
// Trivial case: no characters to skip.
|
|
return sourceFromPos;
|
|
}
|
|
|
|
if (targetComparison < 0) {
|
|
// Skipping forward.
|
|
|
|
var sourceCursor = sourceLines.skipSpaces(sourceFromPos);
|
|
var targetCursor = targetLines.skipSpaces(targetFromPos);
|
|
|
|
var lineDiff = targetToPos.line - targetCursor.line;
|
|
sourceCursor.line += lineDiff;
|
|
targetCursor.line += lineDiff;
|
|
|
|
if (lineDiff > 0) {
|
|
// If jumping to later lines, reset columns to the beginnings
|
|
// of those lines.
|
|
sourceCursor.column = 0;
|
|
targetCursor.column = 0;
|
|
} else {
|
|
assert.strictEqual(lineDiff, 0);
|
|
}
|
|
|
|
while (comparePos(targetCursor, targetToPos) < 0 &&
|
|
targetLines.nextPos(targetCursor, true)) {
|
|
assert.ok(sourceLines.nextPos(sourceCursor, true));
|
|
assert.strictEqual(
|
|
sourceLines.charAt(sourceCursor),
|
|
targetLines.charAt(targetCursor)
|
|
);
|
|
}
|
|
|
|
} else {
|
|
// Skipping backward.
|
|
|
|
var sourceCursor = sourceLines.skipSpaces(sourceFromPos, true);
|
|
var targetCursor = targetLines.skipSpaces(targetFromPos, true);
|
|
|
|
var lineDiff = targetToPos.line - targetCursor.line;
|
|
sourceCursor.line += lineDiff;
|
|
targetCursor.line += lineDiff;
|
|
|
|
if (lineDiff < 0) {
|
|
// If jumping to earlier lines, reset columns to the ends of
|
|
// those lines.
|
|
sourceCursor.column = sourceLines.getLineLength(sourceCursor.line);
|
|
targetCursor.column = targetLines.getLineLength(targetCursor.line);
|
|
} else {
|
|
assert.strictEqual(lineDiff, 0);
|
|
}
|
|
|
|
while (comparePos(targetToPos, targetCursor) < 0 &&
|
|
targetLines.prevPos(targetCursor, true)) {
|
|
assert.ok(sourceLines.prevPos(sourceCursor, true));
|
|
assert.strictEqual(
|
|
sourceLines.charAt(sourceCursor),
|
|
targetLines.charAt(targetCursor)
|
|
);
|
|
}
|
|
}
|
|
|
|
return sourceCursor;
|
|
}
|