您可以设置一个内部属性StringLiteral
来执行此操作:
if (node.kind === ts.SyntaxKind.StringLiteral)
(node as any).singleQuote = true;
见这里和这里。
请务必注意,这将取决于公共 API 中不存在的属性,因此它可能有一天会停止工作。如果您对此感到不舒服,请按照以下说明进行操作。
鉴于发出的文本:
- 解析或重用与发出的文本匹配的 AST。
- 遍历 AST,对于每个搜索引号字符的字符串文字,存储两个引号字符的起始位置。
- 使用发出的源文件文本和引号字符开始位置,用新的引号字符替换每个位置的文本。
这是一些显示示例的代码:
// setup
const emittedFilePath = "/file.js";
const emittedText = `'this'; 'is a'; "test";`;
const emittedSourceFile = ts.createSourceFile(
emittedFilePath,
emittedText,
ts.ScriptTarget.Latest,
false);
// replace all ' with "
console.log(replaceQuoteChars(emittedSourceFile, `'`, `"`));
// main code...
type QuoteChar = "'" | "\"";
function replaceQuoteChars<OldChar extends QuoteChar>(
sourceFile: ts.SourceFile,
oldChar: OldChar,
newChar: Exclude<QuoteChar, OldChar>
) {
return getNewText(
getQuoteCharPositions(emittedSourceFile, oldChar)
);
function getNewText(quoteCharPositions: number[]) {
const fileText = sourceFile.getFullText();
let result = "";
let lastPos = 0;
for (const pos of quoteCharPositions) {
result += fileText.substring(lastPos, pos) + newChar;
lastPos = pos + 1;
}
result += fileText.substring(lastPos);
return result;
}
}
function getQuoteCharPositions(
sourceFile: ts.SourceFile,
searchingChar: QuoteChar
) {
const sourceFileText = sourceFile.getFullText();
const result: number[] = [];
visitNode(sourceFile);
return result;
function visitNode(node: ts.Node) {
if (ts.isStringLiteral(node))
handleStringLiteral(node);
else
ts.forEachChild(node, visitNode);
}
function handleStringLiteral(node: ts.StringLiteral) {
const start = node.getStart(sourceFile);
const quoteChar = sourceFileText[start];
if (quoteChar === searchingChar) {
result.push(start);
result.push(node.end - 1);
}
}
}