* Copyright (c) 2025 Huawei Technologies Co., Ltd.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { AbsolutePath } from '../../core';
import type { SpecCodeGenerator } from '../core';
import {
TurboModuleCppTemplate,
TurboModuleHTemplate,
TurboModuleInterfaceTS,
} from '../templates';
import {
TypeAnnotationToTS,
wrapWithQuotes,
SpecSchema,
CodegenError,
} from '../core';
import { GlueCodeTurboModuleData } from './AppBuildTimeGlueCodeGenerator';
* Generates boilerplate code for Turbo Modules.
*/
export class NativeModuleCodeGenerator implements SpecCodeGenerator {
private glueCodeTurboModulesData: GlueCodeTurboModuleData[] = [];
constructor(
private cppOutputPath: AbsolutePath,
private etsOutputPath: AbsolutePath,
private codegenNoticeLines: string[],
private rnohImport: string
) {}
getGlueCodeData() {
return this.glueCodeTurboModulesData;
}
generate(schema: SpecSchema): Map<AbsolutePath, string> {
const result = new Map<AbsolutePath, string>();
if (schema.type !== 'NativeModule') {
throw new CodegenError({
whatHappened: `NativeModuleCodeGenerator can't generate code for module type: ${schema.type}`,
unexpected: true,
});
}
const typeAnnotationToTS = new TypeAnnotationToTS();
const turboModuleInterfaceTS = new TurboModuleInterfaceTS(
schema.moduleName,
this.codegenNoticeLines,
this.rnohImport
);
const turboModuleH = new TurboModuleHTemplate(
schema.moduleName,
this.codegenNoticeLines
).build();
result.set(
this.cppOutputPath.copyWithNewSegment(`${schema.moduleName}.h`),
turboModuleH
);
const turboModuleCpp = new TurboModuleCppTemplate(
schema.moduleName,
this.codegenNoticeLines
);
Object.entries(schema.aliasMap).map(([name, typeAnnotation]) => {
turboModuleInterfaceTS.addAlias({
name: name,
type: typeAnnotationToTS.convert(typeAnnotation),
});
});
Object.entries(schema.enumMap).map(([name, enumSpec]) => {
turboModuleInterfaceTS.addEnum({
name,
members: enumSpec.members.map((member) => ({
name: member.name,
value:
member.value.type === 'StringLiteralTypeAnnotation'
? wrapWithQuotes(member.value.value)
: member.value.value.toString(),
})),
});
});
schema.spec.methods.map((prop) => {
if (prop.typeAnnotation.type === 'FunctionTypeAnnotation') {
turboModuleCpp.addMethod({
name: prop.name,
argsCount: prop.typeAnnotation.params.length,
isAsync:
prop.typeAnnotation.returnTypeAnnotation.type ===
'PromiseTypeAnnotation',
});
turboModuleInterfaceTS.addMethod({
name: prop.name,
returnType: typeAnnotationToTS.convert(
prop.typeAnnotation.returnTypeAnnotation
),
stringifiedArgs: prop.typeAnnotation.params
.map(
(param) =>
`${param.name}: ${typeAnnotationToTS.convert(
param.typeAnnotation
)}`
)
.join(', '),
});
}
});
result.set(
this.cppOutputPath.copyWithNewSegment(`${schema.moduleName}.cpp`),
turboModuleCpp.build()
);
result.set(
this.etsOutputPath.copyWithNewSegment(`${schema.moduleName}.ts`),
turboModuleInterfaceTS.build()
);
this.glueCodeTurboModulesData.push({ name: schema.moduleName });
return result;
}
}