元编程与跨端 API 插件体系
1. 元编程的概念
元编程是一种编程技术,允许程序将其他程序(或自身)作为数据来处理。具体来说,它是编写能够生成、操作或转换其他代码的程序。元编程的主要特点包括:
- 代码自动生成:根据某些规则或元数据自动生成代码
- 代码分析与转换:分析现有代码结构并进行转换
- 运行时自省:程序在运行时检查自身结构(如类型信息、方法签名等)
这个项目是一个跨端 API 插件体系,核心原理是利用 TypeScript 的类型系统和元编程能力,通过解析 TS 格式定义的 API 插件,自动生成多端(小程序、Android、iOS)可用的代码。
2. 元编程实现方式
- TypeScript 类型解析:使用 TypeScript 的编译器 API 解析插件文件的类型、注释和结构
- 代码生成:根据解析后的元信息,基于模板生成不同平台的代码
- 统一插件定义规范:通过装饰器和特定结构定义统一的插件接口
3. 核心实现
3.1 元编程解析 - TS 插件定义分析
3.1.1 插件解析入口 - Parser 类
typescript
// src/parse/parser.ts
public parse(pluginFile: string): { plugin?: PluginEntity; caniuse?: string; task?: tt.TaskMeta; error?: string } {
const program = ts.createProgram([pluginFile], {});
const source = program.getSourceFile(pluginFile);
if (source) {
const TPlugin =
require(pluginFile).TPlugin;
var entity = this.parsePlugin(source, program.getTypeChecker(), TPlugin);
//若为单一平台,设置所有方法、事件以及属性为单一平台
if (entity.meta.platform != tt.Platforms.All) {
entity.methods.forEach((method) => {
method.meta.platform = entity.meta.platform;
});
// ...同样处理events和registerEvents
}
var caniusej = JSON.stringify(this.caniuserJson);
// ...
return { plugin: entity, caniuse: caniusej, ... };
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这是元编程解析的核心入口,通过 TypeScript Compiler API 创建程序对象,获取源文件,并进行解析。
3.1.2 插件元数据解析 - parsePlugin 方法
typescript
// src/parse/parser.ts
private parsePlugin(source: ts.SourceFile, typeChecker: ts.TypeChecker, plugin): PluginEntity {
// 初始化结构
const entity = { ... } as PluginEntity;
const methods: Array<MethodEntity> = [];
const events: Array<EventEntity> = [];
const registerEvents: Array<RegisterEventEntity> = [];
const customObjects = {};
let constants;
let errorCodes = {};
// 遍历源代码 AST
ts.forEachChild(source, (node) => {
if (ts.isClassDeclaration(node)) {
// 处理类声明...
// 遍历类成员
node.members.forEach((subNode) => {
if (ts.isMethodDeclaration(subNode)) {
// 获取方法名
const nameString = subNode.name.getText();
// 使用装饰器元数据
const metaKey = this.getPlugin();
const meta = Reflect.getMetadata(metaKey, new plugin());
// 处理方法
let metaMethod = Reflect.getMetadata(td.metaKeys.method, new plugin(), nameString);
if (metaMethod) {
let entity = this.parseMethod(source, typeChecker, subNode, metaMethod, nameString, new plugin());
methods.push(entity);
// ...生成caniuse配置
}
// 处理事件
let metaEvent = Reflect.getMetadata(td.metaKeys.event, new plugin(), nameString);
if (metaEvent) {
// ...类似处理事件
}
// 处理注册事件
let registerEvent = Reflect.getMetadata(td.metaKeys.registerEvent, new plugin(), nameString);
if (registerEvent) {
// ...类似处理注册事件
}
}
});
}
});
return { methods, events, registerEvents, customObjects, ... };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
这是核心的元编程解析逻辑,通过 TypeScript AST 遍历源代码结构,结合 Reflect API 获取装饰器元数据,解析 API 插件定义。
3.2 代码生成 - 多端代码转换
3.2.1 代码生成入口 - generate 函数
typescript
// src/bin/uni/plugin-cli-generate.ts
function generate() {
// 初始化解析器
parser = new Parser({ isRN: false, checkErrorCode: checkErrorCode });
// 处理 TypeScript 文件格式化
const pluginTsContent = prettier.format(
fs.readFileSync(path.join(process.cwd(), 'plugin.ts')).toString(),
{ singleQuote: false, parser: 'typescript' }
);
fs.writeFileSync(path.join(process.cwd(), 'plugin.ts'), pluginTsContent);
// 创建模板
createOrUpdateTemplate(false);
// 解析插件定义
let result = parser.parse(path.join(process.cwd(), 'plugin.ts'));
// 生成各端代码
let templatePath = getTemplateDirPath(false);
templatePath += '/anonymization';
**generateAndroid({ result, templatePath, options: { platform, enabled } });
**generateIOS({ result, templatePath, options: { platform } });
if (!isApp) {
__generateJS({
result,
templatePath,
options: { isDev, diff, enabled, operator, parser, ai, pluginVersion, validate },
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
这是代码生成流程的总入口,负责解析插件定义并调用各个平台的代码生成函数。
3.2.2 JavaScript 代码生成
typescript
// src/generate/genJs.ts
export function generateJS({
result,
templatePath,
options: {
parser,
isDev,
diff,
enabled,
operator,
ai,
pluginVersion,
validate,
},
}) {
// 处理普通插件包
console.log("处理普通插件包...");
const jsTemplate = path.join(templatePath, "js", "temp");
// 生成 JS 代码
genOrUpdateJS(
jsTemplate,
process.cwd(),
genJSWrapData(result.plugin, result.caniuse),
isDev
);
// 生成 RN 代码
const rnTemplate = path.join(templatePath, "rn", "temp");
genOrUpdateRN(
rnTemplate,
process.cwd(),
genJSWrapData(result.plugin, result.caniuse),
isDev
);
// 生成文档
generateDoc(result);
// 生成差异文件
if (diff) {
generateDiffWithBackup(result, parser, {
pluginVersion: pluginVersion,
operator,
ai,
});
}
// 生成 native enabled 文件
generateNativeEnabledFile(
{ name: result.plugin.name, version: result.plugin.version },
enabled
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
负责生成 JavaScript 和 React Native 代码,以及相关文档和配置文件。
3.3 类型系统与数据结构
3.3.1 插件实体结构定义
typescript
// src/parse/parser.ts
export interface PluginEntity {
meta: tt.PluginMeta;
events: Array<EventEntity>;
methods: Array<MethodEntity>;
registerEvents: Array<RegisterEventEntity>;
customObjects?: {};
constants?: any;
iOSTime?: IOSCreatTime;
task?: Task;
}
export interface MethodEntity {
meta: tt.MethodMeta;
parameters: Array<ParameterEntity>;
}
export interface EventEntity {
meta: tt.EventMeta;
parameter: ParameterEntity;
}
export interface RegisterEventEntity {
meta: tt.RegisterEventMeta;
parameters: Array<ParameterEntity>;
}
export interface ParameterEntity {
name: string;
type: string;
jsType?: string;
desc: string;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
这些接口定义了插件的结构模型,包括方法、事件、注册事件和参数等。
3.4 元编程核心技术
3.4.1 TypeScript 编译器 API 使用
typescript
// TypeScript 编译器 API 的使用
const program = ts.createProgram([pluginFile], {});
const source = program.getSourceFile(pluginFile);
const typeChecker = program.getTypeChecker();
// 遍历 AST
// TypeScript 编译器 API 的使用
const program = ts.createProgram([pluginFile], {});
const source = program.getSourceFile(pluginFile);
const typeChecker = program.getTypeChecker();
// 遍历 AST
ts.forEachChild(source, (node) => {
if (ts.isClassDeclaration(node)) {
// 处理类声明...
}
});
// 类型检查与信息获取
function serializeSymbol(symbol: ts.Symbol): DocEntry {
return {
name: symbol.getName(),
documentation: ts.displayPartsToString(
symbol.getDocumentationComment(typeChecker)
),
type: getStandardType(symbol.valueDeclaration, typeChecker),
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3.4.2 装饰器反射机制
typescript
// 使用 Reflect 元数据 API 获取装饰器信息
const metaKey = this.getPlugin();
const meta = Reflect.getMetadata(metaKey, new plugin());
// 获取方法元数据
let metaMethod = Reflect.getMetadata(
td.metaKeys.method,
new plugin(),
nameString
);
if (metaMethod) {
// 处理方法...
}
// 获取事件元数据
let metaEvent = Reflect.getMetadata(
td.metaKeys.event,
new plugin(),
nameString
);
if (metaEvent) {
// 处理事件...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
3.5 代码生成与转换流程
3.5.1 代码生成流程
- 解析 plugin.ts 文件,提取 API 元数据
- 构建中间表示 (PluginEntity),包含所有方法、事件和类型信息
- 基于模板生成各平台代码:
- 生成 JavaScript/React Native 代码
- 生成 Android 代码
- 生成 iOS 代码
- 生成 API 文档、测试用例和错误码定义
- 根据差异生成版本迁移文件
核心架构
从代码结构看,项目主要分为以下几个核心模块:
- 解析模块 (parse)
- parser.ts:核心解析器,负责将 TypeScript 插件定义解析为中间表示形式
- 使用 TypeScript 编译器 API (ts 模块) 解析源代码
- 提取方法、事件、注册事件等元数据信息
- 解析 JSDoc 注释作为 API 文档
- 转换模块 (transform)
- 将解析后的插件元数据转换为各平台可用的数据结构
- 处理类型映射关系(TypeScript 类型 → JavaScript/Android/iOS 类型)
- 生成模块 (generate)
- genJs.ts:生成 JavaScript 代码
- genAndroid.ts:生成 Android 代码
- genOrUpdateRN.ts:生成 React Native 代码
- genOrUpdateJS.ts:更新 JavaScript 代码
- generateDoc.ts:生成 API 文档
- 模板模块 (template)
- 存放各平台代码生成模板
- 提供工具函数处理模板
- 包装模块 (wrap)
- js/js-wrap.ts:JavaScript 代码包装器
- ios/ios-wrap.ts:iOS 代码包装器
- js/doc-wrap.ts:文档生成包装器
- CLI 工具模块 (bin)
- 提供命令行工具,便于集成到开发流程和 CI 环境 工作流程
- 解析阶段:
- 通过 TypeScript 编译器解析插件定义文件 (plugin.ts)
- 提取插件元数据、方法、事件、类型定义等
- 转换阶段:
- 将解析得到的元数据转换为各平台可理解的格式
- 处理类型映射和平台特定适配
- 生成阶段:
- 根据转换后的数据,基于模板生成各平台代码
- 生成相应的文档、测试用例和错误码定义
- 发布流程:
- 生成的代码自动发布到相应的仓库(npm、maven 等)
- 与原生应用构建流程集成,实现 API 的版本化依赖
技术亮点
- 单一来源:通过 TypeScript 定义的统一插件,生成多平台代码,避免手动维护多套实现
- 类型安全:利用 TypeScript 的类型系统保证 API 的类型安全和一致性
- 自动化工具链:自动生成代码、文档、测试用例,提高开发效率
- 版本化管理:结合原生 App 构建流程,实现 API 的版本化依赖
- 开发体验:提供代码提示等开发时功能,改善开发体验
这个项目的核心价值在于通过元编程技术,实现了"写一次定义,多端自动生成"的目标,大大提高了跨平台 API 开发的效率和一致性。
1
1