Skip to content

Commit

Permalink
fix: Fix Swift umbrella header includes (#19)
Browse files Browse the repository at this point in the history
* feat: Try bridge more Swift

* Make all Promises `async` in swift

* Rename `Promise` to `JSPromise`

* Update JSPromise.hpp

* Update JSICache.cpp

* fix import

* fix: Init props

* fix: Remove AnyMap and ArrayBuffer apis for now

* fix import

* no more async? idk

* feat: Convert `std::optional<T>` to `swift::Optional<T>`

* Remove all funcs except hello

* fix: Generate Swift Umbrella header

* fix: Organize

* fix: Hardcode forward-decl

* feat: Properly generate umbrella header from known types

* fix: Fix indentation

* order

* feat: Try bridging some primitives over...

* Update NitroDefines.hpp

* Update Property.ts

* fallthrough looks better

* better error

* fix: Fix wrong enum `maxLength`

* feat: Try `CarSwift` experiment

* Revert "feat: Try `CarSwift` experiment"

This reverts commit 7794f38.
  • Loading branch information
mrousavy authored Aug 12, 2024
1 parent 8cccf33 commit 0dd6322
Show file tree
Hide file tree
Showing 86 changed files with 686 additions and 1,382 deletions.
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1465,7 +1465,7 @@ SPEC CHECKSUMS:
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f
hermes-engine: 8c1577f3fdb849cbe7729c2e7b5abc4b845e88f8
NitroImage: d298d1e42faaea39e6abbced44de2b1ba08819c6
NitroImage: 25530093d610c707b25677013918967370b627d3
NitroModules: cd421091537fbdebf47ba7d785d1fb2b647971f7
RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47
RCTDeprecation: 3afceddffa65aee666dafd6f0116f1d975db1584
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def add_nitrogen_files(spec)
current_private_header_files = spec.attributes_hash['private_header_files'] || []
spec.private_header_files = current_private_header_files + [
# iOS specific specs
"nitrogen/generated/ios/c++/**/*.{h,hpp}",
"nitrogen/generated/ios/**/*.{h,hpp}",
]
current_pod_target_xcconfig = spec.attributes_hash['pod_target_xcconfig'] || {}
Expand Down
62 changes: 62 additions & 0 deletions packages/nitrogen/src/autolinking/createSwiftUmbrellaHeader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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 createSwiftUmbrellaHeader(): SourceFile {
const moduleName = NitroConfig.getIosModuleName()
const filename = `${moduleName}-Swift-Cxx-Umbrella.hpp`

const types = getAllKnownTypes()

const swiftForwardDeclares = types
.filter((t) => t.kind === 'hybrid-object')
.map((t) => {
const hybridObjectType = getTypeAs(t, HybridObjectType)
const name = getHybridObjectName(hybridObjectType.hybridObjectName)
return getForwardDeclaration('class', name.HybridTSpecCxx, moduleName)
})
.filter(isNotDuplicate)

const imports = types.flatMap((t) => t.getRequiredImports())
const forwardDeclarations = imports
.map((i) => i.forwardDeclaration)
.filter((f) => f != null)
.filter(isNotDuplicate)
const includes = imports.map((i) => includeHeader(i)).filter(isNotDuplicate)

const code = `
${createFileMetadataString(filename, '///')}
#pragma once
// Forward declarations of C++ defined types
${forwardDeclarations.sort().join('\n')}
// Include C++ defined types
${includes.sort().join('\n')}
// Forward declarations of Swift defined types
${swiftForwardDeclares.sort().join('\n')}
// Include Swift defined types
#if __has_include("${moduleName}-Swift.h")
#include "${moduleName}-Swift.h"
#else
#error ${moduleName}'s autogenerated Swift header cannot be found! Make sure the Swift module's name is actually "${moduleName}", and try building the app first.
#endif
`

return {
content: code,
language: 'c++',
name: filename,
platform: 'ios',
subdirectory: [],
}
}
2 changes: 0 additions & 2 deletions packages/nitrogen/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { isValidLogLevel, setLogLevel } from './Logger.js'

const commandName = 'nitro-codegen'

// TODO: Actually set log-level depending on user command config

// Maximum of 100 col width
const cliWidth = Math.min(process.stdout.columns * 0.9, 100)

Expand Down
2 changes: 2 additions & 0 deletions packages/nitrogen/src/nitrogen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Logger } from './Logger.js'
import { createPodspecRubyExtension } from './autolinking/createPodspecRubyExtension.js'
import { createCMakeExtension } from './autolinking/createCMakeExtension.js'
import { createGradleExtension } from './autolinking/createGradleExtension.js'
import { createSwiftUmbrellaHeader } from './autolinking/createSwiftUmbrellaHeader.js'

