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,129 @@
1
+ import type { FileWithReferencedTypes } from '../SourceFile.js'
2
+ import { indent } from '../../utils.js'
3
+ import { createFileMetadataString, isNotDuplicate } from '../helpers.js'
4
+ import type { NamedType } from '../types/Type.js'
5
+ import { includeHeader, includeNitroHeader } from './includeNitroHeader.js'
6
+ import { NitroConfig } from '../../config/NitroConfig.js'
7
+ import type { GetFunctionCodeOptions } from '../types/FunctionType.js'
8
+
9
+ export function createCppStruct(
10
+ typename: string,
11
+ properties: NamedType[]
12
+ ): FileWithReferencedTypes {
13
+ // Namespace typename
14
+ const fullyQualifiedTypename = NitroConfig.current.getCxxNamespace(
15
+ 'c++',
16
+ typename
17
+ )
18
+ // Get C++ code for all struct members
19
+ const cppStructProps = properties
20
+ .map((p) => `${p.getCode('c++')} ${p.escapedName} SWIFT_PRIVATE;`)
21
+ .join('\n')
22
+ const cppConstructorParams = properties
23
+ .map((p) => `${p.getCode('c++')} ${p.escapedName}`)
24
+ .join(', ')
25
+ const cppInitializerParams = properties
26
+ .map((p) => `${p.escapedName}(${p.escapedName})`)
27
+ .join(', ')
28
+ // Get C++ code for converting each member from a jsi::Value
29
+ const codeOptions: GetFunctionCodeOptions = {
30
+ fullyQualified: true,
31
+ includeNameInfo: false,
32
+ }
33
+ const cppFromJsiParams = properties
34
+ .map(
35
+ (p) =>
36
+ `JSIConverter<${p.getCode('c++', codeOptions)}>::fromJSI(runtime, obj.getProperty(runtime, "${p.name}"))`
37
+ )
38
+ .join(',\n')
39
+ // Get C++ code for converting each member to a jsi::Value
40
+ const cppToJsiCalls = properties
41
+ .map(
42
+ (p) =>
43
+ `obj.setProperty(runtime, "${p.name}", JSIConverter<${p.getCode('c++', codeOptions)}>::toJSI(runtime, arg.${p.escapedName}));`
44
+ )
45
+ .join('\n')
46
+ // Get C++ code for verifying if jsi::Value can be converted to type
47
+ const cppCanConvertCalls = properties
48
+ .map(
49
+ (p) =>
50
+ `if (!JSIConverter<${p.getCode('c++', codeOptions)}>::canConvert(runtime, obj.getProperty(runtime, "${p.name}"))) return false;`
51
+ )
52
+ .join('\n')
53
+
54
+ // Get C++ includes for each extra-file we need to include
55
+ const includedTypes = properties.flatMap((r) => r.getRequiredImports('c++'))
56
+ const cppForwardDeclarations = includedTypes
57
+ .map((i) => i.forwardDeclaration)
58
+ .filter((v) => v != null)
59
+ .filter(isNotDuplicate)
60
+ const cppExtraIncludes = includedTypes
61
+ .map((i) => includeHeader(i))
62
+ .filter(isNotDuplicate)
63
+ const cxxNamespace = NitroConfig.current.getCxxNamespace('c++')
64
+
65
+ const cppCode = `
66
+ ${createFileMetadataString(`${typename}.hpp`)}
67
+
68
+ #pragma once
69
+
70
+ ${includeNitroHeader('JSIConverter.hpp')}
71
+ ${includeNitroHeader('NitroDefines.hpp')}
72
+
73
+ ${cppForwardDeclarations.join('\n')}
74
+
75
+ ${cppExtraIncludes.join('\n')}
76
+
77
+ namespace ${cxxNamespace} {
78
+
79
+ /**
80
+ * A struct which can be represented as a JavaScript object (${typename}).
81
+ */
82
+ struct ${typename} {
83
+ public:
84
+ ${indent(cppStructProps, ' ')}
85
+
86
+ public:
87
+ ${typename}() = default;
88
+ explicit ${typename}(${cppConstructorParams}): ${cppInitializerParams} {}
89
+ };
90
+
91
+ } // namespace ${cxxNamespace}
92
+
93
+ namespace margelo::nitro {
94
+
95
+ // C++ ${typename} <> JS ${typename} (object)
96
+ template <>
97
+ struct JSIConverter<${fullyQualifiedTypename}> final {
98
+ static inline ${fullyQualifiedTypename} fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
99
+ jsi::Object obj = arg.asObject(runtime);
100
+ return ${fullyQualifiedTypename}(
101
+ ${indent(cppFromJsiParams, ' ')}
102
+ );
103
+ }
104
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const ${fullyQualifiedTypename}& arg) {
105
+ jsi::Object obj(runtime);
106
+ ${indent(cppToJsiCalls, ' ')}
107
+ return obj;
108
+ }
109
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
110
+ if (!value.isObject()) {
111
+ return false;
112
+ }
113
+ jsi::Object obj = value.getObject(runtime);
114
+ ${indent(cppCanConvertCalls, ' ')}
115
+ return true;
116
+ }
117
+ };
118
+
119
+ } // namespace margelo::nitro
120
+ `
121
+ return {
122
+ content: cppCode,
123
+ name: `${typename}.hpp`,
124
+ subdirectory: [],
125
+ language: 'c++',
126
+ referencedTypes: properties,
127
+ platform: 'shared',
128
+ }
129
+ }
@@ -0,0 +1,105 @@
1
+ import type { SourceFile } from '../SourceFile.js'
2
+ import { createFileMetadataString } from './../helpers.js'
3
+ import { indent, toLowerCamelCase } from '../../utils.js'
4
+ import type { EnumMember } from '../types/EnumType.js'
5
+ import { includeNitroHeader } from './includeNitroHeader.js'
6
+ import { NitroConfig } from '../../config/NitroConfig.js'
7
+
8
+ /**
9
+ * Creates a C++ enum that converts to a TypeScript union (aka just strings).
10
+ */
11
+ export function createCppUnion(
12
+ typename: string,
13
+ enumMembers: EnumMember[]
14
+ ): SourceFile {
15
+ // Namespace typename
16
+ const fullyQualifiedTypename = NitroConfig.current.getCxxNamespace(
17
+ 'c++',
18
+ typename
19
+ )
20
+ const cppEnumMembers = enumMembers
21
+ .map(
22
+ (m, i) => `${m.name} SWIFT_NAME(${toLowerCamelCase(m.name)}) = ${i},`
23
+ )
24
+ .join('\n')
25
+ const cppFromJsiHashCases = enumMembers
26
+ .map((v) =>
27
+ `case hashString("${v.stringValue}"): return ${fullyQualifiedTypename}::${v.name};`.trim()
28
+ )
29
+ .join('\n')
30
+ const cppToJsiCases = enumMembers
31
+ .map(
32
+ (v) =>
33
+ `case ${fullyQualifiedTypename}::${v.name}: return JSIConverter<std::string>::toJSI(runtime, "${v.stringValue}");`
34
+ )
35
+ .join('\n')
36
+ const cppCanConvertCases = enumMembers
37
+ .map((m) => `case hashString("${m.stringValue}"):`)
38
+ .join('\n')
39
+ const cxxNamespace = NitroConfig.current.getCxxNamespace('c++')
40
+
41
+ const cppCode = `
42
+ ${createFileMetadataString(`${typename}.hpp`)}
43
+
44
+ #pragma once
45
+
46
+ ${includeNitroHeader('NitroHash.hpp')}
47
+ ${includeNitroHeader('JSIConverter.hpp')}
48
+ ${includeNitroHeader('NitroDefines.hpp')}
49
+
50
+ namespace ${cxxNamespace} {
51
+
52
+ /**
53
+ * An enum which can be represented as a JavaScript union (${typename}).
54
+ */
55
+ enum class ${typename} {
56
+ ${indent(cppEnumMembers, ' ')}
57
+ } CLOSED_ENUM;
58
+
59
+ } // namespace ${cxxNamespace}
60
+
61
+ namespace margelo::nitro {
62
+
63
+ // C++ ${typename} <> JS ${typename} (union)
64
+ template <>
65
+ struct JSIConverter<${fullyQualifiedTypename}> final {
66
+ static inline ${fullyQualifiedTypename} fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
67
+ std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
68
+ switch (hashString(unionValue.c_str(), unionValue.size())) {
69
+ ${indent(cppFromJsiHashCases, ' ')}
70
+ default: [[unlikely]]
71
+ throw std::invalid_argument("Cannot convert \\"" + unionValue + "\\" to enum ${typename} - invalid value!");
72
+ }
73
+ }
74
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, ${fullyQualifiedTypename} arg) {
75
+ switch (arg) {
76
+ ${indent(cppToJsiCases, ' ')}
77
+ default: [[unlikely]]
78
+ throw std::invalid_argument("Cannot convert ${typename} to JS - invalid value: "
79
+ + std::to_string(static_cast<int>(arg)) + "!");
80
+ }
81
+ }
82
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
83
+ if (!value.isString()) {
84
+ return false;
85
+ }
86
+ std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
87
+ switch (hashString(unionValue.c_str(), unionValue.size())) {
88
+ ${indent(cppCanConvertCases, ' ')}
89
+ return true;
90
+ default:
91
+ return false;
92
+ }
93
+ }
94
+ };
95
+
96
+ } // namespace margelo::nitro
97
+ `
98
+ return {
99
+ content: cppCode,
100
+ name: `${typename}.hpp`,
101
+ subdirectory: [],
102
+ language: 'c++',
103
+ platform: 'shared',
104
+ }
105
+ }
@@ -0,0 +1,19 @@
1
+ type DeclarationKind = 'class' | 'struct' | 'enum class'
2
+
3
+ export function getForwardDeclaration(
4
+ kind: DeclarationKind,
5
+ className: string,
6
+ namespace?: string
7
+ ): string {
8
+ if (namespace != null) {
9
+ return `
10
+ // Forward declaration of \`${className}\` to properly resolve imports.
11
+ namespace ${namespace} { ${kind} ${className}; }
12
+ `.trim()
13
+ } else {
14
+ return `
15
+ // Forward declaration of \`${className}\` to properly resolve imports.
16
+ ${kind} ${className};
17
+ `.trim()
18
+ }
19
+ }
@@ -0,0 +1,40 @@
1
+ import type { SourceImport } from '../SourceFile.js'
2
+
3
+ /**
4
+ * Generates C++ code for including a `NitroModules` header.
5
+ * @example `Hash.hpp` -> `#include <NitroModules/Hash.hpp>`
6
+ */
7
+ export function includeNitroHeader(headerName: string): string {
8
+ return `
9
+ #if __has_include(<NitroModules/${headerName}>)
10
+ #include <NitroModules/${headerName}>
11
+ #else
12
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
13
+ #endif
14
+ `.trim()
15
+ }
16
+
17
+ export function includeHeader(
18
+ sourceImport: SourceImport,
19
+ force = true
20
+ ): string {
21
+ const header = getHeader(sourceImport.name, sourceImport.space)
22
+ if (force) {
23
+ return `#include ${header}`
24
+ } else {
25
+ return `
26
+ #if __has_include(${header})
27
+ #include ${header}
28
+ #endif
29
+ `.trim()
30
+ }
31
+ }
32
+
33
+ function getHeader(name: string, space: 'user' | 'system'): string {
34
+ switch (space) {
35
+ case 'user':
36
+ return `"${name}"`
37
+ case 'system':
38
+ return `<${name}>`
39
+ }
40
+ }
@@ -0,0 +1,365 @@
1
+ import { ts, Type as TSMorphType, type Signature } from 'ts-morph'
2
+ import type { Type } from './types/Type.js'
3
+ import { NullType } from './types/NullType.js'
4
+ import { BooleanType } from './types/BooleanType.js'
5
+ import { NumberType } from './types/NumberType.js'
6
+ import { StringType } from './types/StringType.js'
7
+ import { BigIntType } from './types/BigIntType.js'
8
+ import { VoidType } from './types/VoidType.js'
9
+ import { ArrayType } from './types/ArrayType.js'
10
+ import { FunctionType } from './types/FunctionType.js'
11
+ import { PromiseType } from './types/PromiseType.js'
12
+ import { RecordType } from './types/RecordType.js'
13
+ import { ArrayBufferType } from './types/ArrayBufferType.js'
14
+ import { EnumType } from './types/EnumType.js'
15
+ import { HybridObjectType } from './types/HybridObjectType.js'
16
+ import { StructType } from './types/StructType.js'
17
+ import { OptionalType } from './types/OptionalType.js'
18
+ import { NamedWrappingType } from './types/NamedWrappingType.js'
19
+ import { getInterfaceProperties } from './getInterfaceProperties.js'
20
+ import { VariantType } from './types/VariantType.js'
21
+ import { MapType } from './types/MapType.js'
22
+ import { TupleType } from './types/TupleType.js'
23
+ import {
24
+ isAnyHybridSubclass,
25
+ isDirectlyHybridObject,
26
+ isHybridView,
27
+ type Language,
28
+ } from '../getPlatformSpecs.js'
29
+ import { HybridObjectBaseType } from './types/HybridObjectBaseType.js'
30
+ import { ErrorType } from './types/ErrorType.js'
31
+ import { getBaseTypes, getHybridObjectNitroModuleConfig } from '../utils.js'
32
+ import { DateType } from './types/DateType.js'
33
+ import { NitroConfig } from '../config/NitroConfig.js'
34
+ import { CustomType } from './types/CustomType.js'
35
+ import {
36
+ isSyncFunction,
37
+ isArrayBuffer,
38
+ isCustomType,
39
+ isDate,
40
+ isError,
41
+ isMap,
42
+ isPromise,
43
+ isRecord,
44
+ } from './isCoreType.js'
45
+ import { getCustomTypeConfig } from './getCustomTypeConfig.js'
46
+
47
+ function getHybridObjectName(type: TSMorphType): string {
48
+ const symbol = isHybridView(type) ? type.getAliasSymbol() : type.getSymbol()
49
+ if (symbol == null) {
50
+ throw new Error(
51
+ `Cannot get name of \`${type.getText()}\` - symbol not found!`
52
+ )
53
+ }
54
+ return symbol.getEscapedName()
55
+ }
56
+
57
+ function getFunctionCallSignature(func: TSMorphType): Signature {
58
+ const callSignatures = func.getCallSignatures()
59
+ const callSignature = callSignatures[0]
60
+ if (callSignatures.length !== 1 || callSignature == null) {
61
+ throw new Error(
62
+ `Function overloads are not supported in Nitrogen! (in ${func.getText()})`
63
+ )
64
+ }
65
+ return callSignature
66
+ }
67
+
68
+ function removeDuplicates(types: Type[]): Type[] {
69
+ return types.filter((t1, index, array) => {
70
+ const firstIndexOfType = array.findIndex(
71
+ (t2) => t1.getCode('c++') === t2.getCode('c++')
72
+ )
73
+ return firstIndexOfType === index
74
+ })
75
+ }
76
+
77
+ type Tuple<
78
+ T,
79
+ N extends number,
80
+ R extends unknown[] = [],
81
+ > = R['length'] extends N ? R : Tuple<T, N, [T, ...R]>
82
+ function getArguments<N extends number>(
83
+ type: TSMorphType,
84
+ typename: string,
85
+ count: N
86
+ ): Tuple<TSMorphType<ts.Type>, N> {
87
+ const typeArguments = type.getTypeArguments()
88
+ if (typeArguments.length === count) {
89
+ return typeArguments as Tuple<TSMorphType<ts.Type>, N>
90
+ }
91
+
92
+ const aliasTypeArguments = type.getAliasTypeArguments()
93
+ if (aliasTypeArguments.length === count) {
94
+ return aliasTypeArguments as Tuple<TSMorphType<ts.Type>, N>
95
+ }
96
+
97
+ throw new Error(
98
+ `Type ${type.getText()} looks like a ${typename}, but has ${typeArguments.length} or ${aliasTypeArguments.length} type arguments instead of ${count}!`
99
+ )
100
+ }
101
+
102
+ export function createNamedType(
103
+ language: Language,
104
+ name: string,
105
+ type: TSMorphType,
106
+ isOptional: boolean
107
+ ) {
108
+ if (name.startsWith('__')) {
109
+ throw new Error(
110
+ `Name cannot start with two underscores (__) as this is reserved syntax for Nitrogen! (In ${type.getText()})`
111
+ )
112
+ }
113
+ return new NamedWrappingType(name, createType(language, type, isOptional))
114
+ }
115
+
116
+ export function createVoidType(): Type {
117
+ return new VoidType()
118
+ }
119
+
120
+ // Caches complex types (types that have a symbol)
121
+ type TypeId = string
122
+ const knownTypes: Record<Language, Map<TypeId, Type>> = {
123
+ 'c++': new Map<TypeId, Type>(),
124
+ 'swift': new Map<TypeId, Type>(),
125
+ 'kotlin': new Map<TypeId, Type>(),
126
+ }
127
+
128
+ /**
129
+ * Get a list of all currently known complex types.
130
+ */
131
+ export function getAllKnownTypes(language?: Language): Type[] {
132
+ if (language != null) {
133
+ // Get types for the given language
134
+ return Array.from(knownTypes[language].values())
135
+ } else {
136
+ // Get types for all languages alltogether
137
+ const allMaps = Object.values(knownTypes)
138
+ return allMaps.flatMap((m) => Array.from(m.values()))
139
+ }
140
+ }
141
+
142
+ function getTypeId(type: TSMorphType, isOptional: boolean): string {
143
+ const symbol = type.getSymbol()
144
+ let key = type.getText()
145
+ if (symbol != null) {
146
+ key += '_' + symbol.getFullyQualifiedName()
147
+ }
148
+ if (isOptional) key += '?'
149
+ return key
150
+ }
151
+
152
+ export function addKnownType(
153
+ key: string,
154
+ type: Type,
155
+ language: Language
156
+ ): void {
157
+ if (knownTypes[language].has(key)) {
158
+ // type is already known
159
+ return
160
+ }
161
+ knownTypes[language].set(key, type)
162
+ }
163
+
164
+ /**
165
+ * Create a new type (or return it from cache if it is already known)
166
+ */
167
+ export function createType(
168
+ language: Language,
169
+ type: TSMorphType,
170
+ isOptional: boolean
171
+ ): Type {
172
+ const key = getTypeId(type, isOptional)
173
+ if (key != null && knownTypes[language].has(key)) {
174
+ const known = knownTypes[language].get(key)!
175
+ if (isOptional === known instanceof OptionalType) {
176
+ return known
177
+ }
178
+ }
179
+
180
+ const get = () => {
181
+ if (isOptional) {
182
+ const wrapping = createType(language, type, false)
183
+ return new OptionalType(wrapping)
184
+ }
185
+
186
+ if (type.isNull() || type.isUndefined()) {
187
+ return new NullType()
188
+ } else if (type.isBoolean() || type.isBooleanLiteral()) {
189
+ return new BooleanType()
190
+ } else if (type.isNumber() || type.isNumberLiteral()) {
191
+ if (type.isEnumLiteral()) {
192
+ // enum literals are technically just numbers - but we treat them differently in C++.
193
+ return createType(language, type.getBaseTypeOfLiteralType(), isOptional)
194
+ }
195
+ return new NumberType()
196
+ } else if (type.isString()) {
197
+ return new StringType()
198
+ } else if (type.isBigInt() || type.isBigIntLiteral()) {
199
+ return new BigIntType()
200
+ } else if (type.isVoid()) {
201
+ return new VoidType()
202
+ } else if (type.isArray()) {
203
+ const arrayElementType = type.getArrayElementTypeOrThrow()
204
+ const elementType = createType(language, arrayElementType, false)
205
+ return new ArrayType(elementType)
206
+ } else if (type.isTuple()) {
207
+ const itemTypes = type
208
+ .getTupleElements()
209
+ .map((t) => createType(language, t, t.isNullable()))
210
+ return new TupleType(itemTypes)
211
+ } else if (type.getCallSignatures().length > 0) {
212
+ // It's a function!
213
+ const callSignature = getFunctionCallSignature(type)
214
+ const funcReturnType = callSignature.getReturnType()
215
+ const returnType = createType(
216
+ language,
217
+ funcReturnType,
218
+ funcReturnType.isNullable()
219
+ )
220
+ const parameters = callSignature.getParameters().map((p) => {
221
+ const declaration = p.getValueDeclarationOrThrow()
222
+ const parameterType = p.getTypeAtLocation(declaration)
223
+ const isNullable = parameterType.isNullable() || p.isOptional()
224
+ return createNamedType(language, p.getName(), parameterType, isNullable)
225
+ })
226
+ const isSync = isSyncFunction(type)
227
+ return new FunctionType(returnType, parameters, isSync)
228
+ } else if (isPromise(type)) {
229
+ // It's a Promise!
230
+ const [promiseResolvingType] = getArguments(type, 'Promise', 1)
231
+ const resolvingType = createType(
232
+ language,
233
+ promiseResolvingType,
234
+ promiseResolvingType.isNullable()
235
+ )
236
+ return new PromiseType(resolvingType)
237
+ } else if (isRecord(type)) {
238
+ // Record<K, V> -> unordered_map<K, V>
239
+ const [keyTypeT, valueTypeT] = getArguments(type, 'Record', 2)
240
+ const keyType = createType(language, keyTypeT, false)
241
+ const valueType = createType(language, valueTypeT, false)
242
+ return new RecordType(keyType, valueType)
243
+ } else if (isArrayBuffer(type)) {
244
+ // ArrayBuffer
245
+ return new ArrayBufferType()
246
+ } else if (isMap(type)) {
247
+ // Map
248
+ return new MapType()
249
+ } else if (isDate(type)) {
250
+ // Date
251
+ return new DateType()
252
+ } else if (isError(type)) {
253
+ // Error
254
+ return new ErrorType()
255
+ } else if (isCustomType(type)) {
256
+ // Custom C++ type (manually written)
257
+ const { name, config } = getCustomTypeConfig(type)
258
+ return new CustomType(name, config)
259
+ } else if (type.isEnum()) {
260
+ // It is an enum. We need to generate a C++ declaration for the enum
261
+ const typename = type.getSymbolOrThrow().getEscapedName()
262
+ const declaration = type.getSymbolOrThrow().getValueDeclarationOrThrow()
263
+ const enumDeclaration = declaration.asKindOrThrow(
264
+ ts.SyntaxKind.EnumDeclaration
265
+ )
266
+ return new EnumType(typename, enumDeclaration)
267
+ } else if (type.isUnion()) {
268
+ // It is some kind of union;
269
+ // - of string literals (then it's an enum)
270
+ // - of type `T | undefined` (then it's just optional `T`)
271
+ // - of different types (then it's a variant `A | B | C`)
272
+ const types = type.getUnionTypes()
273
+ const nonNullTypes = types.filter(
274
+ (t) => !t.isNull() && !t.isUndefined() && !t.isVoid()
275
+ )
276
+ const isEnumUnion = nonNullTypes.every((t) => t.isStringLiteral())
277
+ if (isEnumUnion) {
278
+ // It consists only of string literaly - that means it's describing an enum!
279
+ const symbol = type.getNonNullableType().getAliasSymbol()
280
+ if (symbol == null) {
281
+ // If there is no alias, it is an inline union instead of a separate type declaration!
282
+ throw new Error(
283
+ `Inline union types ("${type.getText()}") are not supported by Nitrogen!\n` +
284
+ `Extract the union to a separate type, and re-run nitrogen!`
285
+ )
286
+ }
287
+ const typename = symbol.getEscapedName()
288
+ return new EnumType(typename, type)
289
+ } else {
290
+ // It consists of different types - that means it's a variant!
291
+ let variants = type
292
+ .getUnionTypes()
293
+ // Filter out any nulls or undefineds, as those are already treated as `isOptional`.
294
+ .filter((t) => !t.isNull() && !t.isUndefined() && !t.isVoid())
295
+ .map((t) => createType(language, t, false))
296
+ variants = removeDuplicates(variants)
297
+
298
+ if (variants.length === 1) {
299
+ // It's just one type with undefined/null variant(s) - so we treat it like a simple optional.
300
+ return variants[0]!
301
+ }
302
+
303
+ const name = type.getAliasSymbol()?.getName()
304
+ return new VariantType(variants, name)
305
+ }
306
+ } else if (isAnyHybridSubclass(type)) {
307
+ // It is another HybridObject being referenced!
308
+ const typename = getHybridObjectName(type)
309
+ const baseTypes = getBaseTypes(type)
310
+ .filter((t) => isAnyHybridSubclass(t))
311
+ .map((b) => createType(language, b, false))
312
+ const baseHybrids = baseTypes.filter((b) => b instanceof HybridObjectType)
313
+ const sourceConfig =
314
+ getHybridObjectNitroModuleConfig(type) ?? NitroConfig.current
315
+ return new HybridObjectType(typename, language, baseHybrids, sourceConfig)
316
+ } else if (isDirectlyHybridObject(type)) {
317
+ // It is a HybridObject directly/literally. Base type
318
+ return new HybridObjectBaseType()
319
+ } else if (type.isInterface()) {
320
+ // It is an `interface T { ... }`, which is a `struct`
321
+ const typename = type.getSymbolOrThrow().getName()
322
+ const properties = getInterfaceProperties(language, type)
323
+ return new StructType(typename, properties)
324
+ } else if (type.isObject()) {
325
+ // It is an object. If it has a symbol/name, it is a `type T = ...` declaration, so a `struct`.
326
+ // Otherwise, it is an anonymous/inline object, which cannot be represented in native.
327
+ const symbol = type.getAliasSymbol()
328
+ if (symbol != null) {
329
+ // it has a `type T = ...` declaration
330
+ const typename = symbol.getName()
331
+ const properties = getInterfaceProperties(language, type)
332
+ return new StructType(typename, properties)
333
+ } else {
334
+ // It's an anonymous object (`{ ... }`)
335
+ throw new Error(
336
+ `Anonymous objects cannot be represented in C++! Extract "${type.getText()}" to a separate interface/type declaration.`
337
+ )
338
+ }
339
+ } else if (type.isStringLiteral()) {
340
+ throw new Error(
341
+ `String literal ${type.getText()} cannot be represented in C++ because it is ambiguous between a string and a discriminating union enum.`
342
+ )
343
+ } else {
344
+ if (type.getSymbol() == null) {
345
+ // There is no declaration for it!
346
+ // Could be an invalid import, e.g. an alias
347
+ throw new Error(
348
+ `The TypeScript type "${type.getText()}" cannot be resolved - is it imported properly? ` +
349
+ `Make sure to import it properly using fully specified relative or absolute imports, no aliases.`
350
+ )
351
+ } else {
352
+ // A different error
353
+ throw new Error(
354
+ `The TypeScript type "${type.getText()}" cannot be represented in C++!`
355
+ )
356
+ }
357
+ }
358
+ }
359
+
360
+ const result = get()
361
+ if (key != null) {
362
+ knownTypes[language].set(key, result)
363
+ }
364
+ return result
365
+ }
@@ -0,0 +1,18 @@
1
+ import type { HybridObjectSpec } from './HybridObjectSpec.js'
2
+ import type { Type } from './types/Type.js'
3
+
4
+ // TODO: Structs or other HybridObjects may reference other types recursively - we need to add a `referencedTypes` prop to each `Type` to be able to resolve that.
5
+ export function getAllTypes(spec: HybridObjectSpec): Type[] {
6
+ const types: Type[] = []
7
+
8
+ // 1. Properties
9
+ types.push(...spec.properties.map((p) => p.type))
10
+
11
+ // 2. Method return types
12
+ types.push(...spec.methods.map((m) => m.returnType))
13
+
14
+ // 3. Method parameters
15
+ types.push(...spec.methods.flatMap((m) => m.parameters.map((p) => p.type)))
16
+
17
+ return types
18
+ }