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,304 @@
1
+ import type { SourceFile } from '../syntax/SourceFile.js'
2
+ import type { HybridObjectSpec } from '../syntax/HybridObjectSpec.js'
3
+ import { createIndentation, indent } from '../utils.js'
4
+ import {
5
+ createFileMetadataString,
6
+ escapeCppName,
7
+ isFunction,
8
+ isNotDuplicate,
9
+ } from '../syntax/helpers.js'
10
+ import { getHybridObjectName } from '../syntax/getHybridObjectName.js'
11
+ import { includeHeader } from '../syntax/c++/includeNitroHeader.js'
12
+ import { createHostComponentJs } from './createHostComponentJs.js'
13
+ import { Property } from '../syntax/Property.js'
14
+ import { FunctionType } from '../syntax/types/FunctionType.js'
15
+ import { VoidType } from '../syntax/types/VoidType.js'
16
+ import { HybridObjectType } from '../syntax/types/HybridObjectType.js'
17
+ import { NamedWrappingType } from '../syntax/types/NamedWrappingType.js'
18
+ import { OptionalType } from '../syntax/types/OptionalType.js'
19
+
20
+ interface ViewComponentNames {
21
+ propsClassName: `${string}Props`
22
+ stateClassName: `${string}State`
23
+ nameVariable: `${string}ComponentName`
24
+ shadowNodeClassName: `${string}ShadowNode`
25
+ descriptorClassName: `${string}ComponentDescriptor`
26
+ component: `${string}Component`
27
+ manager: `${string}Manager`
28
+ }
29
+
30
+ export function getViewComponentNames(
31
+ spec: HybridObjectSpec
32
+ ): ViewComponentNames {
33
+ const name = getHybridObjectName(spec.name)
34
+ return {
35
+ propsClassName: `${name.HybridT}Props`,
36
+ stateClassName: `${name.HybridT}State`,
37
+ nameVariable: `${name.HybridT}ComponentName`,
38
+ shadowNodeClassName: `${name.HybridT}ShadowNode`,
39
+ descriptorClassName: `${name.HybridT}ComponentDescriptor`,
40
+ component: `${name.HybridT}Component`,
41
+ manager: `${name.HybridT}Manager`,
42
+ }
43
+ }
44
+
45
+ function getHybridRefProperty(spec: HybridObjectSpec): Property {
46
+ const hybrid = new HybridObjectType(spec)
47
+ const type = new FunctionType(new VoidType(), [
48
+ new NamedWrappingType('ref', hybrid),
49
+ ])
50
+ return new Property('hybridRef', new OptionalType(type), false)
51
+ }
52
+
53
+ export function createViewComponentShadowNodeFiles(
54
+ spec: HybridObjectSpec
55
+ ): SourceFile[] {
56
+ if (!spec.isHybridView) {
57
+ throw new Error(
58
+ `Cannot create View Component ShadowNode code for ${spec.name} - it's not a HybridView!`
59
+ )
60
+ }
61
+
62
+ const { T, HybridT } = getHybridObjectName(spec.name)
63
+ const {
64
+ propsClassName,
65
+ stateClassName,
66
+ nameVariable,
67
+ shadowNodeClassName,
68
+ descriptorClassName,
69
+ component,
70
+ } = getViewComponentNames(spec)
71
+
72
+ const namespace = spec.config.getCxxNamespace('c++', 'views')
73
+
74
+ const props = [...spec.properties, getHybridRefProperty(spec)]
75
+ const properties = props.map(
76
+ (p) => `CachedProp<${p.type.getCode('c++')}> ${escapeCppName(p.name)};`
77
+ )
78
+ const cases = props.map((p) => `case hashString("${p.name}"): return true;`)
79
+ const includes = props
80
+ .flatMap((p) =>
81
+ p.getRequiredImports('c++').map((i) => includeHeader(i, true))
82
+ )
83
+ .filter(isNotDuplicate)
84
+
85
+ // .hpp code
86
+ const shadowIndent = createIndentation(shadowNodeClassName.length)
87
+ const componentHeaderCode = `
88
+ ${createFileMetadataString(`${component}.hpp`)}
89
+
90
+ #pragma once
91
+
92
+ #include <optional>
93
+ #include <NitroModules/NitroDefines.hpp>
94
+ #include <NitroModules/NitroHash.hpp>
95
+ #include <NitroModules/CachedProp.hpp>
96
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
97
+ #include <react/renderer/core/PropsParserContext.h>
98
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
99
+ #include <react/renderer/components/view/ViewProps.h>
100
+
101
+ ${includes.join('\n')}
102
+
103
+ namespace ${namespace} {
104
+
105
+ using namespace facebook;
106
+
107
+ /**
108
+ * The name of the actual native View.
109
+ */
110
+ extern const char ${nameVariable}[];
111
+
112
+ /**
113
+ * Props for the "${spec.name}" View.
114
+ */
115
+ class ${propsClassName} final: public react::ViewProps {
116
+ public:
117
+ ${propsClassName}() = default;
118
+ ${propsClassName}(const ${propsClassName}&);
119
+ ${propsClassName}(const react::PropsParserContext& context,
120
+ ${createIndentation(propsClassName.length)} const ${propsClassName}& sourceProps,
121
+ ${createIndentation(propsClassName.length)} const react::RawProps& rawProps);
122
+
123
+ public:
124
+ ${indent(properties.join('\n'), ' ')}
125
+
126
+ private:
127
+ static bool filterObjectKeys(const std::string& propName);
128
+ };
129
+
130
+ /**
131
+ * State for the "${spec.name}" View.
132
+ */
133
+ class ${stateClassName} final {
134
+ public:
135
+ ${stateClassName}() = default;
136
+
137
+ public:
138
+ void setProps(const ${propsClassName}& props) { _props.emplace(props); }
139
+ const std::optional<${propsClassName}>& getProps() const { return _props; }
140
+
141
+ public:
142
+ #ifdef ANDROID
143
+ ${stateClassName}(const ${stateClassName}& /* previousState */, folly::dynamic /* data */) {}
144
+ folly::dynamic getDynamic() const {
145
+ throw std::runtime_error("${stateClassName} does not support folly!");
146
+ }
147
+ react::MapBuffer getMapBuffer() const {
148
+ throw std::runtime_error("${stateClassName} does not support MapBuffer!");
149
+ };
150
+ #endif
151
+
152
+ private:
153
+ std::optional<${propsClassName}> _props;
154
+ };
155
+
156
+ /**
157
+ * The Shadow Node for the "${spec.name}" View.
158
+ */
159
+ using ${shadowNodeClassName} = react::ConcreteViewShadowNode<${nameVariable} /* "${HybridT}" */,
160
+ ${shadowIndent} ${propsClassName} /* custom props */,
161
+ ${shadowIndent} react::ViewEventEmitter /* default */,
162
+ ${shadowIndent} ${stateClassName} /* custom state */>;
163
+
164
+ /**
165
+ * The Component Descriptor for the "${spec.name}" View.
166
+ */
167
+ class ${descriptorClassName} final: public react::ConcreteComponentDescriptor<${shadowNodeClassName}> {
168
+ public:
169
+ ${descriptorClassName}(const react::ComponentDescriptorParameters& parameters);
170
+
171
+ public:
172
+ /**
173
+ * A faster path for cloning props - reuses the caching logic from \`${propsClassName}\`.
174
+ */
175
+ std::shared_ptr<const react::Props> cloneProps(const react::PropsParserContext& context,
176
+ const std::shared_ptr<const react::Props>& props,
177
+ react::RawProps rawProps) const override;
178
+ #ifdef ANDROID
179
+ void adopt(react::ShadowNode& shadowNode) const override;
180
+ #endif
181
+ };
182
+
183
+ /* The actual view for "${spec.name}" needs to be implemented in platform-specific code. */
184
+
185
+ } // namespace ${namespace}
186
+ `.trim()
187
+
188
+ // .cpp code
189
+ const propInitializers = [
190
+ 'react::ViewProps(context, sourceProps, rawProps, filterObjectKeys)',
191
+ ]
192
+ const propCopyInitializers = ['react::ViewProps()']
193
+ for (const prop of props) {
194
+ const name = escapeCppName(prop.name)
195
+ const type = prop.type.getCode('c++')
196
+
197
+ let valueConversion = `value`
198
+ if (isFunction(prop.type)) {
199
+ // Due to a React limitation, functions cannot be passed to native directly,
200
+ // because RN converts them to booleans (`true`). Nitro knows this and just
201
+ // wraps functions as objects - the original function is stored in `f`.
202
+ valueConversion = `value.asObject(*runtime).getProperty(*runtime, "f")`
203
+ }
204
+
205
+ propInitializers.push(
206
+ `
207
+ ${name}([&]() -> CachedProp<${type}> {
208
+ try {
209
+ const react::RawValue* rawValue = rawProps.at("${prop.name}", nullptr, nullptr);
210
+ if (rawValue == nullptr) return sourceProps.${name};
211
+ const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
212
+ return CachedProp<${type}>::fromRawValue(*runtime, ${valueConversion}, sourceProps.${name});
213
+ } catch (const std::exception& exc) {
214
+ throw std::runtime_error(std::string("${spec.name}.${prop.name}: ") + exc.what());
215
+ }
216
+ }())`.trim()
217
+ )
218
+ propCopyInitializers.push(`${name}(other.${name})`)
219
+ }
220
+
221
+ const ctorIndent = createIndentation(propsClassName.length * 2)
222
+ const descriptorIndent = createIndentation(descriptorClassName.length)
223
+ const componentCode = `
224
+ ${createFileMetadataString(`${component}.cpp`)}
225
+
226
+ #include "${component}.hpp"
227
+
228
+ #include <string>
229
+ #include <exception>
230
+ #include <utility>
231
+ #include <NitroModules/NitroDefines.hpp>
232
+ #include <NitroModules/JSIConverter.hpp>
233
+ #include <react/renderer/core/RawValue.h>
234
+ #include <react/renderer/core/ShadowNode.h>
235
+ #include <react/renderer/core/ComponentDescriptor.h>
236
+ #include <react/renderer/components/view/ViewProps.h>
237
+
238
+ namespace ${namespace} {
239
+
240
+ extern const char ${nameVariable}[] = "${T}";
241
+
242
+ ${propsClassName}::${propsClassName}(const react::PropsParserContext& context,
243
+ ${ctorIndent} const ${propsClassName}& sourceProps,
244
+ ${ctorIndent} const react::RawProps& rawProps):
245
+ ${indent(propInitializers.join(',\n'), ' ')} { }
246
+
247
+ ${propsClassName}::${propsClassName}(const ${propsClassName}& other):
248
+ ${indent(propCopyInitializers.join(',\n'), ' ')} { }
249
+
250
+ bool ${propsClassName}::filterObjectKeys(const std::string& propName) {
251
+ switch (hashString(propName)) {
252
+ ${indent(cases.join('\n'), ' ')}
253
+ default: return false;
254
+ }
255
+ }
256
+
257
+ ${descriptorClassName}::${descriptorClassName}(const react::ComponentDescriptorParameters& parameters)
258
+ : ConcreteComponentDescriptor(parameters,
259
+ react::RawPropsParser(/* enableJsiParser */ true)) {}
260
+
261
+ std::shared_ptr<const react::Props> ${descriptorClassName}::cloneProps(const react::PropsParserContext& context,
262
+ ${descriptorIndent} const std::shared_ptr<const react::Props>& props,
263
+ ${descriptorIndent} react::RawProps rawProps) const {
264
+ // 1. Prepare raw props parser
265
+ rawProps.parse(rawPropsParser_);
266
+ // 2. Copy props with Nitro's cached copy constructor
267
+ return ${shadowNodeClassName}::Props(context, /* & */ rawProps, props);
268
+ }
269
+
270
+ #ifdef ANDROID
271
+ void ${descriptorClassName}::adopt(react::ShadowNode& shadowNode) const {
272
+ // This is called immediately after \`ShadowNode\` is created, cloned or in progress.
273
+ // On Android, we need to wrap props in our state, which gets routed through Java and later unwrapped in JNI/C++.
274
+ auto& concreteShadowNode = dynamic_cast<${shadowNodeClassName}&>(shadowNode);
275
+ const ${propsClassName}& props = concreteShadowNode.getConcreteProps();
276
+ ${stateClassName} state;
277
+ state.setProps(props);
278
+ concreteShadowNode.setStateData(std::move(state));
279
+ }
280
+ #endif
281
+
282
+ } // namespace ${namespace}
283
+ `.trim()
284
+
285
+ const files: SourceFile[] = [
286
+ {
287
+ name: `${component}.hpp`,
288
+ content: componentHeaderCode,
289
+ language: 'c++',
290
+ platform: 'shared',
291
+ subdirectory: ['views'],
292
+ },
293
+ {
294
+ name: `${component}.cpp`,
295
+ content: componentCode,
296
+ language: 'c++',
297
+ platform: 'shared',
298
+ subdirectory: ['views'],
299
+ },
300
+ ]
301
+ const jsFiles = createHostComponentJs(spec)
302
+ files.push(...(jsFiles as unknown as SourceFile[]))
303
+ return files
304
+ }
@@ -0,0 +1,34 @@
1
+ import type { Language } from '../getPlatformSpecs.js'
2
+ import type { HybridObjectSpec } from '../syntax/HybridObjectSpec.js'
3
+ import type { SourceFile } from '../syntax/SourceFile.js'
4
+ import { getHybridObjectName } from '../syntax/getHybridObjectName.js'
5
+ import { indent } from '../utils.js'
6
+
7
+ export function createHostComponentJs(spec: HybridObjectSpec): SourceFile[] {
8
+ const { T } = getHybridObjectName(spec.name)
9
+
10
+ const props = spec.properties.map((p) => `"${p.name}": true`)
11
+ props.push(`"hybridRef": true`)
12
+
13
+ const code = `
14
+ {
15
+ "uiViewClassName": "${T}",
16
+ "supportsRawText": false,
17
+ "bubblingEventTypes": {},
18
+ "directEventTypes": {},
19
+ "validAttributes": {
20
+ ${indent(props.join(',\n'), ' ')}
21
+ }
22
+ }
23
+ `.trim()
24
+
25
+ return [
26
+ {
27
+ content: code,
28
+ language: 'json' as Language,
29
+ name: `${T}Config.json`,
30
+ platform: 'shared',
31
+ subdirectory: [],
32
+ },
33
+ ]
34
+ }
@@ -0,0 +1,258 @@
1
+ import type { SourceFile } from '../../syntax/SourceFile.js'
2
+ import type { HybridObjectSpec } from '../../syntax/HybridObjectSpec.js'
3
+ import {
4
+ createViewComponentShadowNodeFiles,
5
+ getViewComponentNames,
6
+ } from '../CppHybridViewComponent.js'
7
+ import {
8
+ createFileMetadataString,
9
+ escapeCppName,
10
+ } from '../../syntax/helpers.js'
11
+ import { getHybridObjectName } from '../../syntax/getHybridObjectName.js'
12
+ import { addJNINativeRegistration } from '../../syntax/kotlin/JNINativeRegistrations.js'
13
+ import { indent } from '../../utils.js'
14
+
15
+ export function createKotlinHybridViewManager(
16
+ spec: HybridObjectSpec
17
+ ): SourceFile[] {
18
+ const cppFiles = createViewComponentShadowNodeFiles(spec)
19
+ const javaSubNamespace = spec.config.getAndroidPackage('java/kotlin', 'views')
20
+ const javaNamespace = spec.config.getAndroidPackage('java/kotlin')
21
+ const cxxNamespace = spec.config.getCxxNamespace('c++', 'views')
22
+ const { JHybridTSpec, HybridTSpec } = getHybridObjectName(spec.name)
23
+ const {
24
+ manager,
25
+ stateClassName,
26
+ component,
27
+ propsClassName,
28
+ descriptorClassName,
29
+ } = getViewComponentNames(spec)
30
+ const stateUpdaterName = `${stateClassName}Updater`
31
+ const autolinking = spec.config.getAutolinkedHybridObjects()
32
+ const viewImplementation = autolinking[spec.name]?.kotlin
33
+ if (viewImplementation == null) {
34
+ throw new Error(
35
+ `Cannot create Kotlin HybridView ViewManager for ${spec.name} - it is not autolinked in nitro.json!`
36
+ )
37
+ }
38
+
39
+ const viewManagerCode = `
40
+ ${createFileMetadataString(`${manager}.kt`)}
41
+
42
+ package ${javaSubNamespace}
43
+
44
+ import android.view.View
45
+ import com.facebook.react.uimanager.ReactStylesDiffMap
46
+ import com.facebook.react.uimanager.SimpleViewManager
47
+ import com.facebook.react.uimanager.StateWrapper
48
+ import com.facebook.react.uimanager.ThemedReactContext
49
+ import ${javaNamespace}.*
50
+
51
+ /**
52
+ * Represents the React Native \`ViewManager\` for the "${spec.name}" Nitro HybridView.
53
+ */
54
+ class ${manager}: SimpleViewManager<View>() {
55
+ private val views = hashMapOf<View, ${viewImplementation}>()
56
+
57
+ override fun getName(): String {
58
+ return "${spec.name}"
59
+ }
60
+
61
+ override fun createViewInstance(reactContext: ThemedReactContext): View {
62
+ val hybridView = ${viewImplementation}(reactContext)
63
+ val view = hybridView.view
64
+ views[view] = hybridView
65
+ return view
66
+ }
67
+
68
+ override fun onDropViewInstance(view: View) {
69
+ super.onDropViewInstance(view)
70
+ views.remove(view)
71
+ }
72
+
73
+ override fun updateState(view: View, props: ReactStylesDiffMap, stateWrapper: StateWrapper): Any? {
74
+ val hybridView = views[view] ?: throw Error("Couldn't find view $view in local views table!")
75
+
76
+ // 1. Update each prop individually
77
+ hybridView.beforeUpdate()
78
+ ${stateUpdaterName}.updateViewProps(hybridView, stateWrapper)
79
+ hybridView.afterUpdate()
80
+
81
+ // 2. Continue in base View props
82
+ return super.updateState(view, props, stateWrapper)
83
+ }
84
+ }
85
+ `.trim()
86
+
87
+ const updaterKotlinCode = `
88
+ ${createFileMetadataString(`${stateUpdaterName}.kt`)}
89
+
90
+ package ${javaSubNamespace}
91
+
92
+ import com.facebook.react.uimanager.StateWrapper
93
+ import ${javaNamespace}.*
94
+
95
+ internal class ${stateUpdaterName} {
96
+ companion object {
97
+ /**
98
+ * Updates the props for [view] through C++.
99
+ * The [state] prop is expected to contain [view]'s props as wrapped Fabric state.
100
+ */
101
+ @Suppress("KotlinJniMissingFunction")
102
+ @JvmStatic
103
+ external fun updateViewProps(view: ${HybridTSpec}, state: StateWrapper)
104
+ }
105
+ }
106
+ `.trim()
107
+
108
+ const updaterJniDescriptor = spec.config.getAndroidPackage(
109
+ 'c++/jni',
110
+ 'views',
111
+ stateUpdaterName
112
+ )
113
+ const updaterJniHeaderCode = `
114
+ ${createFileMetadataString(`J${stateUpdaterName}.hpp`)}
115
+
116
+ #pragma once
117
+
118
+ #include <fbjni/fbjni.h>
119
+ #include <react/fabric/StateWrapperImpl.h>
120
+ #include <react/fabric/CoreComponentsRegistry.h>
121
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
122
+ #include <NitroModules/NitroDefines.hpp>
123
+ #include <NitroModules/JStateWrapper.hpp>
124
+ #include "${JHybridTSpec}.hpp"
125
+ #include "views/${component}.hpp"
126
+
127
+ namespace ${cxxNamespace} {
128
+
129
+ using namespace facebook;
130
+
131
+ class J${stateUpdaterName}: public jni::JavaClass<J${stateUpdaterName}> {
132
+ public:
133
+ static constexpr auto kJavaDescriptor = "L${updaterJniDescriptor};";
134
+
135
+ public:
136
+ static void updateViewProps(jni::alias_ref<jni::JClass> /* class */,
137
+ jni::alias_ref<${JHybridTSpec}::javaobject> view,
138
+ jni::alias_ref<JStateWrapper::javaobject> stateWrapperInterface);
139
+
140
+ public:
141
+ static void registerNatives() {
142
+ // Register JNI calls
143
+ javaClassStatic()->registerNatives({
144
+ makeNativeMethod("updateViewProps", J${stateUpdaterName}::updateViewProps),
145
+ });
146
+ // Register React Native view component descriptor
147
+ auto provider = react::concreteComponentDescriptorProvider<${descriptorClassName}>();
148
+ auto providerRegistry = react::CoreComponentsRegistry::sharedProviderRegistry();
149
+ providerRegistry->add(provider);
150
+ }
151
+ };
152
+
153
+ } // namespace ${cxxNamespace}
154
+ `.trim()
155
+
156
+ const propsUpdaterCalls = spec.properties.map((p) => {
157
+ const name = escapeCppName(p.name)
158
+ const setter = p.getSetterName('other')
159
+ return `
160
+ if (props.${name}.isDirty) {
161
+ view->${setter}(props.${name}.value);
162
+ // TODO: Set isDirty = false
163
+ }
164
+ `.trim()
165
+ })
166
+ const updaterJniCppCode = `
167
+ ${createFileMetadataString(`J${stateUpdaterName}.cpp`)}
168
+
169
+ #include "J${stateUpdaterName}.hpp"
170
+ #include "views/${component}.hpp"
171
+ #include <NitroModules/NitroDefines.hpp>
172
+
173
+ namespace ${cxxNamespace} {
174
+
175
+ using namespace facebook;
176
+ using ConcreteStateData = react::ConcreteState<${stateClassName}>;
177
+
178
+ void J${stateUpdaterName}::updateViewProps(jni::alias_ref<jni::JClass> /* class */,
179
+ jni::alias_ref<${JHybridTSpec}::javaobject> javaView,
180
+ jni::alias_ref<JStateWrapper::javaobject> stateWrapperInterface) {
181
+ ${JHybridTSpec}* view = javaView->cthis();
182
+
183
+ // Get concrete StateWrapperImpl from passed StateWrapper interface object
184
+ jobject rawStateWrapper = stateWrapperInterface.get();
185
+ if (!stateWrapperInterface->isInstanceOf(react::StateWrapperImpl::javaClassStatic())) {
186
+ throw std::runtime_error("StateWrapper is not a StateWrapperImpl");
187
+ }
188
+ auto stateWrapper = jni::alias_ref<react::StateWrapperImpl::javaobject>{
189
+ static_cast<react::StateWrapperImpl::javaobject>(rawStateWrapper)};
190
+
191
+ std::shared_ptr<const react::State> state = stateWrapper->cthis()->getState();
192
+ auto concreteState = std::dynamic_pointer_cast<const ConcreteStateData>(state);
193
+ const ${stateClassName}& data = concreteState->getData();
194
+ const std::optional<${propsClassName}>& maybeProps = data.getProps();
195
+ if (!maybeProps.has_value()) {
196
+ // Props aren't set yet!
197
+ throw std::runtime_error("${stateClassName}'s data doesn't contain any props!");
198
+ }
199
+ const ${propsClassName}& props = maybeProps.value();
200
+ ${indent(propsUpdaterCalls.join('\n'), ' ')}
201
+
202
+ // Update hybridRef if it changed
203
+ if (props.hybridRef.isDirty) {
204
+ // hybridRef changed - call it with new this
205
+ const auto& maybeFunc = props.hybridRef.value;
206
+ if (maybeFunc.has_value()) {
207
+ std::shared_ptr<${JHybridTSpec}> shared = javaView->cthis()->shared_cast<${JHybridTSpec}>();
208
+ maybeFunc.value()(shared);
209
+ }
210
+ // TODO: Set isDirty = false
211
+ }
212
+ }
213
+
214
+ } // namespace ${cxxNamespace}
215
+ `.trim()
216
+
217
+ addJNINativeRegistration({
218
+ namespace: cxxNamespace,
219
+ className: `J${stateUpdaterName}`,
220
+ import: {
221
+ name: `views/J${stateUpdaterName}.hpp`,
222
+ space: 'user',
223
+ language: 'c++',
224
+ },
225
+ })
226
+
227
+ return [
228
+ ...cppFiles,
229
+ {
230
+ content: viewManagerCode,
231
+ language: 'kotlin',
232
+ name: `${manager}.kt`,
233
+ platform: 'android',
234
+ subdirectory: [...javaSubNamespace.split('.')],
235
+ },
236
+ {
237
+ content: updaterKotlinCode,
238
+ language: 'kotlin',
239
+ name: `${stateUpdaterName}.kt`,
240
+ platform: 'android',
241
+ subdirectory: [...javaSubNamespace.split('.')],
242
+ },
243
+ {
244
+ content: updaterJniHeaderCode,
245
+ language: 'c++',
246
+ name: `J${stateUpdaterName}.hpp`,
247
+ platform: 'android',
248
+ subdirectory: ['views'],
249
+ },
250
+ {
251
+ content: updaterJniCppCode,
252
+ language: 'c++',
253
+ name: `J${stateUpdaterName}.cpp`,
254
+ platform: 'android',
255
+ subdirectory: ['views'],
256
+ },
257
+ ]
258
+ }