interface NitrogenOptions {
baseDirectory: string
Expand Down Expand Up @@ -195,6 +196,7 @@ export async function runNitrogen({

// iOS Podspec (Autolinking)
const buildSetupFiles = [
createSwiftUmbrellaHeader(),
createPodspecRubyExtension(),
createCMakeExtension(writtenFiles),
createGradleExtension(),
Expand Down
23 changes: 17 additions & 6 deletions packages/nitrogen/src/syntax/Property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,23 @@ export class Property implements CodeNode {
readonly type: NamedType
readonly isReadonly: boolean

constructor(prop: PropertySignature) {
this.name = prop.getSymbolOrThrow().getEscapedName()
this.isReadonly = prop.hasModifier(ts.SyntaxKind.ReadonlyKeyword)
const type = prop.getTypeNodeOrThrow().getType()
const isOptional = prop.hasQuestionToken() || type.isNullable()
this.type = createNamedType(this.name, type, isOptional)
constructor(name: string, type: NamedType, isReadonly: boolean)
constructor(prop: PropertySignature)
constructor(...args: [PropertySignature] | [string, NamedType, boolean]) {
if (typeof args[0] === 'string') {
if (args.length !== 3) throw new Error('Missing argument for type!')
const [name, type, isReadonly] = args
this.name = name
this.type = type
this.isReadonly = isReadonly
} else {
const [prop] = args
this.name = prop.getSymbolOrThrow().getEscapedName()
this.isReadonly = prop.hasModifier(ts.SyntaxKind.ReadonlyKeyword)
const type = prop.getTypeNodeOrThrow().getType()
const isOptional = prop.hasQuestionToken() || type.isNullable()
this.type = createNamedType(this.name, type, isOptional)
}
}

getExtraFiles(): SourceFile[] {
Expand Down
5 changes: 5 additions & 0 deletions packages/nitrogen/src/syntax/SourceFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ export interface SourceImport {
* The language this file is written in (e.g. `c++`)
*/
language: Language
/**
* Whether the import is a user-defined header (something local, like `"MyObject.hpp"`)
* or a shared system header (like `<NitroModules/HybridObject.hpp>`)
*/
space: 'user' | 'system'
}

type GroupedFiles = Record<SourceFile['platform'], SourceFile[]>
Expand Down
2 changes: 1 addition & 1 deletion packages/nitrogen/src/syntax/c++/CppEnum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function createCppEnum(
.map((m) => `${m.name} SWIFT_NAME(${m.name.toLowerCase()}) = ${m.value},`)
.join('\n')
const minValue = 0
const maxValue = cppEnumMembers.length - 1
const maxValue = enumMembers.length - 1
const cxxNamespace = NitroConfig.getCxxNamespace('c++')

// Create entire C++ file
Expand Down
4 changes: 2 additions & 2 deletions packages/nitrogen/src/syntax/c++/CppHybridObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SourceFile } from '../SourceFile.js'
import { createFileMetadataString, isNotDuplicate } from '../helpers.js'
import { indent } from '../../utils.js'
import type { HybridObjectSpec } from '../HybridObjectSpec.js'
import { includeNitroHeader } from './includeNitroHeader.js'
import { includeHeader, includeNitroHeader } from './includeNitroHeader.js'
import { NitroConfig } from '../../config/NitroConfig.js'
import { getHybridObjectName } from '../getHybridObjectName.js'

Expand All @@ -21,7 +21,7 @@ export function createCppHybridObject(spec: HybridObjectSpec): SourceFile[] {
.filter((v) => v != null)
.filter(isNotDuplicate)
const cppExtraIncludes = extraIncludes
.map((i) => `#include "${i.name}"`)
.map((i) => includeHeader(i))
.filter(isNotDuplicate)
const cxxNamespace = NitroConfig.getCxxNamespace('c++')
const name = getHybridObjectName(spec.name)
Expand Down
4 changes: 2 additions & 2 deletions packages/nitrogen/src/syntax/c++/CppStruct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { FileWithReferencedTypes } from '../SourceFile.js'
import { indent } from '../../utils.js'
import { createFileMetadataString, isNotDuplicate } from '../helpers.js'
import type { NamedType } from '../types/Type.js'
import { includeNitroHeader } from './includeNitroHeader.js'
import { includeHeader, includeNitroHeader } from './includeNitroHeader.js'
import { NitroConfig } from '../../config/NitroConfig.js'

export function createCppStruct(
Expand Down Expand Up @@ -48,7 +48,7 @@ export function createCppStruct(
.filter((v) => v != null)
.filter(isNotDuplicate)
const cppExtraIncludes = includedTypes
.map((f) => `#include "${f.name}"`)
.map((i) => includeHeader(i))
.filter(isNotDuplicate)
const cxxNamespace = NitroConfig.getCxxNamespace('c++')

Expand Down
8 changes: 5 additions & 3 deletions packages/nitrogen/src/syntax/c++/CppUnion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function createCppUnion(
)
.join('\n')
const cppCanConvertCases = enumMembers
.map((m) => `case hashString("${m.stringValue}"): return true;`)
.map((m) => `case hashString("${m.stringValue}"):`)
.join('\n')
const cxxNamespace = NitroConfig.getCxxNamespace('c++')

Expand Down Expand Up @@ -63,7 +63,7 @@ namespace margelo::nitro {
switch (hashString(unionValue.c_str(), unionValue.size())) {
${indent(cppFromJsiHashCases, ' ')}
default: [[unlikely]]
throw std::runtime_error("Cannot convert " + unionValue + " to ${typename} - invalid value!");
throw std::runtime_error("Cannot convert \\"" + unionValue + "\\" to enum ${typename} - invalid value!");
}
}
static inline jsi::Value toJSI(jsi::Runtime& runtime, ${typename} arg) {
Expand All @@ -81,7 +81,9 @@ namespace margelo::nitro {
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
switch (hashString(unionValue.c_str(), unionValue.size())) {
${indent(cppCanConvertCases, ' ')}
default: return false;
return true;
default:
return false;
}
}
};
Expand Down
11 changes: 11 additions & 0 deletions packages/nitrogen/src/syntax/c++/includeNitroHeader.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { SourceImport } from '../SourceFile.js'

/**
* Generates C++ code for including a `NitroModules` header.
* @example `Hash.hpp` -> `#include <NitroModules/Hash.hpp>`
Expand All @@ -11,3 +13,12 @@ export function includeNitroHeader(headerName: string): string {
#endif
`.trim()
}

export function includeHeader(sourceImport: SourceImport): string {
switch (sourceImport.space) {
case 'user':
return `#include "${sourceImport.name}"`
case 'system':
return `#include <${sourceImport.name}>`
}
}
Loading

0 comments on commit 0dd6322

Please sign in to comment.