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