@react-native/codegen 0.83.0-nightly-20251014-69dc65500 → 0.83.0-nightly-20251016-e79920c66

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.
@@ -33,7 +33,6 @@ const generateTests = require('./components/GenerateTests.js');
33
33
  const generateThirdPartyFabricComponentsProviderH = require('./components/GenerateThirdPartyFabricComponentsProviderH.js');
34
34
  const generateThirdPartyFabricComponentsProviderObjCpp = require('./components/GenerateThirdPartyFabricComponentsProviderObjCpp.js');
35
35
  const generateViewConfigJs = require('./components/GenerateViewConfigJs.js');
36
- const generateModuleCpp = require('./modules/GenerateModuleCpp.js');
37
36
  const generateModuleH = require('./modules/GenerateModuleH.js');
38
37
  const generateModuleJavaSpec = require('./modules/GenerateModuleJavaSpec.js');
39
38
  const generateModuleJniCpp = require('./modules/GenerateModuleJniCpp.js');
@@ -52,7 +51,6 @@ const ALL_GENERATORS = {
52
51
  generateStateCpp: generateStateCpp.generate,
53
52
  generateStateH: generateStateH.generate,
54
53
  generateModuleH: generateModuleH.generate,
55
- generateModuleCpp: generateModuleCpp.generate,
56
54
  generateModuleObjCpp: generateModuleObjCpp.generate,
57
55
  generateModuleJavaSpec: generateModuleJavaSpec.generate,
58
56
  generateModuleJniCpp: generateModuleJniCpp.generate,
@@ -117,7 +115,7 @@ const LIBRARY_GENERATORS = {
117
115
  generateModuleJniH.generate,
118
116
  generateModuleJavaSpec.generate,
119
117
  ],
120
- modulesCxx: [generateModuleCpp.generate, generateModuleH.generate],
118
+ modulesCxx: [generateModuleH.generate],
121
119
  modulesIOS: [generateModuleObjCpp.generate],
122
120
  tests: [generateTests.generate],
123
121
  'shadow-nodes': [
@@ -36,7 +36,6 @@ const generateTests = require('./components/GenerateTests.js');
36
36
  const generateThirdPartyFabricComponentsProviderH = require('./components/GenerateThirdPartyFabricComponentsProviderH.js');
37
37
  const generateThirdPartyFabricComponentsProviderObjCpp = require('./components/GenerateThirdPartyFabricComponentsProviderObjCpp.js');
38
38
  const generateViewConfigJs = require('./components/GenerateViewConfigJs.js');
39
- const generateModuleCpp = require('./modules/GenerateModuleCpp.js');
40
39
  const generateModuleH = require('./modules/GenerateModuleH.js');
41
40
  const generateModuleJavaSpec = require('./modules/GenerateModuleJavaSpec.js');
42
41
  const generateModuleJniCpp = require('./modules/GenerateModuleJniCpp.js');
@@ -56,7 +55,6 @@ const ALL_GENERATORS = {
56
55
  generateStateCpp: generateStateCpp.generate,
57
56
  generateStateH: generateStateH.generate,
58
57
  generateModuleH: generateModuleH.generate,
59
- generateModuleCpp: generateModuleCpp.generate,
60
58
  generateModuleObjCpp: generateModuleObjCpp.generate,
61
59
  generateModuleJavaSpec: generateModuleJavaSpec.generate,
62
60
  generateModuleJniCpp: generateModuleJniCpp.generate,
@@ -179,7 +177,7 @@ const LIBRARY_GENERATORS: LibraryGeneratorsFunctions = {
179
177
  generateModuleJniH.generate,
180
178
  generateModuleJavaSpec.generate,
181
179
  ],
182
- modulesCxx: [generateModuleCpp.generate, generateModuleH.generate],
180
+ modulesCxx: [generateModuleH.generate],
183
181
  modulesIOS: [generateModuleObjCpp.generate],
184
182
  tests: [generateTests.generate],
185
183
  'shadow-nodes': [
@@ -13,70 +13,136 @@
13
13
  const {unwrapNullable} = require('../../parsers/parsers-commons');
14
14
  const {wrapOptional} = require('../TypeUtils/Cxx');
15
15
  const {getEnumName, toPascalCase, toSafeCppString} = require('../Utils');
16
- const {indent} = require('../Utils');
17
16
  const {
18
17
  createAliasResolver,
19
18
  getModules,
20
19
  isArrayRecursiveMember,
21
20
  isDirectRecursiveMember,
22
21
  } = require('./Utils');
23
- const ModuleClassDeclarationTemplate = ({
24
- hasteModuleName,
25
- moduleProperties,
26
- structs,
27
- enums,
28
- }) => {
29
- return `${enums}
30
- ${structs}class JSI_EXPORT ${hasteModuleName}CxxSpecJSI : public TurboModule {
31
- protected:
32
- ${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);
22
+ function serializeArg(moduleName, arg, index, resolveAlias, enumMap) {
23
+ const {typeAnnotation: nullableTypeAnnotation, optional} = arg;
24
+ const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
25
+ let realTypeAnnotation = typeAnnotation;
26
+ if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
27
+ realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
28
+ }
29
+ function wrap(callback) {
30
+ const val = `args[${index}]`;
31
+ const expression = callback(val);
33
32
 
34
- public:
35
- ${indent(moduleProperties.join('\n'), 2)}
33
+ // param?: T
34
+ if (optional && !nullable) {
35
+ // throw new Error('are we hitting this case? ' + moduleName);
36
+ return `count <= ${index} || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
37
+ }
36
38
 
37
- };`;
38
- };
39
+ // param: ?T
40
+ // param?: ?T
41
+ if (nullable || optional) {
42
+ return `count <= ${index} || ${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
43
+ }
44
+
45
+ // param: T
46
+ return `count <= ${index} ? throw jsi::JSError(rt, "Expected argument in position ${index} to be passed") : ${expression}`;
47
+ }
48
+ switch (realTypeAnnotation.type) {
49
+ case 'ReservedTypeAnnotation':
50
+ switch (realTypeAnnotation.name) {
51
+ case 'RootTag':
52
+ return wrap(val => `${val}.asNumber()`);
53
+ default:
54
+ realTypeAnnotation.name;
55
+ throw new Error(
56
+ `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.name}"`,
57
+ );
58
+ }
59
+ case 'StringTypeAnnotation':
60
+ return wrap(val => `${val}.asString(rt)`);
61
+ case 'StringLiteralTypeAnnotation':
62
+ return wrap(val => `${val}.asString(rt)`);
63
+ case 'StringLiteralUnionTypeAnnotation':
64
+ return wrap(val => `${val}.asString(rt)`);
65
+ case 'BooleanTypeAnnotation':
66
+ return wrap(val => `${val}.asBool()`);
67
+ case 'EnumDeclaration':
68
+ switch (realTypeAnnotation.memberType) {
69
+ case 'NumberTypeAnnotation':
70
+ return wrap(val => `${val}.asNumber()`);
71
+ case 'StringTypeAnnotation':
72
+ return wrap(val => `${val}.asString(rt)`);
73
+ default:
74
+ throw new Error(
75
+ `Unknown enum type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
76
+ );
77
+ }
78
+ case 'NumberTypeAnnotation':
79
+ return wrap(val => `${val}.asNumber()`);
80
+ case 'FloatTypeAnnotation':
81
+ return wrap(val => `${val}.asNumber()`);
82
+ case 'DoubleTypeAnnotation':
83
+ return wrap(val => `${val}.asNumber()`);
84
+ case 'Int32TypeAnnotation':
85
+ return wrap(val => `${val}.asNumber()`);
86
+ case 'NumberLiteralTypeAnnotation':
87
+ return wrap(val => `${val}.asNumber()`);
88
+ case 'ArrayTypeAnnotation':
89
+ return wrap(val => `${val}.asObject(rt).asArray(rt)`);
90
+ case 'FunctionTypeAnnotation':
91
+ return wrap(val => `${val}.asObject(rt).asFunction(rt)`);
92
+ case 'GenericObjectTypeAnnotation':
93
+ return wrap(val => `${val}.asObject(rt)`);
94
+ case 'UnionTypeAnnotation':
95
+ switch (typeAnnotation.memberType) {
96
+ case 'NumberTypeAnnotation':
97
+ return wrap(val => `${val}.asNumber()`);
98
+ case 'ObjectTypeAnnotation':
99
+ return wrap(val => `${val}.asObject(rt)`);
100
+ case 'StringTypeAnnotation':
101
+ return wrap(val => `${val}.asString(rt)`);
102
+ default:
103
+ throw new Error(
104
+ `Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`,
105
+ );
106
+ }
107
+ case 'ObjectTypeAnnotation':
108
+ return wrap(val => `${val}.asObject(rt)`);
109
+ case 'MixedTypeAnnotation':
110
+ return wrap(val => `jsi::Value(rt, ${val})`);
111
+ default:
112
+ realTypeAnnotation.type;
113
+ throw new Error(
114
+ `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
115
+ );
116
+ }
117
+ }
39
118
  const ModuleSpecClassDeclarationTemplate = ({
40
119
  hasteModuleName,
41
120
  moduleName,
121
+ structs,
122
+ enums,
42
123
  moduleEventEmitters,
43
- moduleProperties,
124
+ moduleFunctions,
125
+ methods,
44
126
  }) => {
45
- return `template <typename T>
127
+ return `${enums}${structs}
128
+ template <typename T>
46
129
  class JSI_EXPORT ${hasteModuleName}CxxSpec : public TurboModule {
47
130
  public:
48
- jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override {
49
- return delegate_.create(rt, propName);
50
- }
51
-
52
- std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& runtime) override {
53
- return delegate_.getPropertyNames(runtime);
54
- }
55
-
56
131
  static constexpr std::string_view kModuleName = "${moduleName}";
57
132
 
58
133
  protected:
59
- ${hasteModuleName}CxxSpec(std::shared_ptr<CallInvoker> jsInvoker)
60
- : TurboModule(std::string{${hasteModuleName}CxxSpec::kModuleName}, jsInvoker),
61
- delegate_(reinterpret_cast<T*>(this), jsInvoker) {}
62
- ${moduleEventEmitters.map(e => e.emitFunction).join('\n')}
63
-
134
+ ${hasteModuleName}CxxSpec(std::shared_ptr<CallInvoker> jsInvoker) : TurboModule(std::string{${hasteModuleName}CxxSpec::kModuleName}, jsInvoker) {
135
+ ${methods
136
+ .map(({methodName, paramCount}) => {
137
+ return ` methodMap_["${methodName}"] = MethodMetadata {.argCount = ${paramCount}, .invoker = __${methodName}};`;
138
+ })
139
+ .join(
140
+ '\n',
141
+ )}${moduleEventEmitters.length > 0 ? '\n' : ''}${moduleEventEmitters.map(e => e.registerEventEmitter).join('\n')}
142
+ }
143
+ ${moduleEventEmitters.map(e => e.emitFunction).join('\n')}
64
144
  private:
65
- class Delegate : public ${hasteModuleName}CxxSpecJSI {
66
- public:
67
- Delegate(T *instance, std::shared_ptr<CallInvoker> jsInvoker) :
68
- ${hasteModuleName}CxxSpecJSI(std::move(jsInvoker)), instance_(instance) {
69
- ${moduleEventEmitters.map(e => e.registerEventEmitter).join('\n')}
70
- }
71
-
72
- ${indent(moduleProperties.join('\n'), 4)}
73
-
74
- private:
75
- friend class ${hasteModuleName}CxxSpec;
76
- T *instance_;
77
- };
78
-
79
- Delegate delegate_;
145
+ ${moduleFunctions.join('\n\n')}
80
146
  };`;
81
147
  };
82
148
  const FileTemplate = ({modules}) => {
@@ -238,7 +304,7 @@ function createStructsString(hasteModuleName, aliasMap, resolveAlias, enumMap) {
238
304
  return bridging::toJs(rt, value);
239
305
  }`,
240
306
  )
241
- .join('\n\n');
307
+ .join('\n');
242
308
  return `
243
309
  #pragma mark - ${structName}
244
310
 
@@ -393,17 +459,17 @@ function createEnums(hasteModuleName, enumMap, resolveAlias) {
393
459
  .filter(Boolean)
394
460
  .join('\n');
395
461
  }
396
- function translatePropertyToCpp(
462
+ function translateFunctionToCpp(
397
463
  hasteModuleName,
398
464
  prop,
399
465
  resolveAlias,
400
466
  enumMap,
401
- abstract = false,
467
+ args,
468
+ returnTypeAnnotation,
402
469
  ) {
403
470
  const [propTypeAnnotation] = unwrapNullable(prop.typeAnnotation);
404
- const params = propTypeAnnotation.params.map(
405
- param => `std::move(${param.name})`,
406
- );
471
+ const isNullable = returnTypeAnnotation.type === 'NullableTypeAnnotation';
472
+ const isVoid = returnTypeAnnotation.type === 'VoidTypeAnnotation';
407
473
  const paramTypes = propTypeAnnotation.params.map(param => {
408
474
  const translatedParam = translatePrimitiveJSTypeToCpp(
409
475
  hasteModuleName,
@@ -417,6 +483,7 @@ function translatePropertyToCpp(
417
483
  );
418
484
  return `${translatedParam} ${param.name}`;
419
485
  });
486
+ paramTypes.unshift('jsi::Runtime &rt');
420
487
  const returnType = translatePrimitiveJSTypeToCpp(
421
488
  hasteModuleName,
422
489
  null,
@@ -426,21 +493,15 @@ function translatePropertyToCpp(
426
493
  resolveAlias,
427
494
  enumMap,
428
495
  );
429
-
430
- // The first param will always be the runtime reference.
431
- paramTypes.unshift('jsi::Runtime &rt');
432
- const method = `${returnType} ${prop.name}(${paramTypes.join(', ')})`;
433
- if (abstract) {
434
- return `virtual ${method} = 0;`;
496
+ let methodCallArgs = [...args].join(',\n ');
497
+ if (methodCallArgs.length > 0) {
498
+ methodCallArgs = `,\n ${methodCallArgs}`;
435
499
  }
436
- return `${method} override {
437
- static_assert(
500
+ return ` static jsi::Value __${prop.name}(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* ${args.length > 0 ? 'args' : '/*args*/'}, size_t ${args.length > 0 ? 'count' : '/*count*/'}) {
501
+ static_assert(
438
502
  bridging::getParameterCount(&T::${prop.name}) == ${paramTypes.length},
439
503
  "Expected ${prop.name}(...) to have ${paramTypes.length} parameters");
440
-
441
- return bridging::callFromJs<${returnType}>(
442
- rt, &T::${prop.name}, jsInvoker_, ${['instance_', ...params].join(', ')});
443
- }`;
504
+ ${!isVoid ? (!isNullable ? 'return ' : 'auto result = ') : ''}bridging::callFromJs<${returnType}>(rt, &T::${prop.name}, static_cast<${hasteModuleName}CxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule)${methodCallArgs});${!isVoid ? (!isNullable ? '' : 'return result ? jsi::Value(std::move(*result)) : jsi::Value::null();') : 'return jsi::Value::undefined();'}\n }`;
444
505
  }
445
506
  function translateEventEmitterToCpp(
446
507
  moduleName,
@@ -465,7 +526,7 @@ function translateEventEmitterToCpp(
465
526
  return {
466
527
  isVoidTypeAnnotation: isVoidTypeAnnotation,
467
528
  templateName: isVoidTypeAnnotation ? `/*${templateName}*/` : templateName,
468
- registerEventEmitter: ` eventEmitterMap_["${eventEmitter.name}"] = std::make_shared<AsyncEventEmitter<${isVoidTypeAnnotation ? '' : 'jsi::Value'}>>();`,
529
+ registerEventEmitter: ` eventEmitterMap_["${eventEmitter.name}"] = std::make_shared<AsyncEventEmitter<${isVoidTypeAnnotation ? '' : 'jsi::Value'}>>();`,
469
530
  emitFunction: `
470
531
  ${isVoidTypeAnnotation ? '' : `template <typename ${templateName}> `}void emit${toPascalCase(eventEmitter.name)}(${isVoidTypeAnnotation ? '' : `${isArray ? `std::vector<${templateName}>` : templateName} value`}) {${
471
532
  isVoidTypeAnnotation
@@ -473,7 +534,7 @@ function translateEventEmitterToCpp(
473
534
  : `
474
535
  static_assert(bridging::supportsFromJs<${isArray ? `std::vector<${templateName}>` : templateName}, ${jsiType}>, "value cannnot be converted to ${jsiType}");`
475
536
  }
476
- static_cast<AsyncEventEmitter<${isVoidTypeAnnotation ? '' : 'jsi::Value'}>&>(*delegate_.eventEmitterMap_["${eventEmitter.name}"]).emit(${
537
+ static_cast<AsyncEventEmitter<${isVoidTypeAnnotation ? '' : 'jsi::Value'}>&>(*eventEmitterMap_["${eventEmitter.name}"]).emit(${
477
538
  isVoidTypeAnnotation
478
539
  ? ''
479
540
  : `[jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
@@ -493,8 +554,14 @@ module.exports = {
493
554
  ) {
494
555
  const nativeModules = getModules(schema);
495
556
  const modules = Object.keys(nativeModules).flatMap(hasteModuleName => {
496
- const {aliasMap, enumMap, spec, moduleName} =
497
- nativeModules[hasteModuleName];
557
+ const nativeModule = nativeModules[hasteModuleName];
558
+ const {
559
+ aliasMap,
560
+ enumMap,
561
+ spec: {methods},
562
+ spec,
563
+ moduleName,
564
+ } = nativeModule;
498
565
  const resolveAlias = createAliasResolver(aliasMap);
499
566
  const structs = createStructsString(
500
567
  hasteModuleName,
@@ -504,23 +571,11 @@ module.exports = {
504
571
  );
505
572
  const enums = createEnums(hasteModuleName, enumMap, resolveAlias);
506
573
  return [
507
- ModuleClassDeclarationTemplate({
508
- hasteModuleName,
509
- moduleProperties: spec.methods.map(prop =>
510
- translatePropertyToCpp(
511
- hasteModuleName,
512
- prop,
513
- resolveAlias,
514
- enumMap,
515
- true,
516
- ),
517
- ),
518
- structs,
519
- enums,
520
- }),
521
574
  ModuleSpecClassDeclarationTemplate({
522
575
  hasteModuleName,
523
576
  moduleName,
577
+ structs,
578
+ enums,
524
579
  moduleEventEmitters: spec.eventEmitters.map(eventEmitter =>
525
580
  translateEventEmitterToCpp(
526
581
  moduleName,
@@ -529,13 +584,29 @@ module.exports = {
529
584
  enumMap,
530
585
  ),
531
586
  ),
532
- moduleProperties: spec.methods.map(prop =>
533
- translatePropertyToCpp(
587
+ moduleFunctions: spec.methods.map(property => {
588
+ const [propertyTypeAnnotation] = unwrapNullable(
589
+ property.typeAnnotation,
590
+ );
591
+ return translateFunctionToCpp(
534
592
  hasteModuleName,
535
- prop,
593
+ property,
536
594
  resolveAlias,
537
595
  enumMap,
538
- ),
596
+ propertyTypeAnnotation.params.map((p, i) =>
597
+ serializeArg(moduleName, p, i, resolveAlias, enumMap),
598
+ ),
599
+ propertyTypeAnnotation.returnTypeAnnotation,
600
+ );
601
+ }),
602
+ methods: methods.map(
603
+ ({name: propertyName, typeAnnotation: nullableTypeAnnotation}) => {
604
+ const [{params}] = unwrapNullable(nullableTypeAnnotation);
605
+ return {
606
+ methodName: propertyName,
607
+ paramCount: params.length,
608
+ };
609
+ },
539
610
  ),
540
611
  }),
541
612
  ];
@@ -9,17 +9,17 @@
9
9
  */
10
10
 
11
11
  'use strict';
12
+
12
13
  import type {
13
14
  NamedShape,
14
- NativeModuleBaseTypeAnnotation,
15
- } from '../../CodegenSchema';
16
- import type {
17
15
  NativeModuleAliasMap,
16
+ NativeModuleBaseTypeAnnotation,
18
17
  NativeModuleEnumMap,
19
18
  NativeModuleEnumMember,
20
19
  NativeModuleEnumMemberType,
21
20
  NativeModuleEventEmitterShape,
22
21
  NativeModuleFunctionTypeAnnotation,
22
+ NativeModuleParamTypeAnnotation,
23
23
  NativeModulePropertyShape,
24
24
  NativeModuleTypeAnnotation,
25
25
  Nullable,
@@ -30,7 +30,6 @@ import type {AliasResolver} from './Utils';
30
30
  const {unwrapNullable} = require('../../parsers/parsers-commons');
31
31
  const {wrapOptional} = require('../TypeUtils/Cxx');
32
32
  const {getEnumName, toPascalCase, toSafeCppString} = require('../Utils');
33
- const {indent} = require('../Utils');
34
33
  const {
35
34
  createAliasResolver,
36
35
  getModules,
@@ -40,74 +39,151 @@ const {
40
39
 
41
40
  type FilesOutput = Map<string, string>;
42
41
 
43
- const ModuleClassDeclarationTemplate = ({
44
- hasteModuleName,
45
- moduleProperties,
46
- structs,
47
- enums,
48
- }: $ReadOnly<{
49
- hasteModuleName: string,
50
- moduleProperties: string[],
51
- structs: string,
52
- enums: string,
53
- }>) => {
54
- return `${enums}
55
- ${structs}class JSI_EXPORT ${hasteModuleName}CxxSpecJSI : public TurboModule {
56
- protected:
57
- ${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);
42
+ type Param = NamedShape<Nullable<NativeModuleParamTypeAnnotation>>;
58
43
 
59
- public:
60
- ${indent(moduleProperties.join('\n'), 2)}
44
+ function serializeArg(
45
+ moduleName: string,
46
+ arg: Param,
47
+ index: number,
48
+ resolveAlias: AliasResolver,
49
+ enumMap: NativeModuleEnumMap,
50
+ ): string {
51
+ const {typeAnnotation: nullableTypeAnnotation, optional} = arg;
52
+ const [typeAnnotation, nullable] =
53
+ unwrapNullable<NativeModuleParamTypeAnnotation>(nullableTypeAnnotation);
61
54
 
62
- };`;
63
- };
55
+ let realTypeAnnotation = typeAnnotation;
56
+ if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
57
+ realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
58
+ }
59
+
60
+ function wrap(callback: (val: string) => string) {
61
+ const val = `args[${index}]`;
62
+ const expression = callback(val);
63
+
64
+ // param?: T
65
+ if (optional && !nullable) {
66
+ // throw new Error('are we hitting this case? ' + moduleName);
67
+ return `count <= ${index} || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
68
+ }
69
+
70
+ // param: ?T
71
+ // param?: ?T
72
+ if (nullable || optional) {
73
+ return `count <= ${index} || ${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
74
+ }
75
+
76
+ // param: T
77
+ return `count <= ${index} ? throw jsi::JSError(rt, "Expected argument in position ${index} to be passed") : ${expression}`;
78
+ }
79
+
80
+ switch (realTypeAnnotation.type) {
81
+ case 'ReservedTypeAnnotation':
82
+ switch (realTypeAnnotation.name) {
83
+ case 'RootTag':
84
+ return wrap(val => `${val}.asNumber()`);
85
+ default:
86
+ (realTypeAnnotation.name: empty);
87
+ throw new Error(
88
+ `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.name}"`,
89
+ );
90
+ }
91
+ case 'StringTypeAnnotation':
92
+ return wrap(val => `${val}.asString(rt)`);
93
+ case 'StringLiteralTypeAnnotation':
94
+ return wrap(val => `${val}.asString(rt)`);
95
+ case 'StringLiteralUnionTypeAnnotation':
96
+ return wrap(val => `${val}.asString(rt)`);
97
+ case 'BooleanTypeAnnotation':
98
+ return wrap(val => `${val}.asBool()`);
99
+ case 'EnumDeclaration':
100
+ switch (realTypeAnnotation.memberType) {
101
+ case 'NumberTypeAnnotation':
102
+ return wrap(val => `${val}.asNumber()`);
103
+ case 'StringTypeAnnotation':
104
+ return wrap(val => `${val}.asString(rt)`);
105
+ default:
106
+ throw new Error(
107
+ `Unknown enum type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
108
+ );
109
+ }
110
+ case 'NumberTypeAnnotation':
111
+ return wrap(val => `${val}.asNumber()`);
112
+ case 'FloatTypeAnnotation':
113
+ return wrap(val => `${val}.asNumber()`);
114
+ case 'DoubleTypeAnnotation':
115
+ return wrap(val => `${val}.asNumber()`);
116
+ case 'Int32TypeAnnotation':
117
+ return wrap(val => `${val}.asNumber()`);
118
+ case 'NumberLiteralTypeAnnotation':
119
+ return wrap(val => `${val}.asNumber()`);
120
+ case 'ArrayTypeAnnotation':
121
+ return wrap(val => `${val}.asObject(rt).asArray(rt)`);
122
+ case 'FunctionTypeAnnotation':
123
+ return wrap(val => `${val}.asObject(rt).asFunction(rt)`);
124
+ case 'GenericObjectTypeAnnotation':
125
+ return wrap(val => `${val}.asObject(rt)`);
126
+ case 'UnionTypeAnnotation':
127
+ switch (typeAnnotation.memberType) {
128
+ case 'NumberTypeAnnotation':
129
+ return wrap(val => `${val}.asNumber()`);
130
+ case 'ObjectTypeAnnotation':
131
+ return wrap(val => `${val}.asObject(rt)`);
132
+ case 'StringTypeAnnotation':
133
+ return wrap(val => `${val}.asString(rt)`);
134
+ default:
135
+ throw new Error(
136
+ `Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`,
137
+ );
138
+ }
139
+ case 'ObjectTypeAnnotation':
140
+ return wrap(val => `${val}.asObject(rt)`);
141
+ case 'MixedTypeAnnotation':
142
+ return wrap(val => `jsi::Value(rt, ${val})`);
143
+ default:
144
+ (realTypeAnnotation.type: empty);
145
+ throw new Error(
146
+ `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
147
+ );
148
+ }
149
+ }
64
150
 
65
151
  const ModuleSpecClassDeclarationTemplate = ({
66
152
  hasteModuleName,
67
153
  moduleName,
154
+ structs,
155
+ enums,
68
156
  moduleEventEmitters,
69
- moduleProperties,
157
+ moduleFunctions,
158
+ methods,
70
159
  }: $ReadOnly<{
71
160
  hasteModuleName: string,
72
161
  moduleName: string,
162
+ structs: string,
163
+ enums: string,
73
164
  moduleEventEmitters: EventEmitterCpp[],
74
- moduleProperties: string[],
165
+ moduleFunctions: string[],
166
+ methods: $ReadOnlyArray<$ReadOnly<{methodName: string, paramCount: number}>>,
75
167
  }>) => {
76
- return `template <typename T>
168
+ return `${enums}${structs}
169
+ template <typename T>
77
170
  class JSI_EXPORT ${hasteModuleName}CxxSpec : public TurboModule {
78
171
  public:
79
- jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override {
80
- return delegate_.create(rt, propName);
81
- }
82
-
83
- std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& runtime) override {
84
- return delegate_.getPropertyNames(runtime);
85
- }
86
-
87
172
  static constexpr std::string_view kModuleName = "${moduleName}";
88
173
 
89
174
  protected:
90
- ${hasteModuleName}CxxSpec(std::shared_ptr<CallInvoker> jsInvoker)
91
- : TurboModule(std::string{${hasteModuleName}CxxSpec::kModuleName}, jsInvoker),
92
- delegate_(reinterpret_cast<T*>(this), jsInvoker) {}
93
- ${moduleEventEmitters.map(e => e.emitFunction).join('\n')}
94
-
175
+ ${hasteModuleName}CxxSpec(std::shared_ptr<CallInvoker> jsInvoker) : TurboModule(std::string{${hasteModuleName}CxxSpec::kModuleName}, jsInvoker) {
176
+ ${methods
177
+ .map(({methodName, paramCount}) => {
178
+ return ` methodMap_["${methodName}"] = MethodMetadata {.argCount = ${paramCount}, .invoker = __${methodName}};`;
179
+ })
180
+ .join(
181
+ '\n',
182
+ )}${moduleEventEmitters.length > 0 ? '\n' : ''}${moduleEventEmitters.map(e => e.registerEventEmitter).join('\n')}
183
+ }
184
+ ${moduleEventEmitters.map(e => e.emitFunction).join('\n')}
95
185
  private:
96
- class Delegate : public ${hasteModuleName}CxxSpecJSI {
97
- public:
98
- Delegate(T *instance, std::shared_ptr<CallInvoker> jsInvoker) :
99
- ${hasteModuleName}CxxSpecJSI(std::move(jsInvoker)), instance_(instance) {
100
- ${moduleEventEmitters.map(e => e.registerEventEmitter).join('\n')}
101
- }
102
-
103
- ${indent(moduleProperties.join('\n'), 4)}
104
-
105
- private:
106
- friend class ${hasteModuleName}CxxSpec;
107
- T *instance_;
108
- };
109
-
110
- Delegate delegate_;
186
+ ${moduleFunctions.join('\n\n')}
111
187
  };`;
112
188
  };
113
189
 
@@ -292,7 +368,7 @@ function createStructsString(
292
368
  return bridging::toJs(rt, value);
293
369
  }`,
294
370
  )
295
- .join('\n\n');
371
+ .join('\n');
296
372
  return `
297
373
  #pragma mark - ${structName}
298
374
 
@@ -476,19 +552,19 @@ function createEnums(
476
552
  .join('\n');
477
553
  }
478
554
 
479
- function translatePropertyToCpp(
555
+ function translateFunctionToCpp(
480
556
  hasteModuleName: string,
481
557
  prop: NativeModulePropertyShape,
482
558
  resolveAlias: AliasResolver,
483
559
  enumMap: NativeModuleEnumMap,
484
- abstract: boolean = false,
560
+ args: Array<string>,
561
+ returnTypeAnnotation: Nullable<NativeModuleTypeAnnotation>,
485
562
  ): string {
486
563
  const [propTypeAnnotation] =
487
564
  unwrapNullable<NativeModuleFunctionTypeAnnotation>(prop.typeAnnotation);
488
565
 
489
- const params = propTypeAnnotation.params.map(
490
- param => `std::move(${param.name})`,
491
- );
566
+ const isNullable = returnTypeAnnotation.type === 'NullableTypeAnnotation';
567
+ const isVoid = returnTypeAnnotation.type === 'VoidTypeAnnotation';
492
568
 
493
569
  const paramTypes = propTypeAnnotation.params.map(param => {
494
570
  const translatedParam = translatePrimitiveJSTypeToCpp(
@@ -503,6 +579,7 @@ function translatePropertyToCpp(
503
579
  );
504
580
  return `${translatedParam} ${param.name}`;
505
581
  });
582
+ paramTypes.unshift('jsi::Runtime &rt');
506
583
 
507
584
  const returnType = translatePrimitiveJSTypeToCpp(
508
585
  hasteModuleName,
@@ -514,23 +591,16 @@ function translatePropertyToCpp(
514
591
  enumMap,
515
592
  );
516
593
 
517
- // The first param will always be the runtime reference.
518
- paramTypes.unshift('jsi::Runtime &rt');
519
-
520
- const method = `${returnType} ${prop.name}(${paramTypes.join(', ')})`;
521
-
522
- if (abstract) {
523
- return `virtual ${method} = 0;`;
594
+ let methodCallArgs = [...args].join(',\n ');
595
+ if (methodCallArgs.length > 0) {
596
+ methodCallArgs = `,\n ${methodCallArgs}`;
524
597
  }
525
598
 
526
- return `${method} override {
527
- static_assert(
599
+ return ` static jsi::Value __${prop.name}(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* ${args.length > 0 ? 'args' : '/*args*/'}, size_t ${args.length > 0 ? 'count' : '/*count*/'}) {
600
+ static_assert(
528
601
  bridging::getParameterCount(&T::${prop.name}) == ${paramTypes.length},
529
602
  "Expected ${prop.name}(...) to have ${paramTypes.length} parameters");
530
-
531
- return bridging::callFromJs<${returnType}>(
532
- rt, &T::${prop.name}, jsInvoker_, ${['instance_', ...params].join(', ')});
533
- }`;
603
+ ${!isVoid ? (!isNullable ? 'return ' : 'auto result = ') : ''}bridging::callFromJs<${returnType}>(rt, &T::${prop.name}, static_cast<${hasteModuleName}CxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule)${methodCallArgs});${!isVoid ? (!isNullable ? '' : 'return result ? jsi::Value(std::move(*result)) : jsi::Value::null();') : 'return jsi::Value::undefined();'}\n }`;
534
604
  }
535
605
 
536
606
  type EventEmitterCpp = {
@@ -563,7 +633,7 @@ function translateEventEmitterToCpp(
563
633
  return {
564
634
  isVoidTypeAnnotation: isVoidTypeAnnotation,
565
635
  templateName: isVoidTypeAnnotation ? `/*${templateName}*/` : templateName,
566
- registerEventEmitter: ` eventEmitterMap_["${
636
+ registerEventEmitter: ` eventEmitterMap_["${
567
637
  eventEmitter.name
568
638
  }"] = std::make_shared<AsyncEventEmitter<${
569
639
  isVoidTypeAnnotation ? '' : 'jsi::Value'
@@ -585,7 +655,7 @@ function translateEventEmitterToCpp(
585
655
  }
586
656
  static_cast<AsyncEventEmitter<${
587
657
  isVoidTypeAnnotation ? '' : 'jsi::Value'
588
- }>&>(*delegate_.eventEmitterMap_["${eventEmitter.name}"]).emit(${
658
+ }>&>(*eventEmitterMap_["${eventEmitter.name}"]).emit(${
589
659
  isVoidTypeAnnotation
590
660
  ? ''
591
661
  : `[jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
@@ -607,8 +677,14 @@ module.exports = {
607
677
  const nativeModules = getModules(schema);
608
678
 
609
679
  const modules = Object.keys(nativeModules).flatMap(hasteModuleName => {
610
- const {aliasMap, enumMap, spec, moduleName} =
611
- nativeModules[hasteModuleName];
680
+ const nativeModule = nativeModules[hasteModuleName];
681
+ const {
682
+ aliasMap,
683
+ enumMap,
684
+ spec: {methods},
685
+ spec,
686
+ moduleName,
687
+ } = nativeModule;
612
688
  const resolveAlias = createAliasResolver(aliasMap);
613
689
  const structs = createStructsString(
614
690
  hasteModuleName,
@@ -617,25 +693,12 @@ module.exports = {
617
693
  enumMap,
618
694
  );
619
695
  const enums = createEnums(hasteModuleName, enumMap, resolveAlias);
620
-
621
696
  return [
622
- ModuleClassDeclarationTemplate({
623
- hasteModuleName,
624
- moduleProperties: spec.methods.map(prop =>
625
- translatePropertyToCpp(
626
- hasteModuleName,
627
- prop,
628
- resolveAlias,
629
- enumMap,
630
- true,
631
- ),
632
- ),
633
- structs,
634
- enums,
635
- }),
636
697
  ModuleSpecClassDeclarationTemplate({
637
698
  hasteModuleName,
638
699
  moduleName,
700
+ structs,
701
+ enums,
639
702
  moduleEventEmitters: spec.eventEmitters.map(eventEmitter =>
640
703
  translateEventEmitterToCpp(
641
704
  moduleName,
@@ -644,13 +707,30 @@ module.exports = {
644
707
  enumMap,
645
708
  ),
646
709
  ),
647
- moduleProperties: spec.methods.map(prop =>
648
- translatePropertyToCpp(
710
+ moduleFunctions: spec.methods.map(property => {
711
+ const [propertyTypeAnnotation] =
712
+ unwrapNullable<NativeModuleFunctionTypeAnnotation>(
713
+ property.typeAnnotation,
714
+ );
715
+ return translateFunctionToCpp(
649
716
  hasteModuleName,
650
- prop,
717
+ property,
651
718
  resolveAlias,
652
719
  enumMap,
653
- ),
720
+ propertyTypeAnnotation.params.map((p, i) =>
721
+ serializeArg(moduleName, p, i, resolveAlias, enumMap),
722
+ ),
723
+ propertyTypeAnnotation.returnTypeAnnotation,
724
+ );
725
+ }),
726
+ methods: methods.map(
727
+ ({name: propertyName, typeAnnotation: nullableTypeAnnotation}) => {
728
+ const [{params}] = unwrapNullable(nullableTypeAnnotation);
729
+ return {
730
+ methodName: propertyName,
731
+ paramCount: params.length,
732
+ };
733
+ },
654
734
  ),
655
735
  }),
656
736
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native/codegen",
3
- "version": "0.83.0-nightly-20251014-69dc65500",
3
+ "version": "0.83.0-nightly-20251016-e79920c66",
4
4
  "description": "Code generation tools for React Native",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,230 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- *
8
- * @format
9
- */
10
-
11
- 'use strict';
12
-
13
- const {unwrapNullable} = require('../../parsers/parsers-commons');
14
- const {createAliasResolver, getModules} = require('./Utils');
15
- const HostFunctionTemplate = ({
16
- hasteModuleName,
17
- methodName,
18
- returnTypeAnnotation,
19
- args,
20
- }) => {
21
- const isNullable = returnTypeAnnotation.type === 'NullableTypeAnnotation';
22
- const isVoid = returnTypeAnnotation.type === 'VoidTypeAnnotation';
23
- const methodCallArgs = [' rt', ...args].join(',\n ');
24
- const methodCall = `static_cast<${hasteModuleName}CxxSpecJSI *>(&turboModule)->${methodName}(\n${methodCallArgs}\n )`;
25
- return `static jsi::Value __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {${isVoid ? `\n ${methodCall};` : isNullable ? `\n auto result = ${methodCall};` : ''}
26
- return ${isVoid ? 'jsi::Value::undefined()' : isNullable ? 'result ? jsi::Value(std::move(*result)) : jsi::Value::null()' : methodCall};
27
- }`;
28
- };
29
- const ModuleTemplate = ({
30
- hasteModuleName,
31
- hostFunctions,
32
- moduleName,
33
- methods,
34
- }) => {
35
- return `${hostFunctions.join('\n')}
36
-
37
- ${hasteModuleName}CxxSpecJSI::${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
38
- : TurboModule("${moduleName}", jsInvoker) {
39
- ${methods
40
- .map(({methodName, paramCount}) => {
41
- return ` methodMap_["${methodName}"] = MethodMetadata {${paramCount}, __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}};`;
42
- })
43
- .join('\n')}
44
- }`;
45
- };
46
- const FileTemplate = ({libraryName, modules}) => {
47
- return `/**
48
- * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
49
- *
50
- * Do not edit this file as changes may cause incorrect behavior and will be lost
51
- * once the code is regenerated.
52
- *
53
- * ${'@'}generated by codegen project: GenerateModuleCpp.js
54
- */
55
-
56
- #include "${libraryName}JSI.h"
57
-
58
- namespace facebook::react {
59
-
60
- ${modules}
61
-
62
-
63
- } // namespace facebook::react
64
- `;
65
- };
66
- function serializeArg(moduleName, arg, index, resolveAlias, enumMap) {
67
- const {typeAnnotation: nullableTypeAnnotation, optional} = arg;
68
- const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
69
- let realTypeAnnotation = typeAnnotation;
70
- if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
71
- realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
72
- }
73
- function wrap(callback) {
74
- const val = `args[${index}]`;
75
- const expression = callback(val);
76
-
77
- // param?: T
78
- if (optional && !nullable) {
79
- // throw new Error('are we hitting this case? ' + moduleName);
80
- return `count <= ${index} || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
81
- }
82
-
83
- // param: ?T
84
- // param?: ?T
85
- if (nullable || optional) {
86
- return `count <= ${index} || ${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
87
- }
88
-
89
- // param: T
90
- return `count <= ${index} ? throw jsi::JSError(rt, "Expected argument in position ${index} to be passed") : ${expression}`;
91
- }
92
- switch (realTypeAnnotation.type) {
93
- case 'ReservedTypeAnnotation':
94
- switch (realTypeAnnotation.name) {
95
- case 'RootTag':
96
- return wrap(val => `${val}.asNumber()`);
97
- default:
98
- realTypeAnnotation.name;
99
- throw new Error(
100
- `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.name}"`,
101
- );
102
- }
103
- case 'StringTypeAnnotation':
104
- return wrap(val => `${val}.asString(rt)`);
105
- case 'StringLiteralTypeAnnotation':
106
- return wrap(val => `${val}.asString(rt)`);
107
- case 'StringLiteralUnionTypeAnnotation':
108
- return wrap(val => `${val}.asString(rt)`);
109
- case 'BooleanTypeAnnotation':
110
- return wrap(val => `${val}.asBool()`);
111
- case 'EnumDeclaration':
112
- switch (realTypeAnnotation.memberType) {
113
- case 'NumberTypeAnnotation':
114
- return wrap(val => `${val}.asNumber()`);
115
- case 'StringTypeAnnotation':
116
- return wrap(val => `${val}.asString(rt)`);
117
- default:
118
- throw new Error(
119
- `Unknown enum type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
120
- );
121
- }
122
- case 'NumberTypeAnnotation':
123
- return wrap(val => `${val}.asNumber()`);
124
- case 'FloatTypeAnnotation':
125
- return wrap(val => `${val}.asNumber()`);
126
- case 'DoubleTypeAnnotation':
127
- return wrap(val => `${val}.asNumber()`);
128
- case 'Int32TypeAnnotation':
129
- return wrap(val => `${val}.asNumber()`);
130
- case 'NumberLiteralTypeAnnotation':
131
- return wrap(val => `${val}.asNumber()`);
132
- case 'ArrayTypeAnnotation':
133
- return wrap(val => `${val}.asObject(rt).asArray(rt)`);
134
- case 'FunctionTypeAnnotation':
135
- return wrap(val => `${val}.asObject(rt).asFunction(rt)`);
136
- case 'GenericObjectTypeAnnotation':
137
- return wrap(val => `${val}.asObject(rt)`);
138
- case 'UnionTypeAnnotation':
139
- switch (typeAnnotation.memberType) {
140
- case 'NumberTypeAnnotation':
141
- return wrap(val => `${val}.asNumber()`);
142
- case 'ObjectTypeAnnotation':
143
- return wrap(val => `${val}.asObject(rt)`);
144
- case 'StringTypeAnnotation':
145
- return wrap(val => `${val}.asString(rt)`);
146
- default:
147
- throw new Error(
148
- `Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`,
149
- );
150
- }
151
- case 'ObjectTypeAnnotation':
152
- return wrap(val => `${val}.asObject(rt)`);
153
- case 'MixedTypeAnnotation':
154
- return wrap(val => `jsi::Value(rt, ${val})`);
155
- default:
156
- realTypeAnnotation.type;
157
- throw new Error(
158
- `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
159
- );
160
- }
161
- }
162
- function serializePropertyIntoHostFunction(
163
- moduleName,
164
- hasteModuleName,
165
- property,
166
- resolveAlias,
167
- enumMap,
168
- ) {
169
- const [propertyTypeAnnotation] = unwrapNullable(property.typeAnnotation);
170
- return HostFunctionTemplate({
171
- hasteModuleName,
172
- methodName: property.name,
173
- returnTypeAnnotation: propertyTypeAnnotation.returnTypeAnnotation,
174
- args: propertyTypeAnnotation.params.map((p, i) =>
175
- serializeArg(moduleName, p, i, resolveAlias, enumMap),
176
- ),
177
- });
178
- }
179
- module.exports = {
180
- generate(
181
- libraryName,
182
- schema,
183
- packageName,
184
- assumeNonnull = false,
185
- headerPrefix,
186
- ) {
187
- const nativeModules = getModules(schema);
188
- const modules = Object.keys(nativeModules)
189
- .map(hasteModuleName => {
190
- const nativeModule = nativeModules[hasteModuleName];
191
- const {
192
- aliasMap,
193
- enumMap,
194
- spec: {methods},
195
- moduleName,
196
- } = nativeModule;
197
- const resolveAlias = createAliasResolver(aliasMap);
198
- const hostFunctions = methods.map(property =>
199
- serializePropertyIntoHostFunction(
200
- moduleName,
201
- hasteModuleName,
202
- property,
203
- resolveAlias,
204
- enumMap,
205
- ),
206
- );
207
- return ModuleTemplate({
208
- hasteModuleName,
209
- hostFunctions,
210
- moduleName,
211
- methods: methods.map(
212
- ({name: propertyName, typeAnnotation: nullableTypeAnnotation}) => {
213
- const [{params}] = unwrapNullable(nullableTypeAnnotation);
214
- return {
215
- methodName: propertyName,
216
- paramCount: params.length,
217
- };
218
- },
219
- ),
220
- });
221
- })
222
- .join('\n');
223
- const fileName = `${libraryName}JSI-generated.cpp`;
224
- const replacedTemplate = FileTemplate({
225
- modules,
226
- libraryName,
227
- });
228
- return new Map([[fileName, replacedTemplate]]);
229
- },
230
- };
@@ -1,296 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow strict
8
- * @format
9
- */
10
-
11
- 'use strict';
12
-
13
- import type {
14
- NamedShape,
15
- NativeModuleEnumMap,
16
- NativeModuleFunctionTypeAnnotation,
17
- NativeModuleParamTypeAnnotation,
18
- NativeModulePropertyShape,
19
- NativeModuleTypeAnnotation,
20
- Nullable,
21
- SchemaType,
22
- } from '../../CodegenSchema';
23
- import type {AliasResolver} from './Utils';
24
-
25
- const {unwrapNullable} = require('../../parsers/parsers-commons');
26
- const {createAliasResolver, getModules} = require('./Utils');
27
-
28
- type FilesOutput = Map<string, string>;
29
-
30
- const HostFunctionTemplate = ({
31
- hasteModuleName,
32
- methodName,
33
- returnTypeAnnotation,
34
- args,
35
- }: $ReadOnly<{
36
- hasteModuleName: string,
37
- methodName: string,
38
- returnTypeAnnotation: Nullable<NativeModuleTypeAnnotation>,
39
- args: Array<string>,
40
- }>) => {
41
- const isNullable = returnTypeAnnotation.type === 'NullableTypeAnnotation';
42
- const isVoid = returnTypeAnnotation.type === 'VoidTypeAnnotation';
43
- const methodCallArgs = [' rt', ...args].join(',\n ');
44
- const methodCall = `static_cast<${hasteModuleName}CxxSpecJSI *>(&turboModule)->${methodName}(\n${methodCallArgs}\n )`;
45
-
46
- return `static jsi::Value __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {${
47
- isVoid
48
- ? `\n ${methodCall};`
49
- : isNullable
50
- ? `\n auto result = ${methodCall};`
51
- : ''
52
- }
53
- return ${
54
- isVoid
55
- ? 'jsi::Value::undefined()'
56
- : isNullable
57
- ? 'result ? jsi::Value(std::move(*result)) : jsi::Value::null()'
58
- : methodCall
59
- };
60
- }`;
61
- };
62
-
63
- const ModuleTemplate = ({
64
- hasteModuleName,
65
- hostFunctions,
66
- moduleName,
67
- methods,
68
- }: $ReadOnly<{
69
- hasteModuleName: string,
70
- hostFunctions: $ReadOnlyArray<string>,
71
- moduleName: string,
72
- methods: $ReadOnlyArray<$ReadOnly<{methodName: string, paramCount: number}>>,
73
- }>) => {
74
- return `${hostFunctions.join('\n')}
75
-
76
- ${hasteModuleName}CxxSpecJSI::${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
77
- : TurboModule("${moduleName}", jsInvoker) {
78
- ${methods
79
- .map(({methodName, paramCount}) => {
80
- return ` methodMap_["${methodName}"] = MethodMetadata {${paramCount}, __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}};`;
81
- })
82
- .join('\n')}
83
- }`;
84
- };
85
-
86
- const FileTemplate = ({
87
- libraryName,
88
- modules,
89
- }: $ReadOnly<{
90
- libraryName: string,
91
- modules: string,
92
- }>) => {
93
- return `/**
94
- * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
95
- *
96
- * Do not edit this file as changes may cause incorrect behavior and will be lost
97
- * once the code is regenerated.
98
- *
99
- * ${'@'}generated by codegen project: GenerateModuleCpp.js
100
- */
101
-
102
- #include "${libraryName}JSI.h"
103
-
104
- namespace facebook::react {
105
-
106
- ${modules}
107
-
108
-
109
- } // namespace facebook::react
110
- `;
111
- };
112
-
113
- type Param = NamedShape<Nullable<NativeModuleParamTypeAnnotation>>;
114
-
115
- function serializeArg(
116
- moduleName: string,
117
- arg: Param,
118
- index: number,
119
- resolveAlias: AliasResolver,
120
- enumMap: NativeModuleEnumMap,
121
- ): string {
122
- const {typeAnnotation: nullableTypeAnnotation, optional} = arg;
123
- const [typeAnnotation, nullable] =
124
- unwrapNullable<NativeModuleParamTypeAnnotation>(nullableTypeAnnotation);
125
-
126
- let realTypeAnnotation = typeAnnotation;
127
- if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
128
- realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
129
- }
130
-
131
- function wrap(callback: (val: string) => string) {
132
- const val = `args[${index}]`;
133
- const expression = callback(val);
134
-
135
- // param?: T
136
- if (optional && !nullable) {
137
- // throw new Error('are we hitting this case? ' + moduleName);
138
- return `count <= ${index} || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
139
- }
140
-
141
- // param: ?T
142
- // param?: ?T
143
- if (nullable || optional) {
144
- return `count <= ${index} || ${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
145
- }
146
-
147
- // param: T
148
- return `count <= ${index} ? throw jsi::JSError(rt, "Expected argument in position ${index} to be passed") : ${expression}`;
149
- }
150
-
151
- switch (realTypeAnnotation.type) {
152
- case 'ReservedTypeAnnotation':
153
- switch (realTypeAnnotation.name) {
154
- case 'RootTag':
155
- return wrap(val => `${val}.asNumber()`);
156
- default:
157
- (realTypeAnnotation.name: empty);
158
- throw new Error(
159
- `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.name}"`,
160
- );
161
- }
162
- case 'StringTypeAnnotation':
163
- return wrap(val => `${val}.asString(rt)`);
164
- case 'StringLiteralTypeAnnotation':
165
- return wrap(val => `${val}.asString(rt)`);
166
- case 'StringLiteralUnionTypeAnnotation':
167
- return wrap(val => `${val}.asString(rt)`);
168
- case 'BooleanTypeAnnotation':
169
- return wrap(val => `${val}.asBool()`);
170
- case 'EnumDeclaration':
171
- switch (realTypeAnnotation.memberType) {
172
- case 'NumberTypeAnnotation':
173
- return wrap(val => `${val}.asNumber()`);
174
- case 'StringTypeAnnotation':
175
- return wrap(val => `${val}.asString(rt)`);
176
- default:
177
- throw new Error(
178
- `Unknown enum type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
179
- );
180
- }
181
- case 'NumberTypeAnnotation':
182
- return wrap(val => `${val}.asNumber()`);
183
- case 'FloatTypeAnnotation':
184
- return wrap(val => `${val}.asNumber()`);
185
- case 'DoubleTypeAnnotation':
186
- return wrap(val => `${val}.asNumber()`);
187
- case 'Int32TypeAnnotation':
188
- return wrap(val => `${val}.asNumber()`);
189
- case 'NumberLiteralTypeAnnotation':
190
- return wrap(val => `${val}.asNumber()`);
191
- case 'ArrayTypeAnnotation':
192
- return wrap(val => `${val}.asObject(rt).asArray(rt)`);
193
- case 'FunctionTypeAnnotation':
194
- return wrap(val => `${val}.asObject(rt).asFunction(rt)`);
195
- case 'GenericObjectTypeAnnotation':
196
- return wrap(val => `${val}.asObject(rt)`);
197
- case 'UnionTypeAnnotation':
198
- switch (typeAnnotation.memberType) {
199
- case 'NumberTypeAnnotation':
200
- return wrap(val => `${val}.asNumber()`);
201
- case 'ObjectTypeAnnotation':
202
- return wrap(val => `${val}.asObject(rt)`);
203
- case 'StringTypeAnnotation':
204
- return wrap(val => `${val}.asString(rt)`);
205
- default:
206
- throw new Error(
207
- `Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`,
208
- );
209
- }
210
- case 'ObjectTypeAnnotation':
211
- return wrap(val => `${val}.asObject(rt)`);
212
- case 'MixedTypeAnnotation':
213
- return wrap(val => `jsi::Value(rt, ${val})`);
214
- default:
215
- (realTypeAnnotation.type: empty);
216
- throw new Error(
217
- `Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
218
- );
219
- }
220
- }
221
-
222
- function serializePropertyIntoHostFunction(
223
- moduleName: string,
224
- hasteModuleName: string,
225
- property: NativeModulePropertyShape,
226
- resolveAlias: AliasResolver,
227
- enumMap: NativeModuleEnumMap,
228
- ): string {
229
- const [propertyTypeAnnotation] =
230
- unwrapNullable<NativeModuleFunctionTypeAnnotation>(property.typeAnnotation);
231
-
232
- return HostFunctionTemplate({
233
- hasteModuleName,
234
- methodName: property.name,
235
- returnTypeAnnotation: propertyTypeAnnotation.returnTypeAnnotation,
236
- args: propertyTypeAnnotation.params.map((p, i) =>
237
- serializeArg(moduleName, p, i, resolveAlias, enumMap),
238
- ),
239
- });
240
- }
241
-
242
- module.exports = {
243
- generate(
244
- libraryName: string,
245
- schema: SchemaType,
246
- packageName?: string,
247
- assumeNonnull: boolean = false,
248
- headerPrefix?: string,
249
- ): FilesOutput {
250
- const nativeModules = getModules(schema);
251
-
252
- const modules = Object.keys(nativeModules)
253
- .map((hasteModuleName: string) => {
254
- const nativeModule = nativeModules[hasteModuleName];
255
- const {
256
- aliasMap,
257
- enumMap,
258
- spec: {methods},
259
- moduleName,
260
- } = nativeModule;
261
- const resolveAlias = createAliasResolver(aliasMap);
262
- const hostFunctions = methods.map(property =>
263
- serializePropertyIntoHostFunction(
264
- moduleName,
265
- hasteModuleName,
266
- property,
267
- resolveAlias,
268
- enumMap,
269
- ),
270
- );
271
-
272
- return ModuleTemplate({
273
- hasteModuleName,
274
- hostFunctions,
275
- moduleName,
276
- methods: methods.map(
277
- ({name: propertyName, typeAnnotation: nullableTypeAnnotation}) => {
278
- const [{params}] = unwrapNullable(nullableTypeAnnotation);
279
- return {
280
- methodName: propertyName,
281
- paramCount: params.length,
282
- };
283
- },
284
- ),
285
- });
286
- })
287
- .join('\n');
288
-
289
- const fileName = `${libraryName}JSI-generated.cpp`;
290
- const replacedTemplate = FileTemplate({
291
- modules,
292
- libraryName,
293
- });
294
- return new Map([[fileName, replacedTemplate]]);
295
- },
296
- };