如何序列化 TypeScript AST 节点及其依赖项
How to serialize a TypeScript AST node & its dependencies
如果引用是静态定义的(不是动态创建的),TypeScript 编译器 API 是否提供了一种轻松序列化节点及其依赖项的方法?
例如:
file-a.ts
export const a = () => {
console.log("a");
}
file-b.ts
import { a } from "./file-a"
const b = () => {
a()
console.log("b")
}
当我遇到file-b
的b
声明时,我想提取并打印如下:
const b = () => {
(() => {
console.log("a")
})()
console.log("b")
}
...如果执行此序列化不是编译器的一项功能API,是否需要遍历和内联所有声明?或者有更好的方法吗?
没有内置的方法来序列化节点及其所有依赖项,但我认为您不需要在此处进行任何序列化(取决于您的意思)。
为了解决这个问题,您可以建立自己的图表来说明所有事物是如何连接的,然后遍历它以创建最终的单个函数(可以被认为是折叠它)。这将帮助您缓存已经完成的工作。不过,您可以在没有它的情况下做到这一点,并在进行时构建语句。
简而言之,可能解释得不够好:
- 在该函数内 (
b
),遍历所有节点以查找引用函数外部内容的节点。
- 跟随所有这些节点到它们的声明(例如,使用类型检查器跟随调用表达式标识符的符号,直到到达声明)。
- 重复直到所有内容都被考虑在内。
这是一个可能对制作节点的深度可变克隆有用的函数(有点未经测试,可能会有更好的东西......我不确定是否有办法做到这一点而不用担心语境)。您可以使用它来构造节点的副本。
function getDeepMutableClone<T extends ts.Node>(node: T): T {
return ts.transform(node, [
context => node => deepCloneWithContext(node, context)
]).transformed[0];
function deepCloneWithContext<T extends ts.Node>(
node: T,
context: ts.TransformationContext
): T {
const clonedNode = ts.visitEachChild(
stripRanges(ts.getMutableClone(node)),
child => deepCloneWithContext(child, context),
context
);
clonedNode.parent = undefined as any;
ts.forEachChild(clonedNode, child => { child.parent = clonedNode; });
return clonedNode;
}
}
// See for
// why this is necessary.
function stripRanges<T extends ts.Node>(node: T) {
node.pos = -1;
node.end = -1;
return node;
}
如果引用是静态定义的(不是动态创建的),TypeScript 编译器 API 是否提供了一种轻松序列化节点及其依赖项的方法?
例如:
file-a.ts
export const a = () => {
console.log("a");
}
file-b.ts
import { a } from "./file-a"
const b = () => {
a()
console.log("b")
}
当我遇到file-b
的b
声明时,我想提取并打印如下:
const b = () => {
(() => {
console.log("a")
})()
console.log("b")
}
...如果执行此序列化不是编译器的一项功能API,是否需要遍历和内联所有声明?或者有更好的方法吗?
没有内置的方法来序列化节点及其所有依赖项,但我认为您不需要在此处进行任何序列化(取决于您的意思)。
为了解决这个问题,您可以建立自己的图表来说明所有事物是如何连接的,然后遍历它以创建最终的单个函数(可以被认为是折叠它)。这将帮助您缓存已经完成的工作。不过,您可以在没有它的情况下做到这一点,并在进行时构建语句。
简而言之,可能解释得不够好:
- 在该函数内 (
b
),遍历所有节点以查找引用函数外部内容的节点。 - 跟随所有这些节点到它们的声明(例如,使用类型检查器跟随调用表达式标识符的符号,直到到达声明)。
- 重复直到所有内容都被考虑在内。
这是一个可能对制作节点的深度可变克隆有用的函数(有点未经测试,可能会有更好的东西......我不确定是否有办法做到这一点而不用担心语境)。您可以使用它来构造节点的副本。
function getDeepMutableClone<T extends ts.Node>(node: T): T {
return ts.transform(node, [
context => node => deepCloneWithContext(node, context)
]).transformed[0];
function deepCloneWithContext<T extends ts.Node>(
node: T,
context: ts.TransformationContext
): T {
const clonedNode = ts.visitEachChild(
stripRanges(ts.getMutableClone(node)),
child => deepCloneWithContext(child, context),
context
);
clonedNode.parent = undefined as any;
ts.forEachChild(clonedNode, child => { child.parent = clonedNode; });
return clonedNode;
}
}
// See for
// why this is necessary.
function stripRanges<T extends ts.Node>(node: T) {
node.pos = -1;
node.end = -1;
return node;
}