【问题标题】:Replace quotemarks with TypeScript compiler API transformers用 TypeScript 编译器 API 转换器替换引号
【发布时间】:2019-02-23 04:17:53
【问题描述】:

我有一个 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】:

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

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

    请参阅 here 和 here。

    请务必注意,这将取决于公共 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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-09-18
      • 1970-01-01
      • 2019-05-04
      • 2013-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多