【问题标题】:TypeScript: get syntax treeTypeScript:获取语法树
【发布时间】:2022-05-10 05:03:39
【问题描述】:

我已经阅读了“整个互联网”,但找不到任何关于从 TypeScrypt 源获取语法树(就像在 Esprima 中一样)的示例。 我的意思是我怎样才能得到这样的对象(Esprima Parser 示例)

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "answer"
                    },
                    "init": {
                        "type": "BinaryExpression",
                        "operator": "*",
                        "left": {
                            "type": "Literal",
                            "value": 6,
                            "raw": "6"
                        },
                        "right": {
                            "type": "Literal",
                            "value": 7,
                            "raw": "7"
                        }
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

来自 javascript 代码

var answer = 6 * 7;

仅适用于 TypeScript 源文本?

附:非常希望对你有所帮助,因为我不想写你自己的糟糕自行车)

P.P.S.我认为 lib 文件 typescript.ts(.js) 和 typescriptServices.ts(.js) 可以帮助我,但我不知道如何:(

已解决

非常感谢用户 Steve Fenton。 这是我的代码,如果有人感兴趣的话:

// uses
var typeScriptLS =  new Harness.TypeScriptLS();
var ServicesFactory = new Services.TypeScriptServicesFactory();
var serviceShim = ServicesFactory.createLanguageServiceShim(typeScriptLS);

// add lib.d.ts
var _libText = window.document.getElementById('lib.d.ts').innerText;
typeScriptLS.addScript('lib.d.ts', _libText.replace(/\r\n?/g,"\n"), true);

// add greeter.ts
var _sourceText = window.document.getElementById('greeter.ts').innerText;
typeScriptLS.addScript('greeter.ts', _sourceText.replace(/\r\n?/g,"\n"), true);

// script name
var _scriptName = 'greeter.ts';
// get syntax tree
var _st = serviceShim.languageService.getSyntaxTree(_scriptName);
//console.log(_st);
console.log(JSON.stringify(_st, "", 2));

【问题讨论】:

  • 部署文件中Harness在哪里定义?我在 tsc.js、typescript.js 或 typescriptServices.js 的任何地方都看不到“Harness”。或者更广泛地说,您如何运行此 Solved 代码示例?
  • 抱歉让您久等了。 /src/harness/ 在github.com/Microsoft/TypeScript 上。但是现在我的代码可能会失效
  • 不要使用 Harness,因为它不是公共 API,您需要在 TypeScript 项目本身内部执行此操作(因此您需要重新分发它)或访问非公共 TypeScript API(冒您的软件的风险如果用户没有使用正确的打字稿编译器版本,则会被破坏。可以使用巴比伦解析器来做到这一点 - 请参阅下面的答案

标签: typescript abstract-syntax-tree


【解决方案1】:

TypeScript 解析器不会直接生成这样的树,但您仍然可以使用它的对象模型来做各种事情。例如,我们在一些工具中使用它来进行语法转换以用于测试目的。这是一个可以用来打印语法树的 sn-p:

import ts from "typescript";
 
const code = "enum { x = 1 }";
const sc = ts.createSourceFile("x.ts", code, ts.ScriptTarget.Latest, true);

let indent = 0;
function print(node: ts.Node) {
    console.log(new Array(indent + 1).join(" ") + ts.SyntaxKind[node.kind]);
    indent++;
    ts.forEachChild(node, print);
    indent--;
}
 
print(sc);

【讨论】:

  • 如何将它放入 app.js 文件中?: var TypeScript = require('./typescriptServices');让它运行?
  • 我在这里更详细地解释了这个问题:stackoverflow.com/questions/23983998/…
  • 我想通了,并在blog.ctaggart.com/2014/06/typescript-ast-from-nodejs.html博客上写了我的发现
  • 请注意,您需要 var TypeScript = require('typescript-services'); 在 nodejs 上运行此示例,而不是 var TypeScript = require('typescript');。我花了很长时间才弄清楚这些奇怪的未定义错误来自哪里。但是后面的模块没有export语句。
【解决方案2】:

这个问题是在back in September之前提出的。

目前没有可以为您执行此操作的方法 - 没有可以调用的神奇 getSyntaxTree 方法可以执行此操作。

TypeScript 编译器是开源的 - 并且完全用 TypeScript 编写,因此您可以扫描它以了解是否有可以使用/添加句柄的东西。

这样做的好处是你有很大的机会将你的工作作为一个开源项目发布,从这两个问题的投票来看,这是有一些需求的。

或者,使用EsprimaSpiderMonkey 从已编译的JavaScript(将在运行时实际执行的代码)中获取语法树。

【讨论】:

  • 解析发出的 JavaScript 会丢失很多信息(所有类型)。我认为这个问题的动机就是这样。
【解决方案3】:

可以使用 recast 和 babylon@next。尽管您必须相信这些技术定义的用于表示 TypeScript 代码 AST 的语法,并且它们将保持最新——因为 TypeScript 具有逐个发布(短期)发布的新语言功能——但与其他语言不同(JavaScript ) 你有明确定义的版本并以标准发布 - 所以如果你的用户开始使用新的语言功能,这些技术(我猜巴比伦)应该保持最新,否则解析将失败

// npm install recast babylon@next
const source = `
interface I {
  color: string
}
class C implements I{
  color: string='blue'
}
`
const recast = require('recast')
const tsParser = require("recast/parsers/typescript")
const ast = recast.parse(source, {
  parser: tsParser
});
console.log(`
CODE: 

${source}

AST: 

${JSON.stringify(ast)}
`);

【讨论】:

    【解决方案4】:

    我发现recast 工作得很好。示例:

    var recast = require('recast');
    var ast = recast.parse(`var answer = 6 * 7;`);
    console.log(ast);
    

    这将输出所有需要的信息和事件TypeAnnotation,所以这个库真的很棒:)

    [
       {
          "type": "VariableDeclaration",
          "declarations": [
             {
                "type": "VariableDeclarator",
                "id": {
                   "type": "Identifier",
                   "name": "answer",
                   "typeAnnotation": {
                      "type": "TypeAnnotation",
                      "typeAnnotation": {
                         "type": "NumberTypeAnnotation",
                         "loc": {
                            "start": {
                               "line": 1,
                               "column": 12
                            },
                            "end": {
                               "line": 1,
                               "column": 18
                            },
                            "lines": {},
                            "indent": 0
                         }
                      },
                      "loc": {
                         "start": {
                            "line": 1,
                            "column": 10
                         },
                         "end": {
                            "line": 1,
                            "column": 18
                         },
                         "lines": {},
                         "indent": 0
                      }
                   },
                   "loc": {
                      "start": {
                         "line": 1,
                         "column": 4
                      },
                      "end": {
                         "line": 1,
                         "column": 18
                      },
                      "lines": {},
                      "indent": 0
                   }
                },
                "init": {
                   "type": "BinaryExpression",
                   "operator": "*",
                   "left": {
                      "type": "Literal",
                      "value": 6,
                      "raw": "6",
                      "loc": {
                         "start": {
                            "line": 1,
                            "column": 21
                         },
                         "end": {
                            "line": 1,
                            "column": 22
                         },
                         "lines": {},
                         "indent": 0
                      }
                   },
                   "right": {
                      "type": "Literal",
                      "value": 7,
                      "raw": "7",
                      "loc": {
                         "start": {
                            "line": 1,
                            "column": 25
                         },
                         "end": {
                            "line": 1,
                            "column": 26
                         },
                         "lines": {},
                         "indent": 0
                      }
                   },
                   "loc": {
                      "start": {
                         "line": 1,
                         "column": 21
                      },
                      "end": {
                         "line": 1,
                         "column": 26
                      },
                      "lines": {},
                      "indent": 0
                   }
                },
                "loc": {
                   "start": {
                      "line": 1,
                      "column": 4
                   },
                   "end": {
                      "line": 1,
                      "column": 26
                   },
                   "lines": {},
                   "indent": 0
                }
             }
          ],
          "kind": "var",
          "loc": {
             "start": {
                "line": 1,
                "column": 0
             },
             "end": {
                "line": 1,
                "column": 27
             },
             "lines": {},
             "indent": 0
          }
       }
    ]
    

    【讨论】:

    • 据我尝试,recast 无法识别完整的打字稿语法。
    • 差不多了 - 那是 JavaScript,它不适用于任何 TypeScript,例如:let a: string 但可以使用自定义解析器,请参阅上面的答案。
    猜你喜欢
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    相关资源
    最近更新 更多