mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix(scripts): count comments after regex literals in the comment ratchet (#4879)
* fix(scripts): count comments after regex literals in the comment ratchet * fix(scripts): keep comments after JSX tags, ++/-- and wrapped division in the ratchet
This commit is contained in:
@@ -150,6 +150,45 @@ function stripStrings(line) {
|
||||
return line.replace(/(["'`])(?:\\.|(?!\1)[^\\])*\1/g, (m) => " ".repeat(m.length));
|
||||
}
|
||||
|
||||
// Index just past the literal opened at `start`, or -1 when it does not close on this line.
|
||||
function literalEnd(line, start, regex) {
|
||||
const close = regex ? "/" : line[start];
|
||||
let inClass = false;
|
||||
for (let i = start + 1; i < line.length; i++) {
|
||||
const ch = line[i];
|
||||
if (ch === "\\") i++;
|
||||
else if (regex && ch === "[") inClass = true;
|
||||
else if (regex && ch === "]") inClass = false;
|
||||
else if (ch === close && !inClass) return i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** stripStrings for C-like code, plus regex literals, so `/["'`]/` opens no string or template.
|
||||
* A `/` after a value, `<`, `++` or `--` is division or a tag (`a / b`, `</p>`, `i++ / 2`).
|
||||
* Stops at the first comment. */
|
||||
function stripLiterals(line) {
|
||||
let out = "";
|
||||
for (let i = 0; i < line.length; ) {
|
||||
const ch = line[i];
|
||||
const comment = ch === "/" && (line[i + 1] === "/" || line[i + 1] === "*");
|
||||
if (comment) return out + line.slice(i);
|
||||
// ponytail: `return /re/` reads as division; add a keyword check if that ever hides a comment.
|
||||
const regex = ch === "/" && !/(?:[\w$)\]<]|\+\+|--)$/.test(out.trimEnd());
|
||||
let end = regex || `"'\``.includes(ch) ? literalEnd(line, i, regex) : -1;
|
||||
// A regex never closes on a comment opener: this `/` is division, e.g. continued from the line above.
|
||||
if (regex && (line[end] === "/" || line[end] === "*")) end = -1;
|
||||
if (end === -1) {
|
||||
out += ch;
|
||||
i++;
|
||||
} else {
|
||||
out += " ".repeat(end - i);
|
||||
i = end;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function scanCLike(lines) {
|
||||
const out = [];
|
||||
let inBlock = false;
|
||||
@@ -177,7 +216,7 @@ function scanCLike(lines) {
|
||||
continue;
|
||||
}
|
||||
// Complete literals are blanked, so a backtick left over opens a multi-line template.
|
||||
const code = stripStrings(rest);
|
||||
const code = stripLiterals(rest);
|
||||
const marks = [
|
||||
[code.indexOf("//"), "line"],
|
||||
[code.indexOf("/*"), "block"],
|
||||
|
||||
@@ -32,6 +32,37 @@ test("a JSX comment counts as comment, and code does not", () => {
|
||||
assert.equal(measure("const a = 1;\n", ".ts").comment, 0);
|
||||
});
|
||||
|
||||
test("quotes inside a regex literal open no string, so later comments still count", () => {
|
||||
const source = [
|
||||
"const keys = text.match(/[\"'`]([^\"'`]+)[\"'`]/g);",
|
||||
"// one",
|
||||
"const half = (a + b) / 2; // two",
|
||||
"/* three */",
|
||||
"const n = total / count / 2;",
|
||||
"// four",
|
||||
].join("\n");
|
||||
assert.equal(measure(source, ".ts").comment, 4);
|
||||
});
|
||||
|
||||
test("a JSX closing tag's slash opens no regex", () => {
|
||||
assert.equal(measure("const a = <p>x</p>; // c\n", ".tsx").comment, 1);
|
||||
assert.equal(measure("const a = <a>x</a>{/* note */};\n", ".tsx").comment, 1);
|
||||
assert.equal(measure("const a = <div></div> {/* note */};\n", ".tsx").comment, 1);
|
||||
assert.equal(measure("const a = <p>x</p>, b = 'a/b'; // it's\n", ".tsx").comment, 1);
|
||||
});
|
||||
|
||||
test("a slash after ++ or -- is division", () => {
|
||||
assert.equal(measure("const a = i++ / 2; // c\n", ".ts").comment, 1);
|
||||
assert.equal(measure("const a = i-- / 2; // c\n", ".ts").comment, 1);
|
||||
assert.equal(measure("const a = i++ / 2 + 'a/b'; // it's\n", ".ts").comment, 1);
|
||||
});
|
||||
|
||||
test("a line opening with division continued from the line above keeps its comment", () => {
|
||||
assert.equal(measure("const a = total\n / 2; // c\n", ".ts").comment, 1);
|
||||
assert.equal(measure("const a = total\n / 2; /* c */\n", ".ts").comment, 1);
|
||||
assert.equal(measure("const a = ok &&\n /[\"'`]/.test(s); // c\n", ".ts").comment, 1);
|
||||
});
|
||||
|
||||
// 14 physical lines: a bare opener, 12 of prose, a bare closer.
|
||||
test("a docblock is measured from its opener to its closer", () => {
|
||||
const body = Array.from({ length: 12 }, (_, i) => ` * line ${i + 1}`).join("\n");
|
||||
|
||||
Reference in New Issue
Block a user