我有一个TypeScript代码生成场景,我在其中构建一个AST,然后将其打印并保存到文件中。默认情况下,打印的字符串文字用双引号括起来,我想要一个包含单引号的选项。正如提到的here,我应该能够走树并替换字符串文字,但我不确定如何。
export const quotemarkTransformer = <T extends ts.Node>(context: ts.TransformationContext) => (rootNode: T) => {
function visit(node: ts.Node): ts.Node {
node = ts.visitEachChild(node, visit, context);
if (node.kind === ts.SyntaxKind.StringLiteral) {
const stringLiteral = node as ts.StringLiteral;
// change raw node text?
return ts.createLiteral(stringLiteral.text);
}
return node;
}
return ts.visitNode(rootNode, visit);
}
使用TS工厂函数创建字符串文字ts.createLiteral(stringLiteral.text)
将始终使用双引号。有没有直接访问和更改发出文本的方法?
您可以在StringLiteral
上设置内部属性来执行此操作:
if (node.kind === ts.SyntaxKind.StringLiteral)
(node as any).singleQuote = true;
请注意,这取决于公共API中不存在的属性,因此它可能会在某一天停止工作。如果您对此感到不舒服,请按照以下说明操作。
鉴于发出的文字:
这是一些显示示例的代码:
// 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);
}
}
}