nitrogen 0.31.5 → 0.31.6

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.
@@ -79,12 +79,14 @@ function getHybridObjectSpec(type, language) {
79
79
  }
80
80
  if (Node.isPropertySignature(declaration)) {
81
81
  const t = declaration.getType();
82
- const propType = createType(language, t, prop.isOptional() || t.isNullable());
82
+ const isOptional = prop.isOptional() || t.getUnionTypes().some((u) => u.isUndefined());
83
+ const propType = createType(language, t, isOptional);
83
84
  properties.push(new Property(prop.getName(), propType, declaration.isReadonly()));
84
85
  }
85
86
  else if (Node.isMethodSignature(declaration)) {
86
87
  const returnType = declaration.getReturnType();
87
- const methodReturnType = createType(language, returnType, returnType.isNullable());
88
+ const isOptional = returnType.getUnionTypes().some((t) => t.isUndefined());
89
+ const methodReturnType = createType(language, returnType, isOptional);
88
90
  const methodParameters = declaration
89
91
  .getParameters()
90
92
  .map((p) => new Parameter(p, language));
@@ -1,5 +1,4 @@
1
1
  import { ts, Type as TSMorphType } from 'ts-morph';
2
- import { NullType } from './types/NullType.js';
3
2
  import { BooleanType } from './types/BooleanType.js';
4
3
  import { NumberType } from './types/NumberType.js';
5
4
  import { StringType } from './types/StringType.js';
@@ -29,6 +28,7 @@ import { CustomType } from './types/CustomType.js';
29
28
  import { isSyncFunction, isArrayBuffer, isCustomType, isDate, isError, isMap, isPromise, isRecord, } from './isCoreType.js';
30
29
  import { getCustomTypeConfig } from './getCustomTypeConfig.js';
31
30
  import { compareLooselyness } from './helpers.js';
31
+ import { NullType } from './types/NullType.js';
32
32
  function getHybridObjectName(type) {
33
33
  const symbol = isHybridView(type) ? type.getAliasSymbol() : type.getSymbol();
34
34
  if (symbol == null) {
@@ -122,7 +122,7 @@ export function createType(language, type, isOptional) {
122
122
  const wrapping = createType(language, type, false);
123
123
  return new OptionalType(wrapping);
124
124
  }
125
- if (type.isNull() || type.isUndefined()) {
125
+ if (type.isNull()) {
126
126
  return new NullType();
127
127
  }
128
128
  else if (type.isBoolean() || type.isBooleanLiteral()) {
@@ -166,7 +166,10 @@ export function createType(language, type, isOptional) {
166
166
  // It's a function!
167
167
  const callSignature = getFunctionCallSignature(type);
168
168
  const funcReturnType = callSignature.getReturnType();
169
- const returnType = createType(language, funcReturnType, funcReturnType.isNullable());
169
+ const isReturnOptional = funcReturnType
170
+ .getUnionTypes()
171
+ .some((t) => t.isUndefined());
172
+ const returnType = createType(language, funcReturnType, isReturnOptional);
170
173
  const parameters = callSignature.getParameters().map((p) => {
171
174
  const declaration = p.getValueDeclarationOrThrow();
172
175
  const parameterType = p.getTypeAtLocation(declaration);
@@ -179,7 +182,10 @@ export function createType(language, type, isOptional) {
179
182
  else if (isPromise(type)) {
180
183
  // It's a Promise!
181
184
  const [promiseResolvingType] = getArguments(type, 'Promise', 1);
182
- const resolvingType = createType(language, promiseResolvingType, promiseResolvingType.isNullable());
185
+ const isResolvingOptional = promiseResolvingType
186
+ .getUnionTypes()
187
+ .some((t) => t.isUndefined());
188
+ const resolvingType = createType(language, promiseResolvingType, isResolvingOptional);
183
189
  return new PromiseType(resolvingType);
184
190
  }
185
191
  else if (isRecord(type)) {
@@ -240,8 +246,8 @@ export function createType(language, type, isOptional) {
240
246
  // It consists of different types - that means it's a variant!
241
247
  let variants = type
242
248
  .getUnionTypes()
243
- // Filter out any nulls or undefineds, as those are already treated as `isOptional`.
244
- .filter((t) => !t.isNull() && !t.isUndefined() && !t.isVoid())
249
+ // Filter out any undefineds/voids, as those are already treated as `isOptional`.
250
+ .filter((t) => !t.isUndefined() && !t.isVoid())
245
251
  .map((t) => createType(language, t, false))
246
252
  .toSorted(compareLooselyness);
247
253
  variants = removeDuplicates(variants);
@@ -294,6 +300,12 @@ export function createType(language, type, isOptional) {
294
300
  else if (type.isStringLiteral()) {
295
301
  throw new Error(`String literal ${type.getText()} cannot be represented in C++ because it is ambiguous between a string and a discriminating union enum.`);
296
302
  }
303
+ else if (type.isUndefined()) {
304
+ throw new Error(`The TypeScript type "undefined" cannot be represented in Nitro.\n` +
305
+ `- If you want to make a type optional, add \`?\` to it's name, or make it an union with \`undefined\`.\n` +
306
+ `- If you want a method that returns nothing, use \`void\` instead.\n` +
307
+ `- If you want to represent an explicit absence of a value, use \`null\` instead.`);
308
+ }
297
309
  else if (type.isAny()) {
298
310
  throw new Error(`The TypeScript type "${type.getText()}" resolved to any - any is not supported in Nitro.`);
299
311
  }
@@ -13,6 +13,7 @@ export declare class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'
13
13
  asJniReferenceType(referenceType?: 'alias' | 'local' | 'global'): string;
14
14
  getTypeCode(language: 'kotlin' | 'c++', isBoxed?: boolean): string;
15
15
  parse(parameterName: string, from: 'c++' | 'kotlin', to: 'kotlin' | 'c++', inLanguage: 'kotlin' | 'c++'): string;
16
+ dereferenceToJObject(parameterName: string): string;
16
17
  parseFromCppToKotlin(parameterName: string, language: 'kotlin' | 'c++', isBoxed?: boolean): string;
17
18
  parseFromKotlinToCpp(parameterName: string, language: 'kotlin' | 'c++', isBoxed?: boolean): string;
18
19
  private getFullJHybridObjectName;
@@ -22,7 +22,7 @@ export class KotlinCxxBridgedType {
22
22
  this.type = type;
23
23
  }
24
24
  get hasType() {
25
- return this.type.kind !== 'void' && this.type.kind !== 'null';
25
+ return this.type.kind !== 'void';
26
26
  }
27
27
  get canBePassedByReference() {
28
28
  return this.type.canBePassedByReference;
@@ -37,6 +37,16 @@ export class KotlinCxxBridgedType {
37
37
  const optional = getTypeAs(this.type, OptionalType);
38
38
  return new KotlinCxxBridgedType(optional.wrappingType)
39
39
  .needsSpecialHandling;
40
+ case 'array':
41
+ // Arrays need special handling if their item type needs special handling
42
+ const array = getTypeAs(this.type, ArrayType);
43
+ return new KotlinCxxBridgedType(array.itemType).needsSpecialHandling;
44
+ case 'record':
45
+ // Records need special handling if their key or value type needs special handling
46
+ const record = getTypeAs(this.type, RecordType);
47
+ const keyType = new KotlinCxxBridgedType(record.keyType);
48
+ const valueType = new KotlinCxxBridgedType(record.valueType);
49
+ return keyType.needsSpecialHandling || valueType.needsSpecialHandling;
40
50
  default:
41
51
  break;
42
52
  }
@@ -72,6 +82,13 @@ export class KotlinCxxBridgedType {
72
82
  space: 'user',
73
83
  });
74
84
  break;
85
+ case 'null':
86
+ imports.push({
87
+ language: 'c++',
88
+ name: `NitroModules/JNull.hpp`,
89
+ space: 'system',
90
+ });
91
+ break;
75
92
  case 'array-buffer':
76
93
  imports.push({
77
94
  language: 'c++',
@@ -295,6 +312,13 @@ export class KotlinCxxBridgedType {
295
312
  return this.type.getCode(language);
296
313
  }
297
314
  }
315
+ case 'null':
316
+ switch (language) {
317
+ case 'c++':
318
+ return `JNull`;
319
+ default:
320
+ return this.type.getCode(language);
321
+ }
298
322
  case 'array-buffer':
299
323
  switch (language) {
300
324
  case 'c++':
@@ -379,6 +403,21 @@ export class KotlinCxxBridgedType {
379
403
  throw new Error(`Cannot parse "${parameterName}" from ${from} to ${to}!`);
380
404
  }
381
405
  }
406
+ dereferenceToJObject(parameterName) {
407
+ switch (this.type.kind) {
408
+ // any jni::HybridClass needs to be dereferenced to jobject with .get()
409
+ case 'array-buffer':
410
+ case 'function':
411
+ case 'hybrid-object':
412
+ case 'hybrid-object-base':
413
+ case 'map':
414
+ case 'promise':
415
+ return `${parameterName}.get()`;
416
+ // anything else can be dereferenced to jobject with *
417
+ default:
418
+ return `*${parameterName}`;
419
+ }
420
+ }
382
421
  parseFromCppToKotlin(parameterName, language, isBoxed = false) {
383
422
  switch (this.type.kind) {
384
423
  case 'number':
@@ -423,6 +462,14 @@ export class KotlinCxxBridgedType {
423
462
  return parameterName;
424
463
  }
425
464
  }
465
+ case 'null': {
466
+ switch (language) {
467
+ case 'c++':
468
+ return `JNull::null()`;
469
+ default:
470
+ return parameterName;
471
+ }
472
+ }
426
473
  case 'date': {
427
474
  switch (language) {
428
475
  case 'c++':
@@ -546,7 +593,8 @@ export class KotlinCxxBridgedType {
546
593
  jni::local_ref<${arrayType}> __array = ${arrayType}::newArray(__size);
547
594
  for (size_t __i = 0; __i < __size; __i++) {
548
595
  const auto& __element = ${parameterName}[__i];
549
- __array->setElement(__i, *${indent(bridge.parseFromCppToKotlin('__element', 'c++'), ' ')});
596
+ auto __elementJni = ${indent(bridge.parseFromCppToKotlin('__element', 'c++'), ' ')};
597
+ __array->setElement(__i, ${bridge.dereferenceToJObject('__elementJni')});
550
598
  }
551
599
  return __array;
552
600
  }()
@@ -556,7 +604,9 @@ export class KotlinCxxBridgedType {
556
604
  }
557
605
  case 'kotlin':
558
606
  if (bridge.needsSpecialHandling) {
559
- return `${parameterName}.map { ${bridge.parseFromCppToKotlin('it', language, isBoxed)} }`;
607
+ const variableName = `${parameterName}[i]`;
608
+ const parseCode = bridge.parseFromCppToKotlin(variableName, 'kotlin', isBoxed);
609
+ return `Array(${parameterName}.size) { i -> ${parseCode} }`;
560
610
  }
561
611
  else {
562
612
  return parameterName;
@@ -678,6 +728,14 @@ export class KotlinCxxBridgedType {
678
728
  return parameterName;
679
729
  }
680
730
  }
731
+ case 'null': {
732
+ switch (language) {
733
+ case 'c++':
734
+ return `nitro::null`;
735
+ default:
736
+ return parameterName;
737
+ }
738
+ }
681
739
  case 'hybrid-object': {
682
740
  switch (language) {
683
741
  case 'c++':
@@ -775,10 +833,10 @@ export class KotlinCxxBridgedType {
775
833
  }
776
834
  }
777
835
  case 'array': {
836
+ const array = getTypeAs(this.type, ArrayType);
837
+ const bridge = new KotlinCxxBridgedType(array.itemType);
778
838
  switch (language) {
779
- case 'c++':
780
- const array = getTypeAs(this.type, ArrayType);
781
- const bridge = new KotlinCxxBridgedType(array.itemType);
839
+ case 'c++': {
782
840
  const itemType = array.itemType.getCode('c++');
783
841
  switch (array.itemType.kind) {
784
842
  case 'number':
@@ -811,6 +869,16 @@ export class KotlinCxxBridgedType {
811
869
  `.trim();
812
870
  }
813
871
  }
872
+ }
873
+ case 'kotlin':
874
+ if (bridge.needsSpecialHandling) {
875
+ const variableName = `${parameterName}[i]`;
876
+ const parseCode = bridge.parseFromKotlinToCpp(variableName, 'kotlin', isBoxed);
877
+ return `Array(${parameterName}.size) { i -> ${parseCode} }`;
878
+ }
879
+ else {
880
+ return parameterName;
881
+ }
814
882
  default:
815
883
  return parameterName;
816
884
  }
@@ -31,7 +31,7 @@ export class SwiftCxxBridgedType {
31
31
  this.isBridgingToDirectCppTarget = isBridgingToDirectCppTarget;
32
32
  }
33
33
  get hasType() {
34
- return this.type.kind !== 'void' && this.type.kind !== 'null';
34
+ return this.type.kind !== 'void';
35
35
  }
36
36
  get canBePassedByReference() {
37
37
  return this.type.canBePassedByReference;
@@ -53,6 +53,9 @@ export class SwiftCxxBridgedType {
53
53
  case 'optional':
54
54
  // swift::Optional<T> <> std::optional<T>
55
55
  return true;
56
+ case 'null':
57
+ // NullType <> nitro::null
58
+ return true;
56
59
  case 'string':
57
60
  // swift::String <> std::string
58
61
  return true;
@@ -220,6 +223,13 @@ export class SwiftCxxBridgedType {
220
223
  return this.type.getCode(language);
221
224
  }
222
225
  }
226
+ case 'null':
227
+ switch (language) {
228
+ case 'swift':
229
+ return 'margelo.nitro.NullType';
230
+ default:
231
+ return this.type.getCode(language);
232
+ }
223
233
  case 'array-buffer':
224
234
  if (this.isBridgingToDirectCppTarget) {
225
235
  return this.type.getCode(language);
@@ -393,6 +403,13 @@ export class SwiftCxxBridgedType {
393
403
  return cppParameterName;
394
404
  }
395
405
  }
406
+ case 'null':
407
+ switch (language) {
408
+ case 'swift':
409
+ return `NullType.null`;
410
+ default:
411
+ return cppParameterName;
412
+ }
396
413
  case 'optional': {
397
414
  const optional = getTypeAs(this.type, OptionalType);
398
415
  const wrapping = new SwiftCxxBridgedType(optional.wrappingType, true);
@@ -606,6 +623,13 @@ case ${i}:
606
623
  return swiftParameterName;
607
624
  }
608
625
  }
626
+ case 'null':
627
+ switch (language) {
628
+ case 'swift':
629
+ return `margelo.nitro.NullType.null`;
630
+ default:
631
+ return swiftParameterName;
632
+ }
609
633
  case 'optional': {
610
634
  const optional = getTypeAs(this.type, OptionalType);
611
635
  const wrapping = new SwiftCxxBridgedType(optional.wrappingType, true);
@@ -6,5 +6,5 @@ export declare class NullType implements Type {
6
6
  get kind(): TypeKind;
7
7
  getCode(language: Language): string;
8
8
  getExtraFiles(): SourceFile[];
9
- getRequiredImports(): SourceImport[];
9
+ getRequiredImports(language: Language): SourceImport[];
10
10
  }
@@ -9,7 +9,11 @@ export class NullType {
9
9
  getCode(language) {
10
10
  switch (language) {
11
11
  case 'c++':
12
- return 'std::nullptr_t';
12
+ return 'nitro::NullType';
13
+ case 'swift':
14
+ return 'NullType';
15
+ case 'kotlin':
16
+ return 'NullType';
13
17
  default:
14
18
  throw new Error(`Language ${language} is not yet supported for NullType!`);
15
19
  }
@@ -17,7 +21,31 @@ export class NullType {
17
21
  getExtraFiles() {
18
22
  return [];
19
23
  }
20
- getRequiredImports() {
21
- return [];
24
+ getRequiredImports(language) {
25
+ const imports = [];
26
+ switch (language) {
27
+ case 'c++':
28
+ imports.push({
29
+ language: language,
30
+ name: 'NitroModules/Null.hpp',
31
+ space: 'system',
32
+ });
33
+ break;
34
+ case 'swift':
35
+ imports.push({
36
+ language: language,
37
+ name: 'NitroModules',
38
+ space: 'system',
39
+ });
40
+ break;
41
+ case 'kotlin':
42
+ imports.push({
43
+ language: language,
44
+ name: 'com.margelo.nitro.core.NullType',
45
+ space: 'system',
46
+ });
47
+ break;
48
+ }
49
+ return imports;
22
50
  }
23
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitrogen",
3
- "version": "0.31.5",
3
+ "version": "0.31.6",
4
4
  "description": "The code-generator for react-native-nitro-modules.",
5
5
  "main": "lib/index",
6
6
  "types": "lib/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "chalk": "^5.3.0",
39
- "react-native-nitro-modules": "^0.31.5",
39
+ "react-native-nitro-modules": "^0.31.6",
40
40
  "ts-morph": "^27.0.0",
41
41
  "yargs": "^18.0.0",
42
42
  "zod": "^4.0.5"
@@ -111,21 +111,16 @@ function getHybridObjectSpec(type: Type, language: Language): HybridObjectSpec {
111
111
 
112
112
  if (Node.isPropertySignature(declaration)) {
113
113
  const t = declaration.getType()
114
- const propType = createType(
115
- language,
116
- t,
117
- prop.isOptional() || t.isNullable()
118
- )
114
+ const isOptional =
115
+ prop.isOptional() || t.getUnionTypes().some((u) => u.isUndefined())
116
+ const propType = createType(language, t, isOptional)
119
117
  properties.push(
120
118
  new Property(prop.getName(), propType, declaration.isReadonly())
121
119
  )
122
120
  } else if (Node.isMethodSignature(declaration)) {
123
121
  const returnType = declaration.getReturnType()
124
- const methodReturnType = createType(
125
- language,
126
- returnType,
127
- returnType.isNullable()
128
- )
122
+ const isOptional = returnType.getUnionTypes().some((t) => t.isUndefined())
123
+ const methodReturnType = createType(language, returnType, isOptional)
129
124
  const methodParameters = declaration
130
125
  .getParameters()
131
126
  .map((p) => new Parameter(p, language))
@@ -1,6 +1,5 @@
1
1
  import { ts, Type as TSMorphType, type Signature } from 'ts-morph'
2
2
  import type { Type } from './types/Type.js'
3
- import { NullType } from './types/NullType.js'
4
3
  import { BooleanType } from './types/BooleanType.js'
5
4
  import { NumberType } from './types/NumberType.js'
6
5
  import { StringType } from './types/StringType.js'
@@ -44,6 +43,7 @@ import {
44
43
  } from './isCoreType.js'
45
44
  import { getCustomTypeConfig } from './getCustomTypeConfig.js'
46
45
  import { compareLooselyness } from './helpers.js'
46
+ import { NullType } from './types/NullType.js'
47
47
 
48
48
  function getHybridObjectName(type: TSMorphType): string {
49
49
  const symbol = isHybridView(type) ? type.getAliasSymbol() : type.getSymbol()
@@ -184,7 +184,7 @@ export function createType(
184
184
  return new OptionalType(wrapping)
185
185
  }
186
186
 
187
- if (type.isNull() || type.isUndefined()) {
187
+ if (type.isNull()) {
188
188
  return new NullType()
189
189
  } else if (type.isBoolean() || type.isBooleanLiteral()) {
190
190
  return new BooleanType()
@@ -222,11 +222,10 @@ export function createType(
222
222
  // It's a function!
223
223
  const callSignature = getFunctionCallSignature(type)
224
224
  const funcReturnType = callSignature.getReturnType()
225
- const returnType = createType(
226
- language,
227
- funcReturnType,
228
- funcReturnType.isNullable()
229
- )
225
+ const isReturnOptional = funcReturnType
226
+ .getUnionTypes()
227
+ .some((t) => t.isUndefined())
228
+ const returnType = createType(language, funcReturnType, isReturnOptional)
230
229
  const parameters = callSignature.getParameters().map((p) => {
231
230
  const declaration = p.getValueDeclarationOrThrow()
232
231
  const parameterType = p.getTypeAtLocation(declaration)
@@ -238,10 +237,13 @@ export function createType(
238
237
  } else if (isPromise(type)) {
239
238
  // It's a Promise!
240
239
  const [promiseResolvingType] = getArguments(type, 'Promise', 1)
240
+ const isResolvingOptional = promiseResolvingType
241
+ .getUnionTypes()
242
+ .some((t) => t.isUndefined())
241
243
  const resolvingType = createType(
242
244
  language,
243
245
  promiseResolvingType,
244
- promiseResolvingType.isNullable()
246
+ isResolvingOptional
245
247
  )
246
248
  return new PromiseType(resolvingType)
247
249
  } else if (isRecord(type)) {
@@ -300,8 +302,8 @@ export function createType(
300
302
  // It consists of different types - that means it's a variant!
301
303
  let variants = type
302
304
  .getUnionTypes()
303
- // Filter out any nulls or undefineds, as those are already treated as `isOptional`.
304
- .filter((t) => !t.isNull() && !t.isUndefined() && !t.isVoid())
305
+ // Filter out any undefineds/voids, as those are already treated as `isOptional`.
306
+ .filter((t) => !t.isUndefined() && !t.isVoid())
305
307
  .map((t) => createType(language, t, false))
306
308
  .toSorted(compareLooselyness)
307
309
  variants = removeDuplicates(variants)
@@ -354,6 +356,13 @@ export function createType(
354
356
  throw new Error(
355
357
  `String literal ${type.getText()} cannot be represented in C++ because it is ambiguous between a string and a discriminating union enum.`
356
358
  )
359
+ } else if (type.isUndefined()) {
360
+ throw new Error(
361
+ `The TypeScript type "undefined" cannot be represented in Nitro.\n` +
362
+ `- If you want to make a type optional, add \`?\` to it's name, or make it an union with \`undefined\`.\n` +
363
+ `- If you want a method that returns nothing, use \`void\` instead.\n` +
364
+ `- If you want to represent an explicit absence of a value, use \`null\` instead.`
365
+ )
357
366
  } else if (type.isAny()) {
358
367
  throw new Error(
359
368
  `The TypeScript type "${type.getText()}" resolved to any - any is not supported in Nitro.`
@@ -29,7 +29,7 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
29
29
  }
30
30
 
31
31
  get hasType(): boolean {
32
- return this.type.kind !== 'void' && this.type.kind !== 'null'
32
+ return this.type.kind !== 'void'
33
33
  }
34
34
 
35
35
  get canBePassedByReference(): boolean {
@@ -46,6 +46,16 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
46
46
  const optional = getTypeAs(this.type, OptionalType)
47
47
  return new KotlinCxxBridgedType(optional.wrappingType)
48
48
  .needsSpecialHandling
49
+ case 'array':
50
+ // Arrays need special handling if their item type needs special handling
51
+ const array = getTypeAs(this.type, ArrayType)
52
+ return new KotlinCxxBridgedType(array.itemType).needsSpecialHandling
53
+ case 'record':
54
+ // Records need special handling if their key or value type needs special handling
55
+ const record = getTypeAs(this.type, RecordType)
56
+ const keyType = new KotlinCxxBridgedType(record.keyType)
57
+ const valueType = new KotlinCxxBridgedType(record.valueType)
58
+ return keyType.needsSpecialHandling || valueType.needsSpecialHandling
49
59
  default:
50
60
  break
51
61
  }
@@ -83,6 +93,13 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
83
93
  space: 'user',
84
94
  })
85
95
  break
96
+ case 'null':
97
+ imports.push({
98
+ language: 'c++',
99
+ name: `NitroModules/JNull.hpp`,
100
+ space: 'system',
101
+ })
102
+ break
86
103
  case 'array-buffer':
87
104
  imports.push({
88
105
  language: 'c++',
@@ -316,6 +333,13 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
316
333
  return this.type.getCode(language)
317
334
  }
318
335
  }
336
+ case 'null':
337
+ switch (language) {
338
+ case 'c++':
339
+ return `JNull`
340
+ default:
341
+ return this.type.getCode(language)
342
+ }
319
343
  case 'array-buffer':
320
344
  switch (language) {
321
345
  case 'c++':
@@ -407,6 +431,22 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
407
431
  }
408
432
  }
409
433
 
434
+ dereferenceToJObject(parameterName: string): string {
435
+ switch (this.type.kind) {
436
+ // any jni::HybridClass needs to be dereferenced to jobject with .get()
437
+ case 'array-buffer':
438
+ case 'function':
439
+ case 'hybrid-object':
440
+ case 'hybrid-object-base':
441
+ case 'map':
442
+ case 'promise':
443
+ return `${parameterName}.get()`
444
+ // anything else can be dereferenced to jobject with *
445
+ default:
446
+ return `*${parameterName}`
447
+ }
448
+ }
449
+
410
450
  parseFromCppToKotlin(
411
451
  parameterName: string,
412
452
  language: 'kotlin' | 'c++',
@@ -454,6 +494,14 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
454
494
  return parameterName
455
495
  }
456
496
  }
497
+ case 'null': {
498
+ switch (language) {
499
+ case 'c++':
500
+ return `JNull::null()`
501
+ default:
502
+ return parameterName
503
+ }
504
+ }
457
505
  case 'date': {
458
506
  switch (language) {
459
507
  case 'c++':
@@ -579,7 +627,8 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
579
627
  jni::local_ref<${arrayType}> __array = ${arrayType}::newArray(__size);
580
628
  for (size_t __i = 0; __i < __size; __i++) {
581
629
  const auto& __element = ${parameterName}[__i];
582
- __array->setElement(__i, *${indent(bridge.parseFromCppToKotlin('__element', 'c++'), ' ')});
630
+ auto __elementJni = ${indent(bridge.parseFromCppToKotlin('__element', 'c++'), ' ')};
631
+ __array->setElement(__i, ${bridge.dereferenceToJObject('__elementJni')});
583
632
  }
584
633
  return __array;
585
634
  }()
@@ -589,7 +638,13 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
589
638
  }
590
639
  case 'kotlin':
591
640
  if (bridge.needsSpecialHandling) {
592
- return `${parameterName}.map { ${bridge.parseFromCppToKotlin('it', language, isBoxed)} }`
641
+ const variableName = `${parameterName}[i]`
642
+ const parseCode = bridge.parseFromCppToKotlin(
643
+ variableName,
644
+ 'kotlin',
645
+ isBoxed
646
+ )
647
+ return `Array(${parameterName}.size) { i -> ${parseCode} }`
593
648
  } else {
594
649
  return parameterName
595
650
  }
@@ -713,6 +768,14 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
713
768
  return parameterName
714
769
  }
715
770
  }
771
+ case 'null': {
772
+ switch (language) {
773
+ case 'c++':
774
+ return `nitro::null`
775
+ default:
776
+ return parameterName
777
+ }
778
+ }
716
779
  case 'hybrid-object': {
717
780
  switch (language) {
718
781
  case 'c++':
@@ -820,10 +883,10 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
820
883
  }
821
884
  }
822
885
  case 'array': {
886
+ const array = getTypeAs(this.type, ArrayType)
887
+ const bridge = new KotlinCxxBridgedType(array.itemType)
823
888
  switch (language) {
824
- case 'c++':
825
- const array = getTypeAs(this.type, ArrayType)
826
- const bridge = new KotlinCxxBridgedType(array.itemType)
889
+ case 'c++': {
827
890
  const itemType = array.itemType.getCode('c++')
828
891
  switch (array.itemType.kind) {
829
892
  case 'number':
@@ -856,6 +919,19 @@ export class KotlinCxxBridgedType implements BridgedType<'kotlin', 'c++'> {
856
919
  `.trim()
857
920
  }
858
921
  }
922
+ }
923
+ case 'kotlin':
924
+ if (bridge.needsSpecialHandling) {
925
+ const variableName = `${parameterName}[i]`
926
+ const parseCode = bridge.parseFromKotlinToCpp(
927
+ variableName,
928
+ 'kotlin',
929
+ isBoxed
930
+ )
931
+ return `Array(${parameterName}.size) { i -> ${parseCode} }`
932
+ } else {
933
+ return parameterName
934
+ }
859
935
  default:
860
936
  return parameterName
861
937
  }
@@ -45,7 +45,7 @@ export class SwiftCxxBridgedType implements BridgedType<'swift', 'c++'> {
45
45
  }
46
46
 
47
47
  get hasType(): boolean {
48
- return this.type.kind !== 'void' && this.type.kind !== 'null'
48
+ return this.type.kind !== 'void'
49
49
  }
50
50
 
51
51
  get canBePassedByReference(): boolean {
@@ -69,6 +69,9 @@ export class SwiftCxxBridgedType implements BridgedType<'swift', 'c++'> {
69
69
  case 'optional':
70
70
  // swift::Optional<T> <> std::optional<T>
71
71
  return true
72
+ case 'null':
73
+ // NullType <> nitro::null
74
+ return true
72
75
  case 'string':
73
76
  // swift::String <> std::string
74
77
  return true
@@ -253,6 +256,13 @@ export class SwiftCxxBridgedType implements BridgedType<'swift', 'c++'> {
253
256
  return this.type.getCode(language)
254
257
  }
255
258
  }
259
+ case 'null':
260
+ switch (language) {
261
+ case 'swift':
262
+ return 'margelo.nitro.NullType'
263
+ default:
264
+ return this.type.getCode(language)
265
+ }
256
266
  case 'array-buffer':
257
267
  if (this.isBridgingToDirectCppTarget) {
258
268
  return this.type.getCode(language)
@@ -433,6 +443,13 @@ export class SwiftCxxBridgedType implements BridgedType<'swift', 'c++'> {
433
443
  return cppParameterName
434
444
  }
435
445
  }
446
+ case 'null':
447
+ switch (language) {
448
+ case 'swift':
449
+ return `NullType.null`
450
+ default:
451
+ return cppParameterName
452
+ }
436
453
  case 'optional': {
437
454
  const optional = getTypeAs(this.type, OptionalType)
438
455
  const wrapping = new SwiftCxxBridgedType(optional.wrappingType, true)
@@ -656,6 +673,13 @@ case ${i}:
656
673
  return swiftParameterName
657
674
  }
658
675
  }
676
+ case 'null':
677
+ switch (language) {
678
+ case 'swift':
679
+ return `margelo.nitro.NullType.null`
680
+ default:
681
+ return swiftParameterName
682
+ }
659
683
  case 'optional': {
660
684
  const optional = getTypeAs(this.type, OptionalType)
661
685
  const wrapping = new SwiftCxxBridgedType(optional.wrappingType, true)
@@ -14,7 +14,11 @@ export class NullType implements Type {
14
14
  getCode(language: Language): string {
15
15
  switch (language) {
16
16
  case 'c++':
17
- return 'std::nullptr_t'
17
+ return 'nitro::NullType'
18
+ case 'swift':
19
+ return 'NullType'
20
+ case 'kotlin':
21
+ return 'NullType'
18
22
  default:
19
23
  throw new Error(
20
24
  `Language ${language} is not yet supported for NullType!`
@@ -24,7 +28,31 @@ export class NullType implements Type {
24
28
  getExtraFiles(): SourceFile[] {
25
29
  return []
26
30
  }
27
- getRequiredImports(): SourceImport[] {
28
- return []
31
+ getRequiredImports(language: Language): SourceImport[] {
32
+ const imports: SourceImport[] = []
33
+ switch (language) {
34
+ case 'c++':
35
+ imports.push({
36
+ language: language,
37
+ name: 'NitroModules/Null.hpp',
38
+ space: 'system',
39
+ })
40
+ break
41
+ case 'swift':
42
+ imports.push({
43
+ language: language,
44
+ name: 'NitroModules',
45
+ space: 'system',
46
+ })
47
+ break
48
+ case 'kotlin':
49
+ imports.push({
50
+ language: language,
51
+ name: 'com.margelo.nitro.core.NullType',
52
+ space: 'system',
53
+ })
54
+ break
55
+ }
56
+ return imports
29
57
  }
30
58
  }