Improve postprocess perf for type cast comments (#17566)

Co-authored-by: fisker <lionkay@gmail.com>
This commit is contained in:
Arnaud Barréandfisker authored and GitHub committed 2025-06-05 16:58:30 +08:00
1 parent dde5a389e1
commit eaa40aa266
5 files changed
+47 -28

No files matched your search

+1 -1
View File
@@ -80,7 +80,7 @@ function parse(text, options) {
throw createParseError(error);
}
return postprocess(ast, { text });
return postprocess(ast, { text, supportTypeCastComments: true });
}
export const acorn = createParser(parse);
+1 -1
View File
@@ -163,7 +163,7 @@ function createParse({ isExpression = false, optionsCombinations }) {
ast = wrapBabelExpression(ast, { text, rootMarker: options.rootMarker });
}
return postprocess(ast, { text });
return postprocess(ast, { text, supportTypeCastComments: true });
};
}
+5 -1
View File
@@ -71,7 +71,11 @@ async function parseJs(text, options) {
// @ts-expect-error -- expected
ast.comments = comments;
return postprocess(ast, { text, parser: "oxc" });
return postprocess(ast, {
text,
parser: "oxc",
supportTypeCastComments: true,
});
}
async function parseTs(text, options) {
+25 -17
View File
@@ -34,32 +34,32 @@ const isNodeWithRaw = createTypeCheckFunction([
* @param {{
* text: string,
* parser?: string,
* supportTypeCastComments?: boolean,
* oxcAstType?: string,
* }} options
*/
function postprocess(ast, options) {
const { parser, text } = options;
const { parser, text, supportTypeCastComments } = options;
const { comments } = ast;
// `InterpreterDirective` from babel parser and flow parser
// Other parsers parse it as comment, babel treat it as comment too
// https://github.com/babel/babel/issues/15116
const program = ast.type === "File" ? ast.program : ast;
const { interpreter } = program;
if (interpreter) {
ast.comments.unshift(interpreter);
if (program.interpreter) {
comments.unshift(program.interpreter);
delete program.interpreter;
}
if (parser === "oxc" && options.oxcAstType === "ts" && ast.hashbang) {
const { comments, hashbang } = ast;
comments.unshift(hashbang);
delete program.hashbang;
comments.unshift(ast.hashbang);
delete ast.hashbang;
}
if (ast.comments.length > 0) {
if (comments.length > 0) {
let followingComment;
for (let i = ast.comments.length - 1; i >= 0; i--) {
const comment = ast.comments[i];
for (let i = comments.length - 1; i >= 0; i--) {
const comment = comments[i];
if (
followingComment &&
@@ -69,7 +69,7 @@ function postprocess(ast, options) {
isIndentableBlockComment(comment) &&
isIndentableBlockComment(followingComment)
) {
ast.comments.splice(i + 1, 1);
comments.splice(i + 1, 1);
comment.value += "*//*" + followingComment.value;
comment.range = [locStart(comment), locEnd(followingComment)];
}
@@ -88,6 +88,15 @@ function postprocess(ast, options) {
}
}
const typeCastCommentsEnds = [];
if (supportTypeCastComments) {
for (const comment of comments) {
if (isTypeCastComment(comment)) {
typeCastCommentsEnds.push(locEnd(comment));
}
}
}
ast = visitNode(ast, (node) => {
switch (node.type) {
case "ParenthesizedExpression": {
@@ -101,14 +110,13 @@ function postprocess(ast, options) {
}
// Keep ParenthesizedExpression nodes only if they have Closure-style type cast comments.
const previousComment = ast.comments.findLast(
(comment) => locEnd(comment) <= start,
const previousCommentEnd = typeCastCommentsEnds.findLast(
(end) => end <= start,
);
const keepTypeCast =
previousComment &&
isTypeCastComment(previousComment) &&
previousCommentEnd &&
// check that there are only white spaces between the comment and the parenthesis
text.slice(locEnd(previousComment), start).trim().length === 0;
text.slice(previousCommentEnd, start).trim().length === 0;
if (!keepTypeCast) {
expression.extra = { ...expression.extra, parenthesized: true };
@@ -202,7 +210,7 @@ function postprocess(ast, options) {
const textWithoutComments = getTextWithoutComments(
{
originalText: text,
[Symbol.for("comments")]: ast.comments,
[Symbol.for("comments")]: comments,
},
idEnd,
members[0] ? locStart(members[0]) : locEnd(node),
+15 -8
View File
@@ -4,19 +4,26 @@ import isBlockComment from "./is-block-comment.js";
* @import {Comment} from "../types/estree.js"
*/
const cache = new WeakMap();
/**
* @param {Comment} comment
* @returns {boolean}
*/
function isTypeCastComment(comment) {
return (
isBlockComment(comment) &&
comment.value[0] === "*" &&
// TypeScript expects the type to be enclosed in curly brackets, however
// Closure Compiler accepts types in parens and even without any delimiters at all.
// That's why we just search for "@type" and "@satisfies".
/@(?:type|satisfies)\b/u.test(comment.value)
);
if (!cache.has(comment)) {
cache.set(
comment,
isBlockComment(comment) &&
comment.value[0] === "*" &&
// TypeScript expects the type to be enclosed in curly brackets, however
// Closure Compiler accepts types in parens and even without any delimiters at all.
// That's why we just search for "@type" and "@satisfies".
/@(?:type|satisfies)\b/u.test(comment.value),
);
}
return cache.get(comment);
}
export default isTypeCastComment;