You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.2 KiB
110 lines
3.2 KiB
import { tokenizer } from 'acorn';
|
|
|
|
function stripLiteralAcorn(code) {
|
|
const FILL = " ";
|
|
let result = "";
|
|
function fulfill(index) {
|
|
if (index > result.length)
|
|
result += code.slice(result.length, index).replace(/[^\n]/g, FILL);
|
|
}
|
|
const tokens = tokenizer(code, {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
allowHashBang: true,
|
|
allowAwaitOutsideFunction: true,
|
|
allowImportExportEverywhere: true
|
|
});
|
|
const inter = tokens[Symbol.iterator]();
|
|
while (true) {
|
|
const { done, value: token } = inter.next();
|
|
if (done)
|
|
break;
|
|
fulfill(token.start);
|
|
if (token.type.label === "string")
|
|
result += code[token.start] + FILL.repeat(token.end - token.start - 2) + code[token.end - 1];
|
|
else if (token.type.label === "template")
|
|
result += FILL.repeat(token.end - token.start);
|
|
else
|
|
result += code.slice(token.start, token.end);
|
|
}
|
|
fulfill(code.length);
|
|
return result;
|
|
}
|
|
function createIsLiteralPositionAcorn(code) {
|
|
const positionList = [];
|
|
const tokens = tokenizer(code, {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
allowHashBang: true,
|
|
allowAwaitOutsideFunction: true,
|
|
allowImportExportEverywhere: true,
|
|
onComment(_isBlock, _text, start, end) {
|
|
positionList.push(start);
|
|
positionList.push(end);
|
|
}
|
|
});
|
|
const inter = tokens[Symbol.iterator]();
|
|
while (true) {
|
|
const { done, value: token } = inter.next();
|
|
if (done)
|
|
break;
|
|
if (token.type.label === "string") {
|
|
positionList.push(token.start + 1);
|
|
positionList.push(token.end - 1);
|
|
} else if (token.type.label === "template") {
|
|
positionList.push(token.start);
|
|
positionList.push(token.end);
|
|
}
|
|
}
|
|
return (position) => {
|
|
const i = binarySearch(positionList, (v) => position < v);
|
|
return (i - 1) % 2 === 0;
|
|
};
|
|
}
|
|
function binarySearch(array, pred) {
|
|
let low = -1;
|
|
let high = array.length;
|
|
while (1 + low < high) {
|
|
const mid = low + (high - low >> 1);
|
|
if (pred(array[mid]))
|
|
high = mid;
|
|
else
|
|
low = mid;
|
|
}
|
|
return high;
|
|
}
|
|
|
|
const multilineCommentsRE = /\/\*.*?\*\//gms;
|
|
const singlelineCommentsRE = /(?:^|\n|\r)\s*\/\/.*(?:\r|\n|$)/gm;
|
|
const templateLiteralRE = /\$\{(\s*(?:(?!\$\{).|\n|\r)*?\s*)\}/g;
|
|
const quotesRE = [
|
|
/(["'`])((?:\\\1|(?!\1)|.|\r)*?)\1/gm,
|
|
/([`])((?:\\\1|(?!\1)|.|\n|\r)*?)\1/gm
|
|
];
|
|
function stripLiteralRegex(code) {
|
|
code = code.replace(multilineCommentsRE, (s) => " ".repeat(s.length)).replace(singlelineCommentsRE, (s) => " ".repeat(s.length));
|
|
let expanded = code;
|
|
for (let i = 0; i < 16; i++) {
|
|
const before = expanded;
|
|
expanded = expanded.replace(templateLiteralRE, "` $1`");
|
|
if (expanded === before)
|
|
break;
|
|
}
|
|
quotesRE.forEach((re) => {
|
|
expanded = expanded.replace(re, (s, quote, body, index) => {
|
|
code = code.slice(0, index + 1) + " ".repeat(s.length - 2) + code.slice(index + s.length - 1);
|
|
return quote + " ".repeat(s.length - 2) + quote;
|
|
});
|
|
});
|
|
return code;
|
|
}
|
|
|
|
function stripLiteral(code) {
|
|
try {
|
|
return stripLiteralAcorn(code);
|
|
} catch (e) {
|
|
return stripLiteralRegex(code);
|
|
}
|
|
}
|
|
|
|
export { createIsLiteralPositionAcorn, stripLiteral, stripLiteralAcorn, stripLiteralRegex };
|
|
|