'use strict'; const acorn = require('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 = acorn.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 = acorn.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); } } exports.createIsLiteralPositionAcorn = createIsLiteralPositionAcorn; exports.stripLiteral = stripLiteral; exports.stripLiteralAcorn = stripLiteralAcorn; exports.stripLiteralRegex = stripLiteralRegex;