用TypeScript编译器API转换器替换引号

问题描述 投票:3回答:1

我有一个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)将始终使用双引号。有没有直接访问和更改发出文本的方法?

typescript typescript2.0 typescript-compiler-api
1个回答
1
投票

您可以在StringLiteral上设置内部属性来执行此操作:

if (node.kind === ts.SyntaxKind.StringLiteral)
    (node as any).singleQuote = true;

herehere

请注意,这取决于公共API中不存在的属性,因此它可能会在某一天停止工作。如果您对此感到不舒服,请按照以下说明操作。


鉴于发出的文字:

  1. 解析或重用与发出的文本匹配的AST。
  2. 遍历AST和每个具有搜索引号字符的字符串文字,存储两个引号字符的起始位置。
  3. 使用发出的源文件文本和引号字符开始位置,用新引号字符替换每个位置的文本。

这是一些显示示例的代码:

// 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);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.