feat: 完善注释处理
This commit is contained in:
parent
a7a5623cde
commit
7613df14e6
|
|
@ -557,17 +557,95 @@ function performCustomChecks(pwd, program, typeChecker, customConfig) {
|
|||
};
|
||||
const preprocessIgnoreComments = (sourceFile) => {
|
||||
const fullText = sourceFile.getFullText();
|
||||
// 收集文件中所有的注释及其位置
|
||||
const allComments = [];
|
||||
const scanComments = (pos, end) => {
|
||||
const leading = ts.getLeadingCommentRanges(fullText, pos);
|
||||
const trailing = ts.getTrailingCommentRanges(fullText, end);
|
||||
if (leading) {
|
||||
leading.forEach(comment => {
|
||||
const text = fullText.substring(comment.pos, comment.end);
|
||||
allComments.push({
|
||||
pos: comment.pos,
|
||||
end: comment.end,
|
||||
text,
|
||||
isIgnore: isIgnoreComment(text)
|
||||
});
|
||||
});
|
||||
}
|
||||
if (trailing) {
|
||||
trailing.forEach(comment => {
|
||||
const text = fullText.substring(comment.pos, comment.end);
|
||||
allComments.push({
|
||||
pos: comment.pos,
|
||||
end: comment.end,
|
||||
text,
|
||||
isIgnore: isIgnoreComment(text)
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
// 扫描整个文件的注释
|
||||
const scanNode = (node) => {
|
||||
scanComments(node.getFullStart(), node.getEnd());
|
||||
ts.forEachChild(node, scanNode);
|
||||
};
|
||||
scanNode(sourceFile);
|
||||
// 检查节点是否在忽略注释的影响范围内
|
||||
const isNodeCoveredByIgnoreComment = (node) => {
|
||||
const nodeStart = node.getStart(sourceFile);
|
||||
const nodeEnd = node.getEnd();
|
||||
for (const comment of allComments) {
|
||||
if (!comment.isIgnore)
|
||||
continue;
|
||||
// 情况1:注释在节点之前(前导注释)
|
||||
// 允许注释和节点之间有少量空白(最多50个字符)
|
||||
if (comment.end <= nodeStart && nodeStart - comment.end <= 50) {
|
||||
return true;
|
||||
}
|
||||
// 情况2:注释在节点之后(尾随注释)
|
||||
// 允许节点和注释之间有少量空白(最多50个字符)
|
||||
if (comment.pos >= nodeEnd && comment.pos - nodeEnd <= 50) {
|
||||
return true;
|
||||
}
|
||||
// 情况3:注释在节点内部(JSX 表达式中的注释)
|
||||
if (comment.pos >= nodeStart && comment.end <= nodeEnd) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const visit = (node) => {
|
||||
const nodeFullStart = node.getFullStart();
|
||||
const leadingComments = ts.getLeadingCommentRanges(fullText, nodeFullStart);
|
||||
if (leadingComments) {
|
||||
for (const comment of leadingComments) {
|
||||
const commentText = fullText.substring(comment.pos, comment.end);
|
||||
if (isIgnoreComment(commentText)) {
|
||||
// 标记当前节点及其子节点
|
||||
markNodeAndChildren(node);
|
||||
return; // 不需要继续遍历子节点
|
||||
}
|
||||
// 检查当前节点是否被忽略注释覆盖
|
||||
if (isNodeCoveredByIgnoreComment(node)) {
|
||||
markNodeAndChildren(node);
|
||||
return;
|
||||
}
|
||||
// 特殊处理:JSX 表达式
|
||||
if (ts.isJsxExpression(node)) {
|
||||
// 检查 JSX 表达式内部是否有忽略注释
|
||||
if (node.expression && isNodeCoveredByIgnoreComment(node.expression)) {
|
||||
markNodeAndChildren(node.expression);
|
||||
}
|
||||
}
|
||||
// 特殊处理:条件表达式(三元运算符)
|
||||
if (ts.isConditionalExpression(node)) {
|
||||
// 检查 whenTrue 和 whenFalse 分支
|
||||
if (isNodeCoveredByIgnoreComment(node.whenTrue)) {
|
||||
markNodeAndChildren(node.whenTrue);
|
||||
}
|
||||
if (isNodeCoveredByIgnoreComment(node.whenFalse)) {
|
||||
markNodeAndChildren(node.whenFalse);
|
||||
}
|
||||
}
|
||||
// 特殊处理:二元表达式
|
||||
if (ts.isBinaryExpression(node)) {
|
||||
// 检查左右操作数
|
||||
if (isNodeCoveredByIgnoreComment(node.left)) {
|
||||
markNodeAndChildren(node.left);
|
||||
}
|
||||
if (isNodeCoveredByIgnoreComment(node.right)) {
|
||||
markNodeAndChildren(node.right);
|
||||
}
|
||||
}
|
||||
ts.forEachChild(node, visit);
|
||||
|
|
@ -584,6 +662,16 @@ function performCustomChecks(pwd, program, typeChecker, customConfig) {
|
|||
if (ignoreCommentNodes.has(node)) {
|
||||
return true;
|
||||
}
|
||||
// 如果文件开头有忽略注释,整个文件都忽略
|
||||
const fileStartComments = ts.getLeadingCommentRanges(sourceFile.getFullText(), 0);
|
||||
if (fileStartComments) {
|
||||
for (const comment of fileStartComments) {
|
||||
const commentText = sourceFile.getFullText().substring(comment.pos, comment.end);
|
||||
if (isIgnoreComment(commentText)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 向上查找父节点(最多3层)
|
||||
let current = node.parent;
|
||||
let depth = 0;
|
||||
|
|
@ -2286,7 +2374,7 @@ function performCustomChecks(pwd, program, typeChecker, customConfig) {
|
|||
}
|
||||
else {
|
||||
// 普通格式的 key,但本地没有 i18n 文件
|
||||
addDiagnostic(callNode, `i18n key "${key}" 无法检查,因为未找到本地化文件: ${localePath}。`, 9202);
|
||||
addDiagnostic(callNode, `i18n key "${key}" 无法检查,因为找不到locales文件: ${localePath}。`, 9202);
|
||||
}
|
||||
}
|
||||
else if (ts.isTemplateExpression(firstArg) ||
|
||||
|
|
|
|||
|
|
@ -727,18 +727,108 @@ export function performCustomChecks(
|
|||
const preprocessIgnoreComments = (sourceFile: ts.SourceFile): void => {
|
||||
const fullText = sourceFile.getFullText();
|
||||
|
||||
const visit = (node: ts.Node): void => {
|
||||
const nodeFullStart = node.getFullStart();
|
||||
const leadingComments = ts.getLeadingCommentRanges(fullText, nodeFullStart);
|
||||
// 收集文件中所有的注释及其位置
|
||||
const allComments: Array<{ pos: number; end: number; text: string; isIgnore: boolean }> = [];
|
||||
|
||||
if (leadingComments) {
|
||||
for (const comment of leadingComments) {
|
||||
const commentText = fullText.substring(comment.pos, comment.end);
|
||||
if (isIgnoreComment(commentText)) {
|
||||
// 标记当前节点及其子节点
|
||||
markNodeAndChildren(node);
|
||||
return; // 不需要继续遍历子节点
|
||||
}
|
||||
const scanComments = (pos: number, end: number) => {
|
||||
const leading = ts.getLeadingCommentRanges(fullText, pos);
|
||||
const trailing = ts.getTrailingCommentRanges(fullText, end);
|
||||
|
||||
if (leading) {
|
||||
leading.forEach(comment => {
|
||||
const text = fullText.substring(comment.pos, comment.end);
|
||||
allComments.push({
|
||||
pos: comment.pos,
|
||||
end: comment.end,
|
||||
text,
|
||||
isIgnore: isIgnoreComment(text)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (trailing) {
|
||||
trailing.forEach(comment => {
|
||||
const text = fullText.substring(comment.pos, comment.end);
|
||||
allComments.push({
|
||||
pos: comment.pos,
|
||||
end: comment.end,
|
||||
text,
|
||||
isIgnore: isIgnoreComment(text)
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 扫描整个文件的注释
|
||||
const scanNode = (node: ts.Node): void => {
|
||||
scanComments(node.getFullStart(), node.getEnd());
|
||||
ts.forEachChild(node, scanNode);
|
||||
};
|
||||
scanNode(sourceFile);
|
||||
|
||||
// 检查节点是否在忽略注释的影响范围内
|
||||
const isNodeCoveredByIgnoreComment = (node: ts.Node): boolean => {
|
||||
const nodeStart = node.getStart(sourceFile);
|
||||
const nodeEnd = node.getEnd();
|
||||
|
||||
for (const comment of allComments) {
|
||||
if (!comment.isIgnore) continue;
|
||||
|
||||
// 情况1:注释在节点之前(前导注释)
|
||||
// 允许注释和节点之间有少量空白(最多50个字符)
|
||||
if (comment.end <= nodeStart && nodeStart - comment.end <= 50) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 情况2:注释在节点之后(尾随注释)
|
||||
// 允许节点和注释之间有少量空白(最多50个字符)
|
||||
if (comment.pos >= nodeEnd && comment.pos - nodeEnd <= 50) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 情况3:注释在节点内部(JSX 表达式中的注释)
|
||||
if (comment.pos >= nodeStart && comment.end <= nodeEnd) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const visit = (node: ts.Node): void => {
|
||||
// 检查当前节点是否被忽略注释覆盖
|
||||
if (isNodeCoveredByIgnoreComment(node)) {
|
||||
markNodeAndChildren(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// 特殊处理:JSX 表达式
|
||||
if (ts.isJsxExpression(node)) {
|
||||
// 检查 JSX 表达式内部是否有忽略注释
|
||||
if (node.expression && isNodeCoveredByIgnoreComment(node.expression)) {
|
||||
markNodeAndChildren(node.expression);
|
||||
}
|
||||
}
|
||||
|
||||
// 特殊处理:条件表达式(三元运算符)
|
||||
if (ts.isConditionalExpression(node)) {
|
||||
// 检查 whenTrue 和 whenFalse 分支
|
||||
if (isNodeCoveredByIgnoreComment(node.whenTrue)) {
|
||||
markNodeAndChildren(node.whenTrue);
|
||||
}
|
||||
if (isNodeCoveredByIgnoreComment(node.whenFalse)) {
|
||||
markNodeAndChildren(node.whenFalse);
|
||||
}
|
||||
}
|
||||
|
||||
// 特殊处理:二元表达式
|
||||
if (ts.isBinaryExpression(node)) {
|
||||
// 检查左右操作数
|
||||
if (isNodeCoveredByIgnoreComment(node.left)) {
|
||||
markNodeAndChildren(node.left);
|
||||
}
|
||||
if (isNodeCoveredByIgnoreComment(node.right)) {
|
||||
markNodeAndChildren(node.right);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -760,6 +850,21 @@ export function performCustomChecks(
|
|||
return true;
|
||||
}
|
||||
|
||||
// 如果文件开头有忽略注释,整个文件都忽略
|
||||
const fileStartComments = ts.getLeadingCommentRanges(
|
||||
sourceFile.getFullText(),
|
||||
0
|
||||
);
|
||||
|
||||
if (fileStartComments) {
|
||||
for (const comment of fileStartComments) {
|
||||
const commentText = sourceFile.getFullText().substring(comment.pos, comment.end);
|
||||
if (isIgnoreComment(commentText)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 向上查找父节点(最多3层)
|
||||
let current: ts.Node | undefined = node.parent;
|
||||
let depth = 0;
|
||||
|
|
@ -2839,7 +2944,7 @@ export function performCustomChecks(
|
|||
// 普通格式的 key,但本地没有 i18n 文件
|
||||
addDiagnostic(
|
||||
callNode,
|
||||
`i18n key "${key}" 无法检查,因为未找到本地化文件: ${localePath}。`,
|
||||
`i18n key "${key}" 无法检查,因为找不到locales文件: ${localePath}。`,
|
||||
9202
|
||||
);
|
||||
}
|
||||
|
|
@ -3368,4 +3473,4 @@ export const build = (pwd: string, args: any[]) => {
|
|||
|
||||
options.project = configPath;
|
||||
compile(pwd, options);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue