nitro-codegen
Version:
The code-generator for react-native-nitro-modules.
139 lines (115 loc) • 4.22 kB
text/typescript
import { NitroConfig } from '../../config/NitroConfig.js'
import { includeHeader } from '../../syntax/c++/includeNitroHeader.js'
import { getAllKnownTypes } from '../../syntax/createType.js'
import {
createFileMetadataString,
isNotDuplicate,
} from '../../syntax/helpers.js'
import type { SourceFile } from '../../syntax/SourceFile.js'
import { getReferencedTypes } from '../../syntax/getReferencedTypes.js'
import { SwiftCxxBridgedType } from '../../syntax/swift/SwiftCxxBridgedType.js'
import { filterDuplicateHelperBridges, indent } from '../../utils.js'
import { getTypeAs } from '../../syntax/types/getTypeAs.js'
import { HybridObjectType } from '../../syntax/types/HybridObjectType.js'
import { getForwardDeclaration } from '../../syntax/c++/getForwardDeclaration.js'
import { getHybridObjectName } from '../../syntax/getHybridObjectName.js'
const SWIFT_BRIDGE_NAMESPACE = ['bridge', 'swift']
export function createSwiftCxxBridge(): SourceFile[] {
const moduleName = NitroConfig.getIosModuleName()
const bridgeName = `${moduleName}-Swift-Cxx-Bridge`
const types = getAllKnownTypes('swift').map((t) => new SwiftCxxBridgedType(t))
const bridges = types
.flatMap((t) => {
const referenced = getReferencedTypes(t.type)
return referenced.map((r) => {
const bridge = new SwiftCxxBridgedType(r)
return bridge.getRequiredBridge()
})
})
.filter((b) => b != null)
.flatMap((b) => [b, ...b?.dependencies])
.filter(filterDuplicateHelperBridges)
const headerHelperFunctions = bridges
.map((b) => `// pragma MARK: ${b.cxxType}\n${b.cxxHeader.code}`)
.filter(isNotDuplicate)
.join('\n\n')
const implementationHelperFunctions = bridges
.map((b) => {
if (b.cxxImplementation == null) return undefined
else return `// pragma MARK: ${b.cxxType}\n${b.cxxImplementation.code}`
})
.filter((c) => c != null)
.filter(isNotDuplicate)
.join('\n\n')
const requiredImportsHeader = bridges.flatMap(
(b) => b.cxxHeader.requiredIncludes
)
const includesHeader = requiredImportsHeader
.map((i) => includeHeader(i, true))
.filter(isNotDuplicate)
const forwardDeclarationsHeader = requiredImportsHeader
.map((i) => i.forwardDeclaration)
.filter((f) => f != null)
.filter(isNotDuplicate)
const includesImplementation = bridges
.flatMap((b) => b.cxxImplementation?.requiredIncludes)
.filter((i) => i != null)
.map((i) => includeHeader(i, true))
.filter(isNotDuplicate)
const namespace = NitroConfig.getCxxNamespace(
'c++',
...SWIFT_BRIDGE_NAMESPACE
)
const forwardDeclaredSwiftTypes = types
.filter((t) => t.type.kind === 'hybrid-object')
.map((t) => {
const hybridObject = getTypeAs(t.type, HybridObjectType)
const { HybridTSpecCxx } = getHybridObjectName(
hybridObject.hybridObjectName
)
return getForwardDeclaration('class', HybridTSpecCxx, moduleName)
})
.filter(isNotDuplicate)
const header = `
${createFileMetadataString(`${bridgeName}.hpp`)}
#pragma once
// Forward declarations of C++ defined types
${forwardDeclarationsHeader.sort().join('\n')}
// Forward declarations of Swift defined types
${forwardDeclaredSwiftTypes.sort().join('\n')}
// Include C++ defined types
${includesHeader.sort().join('\n')}
/**
* Contains specialized versions of C++ templated types so they can be accessed from Swift,
* as well as helper functions to interact with those C++ types from Swift.
*/
namespace ${namespace} {
${indent(headerHelperFunctions, ' ')}
} // namespace ${namespace}
`
const source = `
${createFileMetadataString(`${bridgeName}.cpp`)}
#include "${bridgeName}.hpp"
// Include C++ implementation defined types
${includesImplementation.sort().join('\n')}
namespace ${namespace} {
${indent(implementationHelperFunctions, ' ')}
} // namespace ${namespace}
`
const files: SourceFile[] = []
files.push({
content: header,
language: 'c++',
name: `${bridgeName}.hpp`,
platform: 'ios',
subdirectory: [],
})
files.push({
content: source,
language: 'c++',
name: `${bridgeName}.cpp`,
platform: 'ios',
subdirectory: [],
})
return files
}