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.
- package/lib/createPlatformSpec.js +4 -2
- package/lib/syntax/createType.js +18 -6
- package/lib/syntax/kotlin/KotlinCxxBridgedType.d.ts +1 -0
- package/lib/syntax/kotlin/KotlinCxxBridgedType.js +74 -6
- package/lib/syntax/swift/SwiftCxxBridgedType.js +25 -1
- package/lib/syntax/types/NullType.d.ts +1 -1
- package/lib/syntax/types/NullType.js +31 -3
- package/package.json +2 -2
- package/src/createPlatformSpec.ts +5 -10
- package/src/syntax/createType.ts +19 -10
- package/src/syntax/kotlin/KotlinCxxBridgedType.ts +82 -6
- package/src/syntax/swift/SwiftCxxBridgedType.ts +25 -1
- package/src/syntax/types/NullType.ts +31 -3
|
@@ -79,12 +79,14 @@ function getHybridObjectSpec(type, language) {
|
|
|
79
79
|
}
|
|
80
80
|
if (Node.isPropertySignature(declaration)) {
|
|
81
81
|
const t = declaration.getType();
|
|
82
|
-
const
|
|
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
|
|
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));
|
package/lib/syntax/createType.js
CHANGED
|
@@ -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()
|
|
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
|
|
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
|
|
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
|
|
244
|
-
.filter((t) => !t.
|
|
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'
|
|
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
|
-
|
|
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
|
-
|
|
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'
|
|
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);
|
|
@@ -9,7 +9,11 @@ export class NullType {
|
|
|
9
9
|
getCode(language) {
|
|
10
10
|
switch (language) {
|
|
11
11
|
case 'c++':
|
|
12
|
-
return '
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
125
|
-
|
|
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))
|
package/src/syntax/createType.ts
CHANGED
|
@@ -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()
|
|
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
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
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
|
|
304
|
-
.filter((t) => !t.
|
|
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'
|
|
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
|
-
|
|
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
|
-
|
|
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'
|
|
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 '
|
|
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
|
-
|
|
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
|
}
|