From f52d88e7d23048862e4d67c3f475aae2b74073fc Mon Sep 17 00:00:00 2001 From: dhruvpatel374 Date: Fri, 30 Oct 2026 11:37:51 +0530 Subject: [PATCH] refactor: make Swift forward-declaration collection polymorphic (#1846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the knowledge of how to produce a Swift-Cxx forward declaration out of two identical caller-side type-checks and into HybridObjectType itself via an optional Type interface method. Before: both createSwiftCxxBridge and createSwiftUmbrellaHeader had to independently check `kind === 'hybrid-object'`, cast with getTypeAs, and reconstruct the same getForwardDeclaration call. After: HybridObjectType implements getForwardDeclarations() once. Both callers collapse to flatMap(t => t.getForwardDeclarations?.() ?? []). Any future type that needs Swift forward declarations just implements the method — callers do not change. Also fixes a pre-existing TypeScript error in createSwiftCxxBridge where .filter((b) => b != null) did not narrow the type, causing b?.dependencies to spread undefined. Replaced with a proper type-guard predicate. Generated output is identical — confirmed with bun specs (zero diff on all generated files). Typecheck and all offline tests pass. --- .../autolinking/ios/createSwiftCxxBridge.ts | 24 ++++--------------- .../ios/createSwiftUmbrellaHeader.ts | 17 +------------ .../src/syntax/types/HybridObjectType.ts | 6 +++++ packages/nitrogen/src/syntax/types/Type.ts | 11 +++++++++ 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/packages/nitrogen/src/autolinking/ios/createSwiftCxxBridge.ts b/packages/nitrogen/src/autolinking/ios/createSwiftCxxBridge.ts index 1a32c02d5c..410ece0644 100644 --- a/packages/nitrogen/src/autolinking/ios/createSwiftCxxBridge.ts +++ b/packages/nitrogen/src/autolinking/ios/createSwiftCxxBridge.ts @@ -8,11 +8,8 @@ import { import type { SourceFile } from '../../syntax/SourceFile.js' import { getReferencedTypes } from '../../syntax/getReferencedTypes.js' import { SwiftCxxBridgedType } from '../../syntax/swift/SwiftCxxBridgedType.js' +import type { SwiftCxxHelper } from '../../syntax/swift/SwiftCxxTypeHelper.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' export function createSwiftCxxBridge(): SourceFile[] { const bridgeName = NitroConfig.current.getSwiftBridgeHeaderName() @@ -28,8 +25,8 @@ export function createSwiftCxxBridge(): SourceFile[] { return bridge.getRequiredBridge() }) }) - .filter((b) => b != null) - .flatMap((b) => [b, ...b?.dependencies]) + .filter((b): b is SwiftCxxHelper => b != null) + .flatMap((b) => [b, ...b.dependencies]) .filter(filterDuplicateHelperBridges) const headerHelperFunctions = bridges .map((b) => `// pragma MARK: ${b.cxxType}\n${b.cxxHeader.code}`) @@ -62,20 +59,7 @@ export function createSwiftCxxBridge(): SourceFile[] { .filter(isNotDuplicate) const forwardDeclaredSwiftTypes = types - .filter((t) => t.type.kind === 'hybrid-object') - .map((t) => { - const hybridObject = getTypeAs(t.type, HybridObjectType) - const hybridObjectModuleName = - hybridObject.sourceConfig.getIosModuleName() - const { HybridTSpecCxx } = getHybridObjectName( - hybridObject.hybridObjectName - ) - return getForwardDeclaration( - 'class', - HybridTSpecCxx, - hybridObjectModuleName - ) - }) + .flatMap((t) => t.type.getForwardDeclarations?.() ?? []) .filter(isNotDuplicate) const header = ` diff --git a/packages/nitrogen/src/autolinking/ios/createSwiftUmbrellaHeader.ts b/packages/nitrogen/src/autolinking/ios/createSwiftUmbrellaHeader.ts index 71e5d0dfe3..3bedbc5679 100644 --- a/packages/nitrogen/src/autolinking/ios/createSwiftUmbrellaHeader.ts +++ b/packages/nitrogen/src/autolinking/ios/createSwiftUmbrellaHeader.ts @@ -1,15 +1,11 @@ import { NitroConfig } from '../../config/NitroConfig.js' -import { getForwardDeclaration } from '../../syntax/c++/getForwardDeclaration.js' import { includeHeader } from '../../syntax/c++/includeNitroHeader.js' import { getAllKnownTypes } from '../../syntax/createType.js' -import { getHybridObjectName } from '../../syntax/getHybridObjectName.js' import { createFileMetadataString, isNotDuplicate, } from '../../syntax/helpers.js' import type { SourceFile } from '../../syntax/SourceFile.js' -import { getTypeAs } from '../../syntax/types/getTypeAs.js' -import { HybridObjectType } from '../../syntax/types/HybridObjectType.js' export function getUmbrellaHeaderName(): string { const moduleName = NitroConfig.current.getIosModuleName() @@ -23,18 +19,7 @@ export function createSwiftUmbrellaHeader(): SourceFile { const types = getAllKnownTypes('swift') const swiftForwardDeclares = types - .filter((t) => t.kind === 'hybrid-object') - .map((t) => { - const hybridObjectType = getTypeAs(t, HybridObjectType) - const hybridObjectModuleName = - hybridObjectType.sourceConfig.getIosModuleName() - const name = getHybridObjectName(hybridObjectType.hybridObjectName) - return getForwardDeclaration( - 'class', - name.HybridTSpecCxx, - hybridObjectModuleName - ) - }) + .flatMap((t) => t.getForwardDeclarations?.() ?? []) .filter(isNotDuplicate) const imports = types.flatMap((t) => t.getRequiredImports('c++')) diff --git a/packages/nitrogen/src/syntax/types/HybridObjectType.ts b/packages/nitrogen/src/syntax/types/HybridObjectType.ts index ceeed0f1eb..0c2d93af37 100644 --- a/packages/nitrogen/src/syntax/types/HybridObjectType.ts +++ b/packages/nitrogen/src/syntax/types/HybridObjectType.ts @@ -198,4 +198,10 @@ export class HybridObjectType implements Type { return imports } + + getForwardDeclarations(): string[] { + const name = getHybridObjectName(this.hybridObjectName) + const moduleName = this.sourceConfig.getIosModuleName() + return [getForwardDeclaration('class', name.HybridTSpecCxx, moduleName)] + } } diff --git a/packages/nitrogen/src/syntax/types/Type.ts b/packages/nitrogen/src/syntax/types/Type.ts index ea6954394d..cd1cd11e06 100644 --- a/packages/nitrogen/src/syntax/types/Type.ts +++ b/packages/nitrogen/src/syntax/types/Type.ts @@ -69,6 +69,17 @@ export interface Type { * Get all required extra imports that need to be **imported** for this type to properly work. */ getRequiredImports(language: Language): SourceImport[] + /** + * Get any C++ forward declarations this type needs beyond those already + * carried by {@linkcode getRequiredImports | getRequiredImports()}. + * + * This is an optional capability: only some types declare any (currently + * `HybridObjectType`, to forward-declare its Swift-generated `*Cxx` wrapper + * class). Letting the type own this keeps dependency collection polymorphic + * instead of callers hardcoding `kind`-checks and reaching into concrete + * type classes. + */ + getForwardDeclarations?(): string[] } export interface NamedType extends Type {