248 lines
8.8 KiB
Plaintext
248 lines
8.8 KiB
Plaintext
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.ClientScript = void 0;
|
||
|
const types_1 = require("@typescript-eslint/types");
|
||
|
const parse_expression_1 = require("./parse-expression");
|
||
|
const RE_LEADING_SPACES = /^[\t ]+/u;
|
||
|
let seq = 0;
|
||
|
class Locs {
|
||
|
constructor(lines) {
|
||
|
const lineStartIndices = [0];
|
||
|
let index = 0;
|
||
|
for (const line of lines[lines.length - 1] ? lines : lines.slice(0, -1)) {
|
||
|
index += line.length;
|
||
|
lineStartIndices.push(index);
|
||
|
}
|
||
|
this.lineStartIndices = lineStartIndices;
|
||
|
}
|
||
|
getLocFromIndex(index) {
|
||
|
const lineNumber = sortedLastIndex(this.lineStartIndices, index);
|
||
|
return {
|
||
|
line: lineNumber,
|
||
|
column: index - this.lineStartIndices[lineNumber - 1],
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
class ClientScript {
|
||
|
constructor(code, script, parsed) {
|
||
|
this.code = code;
|
||
|
this.script = script;
|
||
|
this.parsed = parsed;
|
||
|
this.id = ++seq;
|
||
|
this.block = this.initBlock();
|
||
|
}
|
||
|
initBlock() {
|
||
|
const textNode = this.script.children[0];
|
||
|
const startOffset = textNode.position.start.offset;
|
||
|
const endOffset = this.parsed.getEndOffset(textNode);
|
||
|
const startLoc = this.parsed.getLocFromIndex(startOffset);
|
||
|
const lines = this.code.slice(startOffset, endOffset).split(/(?<=\n)/u);
|
||
|
const firstLine = lines.shift();
|
||
|
const textLines = [];
|
||
|
const remapColumnOffsets = [];
|
||
|
const remapLines = [];
|
||
|
const defineVars = this.extractDefineVars();
|
||
|
if (defineVars.length) {
|
||
|
textLines.push("/* global\n");
|
||
|
remapLines.push(-1);
|
||
|
remapColumnOffsets.push(-1);
|
||
|
for (const defineVar of defineVars) {
|
||
|
textLines.push(`${defineVar.name}\n`);
|
||
|
remapLines.push(defineVar.loc.line);
|
||
|
remapColumnOffsets.push(defineVar.loc.column);
|
||
|
}
|
||
|
textLines.push("-- define:vars */\n");
|
||
|
remapLines.push(-1);
|
||
|
remapColumnOffsets.push(-1);
|
||
|
}
|
||
|
if (firstLine.trim()) {
|
||
|
const firstLineIndent = (RE_LEADING_SPACES.exec(firstLine) || [""])[0]
|
||
|
.length;
|
||
|
textLines.push(firstLine.slice(firstLineIndent));
|
||
|
remapLines.push(startLoc.line);
|
||
|
remapColumnOffsets.push(firstLineIndent + startLoc.column);
|
||
|
}
|
||
|
const indent = getIndent(lines);
|
||
|
for (let index = 0; index < lines.length; index++) {
|
||
|
const line = lines[index];
|
||
|
const lineIndent = Math.min(indent, line.length);
|
||
|
const lineText = line.slice(lineIndent);
|
||
|
if (lineText) {
|
||
|
textLines.push(line.slice(lineIndent));
|
||
|
remapColumnOffsets.push(lineIndent);
|
||
|
}
|
||
|
else if (line.endsWith("\n")) {
|
||
|
const eol = line.endsWith("\r\n") ? "\r\n" : "\n";
|
||
|
textLines.push(eol);
|
||
|
remapColumnOffsets.push(line.length - eol.length);
|
||
|
}
|
||
|
else {
|
||
|
textLines.push("");
|
||
|
remapColumnOffsets.push(lineIndent);
|
||
|
}
|
||
|
remapLines.push(startLoc.line + index + 1);
|
||
|
}
|
||
|
const text = textLines.join("");
|
||
|
const textLocs = new Locs(textLines);
|
||
|
const remapLoc = (loc) => {
|
||
|
const lineIndex = loc.line - 1;
|
||
|
if (remapLines.length > lineIndex) {
|
||
|
return {
|
||
|
line: remapLines[lineIndex],
|
||
|
column: loc.column + remapColumnOffsets[lineIndex],
|
||
|
};
|
||
|
}
|
||
|
if (remapLines.length === lineIndex) {
|
||
|
return this.parsed.getLocFromIndex(endOffset + loc.column);
|
||
|
}
|
||
|
return {
|
||
|
line: -1,
|
||
|
column: loc.column + 0,
|
||
|
};
|
||
|
};
|
||
|
const remapRange = (range) => {
|
||
|
const startLoc = textLocs.getLocFromIndex(range[0]);
|
||
|
const normalEndLoc = textLocs.getLocFromIndex(range[1]);
|
||
|
const endLoc = normalEndLoc.column > 0
|
||
|
? normalEndLoc
|
||
|
: textLocs.getLocFromIndex(range[1] - 1);
|
||
|
const remappedStartLoc = remapLoc(startLoc);
|
||
|
const remappedEndLoc = remapLoc(endLoc);
|
||
|
if (remappedStartLoc.line < 0 || remappedEndLoc.line < 0) {
|
||
|
return null;
|
||
|
}
|
||
|
return [
|
||
|
this.parsed.getIndexFromLoc(remappedStartLoc),
|
||
|
this.parsed.getIndexFromLoc(remappedEndLoc) +
|
||
|
(normalEndLoc.column > 0 ? 0 : 1),
|
||
|
];
|
||
|
};
|
||
|
return {
|
||
|
text,
|
||
|
remapMessage(message) {
|
||
|
const loc = remapLoc(message);
|
||
|
message.line = loc.line;
|
||
|
message.column = loc.column;
|
||
|
if (typeof message.endLine === "number" &&
|
||
|
typeof message.endColumn === "number") {
|
||
|
const loc = remapLoc({
|
||
|
line: message.endLine,
|
||
|
column: message.endColumn,
|
||
|
});
|
||
|
message.endLine = loc.line;
|
||
|
message.endColumn = loc.column;
|
||
|
}
|
||
|
if (message.fix) {
|
||
|
const remappedRange = remapRange(message.fix.range);
|
||
|
if (remappedRange) {
|
||
|
message.fix.range = remappedRange;
|
||
|
}
|
||
|
else {
|
||
|
delete message.fix;
|
||
|
}
|
||
|
}
|
||
|
if (message.suggestions) {
|
||
|
for (const suggestion of [...message.suggestions]) {
|
||
|
const remappedRange = remapRange(suggestion.fix.range);
|
||
|
if (remappedRange) {
|
||
|
suggestion.fix.range = remappedRange;
|
||
|
}
|
||
|
else {
|
||
|
message.suggestions.splice(message.suggestions.indexOf(suggestion), 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return message;
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
extractDefineVars() {
|
||
|
const defineVars = this.script.attributes.find((attr) => attr.kind === "expression" && attr.name === "define:vars");
|
||
|
if (!defineVars) {
|
||
|
return [];
|
||
|
}
|
||
|
const valueStart = this.parsed.calcAttributeValueStartOffset(defineVars);
|
||
|
const valueEnd = this.parsed.calcAttributeEndOffset(defineVars);
|
||
|
let expression;
|
||
|
try {
|
||
|
expression = (0, parse_expression_1.parseExpression)(this.code.slice(valueStart + 1, valueEnd - 1));
|
||
|
}
|
||
|
catch (_a) {
|
||
|
return [];
|
||
|
}
|
||
|
if (expression.type !== types_1.AST_NODE_TYPES.ObjectExpression)
|
||
|
return [];
|
||
|
const startLoc = this.parsed.getLocFromIndex(valueStart + 1);
|
||
|
return expression.properties
|
||
|
.filter((p) => p.type === types_1.AST_NODE_TYPES.Property)
|
||
|
.filter((p) => !p.computed)
|
||
|
.map((p) => {
|
||
|
return {
|
||
|
name: p.key.type === types_1.AST_NODE_TYPES.Identifier ? p.key.name : p.key.value,
|
||
|
loc: {
|
||
|
line: p.key.loc.start.line + startLoc.line - 1,
|
||
|
column: p.key.loc.start.column +
|
||
|
(p.key.loc.start.line === 1 ? startLoc.column : 0),
|
||
|
},
|
||
|
};
|
||
|
});
|
||
|
}
|
||
|
getProcessorFile(ext) {
|
||
|
return {
|
||
|
text: this.block.text,
|
||
|
filename: `${this.id}${ext}`,
|
||
|
};
|
||
|
}
|
||
|
remapMessages(messages) {
|
||
|
return messages
|
||
|
.filter((m) => !this.isIgnoreMessage(m))
|
||
|
.map((m) => this.block.remapMessage(m))
|
||
|
.filter((m) => m.line >= 0);
|
||
|
}
|
||
|
isIgnoreMessage(message) {
|
||
|
if ((message.ruleId === "eol-last" ||
|
||
|
message.ruleId === "rule-to-test/eol-last") &&
|
||
|
message.messageId === "unexpected") {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
exports.ClientScript = ClientScript;
|
||
|
function getIndent(lines) {
|
||
|
let indent = null;
|
||
|
for (const line of lines) {
|
||
|
if (!line.trim())
|
||
|
continue;
|
||
|
const lineIndent = (RE_LEADING_SPACES.exec(line) || [""])[0].length;
|
||
|
if (indent == null) {
|
||
|
indent = lineIndent;
|
||
|
}
|
||
|
else {
|
||
|
indent = Math.min(indent, lineIndent);
|
||
|
}
|
||
|
if (indent === 0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return indent || 0;
|
||
|
}
|
||
|
function sortedLastIndex(array, value) {
|
||
|
let lower = 0;
|
||
|
let upper = array.length;
|
||
|
while (lower < upper) {
|
||
|
const mid = Math.floor(lower + (upper - lower) / 2);
|
||
|
const target = array[mid];
|
||
|
if (target < value) {
|
||
|
lower = mid + 1;
|
||
|
}
|
||
|
else if (target > value) {
|
||
|
upper = mid;
|
||
|
}
|
||
|
else {
|
||
|
return mid + 1;
|
||
|
}
|
||
|
}
|
||
|
return upper;
|
||
|
}
|