UNPKG

nitro-codegen

Version:

The code-generator for react-native-nitro-modules.

153 lines (137 loc) 4.77 kB
import type { CodeNode } from './CodeNode.js' import type { Language } from '../getPlatformSpecs.js' import { type SourceFile, type SourceImport } from './SourceFile.js' import { Parameter } from './Parameter.js' import type { Type } from './types/Type.js' import { indent } from '../utils.js' export type MethodBody = string export interface MethodModifiers { /** * The name of the class that defines this C++ method. * Example: `Person` -> `void Person::sayHi()` */ classDefinitionName?: string /** * Whether the function should be marked as inlineable. */ inline?: boolean /*+ * Whether the func is a pure virtual C++ function. */ virtual?: boolean /** * Whether the function is marked as `noexcept` (doesn't throw) or not. */ noexcept?: boolean /** * Whether this function overrides a base/super function. */ override?: boolean /** * Whether this method has a `@DoNotStrip` and `@Keep` attribute to avoid * it from being stripped from the binary by the Java compiler or ProGuard. */ doNotStrip?: boolean } export class Method implements CodeNode { readonly name: string readonly returnType: Type readonly parameters: Parameter[] constructor(name: string, returnType: Type, parameters: Parameter[]) { this.name = name this.returnType = returnType this.parameters = parameters if (this.name.startsWith('__')) { throw new Error( `Method names are not allowed to start with two underscores (__)! (In ${this.jsSignature})` ) } } get jsSignature(): string { const returnType = this.returnType.kind const params = this.parameters.map((p) => `${p.name}: ${p.type.kind}`) return `${this.name}(${params.join(', ')}): ${returnType}` } getCode( language: Language, modifiers?: MethodModifiers, body?: MethodBody ): string { body = body?.trim() switch (language) { case 'c++': { const returnType = this.returnType.getCode('c++') const params = this.parameters.map((p) => p.getCode('c++')) // C++ modifiers start in the beginning const name = modifiers?.classDefinitionName ? `${modifiers.classDefinitionName}::${this.name}` : this.name let signature = `${returnType} ${name}(${params.join(', ')})` if (modifiers?.inline) signature = `inline ${signature}` if (modifiers?.virtual) signature = `virtual ${signature}` if (modifiers?.noexcept) signature = `${signature} noexcept` if (modifiers?.override) signature = `${signature} override` if (body == null) { // It's a function declaration (no body) if (modifiers?.virtual) { // if it is a virtual function, we have no implementation (= 0) signature = `${signature} = 0` } return `${signature};` } else { return ` ${signature} { ${indent(body, ' ')} }`.trim() } } case 'swift': { const params = this.parameters.map((p) => p.getCode('swift')) const returnType = this.returnType.getCode('swift') let signature = `func ${this.name}(${params.join(', ')}) throws -> ${returnType}` if (modifiers?.inline) signature = `@inline(__always)\n${signature}` if (body == null) { return signature } else { return ` ${signature} { ${indent(body, ' ')} }`.trim() } } case 'kotlin': { const params = this.parameters.map((p) => p.getCode('kotlin')) const returnType = this.returnType.getCode('kotlin') let signature = `fun ${this.name}(${params.join(', ')}): ${returnType}` if (modifiers?.inline) signature = `inline ${signature}` if (modifiers?.override) signature = `override ${signature}` if (modifiers?.virtual) signature = `abstract ${signature}` if (modifiers?.doNotStrip) signature = `@DoNotStrip\n@Keep\n${signature}` if (body == null) { return signature } else { return ` ${signature} { ${indent(body, ' ')} } `.trim() } } default: throw new Error( `Language ${language} is not yet supported for property getters!` ) } } getExtraFiles(): SourceFile[] { const returnTypeExtraFiles = this.returnType.getExtraFiles() const paramsExtraFiles = this.parameters.flatMap((p) => p.getExtraFiles()) return [...returnTypeExtraFiles, ...paramsExtraFiles] } getRequiredImports(): SourceImport[] { const returnTypeFiles = this.returnType.getRequiredImports() const paramsImports = this.parameters.flatMap((p) => p.getRequiredImports()) return [...returnTypeFiles, ...paramsImports] } }