nitrogen 0.2.24 → 0.29.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/README.md +18 -108
  2. package/lib/Logger.js +56 -0
  3. package/lib/autolinking/Autolinking.js +1 -0
  4. package/lib/autolinking/android/createCMakeExtension.js +109 -0
  5. package/lib/autolinking/android/createGradleExtension.js +36 -0
  6. package/lib/autolinking/android/createHybridObjectInitializer.js +159 -0
  7. package/lib/autolinking/createAndroidAutolinking.js +13 -0
  8. package/lib/autolinking/createIOSAutolinking.js +19 -0
  9. package/lib/autolinking/ios/createHybridObjectInitializer.js +97 -0
  10. package/lib/autolinking/ios/createPodspecRubyExtension.js +69 -0
  11. package/lib/autolinking/ios/createSwiftCxxBridge.js +117 -0
  12. package/lib/autolinking/ios/createSwiftUmbrellaHeader.js +74 -0
  13. package/lib/config/NitroConfig.js +112 -0
  14. package/lib/config/NitroUserConfig.js +88 -0
  15. package/lib/config/getConfig.js +84 -0
  16. package/lib/createGitAttributes.js +11 -0
  17. package/lib/createPlatformSpec.js +127 -0
  18. package/lib/getFiles.js +28 -0
  19. package/lib/getPlatformSpecs.js +153 -0
  20. package/lib/index.js +113 -10
  21. package/lib/init.js +123 -0
  22. package/lib/nitrogen.js +165 -0
  23. package/lib/prettifyDirectory.js +27 -0
  24. package/lib/syntax/BridgedType.js +1 -0
  25. package/lib/syntax/CodeNode.js +1 -0
  26. package/lib/syntax/HybridObjectSpec.js +1 -0
  27. package/lib/syntax/Method.js +108 -0
  28. package/lib/syntax/Parameter.js +65 -0
  29. package/lib/syntax/Property.js +147 -0
  30. package/lib/syntax/SourceFile.js +7 -0
  31. package/lib/syntax/c++/CppEnum.js +110 -0
  32. package/lib/syntax/c++/CppHybridObject.js +146 -0
  33. package/lib/syntax/c++/CppHybridObjectRegistration.js +18 -0
  34. package/lib/syntax/c++/CppStruct.js +108 -0
  35. package/lib/syntax/c++/CppUnion.js +88 -0
  36. package/lib/syntax/c++/getForwardDeclaration.js +14 -0
  37. package/lib/syntax/c++/includeNitroHeader.js +34 -0
  38. package/lib/syntax/createType.js +303 -0
  39. package/lib/syntax/getAllTypes.js +11 -0
  40. package/lib/syntax/getCustomTypeConfig.js +53 -0
  41. package/lib/syntax/getHybridObjectName.d.ts +36 -0
  42. package/lib/syntax/getHybridObjectName.js +10 -0
  43. package/lib/syntax/getInterfaceProperties.js +9 -0
  44. package/lib/syntax/getReferencedTypes.js +47 -0
  45. package/lib/syntax/helpers.js +53 -0
  46. package/lib/syntax/isCoreType.js +47 -0
  47. package/lib/syntax/kotlin/FbjniHybridObject.js +261 -0
  48. package/lib/syntax/kotlin/JNINativeRegistrations.js +7 -0
  49. package/lib/syntax/kotlin/KotlinBoxedPrimitive.js +17 -0
  50. package/lib/syntax/kotlin/KotlinCxxBridgedType.js +893 -0
  51. package/lib/syntax/kotlin/KotlinEnum.js +113 -0
  52. package/lib/syntax/kotlin/KotlinFunction.js +256 -0
  53. package/lib/syntax/kotlin/KotlinHybridObject.js +177 -0
  54. package/lib/syntax/kotlin/KotlinHybridObjectRegistration.js +26 -0
  55. package/lib/syntax/kotlin/KotlinStruct.js +172 -0
  56. package/lib/syntax/kotlin/KotlinVariant.js +191 -0
  57. package/lib/syntax/swift/SwiftCxxBridgedType.js +819 -0
  58. package/lib/syntax/swift/SwiftCxxTypeHelper.js +613 -0
  59. package/lib/syntax/swift/SwiftEnum.js +52 -0
  60. package/lib/syntax/swift/SwiftFunction.js +83 -0
  61. package/lib/syntax/swift/SwiftHybridObject.js +103 -0
  62. package/lib/syntax/swift/SwiftHybridObjectBridge.js +451 -0
  63. package/lib/syntax/swift/SwiftHybridObjectRegistration.js +42 -0
  64. package/lib/syntax/swift/SwiftStruct.js +75 -0
  65. package/lib/syntax/swift/SwiftVariant.js +58 -0
  66. package/lib/syntax/types/ArrayBufferType.js +37 -0
  67. package/lib/syntax/types/ArrayType.d.ts +12 -0
  68. package/lib/syntax/types/ArrayType.js +52 -0
  69. package/lib/syntax/types/BigIntType.js +27 -0
  70. package/lib/syntax/types/BooleanType.js +27 -0
  71. package/lib/syntax/types/CustomType.d.ts +14 -0
  72. package/lib/syntax/types/CustomType.js +36 -0
  73. package/lib/syntax/types/DateType.js +35 -0
  74. package/lib/syntax/types/EnumType.js +101 -0
  75. package/lib/syntax/types/ErrorType.js +37 -0
  76. package/lib/syntax/types/FunctionType.js +147 -0
  77. package/lib/syntax/types/HybridObjectBaseType.js +38 -0
  78. package/lib/syntax/types/HybridObjectType.js +131 -0
  79. package/lib/syntax/types/MapType.js +37 -0
  80. package/lib/syntax/types/NamedWrappingType.js +27 -0
  81. package/lib/syntax/types/NullType.js +23 -0
  82. package/lib/syntax/types/NumberType.js +27 -0
  83. package/lib/syntax/types/OptionalType.js +59 -0
  84. package/lib/syntax/types/PromiseType.js +62 -0
  85. package/lib/syntax/types/RecordType.js +47 -0
  86. package/lib/syntax/types/ResultWrappingType.js +44 -0
  87. package/lib/syntax/types/StringType.js +35 -0
  88. package/lib/syntax/types/StructType.js +61 -0
  89. package/lib/syntax/types/TupleType.js +39 -0
  90. package/lib/syntax/types/Type.js +1 -0
  91. package/lib/syntax/types/VariantType.js +75 -0
  92. package/lib/syntax/types/VoidType.js +27 -0
  93. package/lib/syntax/types/getTypeAs.js +12 -0
  94. package/lib/utils.js +126 -0
  95. package/lib/views/CppHybridViewComponent.js +256 -0
  96. package/lib/views/createHostComponentJs.js +27 -0
  97. package/lib/views/kotlin/KotlinHybridViewManager.js +229 -0
  98. package/lib/views/swift/SwiftHybridViewManager.js +131 -0
  99. package/lib/writeFile.js +19 -0
  100. package/package.json +58 -29
  101. package/src/Logger.ts +63 -0
  102. package/src/autolinking/Autolinking.ts +9 -0
  103. package/src/autolinking/android/createCMakeExtension.ts +126 -0
  104. package/src/autolinking/android/createGradleExtension.ts +43 -0
  105. package/src/autolinking/android/createHybridObjectInitializer.ts +174 -0
  106. package/src/autolinking/createAndroidAutolinking.ts +28 -0
  107. package/src/autolinking/createIOSAutolinking.ts +24 -0
  108. package/src/autolinking/ios/createHybridObjectInitializer.ts +112 -0
  109. package/src/autolinking/ios/createPodspecRubyExtension.ts +76 -0
  110. package/src/autolinking/ios/createSwiftCxxBridge.ts +137 -0
  111. package/src/autolinking/ios/createSwiftUmbrellaHeader.ts +90 -0
  112. package/src/config/NitroConfig.ts +139 -0
  113. package/src/config/NitroUserConfig.ts +105 -0
  114. package/src/config/getConfig.ts +91 -0
  115. package/src/createGitAttributes.ts +15 -0
  116. package/src/createPlatformSpec.ts +176 -0
  117. package/src/getFiles.ts +31 -0
  118. package/src/getPlatformSpecs.ts +202 -0
  119. package/src/index.ts +146 -0
  120. package/src/init.ts +186 -0
  121. package/src/nitrogen.ts +246 -0
  122. package/src/prettifyDirectory.ts +32 -0
  123. package/src/syntax/BridgedType.ts +59 -0
  124. package/src/syntax/CodeNode.ts +24 -0
  125. package/src/syntax/HybridObjectSpec.ts +14 -0
  126. package/src/syntax/Method.ts +154 -0
  127. package/src/syntax/Parameter.ts +81 -0
  128. package/src/syntax/Property.ts +203 -0
  129. package/src/syntax/SourceFile.ts +80 -0
  130. package/src/syntax/c++/CppEnum.ts +128 -0
  131. package/src/syntax/c++/CppHybridObject.ts +165 -0
  132. package/src/syntax/c++/CppHybridObjectRegistration.ts +39 -0
  133. package/src/syntax/c++/CppStruct.ts +129 -0
  134. package/src/syntax/c++/CppUnion.ts +105 -0
  135. package/src/syntax/c++/getForwardDeclaration.ts +19 -0
  136. package/src/syntax/c++/includeNitroHeader.ts +40 -0
  137. package/src/syntax/createType.ts +365 -0
  138. package/src/syntax/getAllTypes.ts +18 -0
  139. package/src/syntax/getCustomTypeConfig.ts +71 -0
  140. package/src/syntax/getHybridObjectName.ts +48 -0
  141. package/src/syntax/getInterfaceProperties.ts +21 -0
  142. package/src/syntax/getReferencedTypes.ts +57 -0
  143. package/src/syntax/helpers.ts +79 -0
  144. package/src/syntax/isCoreType.ts +60 -0
  145. package/src/syntax/kotlin/FbjniHybridObject.ts +313 -0
  146. package/src/syntax/kotlin/JNINativeRegistrations.ts +19 -0
  147. package/src/syntax/kotlin/KotlinBoxedPrimitive.ts +19 -0
  148. package/src/syntax/kotlin/KotlinCxxBridgedType.ts +942 -0
  149. package/src/syntax/kotlin/KotlinEnum.ts +130 -0
  150. package/src/syntax/kotlin/KotlinFunction.ts +277 -0
  151. package/src/syntax/kotlin/KotlinHybridObject.ts +205 -0
  152. package/src/syntax/kotlin/KotlinHybridObjectRegistration.ts +51 -0
  153. package/src/syntax/kotlin/KotlinStruct.ts +198 -0
  154. package/src/syntax/kotlin/KotlinVariant.ts +212 -0
  155. package/src/syntax/swift/SwiftCxxBridgedType.ts +874 -0
  156. package/src/syntax/swift/SwiftCxxTypeHelper.ts +674 -0
  157. package/src/syntax/swift/SwiftEnum.ts +65 -0
  158. package/src/syntax/swift/SwiftFunction.ts +91 -0
  159. package/src/syntax/swift/SwiftHybridObject.ts +121 -0
  160. package/src/syntax/swift/SwiftHybridObjectBridge.ts +522 -0
  161. package/src/syntax/swift/SwiftHybridObjectRegistration.ts +75 -0
  162. package/src/syntax/swift/SwiftStruct.ts +85 -0
  163. package/src/syntax/swift/SwiftVariant.ts +67 -0
  164. package/src/syntax/types/ArrayBufferType.ts +49 -0
  165. package/src/syntax/types/ArrayType.ts +62 -0
  166. package/src/syntax/types/BigIntType.ts +35 -0
  167. package/src/syntax/types/BooleanType.ts +35 -0
  168. package/src/syntax/types/CustomType.ts +47 -0
  169. package/src/syntax/types/DateType.ts +43 -0
  170. package/src/syntax/types/EnumType.ts +130 -0
  171. package/src/syntax/types/ErrorType.ts +44 -0
  172. package/src/syntax/types/FunctionType.ts +167 -0
  173. package/src/syntax/types/HybridObjectBaseType.ts +54 -0
  174. package/src/syntax/types/HybridObjectType.ts +198 -0
  175. package/src/syntax/types/MapType.ts +49 -0
  176. package/src/syntax/types/NamedWrappingType.ts +33 -0
  177. package/src/syntax/types/NullType.ts +30 -0
  178. package/src/syntax/types/NumberType.ts +34 -0
  179. package/src/syntax/types/OptionalType.ts +66 -0
  180. package/src/syntax/types/PromiseType.ts +72 -0
  181. package/src/syntax/types/RecordType.ts +56 -0
  182. package/src/syntax/types/ResultWrappingType.ts +53 -0
  183. package/src/syntax/types/StringType.ts +44 -0
  184. package/src/syntax/types/StructType.ts +83 -0
  185. package/src/syntax/types/TupleType.ts +53 -0
  186. package/src/syntax/types/Type.ts +82 -0
  187. package/src/syntax/types/VariantType.ts +92 -0
  188. package/src/syntax/types/VoidType.ts +34 -0
  189. package/src/syntax/types/getTypeAs.ts +15 -0
  190. package/src/utils.ts +162 -0
  191. package/src/views/CppHybridViewComponent.ts +304 -0
  192. package/src/views/createHostComponentJs.ts +34 -0
  193. package/src/views/kotlin/KotlinHybridViewManager.ts +258 -0
  194. package/src/views/swift/SwiftHybridViewManager.ts +153 -0
  195. package/src/writeFile.ts +27 -0
  196. package/.jshintignore +0 -6
  197. package/.jshintrc +0 -3
  198. package/.npmignore +0 -3
  199. package/.travis.yml +0 -13
  200. package/LICENSE +0 -13
  201. package/browser/nitrogen-min.js +0 -3
  202. package/browser/nitrogen.js +0 -6369
  203. package/lib/apiKey.js +0 -67
  204. package/lib/blob.js +0 -57
  205. package/lib/commandManager.js +0 -350
  206. package/lib/device.js +0 -19
  207. package/lib/memoryStore.js +0 -24
  208. package/lib/message.js +0 -298
  209. package/lib/permission.js +0 -121
  210. package/lib/principal.js +0 -330
  211. package/lib/service.js +0 -347
  212. package/lib/session.js +0 -494
  213. package/lib/user.js +0 -20
  214. package/publish +0 -2
  215. package/scripts/build-documentation +0 -4
  216. package/scripts/build-module +0 -27
  217. package/scripts/module.js +0 -12
  218. package/scripts/postamble.js +0 -1
  219. package/scripts/preamble.js +0 -2
  220. package/scripts/run-test-server +0 -9
  221. package/test/config.js +0 -12
  222. package/test/fixtures/images/image.jpg +0 -0
  223. package/test/fixtures/images/motion0.jpg +0 -0
  224. package/test/fixtures/images/motion1.jpg +0 -0
  225. package/test/fixtures/images/motion2.jpg +0 -0
  226. package/test/fixtures/index.js +0 -76
  227. package/test/main.js +0 -5
  228. package/test/memoryStore.js +0 -22
  229. package/test/mocha.opts +0 -3
  230. package/test/units/apiKey.js +0 -46
  231. package/test/units/blob.js +0 -35
  232. package/test/units/commandManager.js +0 -67
  233. package/test/units/device.js +0 -26
  234. package/test/units/heartbeat.js +0 -28
  235. package/test/units/message.js +0 -79
  236. package/test/units/permissions.js +0 -43
  237. package/test/units/principal.js +0 -116
  238. package/test/units/service.js +0 -92
  239. package/test/units/session.js +0 -97
  240. package/test/units/user.js +0 -48
  241. package/yuidoc.json +0 -8
