extra-javascript-text
Version:
Utilities for processing JavaScript text.
200 lines (197 loc) • 7.37 kB
JavaScript
;
function indexOfClosingString(txt, i) {
var q = txt.charAt(i);
while (true) {
var I = txt.indexOf(q, i + 1);
if (txt.charAt(I - 1) != "\\")
return I;
i = I + 1;
}
}
function forEachString(txt, fn) {
var RCOMSTR = /\/\/|\/\*|(?:[=(]\s*)(\/[^\n]+\/[gimsuy]*)|['"`]/g, m = null;
while ((m = RCOMSTR.exec(txt)) != null) {
var i = m.index, I = 0;
if (m[0] === "//")
I = txt.indexOf("\n", i + 1);
else if (m[0] === "/*")
I = txt.indexOf("*/", i + 1);
else if (m[1] != null)
I = i + m[0].length;
else {
I = indexOfClosingString(txt, i);
fn(txt.substring(i, I + 1));
}
RCOMSTR.lastIndex = I + 1;
}
}
function strings(txt) {
var a = [];
forEachString(txt, full => a.push(full));
return a;
}
function replaceStrings(txt, fn) {
var RCOMSTR = /\/\/|\/\*|['"`]/g, m = null, a = "", ai = 0;
while ((m = RCOMSTR.exec(txt)) != null) {
var i = m.index, I = 0;
if (m[0] === "//")
I = txt.indexOf("\n", i + 1);
else if (m[0] === "/*")
I = txt.indexOf("*/", i + 1);
else {
I = indexOfClosingString(txt, i);
a += txt.substring(ai, i) + fn(txt.substring(i, I + 1));
ai = I + 1;
}
RCOMSTR.lastIndex = I + 1;
}
a += txt.substring(ai);
return a;
}
function tagStrings(txt) {
var tags = new Map(), i = -1;
var txt = replaceStrings(txt, full => {
var k = `AUTO_STRING_${++i}`;
tags.set(k, full);
return `"${k}"`;
});
return [txt, tags];
}
function untagStrings(txt, tags) {
for (var [tag, full] of tags)
txt = txt.replace(`"${tag}"`, full);
return txt;
}
const RCOMMENT = /\/\/[\s\S]*?$|\/\*[\s\S]*?\*\//gm;
function forEachComment(txt, fn) {
var txt = replaceStrings(txt, () => '"AUTO_STRING"'), m = null;
while ((m = RCOMMENT.exec(txt)) != null)
fn(m[0]);
}
function comments(txt) {
var a = [];
forEachComment(txt, full => a.push(full));
return a;
}
function replaceComments(txt, fn) {
var [txt, tags] = tagStrings(txt);
txt = txt.replace(RCOMMENT, fn);
return untagStrings(txt, tags);
}
function tagComments(txt) {
var tags = new Map(), i = -1;
var txt = replaceComments(txt, full => {
var k = `AUTO_COMMENT_${++i}`;
tags.set(k, full);
return `/* ${k} */`;
});
return [txt, tags];
}
function untagComments(txt, tags) {
for (var [tag, full] of tags)
txt = txt.replace(`/* ${tag} */`, full);
return txt;
}
function uncomment(txt, empty = false) {
txt = replaceComments(txt, () => "").replace(/[ \t]+$/gm, "");
if (empty)
txt = txt.replace(/\n\n+/g, "\n");
return txt.trim() + "\n";
}
const RJSDOCSYMBOL = /(\/\*\*[\s\S]*?\*\/)(?:\s+(?:(export)\s+(?:(default)\s+)?)?(?:declare\s+)?(type|enum|interface|const|var|let|(?:async\s+)?function\*?|class)\s+([\w$]+))?/g;
function forEachJsdocSymbol(txt, fn) {
var txt = replaceStrings(txt, () => '"AUTO_STRING"'), m = null;
while ((m = RJSDOCSYMBOL.exec(txt)) != null)
fn(m[0], m[1] || "", m[5] || "", (m[4] || "").replace(/\s+/g, " "), m[2] === "export", m[3] === "default");
}
function jsdocSymbols(txt) {
var a = [];
forEachJsdocSymbol(txt, (full, jsdoc, name, kind, isExported, isDefault) => {
a.push({ full, jsdoc, name, kind, isExported, isDefault });
});
return a;
}
function replaceJsdocSymbols(txt, fn) {
var [txt, tags] = tagStrings(txt);
txt = txt.replace(RJSDOCSYMBOL, (m, p1, p2, p3, p4, p5) => {
return fn(m, p1 || "", p5 || "", (p4 || "").replace(/\s+/g, " "), p2 === "export", p3 === "default");
});
return untagStrings(txt, tags);
}
const REXPORTSYMBOL = /export\s+\{\s*(?:(\S+)|(?:\S+\s+as\s+(\S+)))\s*\}|export\s+(?:(default)\s+)?(type|enum|interface|const|var|let|(?:async\s+)?function\*?|class)\s+([\w$]+)|export\s+(default)\s+([\w$]+)|module\s*\.\s*([\w$]+)|module\s*\[\s*['"`](.*?)['"`]\s*\]|(module)\s*\.\s*exports\s*=\s*\{(.*?)\}|(module)\s*\.\s*exports\s*=/g;
function forEachExportSymbol(txt, fn) {
var txt = replaceStrings(txt, () => '"AUTO_STRING"');
var txt = replaceComments(txt, () => `/* AUTO_COMMENT */`), m = null;
while ((m = REXPORTSYMBOL.exec(txt)) != null)
fn(m[0], m[11] || m[9] || m[8] || m[7] || m[5] || m[2] || m[1] || "", (m[4] || "").replace(/\s+/g, " "), (m[6] || m[3]) === "default" || (m[12] || m[10]) === "module");
}
function exportSymbols(txt) {
var a = [];
forEachExportSymbol(txt, (full, name, kind, isDefault) => {
a.push({ full, name, kind, isDefault });
});
return a;
}
function replaceExportSymbols(txt, fn) {
var [txt, stags] = tagStrings(txt);
var [txt, ctags] = tagComments(txt);
txt = txt.replace(REXPORTSYMBOL, (m, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) => {
return fn(m, p11 || p9 || p8 || p7 || p5 || p2 || p1 || "", (p4 || "").replace(/\s+/g, " "), (p6 || p3) === "default" || (p12 || p10) === "module");
});
txt = untagComments(txt, ctags);
txt = untagStrings(txt, stags);
return txt;
}
const RIMPORTSYMBOL = /(?:import|export).*?from\s*['"`](.*?)['"`]|require\s*\(\s*['"`](.*?)['"`]\s*\)/g;
function forEachImportSymbol(txt, fn) {
var txt = replaceStrings(txt, () => '"AUTO_STRING"');
var txt = replaceComments(txt, () => `/* AUTO_COMMENT */`), m = null;
while ((m = RIMPORTSYMBOL.exec(txt)) != null)
fn(m[0], m[2] || m[1] || "");
}
function importSymbols(txt) {
var a = [];
forEachImportSymbol(txt, (full, file) => a.push({ full, file }));
return a;
}
function replaceImportSymbols(txt, fn) {
var [txt, stags] = tagStrings(txt);
var [txt, ctags] = tagComments(txt);
txt = txt.replace(RIMPORTSYMBOL, (m, p1, p2) => fn(m, p2 || p1 || ""));
txt = untagComments(txt, ctags);
txt = untagStrings(txt, stags);
return txt;
}
function correctDeclarations(txt, module = null) {
var [txt, stags] = tagStrings(txt);
var [txt, ctags] = tagComments(txt);
txt = txt.replace(/export\s+declare/g, "export");
txt = txt.replace(/export\s+default\s+/, "export = ");
txt = txt.replace(/declare\s+module\s+['"`](.*?)['"`]/g, (m, p1) => {
return module != null ? `declare module "${module}"` : m;
});
txt = untagComments(txt, ctags);
txt = untagStrings(txt, stags);
return txt;
}
exports.comments = comments;
exports.correctDeclarations = correctDeclarations;
exports.exportSymbols = exportSymbols;
exports.forEachComment = forEachComment;
exports.forEachExportSymbol = forEachExportSymbol;
exports.forEachImportSymbol = forEachImportSymbol;
exports.forEachJsdocSymbol = forEachJsdocSymbol;
exports.forEachString = forEachString;
exports.importSymbols = importSymbols;
exports.jsdocSymbols = jsdocSymbols;
exports.replaceComments = replaceComments;
exports.replaceExportSymbols = replaceExportSymbols;
exports.replaceImportSymbols = replaceImportSymbols;
exports.replaceJsdocSymbols = replaceJsdocSymbols;
exports.replaceStrings = replaceStrings;
exports.strings = strings;
exports.tagComments = tagComments;
exports.tagStrings = tagStrings;
exports.uncomment = uncomment;
exports.untagComments = untagComments;
exports.untagStrings = untagStrings;