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,942 @@
1
+ import type { Language } from '../../getPlatformSpecs.js'
2
+ import { indent } from '../../utils.js'
3
+ import type { BridgedType } from '../BridgedType.js'
4
+ import { getHybridObjectName } from '../getHybridObjectName.js'
5
+ import { getReferencedTypes } from '../getReferencedTypes.js'
6
+ import type { SourceFile, SourceImport } from '../SourceFile.js'
7
+ import { ArrayType } from '../types/ArrayType.js'
8
+ import { EnumType } from '../types/EnumType.js'
9
+ import { FunctionType } from '../types/FunctionType.js'
10
+ import { getTypeAs } from '../types/getTypeAs.js'
11
+ import { HybridObjectType } from '../types/HybridObjectType.js'
12
+ import { OptionalType } from '../types/OptionalType.js'
13
+ import { PromiseType } from '../types/PromiseType.js'
14
+ import { RecordType } from '../types/RecordType.js'
15
+ import { StructType } from '../types/StructType.js'
16
+ import type { Type } from '../types/Type.js'
17
+ import { VariantType } from '../types/VariantType.js'
18
+ import { getKotlinBoxedPrimitiveType } from './KotlinBoxedPrimitive.js'
19
+ import { createKotlinEnum } from './KotlinEnum.js'
20
+ import { createKotlinFunction } from './KotlinFunction.js'
21
+ import { createKotlinStruct } from './KotlinStruct.js'
22
+ import { createKotlinVariant } from './KotlinVariant.js'
23
+
24
+ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
25
+ readonly type: Type
26
+
27
+ constructor(type: Type) {
28
+ this.type = type
29
+ }
30
+
31
+ get hasType(): boolean {
32
+ return this.type.kind !== 'void' && this.type.kind !== 'null'
33
+ }
34
+
35
+ get canBePassedByReference(): boolean {
36
+ return this.type.canBePassedByReference
37
+ }
38
+
39
+ get needsSpecialHandling(): boolean {
40
+ switch (this.type.kind) {
41
+ case 'function':
42
+ // Function needs to be converted from JFunc_... to Lambda
43
+ return true
44
+ case 'struct':
45
+ // Structs don't need special handling - they have direct mappings
46
+ // Returning false prevents secondary constructor generation that causes duplicates
47
+ return false
48
+ case 'optional':
49
+ // Optionals need special handling if the wrapped type needs special handling
50
+ const optional = getTypeAs(this.type, OptionalType)
51
+ return new KotlinCxxBridgedType(optional.wrappingType)
52
+ .needsSpecialHandling
53
+ default:
54
+ break
55
+ }
56
+ // check if any types this type references (e.g. underlying optional, array element, ...)
57
+ // needs special handling. if yes, we need it as well
58
+ const referencedTypes = getReferencedTypes(this.type)
59
+ .filter((t) => t !== this.type)
60
+ .map((t) => new KotlinCxxBridgedType(t))
61
+ for (const type of referencedTypes) {
62
+ if (type.needsSpecialHandling) {
63
+ return true
64
+ }
65
+ }
66
+ // no special handling needed
67
+ return false
68
+ }
69
+
70
+ getRequiredImports(language: Language): SourceImport[] {
71
+ const imports = this.type.getRequiredImports(language)
72
+
73
+ if (language === 'c++') {
74
+ // All C++ imports we need for the JNI bridge
75
+ switch (this.type.kind) {
76
+ case 'enum':
77
+ const enumType = getTypeAs(this.type, EnumType)
78
+ imports.push({
79
+ language: 'c++',
80
+ name: `J${enumType.enumName}.hpp`,
81
+ space: 'user',
82
+ })
83
+ break
84
+ case 'struct':
85
+ const structType = getTypeAs(this.type, StructType)
86
+ imports.push({
87
+ language: 'c++',
88
+ name: `J${structType.structName}.hpp`,
89
+ space: 'user',
90
+ })
91
+ break
92
+ case 'function':
93
+ const functionType = getTypeAs(this.type, FunctionType)
94
+ imports.push({
95
+ language: 'c++',
96
+ name: `J${functionType.specializationName}.hpp`,
97
+ space: 'user',
98
+ })
99
+ break
100
+ case 'array-buffer':
101
+ imports.push({
102
+ language: 'c++',
103
+ name: 'NitroModules/JArrayBuffer.hpp',
104
+ space: 'system',
105
+ })
106
+ imports.push({
107
+ language: 'c++',
108
+ name: 'NitroModules/JUnit.hpp',
109
+ space: 'system',
110
+ })
111
+ break
112
+ case 'promise':
113
+ imports.push({
114
+ language: 'c++',
115
+ name: 'NitroModules/JPromise.hpp',
116
+ space: 'system',
117
+ })
118
+ break
119
+ case 'date':
120
+ imports.push({
121
+ language: 'c++',
122
+ name: 'NitroModules/JInstant.hpp',
123
+ space: 'system',
124
+ })
125
+ break
126
+ case 'map':
127
+ imports.push({
128
+ language: 'c++',
129
+ name: 'NitroModules/JAnyMap.hpp',
130
+ space: 'system',
131
+ })
132
+ break
133
+ case 'variant':
134
+ const variantType = getTypeAs(this.type, VariantType)
135
+ const variantName = variantType.getAliasName('kotlin')
136
+ imports.push({
137
+ language: 'c++',
138
+ name: `J${variantName}.hpp`,
139
+ space: 'user',
140
+ })
141
+ break
142
+ case 'hybrid-object': {
143
+ const hybridObjectType = getTypeAs(this.type, HybridObjectType)
144
+ const name = getHybridObjectName(hybridObjectType.hybridObjectName)
145
+ if (hybridObjectType.sourceConfig.isExternalConfig) {
146
+ // It's an externally imported type
147
+ imports.push({
148
+ language: 'c++',
149
+ name: `${hybridObjectType.sourceConfig.getAndroidCxxLibName()}/${name.JHybridTSpec}.hpp`,
150
+ space: 'system',
151
+ })
152
+ } else {
153
+ // It's our custom type
154
+ imports.push({
155
+ language: 'c++',
156
+ name: `${name.JHybridTSpec}.hpp`,
157
+ space: 'user',
158
+ })
159
+ }
160
+ break
161
+ }
162
+ }
163
+ }
164
+
165
+ // Recursively look into referenced types (e.g. the `T` of a `optional<T>`, or `T` of a `T[]`)
166
+ const referencedTypes = getReferencedTypes(this.type)
167
+ referencedTypes.forEach((t) => {
168
+ if (t === this.type) {
169
+ // break a recursion - we already know this type
170
+ return
171
+ }
172
+ const bridged = new KotlinCxxBridgedType(t)
173
+ imports.push(...bridged.getRequiredImports(language))
174
+ })
175
+
176
+ return imports
177
+ }
178
+
179
+ getExtraFiles(): SourceFile[] {
180
+ const files: SourceFile[] = []
181
+
182
+ switch (this.type.kind) {
183
+ case 'enum':
184
+ const enumType = getTypeAs(this.type, EnumType)
185
+ const enumFiles = createKotlinEnum(enumType)
186
+ files.push(...enumFiles)
187
+ break
188
+ case 'struct':
189
+ const structType = getTypeAs(this.type, StructType)
190
+ const structFiles = createKotlinStruct(structType)
191
+ files.push(...structFiles)
192
+ break
193
+ case 'variant':
194
+ const variantType = getTypeAs(this.type, VariantType)
195
+ const variantFiles = createKotlinVariant(variantType)
196
+ files.push(...variantFiles)
197
+ break
198
+ case 'function':
199
+ const functionType = getTypeAs(this.type, FunctionType)
200
+ const funcFiles = createKotlinFunction(functionType)
201
+ files.push(...funcFiles)
202
+ break
203
+ }
204
+
205
+ // Recursively look into referenced types (e.g. the `T` of a `optional<T>`, or `T` of a `T[]`)
206
+ const referencedTypes = getReferencedTypes(this.type)
207
+ referencedTypes.forEach((t) => {
208
+ if (t === this.type) {
209
+ // break a recursion - we already know this type
210
+ return
211
+ }
212
+ const bridged = new KotlinCxxBridgedType(t)
213
+ files.push(...bridged.getExtraFiles())
214
+ })
215
+
216
+ return files
217
+ }
218
+
219
+ asJniReferenceType(referenceType: 'alias' | 'local' | 'global' = 'alias') {
220
+ switch (this.type.kind) {
221
+ case 'void':
222
+ case 'number':
223
+ case 'boolean':
224
+ case 'bigint':
225
+ // primitives are not references
226
+ return this.getTypeCode('c++')
227
+ default:
228
+ return `jni::${referenceType}_ref<${this.getTypeCode('c++')}>`
229
+ }
230
+ }
231
+
232
+ getTypeCode(language: 'kotlin' | 'c++', isBoxed = false): string {
233
+ switch (this.type.kind) {
234
+ case 'number':
235
+ case 'bigint':
236
+ case 'boolean':
237
+ if (isBoxed) {
238
+ return getKotlinBoxedPrimitiveType(this.type)
239
+ } else {
240
+ if (this.type.kind === 'boolean' && language === 'c++') {
241
+ // JNI does not use `bool`, so it is a jboolean instead.
242
+ return 'jboolean'
243
+ }
244
+ return this.type.getCode(language)
245
+ }
246
+ case 'array':
247
+ const array = getTypeAs(this.type, ArrayType)
248
+ const bridgedItem = new KotlinCxxBridgedType(array.itemType)
249
+ switch (language) {
250
+ case 'c++':
251
+ switch (array.itemType.kind) {
252
+ case 'number':
253
+ return 'jni::JArrayDouble'
254
+ case 'boolean':
255
+ return 'jni::JArrayBoolean'
256
+ case 'bigint':
257
+ return 'jni::JArrayLong'
258
+ default:
259
+ return `jni::JArrayClass<${bridgedItem.getTypeCode(language)}>`
260
+ }
261
+ case 'kotlin':
262
+ switch (array.itemType.kind) {
263
+ case 'number':
264
+ return 'DoubleArray'
265
+ case 'boolean':
266
+ return 'BooleanArray'
267
+ case 'bigint':
268
+ return 'LongArray'
269
+ default:
270
+ return `Array<${bridgedItem.getTypeCode(language)}>`
271
+ }
272
+ default:
273
+ return this.type.getCode(language)
274
+ }
275
+ case 'string':
276
+ switch (language) {
277
+ case 'c++':
278
+ return 'jni::JString'
279
+ default:
280
+ return this.type.getCode(language)
281
+ }
282
+ case 'record': {
283
+ switch (language) {
284
+ case 'c++':
285
+ const recordType = getTypeAs(this.type, RecordType)
286
+ const keyType = new KotlinCxxBridgedType(
287
+ recordType.keyType
288
+ ).getTypeCode(language)
289
+ const valueType = new KotlinCxxBridgedType(
290
+ recordType.valueType
291
+ ).getTypeCode(language)
292
+ return `jni::JMap<${keyType}, ${valueType}>`
293
+ default:
294
+ return this.type.getCode(language)
295
+ }
296
+ }
297
+ case 'enum':
298
+ switch (language) {
299
+ case 'c++':
300
+ const enumType = getTypeAs(this.type, EnumType)
301
+ return `J${enumType.enumName}`
302
+ default:
303
+ return this.type.getCode(language)
304
+ }
305
+ case 'struct':
306
+ switch (language) {
307
+ case 'c++':
308
+ const structType = getTypeAs(this.type, StructType)
309
+ return `J${structType.structName}`
310
+ default:
311
+ return this.type.getCode(language)
312
+ }
313
+ case 'function':
314
+ const functionType = getTypeAs(this.type, FunctionType)
315
+ switch (language) {
316
+ case 'c++':
317
+ return `J${functionType.specializationName}::javaobject`
318
+ case 'kotlin':
319
+ return functionType.specializationName
320
+ default:
321
+ return this.type.getCode(language)
322
+ }
323
+ case 'hybrid-object': {
324
+ switch (language) {
325
+ case 'c++':
326
+ const hybridObjectType = getTypeAs(this.type, HybridObjectType)
327
+ const fullName = this.getFullJHybridObjectName(hybridObjectType)
328
+ return `${fullName}::javaobject`
329
+ default:
330
+ return this.type.getCode(language)
331
+ }
332
+ }
333
+ case 'array-buffer':
334
+ switch (language) {
335
+ case 'c++':
336
+ return `JArrayBuffer::javaobject`
337
+ default:
338
+ return this.type.getCode(language)
339
+ }
340
+ case 'date':
341
+ switch (language) {
342
+ case 'c++':
343
+ return `JInstant`
344
+ default:
345
+ return this.type.getCode(language)
346
+ }
347
+ case 'variant': {
348
+ const variant = getTypeAs(this.type, VariantType)
349
+ const name = variant.getAliasName('kotlin')
350
+ switch (language) {
351
+ case 'c++':
352
+ return `J${name}`
353
+ case 'kotlin':
354
+ return name
355
+ default:
356
+ return this.type.getCode(language)
357
+ }
358
+ }
359
+ case 'promise':
360
+ switch (language) {
361
+ case 'c++':
362
+ return `JPromise::javaobject`
363
+ default:
364
+ return this.type.getCode(language)
365
+ }
366
+ case 'map':
367
+ switch (language) {
368
+ case 'c++':
369
+ return `JAnyMap::javaobject`
370
+ default:
371
+ return this.type.getCode(language)
372
+ }
373
+ case 'optional': {
374
+ const optional = getTypeAs(this.type, OptionalType)
375
+ const bridgedWrappingType = new KotlinCxxBridgedType(
376
+ optional.wrappingType
377
+ )
378
+ switch (language) {
379
+ case 'c++':
380
+ switch (optional.wrappingType.kind) {
381
+ // primitives need to be boxed to make them nullable
382
+ case 'number':
383
+ case 'boolean':
384
+ case 'bigint':
385
+ const boxed = getKotlinBoxedPrimitiveType(optional.wrappingType)
386
+ return boxed
387
+ default:
388
+ // all other types can be nullable as they are objects.
389
+ return bridgedWrappingType.getTypeCode('c++')
390
+ }
391
+ case 'kotlin':
392
+ return `${bridgedWrappingType.getTypeCode(language)}?`
393
+ default:
394
+ return this.type.getCode(language)
395
+ }
396
+ }
397
+ case 'error':
398
+ switch (language) {
399
+ case 'c++':
400
+ return 'jni::JThrowable'
401
+ default:
402
+ return this.type.getCode(language)
403
+ }
404
+ default:
405
+ return this.type.getCode(language)
406
+ }
407
+ }
408
+
409
+ parse(
410
+ parameterName: string,
411
+ from: 'c++' | 'kotlin',
412
+ to: 'kotlin' | 'c++',
413
+ inLanguage: 'kotlin' | 'c++'
414
+ ): string {
415
+ if (from === 'c++') {
416
+ return this.parseFromCppToKotlin(parameterName, inLanguage)
417
+ } else if (from === 'kotlin') {
418
+ return this.parseFromKotlinToCpp(parameterName, inLanguage)
419
+ } else {
420
+ throw new Error(`Cannot parse "${parameterName}" from ${from} to ${to}!`)
421
+ }
422
+ }
423
+
424
+ parseFromCppToKotlin(
425
+ parameterName: string,
426
+ language: 'kotlin' | 'c++',
427
+ isBoxed = false
428
+ ): string {
429
+ switch (this.type.kind) {
430
+ case 'number':
431
+ case 'boolean':
432
+ case 'bigint':
433
+ switch (language) {
434
+ case 'c++':
435
+ if (isBoxed) {
436
+ // box a primitive (double) to an object (JDouble)
437
+ const boxed = getKotlinBoxedPrimitiveType(this.type)
438
+ return `${boxed}::valueOf(${parameterName})`
439
+ } else {
440
+ return parameterName
441
+ }
442
+ default:
443
+ return parameterName
444
+ }
445
+ case 'string':
446
+ switch (language) {
447
+ case 'c++':
448
+ return `jni::make_jstring(${parameterName})`
449
+ default:
450
+ return parameterName
451
+ }
452
+ case 'struct': {
453
+ switch (language) {
454
+ case 'c++':
455
+ const struct = getTypeAs(this.type, StructType)
456
+ return `J${struct.structName}::fromCpp(${parameterName})`
457
+ default:
458
+ return parameterName
459
+ }
460
+ }
461
+ case 'variant': {
462
+ switch (language) {
463
+ case 'c++':
464
+ const variant = getTypeAs(this.type, VariantType)
465
+ const name = variant.getAliasName('kotlin')
466
+ return `J${name}::fromCpp(${parameterName})`
467
+ default:
468
+ return parameterName
469
+ }
470
+ }
471
+ case 'date': {
472
+ switch (language) {
473
+ case 'c++':
474
+ return `JInstant::fromChrono(${parameterName})`
475
+ default:
476
+ return parameterName
477
+ }
478
+ }
479
+ case 'enum': {
480
+ switch (language) {
481
+ case 'c++':
482
+ const enumType = getTypeAs(this.type, EnumType)
483
+ return `J${enumType.enumName}::fromCpp(${parameterName})`
484
+ default:
485
+ return parameterName
486
+ }
487
+ }
488
+ case 'function': {
489
+ switch (language) {
490
+ case 'c++':
491
+ const func = getTypeAs(this.type, FunctionType)
492
+ return `J${func.specializationName}_cxx::fromCpp(${parameterName})`
493
+ case 'kotlin':
494
+ return parameterName
495
+ default:
496
+ return parameterName
497
+ }
498
+ }
499
+ case 'hybrid-object': {
500
+ switch (language) {
501
+ case 'c++':
502
+ const hybrid = getTypeAs(this.type, HybridObjectType)
503
+ const fullName = this.getFullJHybridObjectName(hybrid)
504
+ return `std::dynamic_pointer_cast<${fullName}>(${parameterName})->getJavaPart()`
505
+ default:
506
+ return parameterName
507
+ }
508
+ }
509
+ case 'optional': {
510
+ const optional = getTypeAs(this.type, OptionalType)
511
+ const bridge = new KotlinCxxBridgedType(optional.wrappingType)
512
+ switch (language) {
513
+ case 'c++':
514
+ return `${parameterName}.has_value() ? ${bridge.parseFromCppToKotlin(`${parameterName}.value()`, 'c++', true)} : nullptr`
515
+ case 'kotlin':
516
+ if (bridge.needsSpecialHandling) {
517
+ return `${parameterName}?.let { ${bridge.parseFromCppToKotlin('it', language, isBoxed)} }`
518
+ } else {
519
+ return parameterName
520
+ }
521
+ default:
522
+ return parameterName
523
+ }
524
+ }
525
+ case 'array-buffer': {
526
+ switch (language) {
527
+ case 'c++':
528
+ return `JArrayBuffer::wrap(${parameterName})`
529
+ default:
530
+ return parameterName
531
+ }
532
+ }
533
+ case 'map': {
534
+ switch (language) {
535
+ case 'c++':
536
+ return `JAnyMap::create(${parameterName})`
537
+ default:
538
+ return parameterName
539
+ }
540
+ }
541
+ case 'record': {
542
+ switch (language) {
543
+ case 'c++':
544
+ const record = getTypeAs(this.type, RecordType)
545
+ const key = new KotlinCxxBridgedType(record.keyType)
546
+ const value = new KotlinCxxBridgedType(record.valueType)
547
+ const parseKey = key.parseFromCppToKotlin('__entry.first', 'c++')
548
+ const parseValue = value.parseFromCppToKotlin(
549
+ '__entry.second',
550
+ 'c++'
551
+ )
552
+ const javaMapType = `jni::JMap<${key.getTypeCode('c++')}, ${value.getTypeCode('c++')}>`
553
+ const javaHashMapType = `jni::JHashMap<${key.getTypeCode('c++')}, ${value.getTypeCode('c++')}>`
554
+ return `
555
+ [&]() -> jni::local_ref<${javaMapType}> {
556
+ auto __map = ${javaHashMapType}::create(${parameterName}.size());
557
+ for (const auto& __entry : ${parameterName}) {
558
+ __map->put(${indent(parseKey, ' ')}, ${indent(parseValue, ' ')});
559
+ }
560
+ return __map;
561
+ }()
562
+ `.trim()
563
+ default:
564
+ return parameterName
565
+ }
566
+ }
567
+ case 'array': {
568
+ const array = getTypeAs(this.type, ArrayType)
569
+ const arrayType = this.getTypeCode('c++')
570
+ const bridge = new KotlinCxxBridgedType(array.itemType)
571
+ switch (language) {
572
+ case 'c++': {
573
+ switch (array.itemType.kind) {
574
+ case 'number':
575
+ case 'boolean':
576
+ case 'bigint': {
577
+ // primitive arrays can be constructed more efficiently with region/batch access.
578
+ // no need to iterate through the entire array.
579
+ return `
580
+ [&]() {
581
+ size_t __size = ${parameterName}.size();
582
+ jni::local_ref<${arrayType}> __array = ${arrayType}::newArray(__size);
583
+ __array->setRegion(0, __size, ${parameterName}.data());
584
+ return __array;
585
+ }()
586
+ `.trim()
587
+ }
588
+ default: {
589
+ // other arrays need to loop through
590
+ return `
591
+ [&]() {
592
+ size_t __size = ${parameterName}.size();
593
+ jni::local_ref<${arrayType}> __array = ${arrayType}::newArray(__size);
594
+ for (size_t __i = 0; __i < __size; __i++) {
595
+ const auto& __element = ${parameterName}[__i];
596
+ __array->setElement(__i, *${indent(bridge.parseFromCppToKotlin('__element', 'c++'), ' ')});
597
+ }
598
+ return __array;
599
+ }()
600
+ `.trim()
601
+ }
602
+ }
603
+ }
604
+ case 'kotlin':
605
+ if (bridge.needsSpecialHandling) {
606
+ return `${parameterName}.map { ${bridge.parseFromCppToKotlin('it', language, isBoxed)} }`
607
+ } else {
608
+ return parameterName
609
+ }
610
+ default:
611
+ return parameterName
612
+ }
613
+ }
614
+ case 'promise': {
615
+ switch (language) {
616
+ case 'c++': {
617
+ const promise = getTypeAs(this.type, PromiseType)
618
+ const resolvingType = promise.resultingType.getCode('c++')
619
+ const bridge = new KotlinCxxBridgedType(promise.resultingType)
620
+ if (promise.resultingType.kind === 'void') {
621
+ // void: resolve()
622
+ return `
623
+ [&]() {
624
+ jni::local_ref<JPromise::javaobject> __localPromise = JPromise::create();
625
+ jni::global_ref<JPromise::javaobject> __promise = jni::make_global(__localPromise);
626
+ ${parameterName}->addOnResolvedListener([=]() {
627
+ __promise->cthis()->resolve(JUnit::instance());
628
+ });
629
+ ${parameterName}->addOnRejectedListener([=](const std::exception_ptr& __error) {
630
+ auto __jniError = jni::getJavaExceptionForCppException(__error);
631
+ __promise->cthis()->reject(__jniError);
632
+ });
633
+ return __localPromise;
634
+ }()
635
+ `.trim()
636
+ } else {
637
+ // T: resolve(T)
638
+ return `
639
+ [&]() {
640
+ jni::local_ref<JPromise::javaobject> __localPromise = JPromise::create();
641
+ jni::global_ref<JPromise::javaobject> __promise = jni::make_global(__localPromise);
642
+ ${parameterName}->addOnResolvedListener([=](const ${resolvingType}& __result) {
643
+ __promise->cthis()->resolve(${indent(bridge.parseFromCppToKotlin('__result', 'c++', true), ' ')});
644
+ });
645
+ ${parameterName}->addOnRejectedListener([=](const std::exception_ptr& __error) {
646
+ auto __jniError = jni::getJavaExceptionForCppException(__error);
647
+ __promise->cthis()->reject(__jniError);
648
+ });
649
+ return __localPromise;
650
+ }()
651
+ `.trim()
652
+ }
653
+ }
654
+ default:
655
+ return parameterName
656
+ }
657
+ }
658
+ case 'error':
659
+ switch (language) {
660
+ case 'c++':
661
+ return `jni::getJavaExceptionForCppException(${parameterName})`
662
+ default:
663
+ return parameterName
664
+ }
665
+ default:
666
+ // no need to parse anything, just return as is
667
+ return parameterName
668
+ }
669
+ }
670
+
671
+ parseFromKotlinToCpp(
672
+ parameterName: string,
673
+ language: 'kotlin' | 'c++',
674
+ isBoxed = false
675
+ ): string {
676
+ switch (this.type.kind) {
677
+ case 'number':
678
+ case 'boolean':
679
+ case 'bigint':
680
+ switch (language) {
681
+ case 'c++':
682
+ let code: string
683
+ if (isBoxed) {
684
+ // unbox an object (JDouble) to a primitive (double)
685
+ code = `${parameterName}->value()`
686
+ } else {
687
+ // it's just the primitive type directly
688
+ code = parameterName
689
+ }
690
+ if (this.type.kind === 'boolean') {
691
+ // jboolean =/= bool (it's a char in Java)
692
+ code = `static_cast<bool>(${code})`
693
+ }
694
+ return code
695
+ default:
696
+ return parameterName
697
+ }
698
+ case 'string':
699
+ switch (language) {
700
+ case 'c++':
701
+ return `${parameterName}->toStdString()`
702
+ default:
703
+ return parameterName
704
+ }
705
+ case 'struct':
706
+ case 'enum': {
707
+ switch (language) {
708
+ case 'c++':
709
+ return `${parameterName}->toCpp()`
710
+ default:
711
+ return parameterName
712
+ }
713
+ }
714
+ case 'variant': {
715
+ switch (language) {
716
+ case 'c++':
717
+ return `${parameterName}->toCpp()`
718
+ default:
719
+ return parameterName
720
+ }
721
+ }
722
+ case 'date': {
723
+ switch (language) {
724
+ case 'c++':
725
+ return `${parameterName}->toChrono()`
726
+ default:
727
+ return parameterName
728
+ }
729
+ }
730
+ case 'hybrid-object': {
731
+ switch (language) {
732
+ case 'c++':
733
+ const hybrid = getTypeAs(this.type, HybridObjectType)
734
+ const fullName = this.getFullJHybridObjectName(hybrid)
735
+ return `${parameterName}->cthis()->shared_cast<${fullName}>()`
736
+ default:
737
+ return parameterName
738
+ }
739
+ }
740
+ case 'optional': {
741
+ const optional = getTypeAs(this.type, OptionalType)
742
+ const bridge = new KotlinCxxBridgedType(optional.wrappingType)
743
+ switch (language) {
744
+ case 'c++':
745
+ const parsed = bridge.parseFromKotlinToCpp(
746
+ parameterName,
747
+ 'c++',
748
+ true
749
+ )
750
+ return `${parameterName} != nullptr ? std::make_optional(${parsed}) : std::nullopt`
751
+ case 'kotlin':
752
+ if (bridge.needsSpecialHandling) {
753
+ return `${parameterName}?.let { ${bridge.parseFromKotlinToCpp('it', language, isBoxed)} }`
754
+ } else {
755
+ return parameterName
756
+ }
757
+ default:
758
+ return parameterName
759
+ }
760
+ }
761
+ case 'function': {
762
+ const functionType = getTypeAs(this.type, FunctionType)
763
+ switch (language) {
764
+ case 'c++': {
765
+ const returnType = functionType.returnType.getCode('c++')
766
+ const params = functionType.parameters.map(
767
+ (p) => `${p.getCode('c++')} ${p.escapedName}`
768
+ )
769
+ const paramsForward = functionType.parameters.map(
770
+ (p) => p.escapedName
771
+ )
772
+ const jniType = `J${functionType.specializationName}_cxx`
773
+ return `
774
+ [&]() -> ${functionType.getCode('c++')} {
775
+ if (${parameterName}->isInstanceOf(${jniType}::javaClassStatic())) [[likely]] {
776
+ auto downcast = jni::static_ref_cast<${jniType}::javaobject>(${parameterName});
777
+ return downcast->cthis()->getFunction();
778
+ } else {
779
+ auto ${parameterName}Ref = jni::make_global(${parameterName});
780
+ return [${parameterName}Ref](${params.join(', ')}) -> ${returnType} {
781
+ return ${parameterName}Ref->invoke(${paramsForward});
782
+ };
783
+ }
784
+ }()
785
+ `.trim()
786
+ }
787
+ case 'kotlin': {
788
+ return `${functionType.specializationName}_java(${parameterName})`
789
+ }
790
+ default:
791
+ return parameterName
792
+ }
793
+ }
794
+ case 'array-buffer': {
795
+ switch (language) {
796
+ case 'c++':
797
+ return `${parameterName}->cthis()->getArrayBuffer()`
798
+ default:
799
+ return parameterName
800
+ }
801
+ }
802
+ case 'map': {
803
+ switch (language) {
804
+ case 'c++':
805
+ return `${parameterName}->cthis()->getMap()`
806
+ default:
807
+ return parameterName
808
+ }
809
+ }
810
+ case 'record': {
811
+ switch (language) {
812
+ case 'c++':
813
+ const record = getTypeAs(this.type, RecordType)
814
+ const key = new KotlinCxxBridgedType(record.keyType)
815
+ const value = new KotlinCxxBridgedType(record.valueType)
816
+ const parseKey = key.parseFromKotlinToCpp('__entry.first', 'c++')
817
+ const parseValue = value.parseFromKotlinToCpp(
818
+ '__entry.second',
819
+ 'c++'
820
+ )
821
+ const cxxType = this.type.getCode('c++')
822
+ return `
823
+ [&]() {
824
+ ${cxxType} __map;
825
+ __map.reserve(${parameterName}->size());
826
+ for (const auto& __entry : *${parameterName}) {
827
+ __map.emplace(${indent(parseKey, ' ')}, ${indent(parseValue, ' ')});
828
+ }
829
+ return __map;
830
+ }()
831
+ `.trim()
832
+ default:
833
+ return parameterName
834
+ }
835
+ }
836
+ case 'array': {
837
+ switch (language) {
838
+ case 'c++':
839
+ const array = getTypeAs(this.type, ArrayType)
840
+ const bridge = new KotlinCxxBridgedType(array.itemType)
841
+ const itemType = array.itemType.getCode('c++')
842
+ switch (array.itemType.kind) {
843
+ case 'number':
844
+ case 'boolean':
845
+ case 'bigint': {
846
+ // primitive arrays can use region/batch access,
847
+ // which we can use to construct the vector directly instead of looping through it.
848
+ return `
849
+ [&]() {
850
+ size_t __size = ${parameterName}->size();
851
+ std::vector<${itemType}> __vector(__size);
852
+ ${parameterName}->getRegion(0, __size, __vector.data());
853
+ return __vector;
854
+ }()
855
+ `.trim()
856
+ }
857
+ default: {
858
+ // other arrays need to loop through
859
+ return `
860
+ [&]() {
861
+ size_t __size = ${parameterName}->size();
862
+ std::vector<${itemType}> __vector;
863
+ __vector.reserve(__size);
864
+ for (size_t __i = 0; __i < __size; __i++) {
865
+ auto __element = ${parameterName}->getElement(__i);
866
+ __vector.push_back(${bridge.parseFromKotlinToCpp('__element', 'c++')});
867
+ }
868
+ return __vector;
869
+ }()
870
+ `.trim()
871
+ }
872
+ }
873
+ default:
874
+ return parameterName
875
+ }
876
+ }
877
+ case 'promise': {
878
+ switch (language) {
879
+ case 'c++':
880
+ const promise = getTypeAs(this.type, PromiseType)
881
+ const actualCppType = promise.resultingType.getCode('c++')
882
+ const resultingType = new KotlinCxxBridgedType(
883
+ promise.resultingType
884
+ )
885
+ let resolveBody: string
886
+ if (resultingType.hasType) {
887
+ // it's a Promise<T>
888
+ resolveBody = `
889
+ auto __result = jni::static_ref_cast<${resultingType.getTypeCode('c++', true)}>(__boxedResult);
890
+ __promise->resolve(${resultingType.parseFromKotlinToCpp('__result', 'c++', true)});
891
+ `.trim()
892
+ } else {
893
+ // it's a Promise<void>
894
+ resolveBody = `
895
+ __promise->resolve();
896
+ `.trim()
897
+ }
898
+ return `
899
+ [&]() {
900
+ auto __promise = Promise<${actualCppType}>::create();
901
+ ${parameterName}->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& ${resultingType.hasType ? '__boxedResult' : '/* unit */'}) {
902
+ ${indent(resolveBody, ' ')}
903
+ });
904
+ ${parameterName}->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
905
+ jni::JniException __jniError(__throwable);
906
+ __promise->reject(std::make_exception_ptr(__jniError));
907
+ });
908
+ return __promise;
909
+ }()
910
+ `.trim()
911
+ default:
912
+ return parameterName
913
+ }
914
+ }
915
+ case 'error':
916
+ switch (language) {
917
+ case 'c++':
918
+ return `jni::JniException(${parameterName})`
919
+ default:
920
+ return parameterName
921
+ }
922
+ default:
923
+ // no need to parse anything, just return as is
924
+ return parameterName
925
+ }
926
+ }
927
+
928
+ private getFullJHybridObjectName(hybridObject: HybridObjectType): string {
929
+ const name = getHybridObjectName(hybridObject.hybridObjectName)
930
+ if (hybridObject.sourceConfig.isExternalConfig) {
931
+ // fully qualified name like "margelo::nitro::image::JImage"
932
+ const fullName = hybridObject.sourceConfig.getCxxNamespace(
933
+ 'c++',
934
+ name.JHybridTSpec
935
+ )
936
+ return fullName
937
+ } else {
938
+ // relative name like "JImage"
939
+ return name.JHybridTSpec
940
+ }
941
+ }
942
+ }