@@ -0,0 +1,71 @@
1
+ import type { CustomTypeConfig } from 'react-native-nitro-modules'
2
+ import type { Type as TSMorphType } from 'ts-morph'
3
+
4
+ interface Result {
5
+ name: string
6
+ config: CustomTypeConfig
7
+ }
8
+
9
+ export function getCustomTypeConfig(type: TSMorphType): Result {
10
+ const parts = type.getIntersectionTypes()
11
+ for (const part of parts) {
12
+ const typeNameProperty = part.getProperty('__customTypeName')
13
+ if (typeNameProperty == null) continue
14
+ const typeConfigProperty = part.getProperty('__customTypeConfig')
15
+ if (typeConfigProperty == null) continue
16
+
17
+ const declaration = type.getAliasSymbolOrThrow().getDeclarations()[0]
18
+ if (declaration == null)
19
+ throw new Error(`Type has no declaration! ${type.getText()}`)
20
+
21
+ const typeNameTypeOrUndefined =
22
+ typeNameProperty.getTypeAtLocation(declaration)
23
+ const typeConfigTypeOrUndefined =
24
+ typeConfigProperty.getTypeAtLocation(declaration)
25
+
26
+ const typeNameType = typeNameTypeOrUndefined
27
+ .getUnionTypes()
28
+ .find((t) => t.isLiteral())
29
+ if (typeNameType == null) continue
30
+ const typeConfigType = typeConfigTypeOrUndefined
31
+ .getUnionTypes()
32
+ .find((t) => t.isObject())
33
+ if (typeConfigType == null) continue
34
+
35
+ const typeName = typeNameType.getLiteralValue()
36
+ if (typeof typeName !== 'string') {
37
+ throw new Error(
38
+ `CustomType's second argument (TypeName) needs to be a string! Instead, it is a ${typeof typeName} (${typeName})`
39
+ )
40
+ }
41
+ const includeType = typeConfigType
42
+ .getPropertyOrThrow('include')
43
+ .getTypeAtLocation(declaration)
44
+ const include = includeType.getLiteralValue()
45
+ if (typeof include !== 'string')
46
+ throw new Error(
47
+ `CustomType's third argument (Config) needs to contain { include }, which should be a string! (It is ${includeType.getText()} instead)`
48
+ )
49
+ const canBePassedByReferenceType = typeConfigType
50
+ .getProperty('canBePassedByReference')
51
+ ?.getTypeAtLocation(declaration)
52
+ .getUnionTypes()
53
+ .find((u) => u.isBooleanLiteral())
54
+ ?.getLiteralValue()
55
+ const canBePassedByReference =
56
+ typeof canBePassedByReferenceType === 'boolean'
57
+ ? canBePassedByReferenceType
58
+ : false
59
+
60
+ return {
61
+ name: typeName,
62
+ config: {
63
+ include: include,
64
+ canBePassedByReference: canBePassedByReference,
65
+ },
66
+ }
67
+ }
68
+ throw new Error(
69
+ `Type looks like a CustomType<...>, but doesn't have generic arguments! ${type.getText()}`
70
+ )
71
+ }
@@ -0,0 +1,48 @@
1
+ export interface HybridObjectName {
2
+ /**
3
+ * The raw name of the Hybrid Object (same as the TS interface name).
4
+ * @example "Image"
5
+ */
6
+ T: string
7
+ /**
8
+ * The debug-only description name of the Hybrid Object as it can be described in natively.
9
+ * @example "HybridImage"
10
+ */
11
+ HybridT: string
12
+ /**
13
+ * The name of the C++ class, Kotlin interface or Swift protocol that represents the
14
+ * specification (all of it's virtual properties and methods) of the Hybrid Object.
15
+ * @example "HybridImageSpec"
16
+ */
17
+ HybridTSpec: string
18
+ /**
19
+ * The name of the Swift class that bridges any types from
20
+ * {@linkcode HybridTSpec} over to C++.
21
+ * This includes a few type conversions or result/exception wrapping.
22
+ * @example "HybridImage_cxx"
23
+ */
24
+ HybridTSpecCxx: string
25
+ /**
26
+ * The name of the C++ class that actually bridges to the Java Hybrid Object.
27
+ * @example "JHybridImage"
28
+ */
29
+ JHybridTSpec: string
30
+ /**
31
+ * The name of the C++ class that extends the Hybrid Object and bridges over to the Swift C++ wrapper class.
32
+ * @example "HybridImageSwift"
33
+ */
34
+ HybridTSpecSwift: string
35
+ }
36
+
37
+ export function getHybridObjectName(
38
+ hybridObjectName: string
39
+ ): HybridObjectName {
40
+ return {
41
+ T: hybridObjectName,
42
+ HybridT: `Hybrid${hybridObjectName}`,
43
+ HybridTSpec: `Hybrid${hybridObjectName}Spec`,
44
+ HybridTSpecCxx: `Hybrid${hybridObjectName}Spec_cxx`,
45
+ JHybridTSpec: `JHybrid${hybridObjectName}Spec`,
46
+ HybridTSpecSwift: `Hybrid${hybridObjectName}SpecSwift`,
47
+ }
48
+ }
@@ -0,0 +1,21 @@
1
+ import type { ts, Type } from 'ts-morph'
2
+ import type { NamedType } from './types/Type.js'
3
+ import { createNamedType } from './createType.js'
4
+ import type { Language } from '../getPlatformSpecs.js'
5
+
6
+ export function getInterfaceProperties(
7
+ language: Language,
8
+ interfaceType: Type<ts.ObjectType>
9
+ ): NamedType[] {
10
+ return interfaceType.getProperties().map((prop) => {
11
+ const declaration = prop.getValueDeclarationOrThrow()
12
+ const propType = prop.getTypeAtLocation(declaration)
13
+ const refType = createNamedType(
14
+ language,
15
+ prop.getName(),
16
+ propType,
17
+ prop.isOptional() || propType.isNullable()
18
+ )
19
+ return refType
20
+ })
21
+ }
@@ -0,0 +1,57 @@
1
+ import { ArrayType } from './types/ArrayType.js'
2
+ import { FunctionType } from './types/FunctionType.js'
3
+ import { getTypeAs } from './types/getTypeAs.js'
4
+ import { OptionalType } from './types/OptionalType.js'
5
+ import { PromiseType } from './types/PromiseType.js'
6
+ import { RecordType } from './types/RecordType.js'
7
+ import { StructType } from './types/StructType.js'
8
+ import { TupleType } from './types/TupleType.js'
9
+ import type { Type } from './types/Type.js'
10
+ import { VariantType } from './types/VariantType.js'
11
+
12
+ export function getReferencedTypes(type: Type): Type[] {
13
+ switch (type.kind) {
14
+ case 'array':
15
+ const array = getTypeAs(type, ArrayType)
16
+ return [type, ...getReferencedTypes(array.itemType)]
17
+
18
+ case 'function':
19
+ const func = getTypeAs(type, FunctionType)
20
+ return [
21
+ type,
22
+ ...getReferencedTypes(func.returnType),
23
+ ...func.parameters.flatMap((t) => getReferencedTypes(t)),
24
+ ]
25
+
26
+ case 'optional':
27
+ const optional = getTypeAs(type, OptionalType)
28
+ return [type, ...getReferencedTypes(optional.wrappingType)]
29
+
30
+ case 'promise':
31
+ const promise = getTypeAs(type, PromiseType)
32
+ return [type, ...getReferencedTypes(promise.resultingType)]
33
+
34
+ case 'record':
35
+ const record = getTypeAs(type, RecordType)
36
+ return [
37
+ type,
38
+ ...getReferencedTypes(record.keyType),
39
+ ...getReferencedTypes(record.valueType),
40
+ ]
41
+
42
+ case 'struct':
43
+ const struct = getTypeAs(type, StructType)
44
+ return [type, ...struct.properties.flatMap((p) => getReferencedTypes(p))]
45
+
46
+ case 'tuple':
47
+ const tuple = getTypeAs(type, TupleType)
48
+ return [type, ...tuple.itemTypes.flatMap((t) => getReferencedTypes(t))]
49
+
50
+ case 'variant':
51
+ const variant = getTypeAs(type, VariantType)
52
+ return [type, ...variant.variants.flatMap((t) => getReferencedTypes(t))]
53
+
54
+ default:
55
+ return [type]
56
+ }
57
+ }
@@ -0,0 +1,79 @@
1
+ import path from 'path'
2
+ import type { SourceFile } from './SourceFile.js'
3
+ import type { Type } from './types/Type.js'
4
+ import { getTypeAs } from './types/getTypeAs.js'
5
+ import { OptionalType } from './types/OptionalType.js'
6
+
7
+ type Comment = '///' | '#'
8
+
9
+ export function createFileMetadataString(
10
+ filename: string,
11
+ comment: Comment = '///'
12
+ ): string {
13
+ const now = new Date()
14
+ return `
15
+ ${comment}
16
+ ${comment} ${filename}
17
+ ${comment} This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
18
+ ${comment} https://github.com/mrousavy/nitro
19
+ ${comment} Copyright © ${now.getFullYear()} Marc Rousavy @ Margelo
20
+ ${comment}
21
+ `.trim()
22
+ }
23
+
24
+ export function isFunction(type: Type): boolean {
25
+ switch (type.kind) {
26
+ case 'function':
27
+ return true
28
+ case 'optional': {
29
+ const optional = getTypeAs(type, OptionalType)
30
+ return isFunction(optional.wrappingType)
31
+ }
32
+ default:
33
+ return false
34
+ }
35
+ }
36
+
37
+ export function toReferenceType(type: string): `const ${typeof type}&` {
38
+ return `const ${type}&`
39
+ }
40
+
41
+ export function escapeCppName(string: string): string {
42
+ // Replace non-alphanumeric characters with underscores
43
+ let escapedStr = string.replace(/[^a-zA-Z0-9_]/g, '_')
44
+
45
+ // Ensure the first character is a letter or underscore
46
+ if (!/^[a-zA-Z_]/.test(escapedStr)) {
47
+ escapedStr = '_' + escapedStr
48
+ }
49
+
50
+ return escapedStr
51
+ }
52
+
53
+ export function isBooleanPropertyPrefix(name: string): boolean {
54
+ return name.startsWith('is') || name.startsWith('has')
55
+ }
56
+
57
+ export function isNotDuplicate<T>(item: T, index: number, array: T[]): boolean {
58
+ return array.indexOf(item) === index
59
+ }
60
+
61
+ export function isCppFile(file: SourceFile): boolean {
62
+ return file.name.endsWith('cpp') || file.name.endsWith('c')
63
+ }
64
+
65
+ export function getRelativeDirectory(file: SourceFile): string {
66
+ return path.join(
67
+ '..',
68
+ 'nitrogen',
69
+ 'generated',
70
+ file.platform,
71
+ file.language,
72
+ ...file.subdirectory,
73
+ file.name
74
+ )
75
+ }
76
+
77
+ export function getRelativeDirectoryGenerated(...subpath: string[]): string {
78
+ return path.join('..', 'nitrogen', 'generated', ...subpath)
79
+ }
@@ -0,0 +1,60 @@
1
+ import { Type as TSMorphType } from 'ts-morph'
2
+
3
+ function isSymbol(type: TSMorphType, symbolName: string): boolean {
4
+ // check the symbol directly
5
+ const symbol = type.getSymbol()
6
+ if (symbol?.getName() === symbolName) {
7
+ return true
8
+ }
9
+
10
+ // loop through the alias symbol alias chain to test each one
11
+ let aliasSymbol = type.getAliasSymbol()
12
+ while (aliasSymbol != null) {
13
+ if (aliasSymbol.getName() === symbolName) {
14
+ return true
15
+ }
16
+ aliasSymbol = aliasSymbol.getAliasedSymbol()
17
+ }
18
+
19
+ // nothing found.
20
+ return false
21
+ }
22
+
23
+ export function isPromise(type: TSMorphType): boolean {
24
+ return isSymbol(type, 'Promise')
25
+ }
26
+
27
+ export function isRecord(type: TSMorphType): boolean {
28
+ return isSymbol(type, 'Record')
29
+ }
30
+
31
+ export function isArrayBuffer(type: TSMorphType): boolean {
32
+ return isSymbol(type, 'ArrayBuffer')
33
+ }
34
+
35
+ export function isDate(type: TSMorphType): boolean {
36
+ return isSymbol(type, 'Date')
37
+ }
38
+
39
+ export function isMap(type: TSMorphType): boolean {
40
+ return isSymbol(type, 'AnyMap')
41
+ }
42
+
43
+ export function isError(type: TSMorphType): boolean {
44
+ return isSymbol(type, 'Error')
45
+ }
46
+
47
+ export function isCustomType(type: TSMorphType): boolean {
48
+ return (
49
+ type.getProperty('__customTypeName') != null &&
50
+ type.getProperty('__customTypeConfig') != null
51
+ )
52
+ }
53
+
54
+ export function isSyncFunction(type: TSMorphType): boolean {
55
+ if (type.getCallSignatures().length < 1)
56
+ // not a function.
57
+ return false
58
+ const syncTag = type.getProperty('__syncTag')
59
+ return syncTag != null
60
+ }
@@ -0,0 +1,313 @@
1
+ import { createIndentation, indent } from '../../utils.js'
2
+ import { getForwardDeclaration } from '../c++/getForwardDeclaration.js'
3
+ import { includeHeader } from '../c++/includeNitroHeader.js'
4
+ import { getAllTypes } from '../getAllTypes.js'
5
+ import { getHybridObjectName } from '../getHybridObjectName.js'
6
+ import { createFileMetadataString, isNotDuplicate } from '../helpers.js'
7
+ import type { HybridObjectSpec } from '../HybridObjectSpec.js'
8
+ import { Method } from '../Method.js'
9
+ import type { Property } from '../Property.js'
10
+ import type { SourceFile, SourceImport } from '../SourceFile.js'
11
+ import type { Type } from '../types/Type.js'
12
+ import { addJNINativeRegistration } from './JNINativeRegistrations.js'
13
+ import { KotlinCxxBridgedType } from './KotlinCxxBridgedType.js'
14
+
15
+ export function createFbjniHybridObject(spec: HybridObjectSpec): SourceFile[] {
16
+ const name = getHybridObjectName(spec.name)
17
+
18
+ // Because we cache JNI methods as `static` inside our method bodies,
19
+ // we need to re-create the method bodies per inherited class.
20
+ // This way `Child`'s statically cached `someMethod()` JNI reference
21
+ // is not the same as `Base`'s statically cached `someMethod()` JNI reference.
22
+ const properties = [
23
+ ...spec.properties,
24
+ ...spec.baseTypes.flatMap((b) => b.properties),
25
+ ]
26
+ const methods = [...spec.methods, ...spec.baseTypes.flatMap((b) => b.methods)]
27
+
28
+ const propertiesDecl = properties
29
+ .map((p) => p.getCode('c++', { override: true }))
30
+ .join('\n')
31
+ const methodsDecl = methods
32
+ .map((p) => p.getCode('c++', { override: true }))
33
+ .join('\n')
34
+ const jniClassDescriptor = spec.config.getAndroidPackage(
35
+ 'c++/jni',
36
+ name.HybridTSpec
37
+ )
38
+ const cxxNamespace = spec.config.getCxxNamespace('c++')
39
+ const spaces = createIndentation(name.JHybridTSpec.length)
40
+
41
+ let cppBase = 'JHybridObject'
42
+ if (spec.baseTypes.length > 0) {
43
+ if (spec.baseTypes.length > 1) {
44
+ throw new Error(
45
+ `${name.T}: Inheriting from multiple HybridObject bases is not yet supported on Kotlin!`
46
+ )
47
+ }
48
+ const base = spec.baseTypes[0]!
49
+ cppBase = getHybridObjectName(base.name).JHybridTSpec
50
+ if (base.config.isExternalConfig) {
51
+ // It's an external type we inherit from - we have to prefix the namespace
52
+ cppBase = base.config.getCxxNamespace('c++', cppBase)
53
+ }
54
+ }
55
+ const cppImports: SourceImport[] = []
56
+ for (const base of spec.baseTypes) {
57
+ const { JHybridTSpec } = getHybridObjectName(base.name)
58
+
59
+ const headerName = base.config.isExternalConfig
60
+ ? `${base.config.getAndroidCxxLibName()}/${JHybridTSpec}.hpp`
61
+ : `${JHybridTSpec}.hpp`
62
+ cppImports.push({
63
+ language: 'c++',
64
+ name: headerName,
65
+ space: base.config.isExternalConfig ? 'system' : 'user',
66
+ forwardDeclaration: getForwardDeclaration(
67
+ 'class',
68
+ JHybridTSpec,
69
+ base.config.getCxxNamespace('c++')
70
+ ),
71
+ })
72
+ }
73
+
74
+ const cppHeaderCode = `
75
+ ${createFileMetadataString(`${name.HybridTSpec}.hpp`)}
76
+
77
+ #pragma once
78
+
79
+ #include <NitroModules/JHybridObject.hpp>
80
+ #include <fbjni/fbjni.h>
81
+ #include "${name.HybridTSpec}.hpp"
82
+
83
+ ${cppImports
84
+ .map((i) => i.forwardDeclaration)
85
+ .filter((f) => f != null)
86
+ .join('\n')}
87
+ ${cppImports.map((i) => includeHeader(i)).join('\n')}
88
+
89
+ namespace ${cxxNamespace} {
90
+
91
+ using namespace facebook;
92
+
93
+ class ${name.JHybridTSpec}: public jni::HybridClass<${name.JHybridTSpec}, ${cppBase}>,
94
+ ${spaces} public virtual ${name.HybridTSpec} {
95
+ public:
96
+ static auto constexpr kJavaDescriptor = "L${jniClassDescriptor};";
97
+ static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis);
98
+ static void registerNatives();
99
+
100
+ protected:
101
+ // C++ constructor (called from Java via \`initHybrid()\`)
102
+ explicit ${name.JHybridTSpec}(jni::alias_ref<jhybridobject> jThis) :
103
+ HybridObject(${name.HybridTSpec}::TAG),
104
+ HybridBase(jThis),
105
+ _javaPart(jni::make_global(jThis)) {}
106
+
107
+ public:
108
+ ~${name.JHybridTSpec}() override {
109
+ // Hermes GC can destroy JS objects on a non-JNI Thread.
110
+ jni::ThreadScope::WithClassLoader([&] { _javaPart.reset(); });
111
+ }
112
+
113
+ public:
114
+ size_t getExternalMemorySize() noexcept override;
115
+ void dispose() noexcept override;
116
+
117
+ public:
118
+ inline const jni::global_ref<${name.JHybridTSpec}::javaobject>& getJavaPart() const noexcept {
119
+ return _javaPart;
120
+ }
121
+
122
+ public:
123
+ // Properties
124
+ ${indent(propertiesDecl, ' ')}
125
+
126
+ public:
127
+ // Methods
128
+ ${indent(methodsDecl, ' ')}
129
+
130
+ private:
131
+ friend HybridBase;
132
+ using HybridBase::HybridBase;
133
+ jni::global_ref<${name.JHybridTSpec}::javaobject> _javaPart;
134
+ };
135
+
136
+ } // namespace ${cxxNamespace}
137
+ `.trim()
138
+
139
+ // Make sure we register all native JNI methods on app startup
140
+ addJNINativeRegistration({
141
+ namespace: cxxNamespace,
142
+ className: `${name.JHybridTSpec}`,
143
+ import: {
144
+ name: `${name.JHybridTSpec}.hpp`,
145
+ space: 'user',
146
+ language: 'c++',
147
+ },
148
+ })
149
+
150
+ const propertiesImpl = properties
151
+ .map((m) => getFbjniPropertyForwardImplementation(spec, m))
152
+ .join('\n')
153
+ const methodsImpl = methods
154
+ .map((m) => getFbjniMethodForwardImplementation(spec, m, m.name))
155
+ .join('\n')
156
+ const allTypes = getAllTypes(spec)
157
+ allTypes.push(...getAllBaseTypes(spec)) // <-- remember, we copy all base methods & properties over too
158
+ const jniImports = allTypes
159
+ .map((t) => new KotlinCxxBridgedType(t))
160
+ .flatMap((t) => t.getRequiredImports('c++'))
161
+ .filter((i) => i != null)
162
+ const cppIncludes = jniImports
163
+ .map((i) => includeHeader(i))
164
+ .filter(isNotDuplicate)
165
+ const cppForwardDeclarations = jniImports
166
+ .map((i) => i.forwardDeclaration)
167
+ .filter((d) => d != null)
168
+ .filter(isNotDuplicate)
169
+
170
+ const cppImplCode = `
171
+ ${createFileMetadataString(`${name.JHybridTSpec}.cpp`)}
172
+
173
+ #include "${name.JHybridTSpec}.hpp"
174
+
175
+ ${cppForwardDeclarations.join('\n')}
176
+
177
+ ${cppIncludes.join('\n')}
178
+
179
+ namespace ${cxxNamespace} {
180
+
181
+ jni::local_ref<${name.JHybridTSpec}::jhybriddata> ${name.JHybridTSpec}::initHybrid(jni::alias_ref<jhybridobject> jThis) {
182
+ return makeCxxInstance(jThis);
183
+ }
184
+
185
+ void ${name.JHybridTSpec}::registerNatives() {
186
+ registerHybrid({
187
+ makeNativeMethod("initHybrid", ${name.JHybridTSpec}::initHybrid),
188
+ });
189
+ }
190
+
191
+ size_t ${name.JHybridTSpec}::getExternalMemorySize() noexcept {
192
+ static const auto method = javaClassStatic()->getMethod<jlong()>("getMemorySize");
193
+ return method(_javaPart);
194
+ }
195
+
196
+ void ${name.JHybridTSpec}::dispose() noexcept {
197
+ static const auto method = javaClassStatic()->getMethod<void()>("dispose");
198
+ method(_javaPart);
199
+ }
200
+
201
+ // Properties
202
+ ${indent(propertiesImpl, ' ')}
203
+
204
+ // Methods
205
+ ${indent(methodsImpl, ' ')}
206
+
207
+ } // namespace ${cxxNamespace}
208
+ `.trim()
209
+
210
+ const files: SourceFile[] = []
211
+ files.push({
212
+ content: cppHeaderCode,
213
+ language: 'c++',
214
+ name: `${name.JHybridTSpec}.hpp`,
215
+ subdirectory: [],
216
+ platform: 'android',
217
+ })
218
+ files.push({
219
+ content: cppImplCode,
220
+ language: 'c++',
221
+ name: `${name.JHybridTSpec}.cpp`,
222
+ subdirectory: [],
223
+ platform: 'android',
224
+ })
225
+ return files
226
+ }
227
+
228
+ function getFbjniMethodForwardImplementation(
229
+ spec: HybridObjectSpec,
230
+ method: Method,
231
+ jniMethodName: string
232
+ ): string {
233
+ const name = getHybridObjectName(spec.name)
234
+
235
+ const returnJNI = new KotlinCxxBridgedType(method.returnType)
236
+ const requiresBridge =
237
+ returnJNI.needsSpecialHandling ||
238
+ method.parameters.some((p) => {
239
+ const bridged = new KotlinCxxBridgedType(p.type)
240
+ return bridged.needsSpecialHandling
241
+ })
242
+ const methodName = requiresBridge ? `${jniMethodName}_cxx` : jniMethodName
243
+
244
+ const returnType = returnJNI.asJniReferenceType('local')
245
+ const paramsTypes = method.parameters
246
+ .map((p) => {
247
+ const bridge = new KotlinCxxBridgedType(p.type)
248
+ return `${bridge.asJniReferenceType('alias')} /* ${p.name} */`
249
+ })
250
+ .join(', ')
251
+ const cxxSignature = `${returnType}(${paramsTypes})`
252
+
253
+ const paramsForward = method.parameters.map((p) => {
254
+ const bridged = new KotlinCxxBridgedType(p.type)
255
+ return bridged.parse(p.name, 'c++', 'kotlin', 'c++')
256
+ })
257
+ paramsForward.unshift('_javaPart') // <-- first param is always Java `this`
258
+
259
+ let body: string
260
+ if (returnJNI.hasType) {
261
+ // return something - we need to parse it
262
+ body = `
263
+ static const auto method = javaClassStatic()->getMethod<${cxxSignature}>("${methodName}");
264
+ auto __result = method(${paramsForward.join(', ')});
265
+ return ${returnJNI.parse('__result', 'kotlin', 'c++', 'c++')};
266
+ `
267
+ } else {
268
+ // void method. no return
269
+ body = `
270
+ static const auto method = javaClassStatic()->getMethod<${cxxSignature}>("${methodName}");
271
+ method(${paramsForward.join(', ')});
272
+ `
273
+ }
274
+ const code = method.getCode(
275
+ 'c++',
276
+ {
277
+ classDefinitionName: name.JHybridTSpec,
278
+ },
279
+ body.trim()
280
+ )
281
+ return code
282
+ }
283
+
284
+ function getFbjniPropertyForwardImplementation(
285
+ spec: HybridObjectSpec,
286
+ property: Property
287
+ ): string {
288
+ const methods: string[] = []
289
+
290
+ // getter
291
+ const getter = getFbjniMethodForwardImplementation(
292
+ spec,
293
+ property.cppGetter,
294
+ property.getGetterName('jvm')
295
+ )
296
+ methods.push(getter)
297
+
298
+ if (property.cppSetter != null) {
299
+ // setter
300
+ const setter = getFbjniMethodForwardImplementation(
301
+ spec,
302
+ property.cppSetter,
303
+ property.getSetterName('jvm')
304
+ )
305
+ methods.push(setter)
306
+ }
307
+
308
+ return methods.join('\n')
309
+ }
310
+
311
+ function getAllBaseTypes(spec: HybridObjectSpec): Type[] {
312
+ return spec.baseTypes.flatMap((b) => getAllTypes(b))
313
+ }
@@ -0,0 +1,19 @@
1
+ import type { SourceImport } from '../SourceFile.js'
2
+
3
+ export interface JNINativeRegistration {
4
+ namespace: string
5
+ className: string
6
+ import: SourceImport
7
+ }
8
+
9
+ const jniNativeRegistrations: JNINativeRegistration[] = []
10
+
11
+ export function addJNINativeRegistration(
12
+ registerFunc: JNINativeRegistration
13
+ ): void {
14
+ jniNativeRegistrations.push(registerFunc)
15
+ }
16
+
17
+ export function getJNINativeRegistrations(): JNINativeRegistration[] {
18
+ return jniNativeRegistrations
19
+ }
@@ -0,0 +1,19 @@
1
+ import type { Type } from '../types/Type.js'
2
+
3
+ /**
4
+ * Returns a boxed version of the given primitive type.
5
+ * In JNI/Kotlin, primitive types (like `double` or `boolean`)
6
+ * cannot be nullable, so we need to box them - e.g. as `JDouble` or `JBoolean`.
7
+ */
8
+ export function getKotlinBoxedPrimitiveType(type: Type): string {
9
+ switch (type.kind) {
10
+ case 'number':
11
+ return 'jni::JDouble'
12
+ case 'boolean':
13
+ return 'jni::JBoolean'
14
+ case 'bigint':
15
+ return 'jni::JLong'
16
+ default:
17
+ throw new Error(`Type ${type.kind} is not a primitive!`)
18
+ }
19
+ }