在 compiler.ts 中,类型编码的主要流程如下:
- 首先在
ReflectionTransformer
类中的packOpsAndStack
方法中进行打包:
protected packOpsAndStack(program: CompilerProgram) {
const packStruct = program.buildPackStruct();
if (packStruct.ops.length === 0) return;
// debugPackStruct(this.sourceFile, program.forNode, packStruct);
const packed = [...packStruct.stack, encodeOps(packStruct.ops)];
return this.valueToExpression(packed);
}
buildPackStruct
方法在CompilerProgram
类中:
buildPackStruct() {
const ops: ReflectionOp[] = [...this.ops];
if (this.coRoutines.length) {
for (let i = this.coRoutines.length - 1; i >= 0; i--) {
ops.unshift(...this.coRoutines[i].ops);
}
}
if (this.mainOffset) {
ops.unshift(ReflectionOp.jump, this.mainOffset);
}
return { ops, stack: this.stack };
}
关键的编码函数是 encodeOps
:
export function encodeOps(ops: ReflectionOp[]): string {
return ops.map(v => String.fromCharCode(v + 33)).join('');
}
编码的基本原理是:
- 收集类型信息时会生成一系列操作码(ReflectionOp)和相关的栈数据
- 操作码通过
encodeOps
函数编码成字符串:- 每个操作码加33后转换为ASCII字符
- 33是为了避开控制字符,使得编码后的字符都是可打印字符
- 最终生成的类型信息是一个数组,包含:
- 栈数据(类型名称、参数等)
- 编码后的操作码字符串
例如测试用例:
interface User {
id: number;
name: string;
password: string;
}
type ReadUser = Omit<User, 'password'>;
编码过程大致是:
- 解析AST生成操作码序列
- 将操作码编码为字符串
- 与栈数据一起组成最终的类型信息数组