nitrogen 0.35.9 → 0.36.0
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/README.md +1 -1
- package/lib/createPlatformSpec.js +2 -2
- package/lib/syntax/Parameter.js +1 -1
- package/lib/syntax/createType.d.ts +5 -3
- package/lib/syntax/createType.js +40 -11
- package/lib/syntax/getInterfaceProperties.d.ts +1 -1
- package/lib/syntax/getInterfaceProperties.js +5 -1
- package/lib/syntax/kotlin/KotlinEnum.js +1 -1
- package/lib/syntax/kotlin/KotlinStruct.js +1 -1
- package/lib/views/CppHybridViewComponent.js +1 -1
- package/package.json +7 -7
- package/src/createPlatformSpec.ts +12 -2
- package/src/syntax/Parameter.ts +7 -1
- package/src/syntax/createType.ts +67 -13
- package/src/syntax/getInterfaceProperties.ts +6 -2
- package/src/syntax/kotlin/KotlinEnum.ts +1 -1
- package/src/syntax/kotlin/KotlinStruct.ts +1 -1
- package/src/views/CppHybridViewComponent.ts +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<a href="https://margelo.com">
|
|
1
|
+
<a href="https://nitro.margelo.com/docs/concepts/nitrogen">
|
|
2
2
|
<picture>
|
|
3
3
|
<source media="(prefers-color-scheme: dark)" srcset="../../docs/static/img/banner-nitrogen-dark.png" />
|
|
4
4
|
<source media="(prefers-color-scheme: light)" srcset="../../docs/static/img/banner-nitrogen-light.png" />
|
|
@@ -80,13 +80,13 @@ function getHybridObjectSpec(type, language) {
|
|
|
80
80
|
if (Node.isPropertySignature(declaration)) {
|
|
81
81
|
const t = declaration.getType();
|
|
82
82
|
const isOptional = prop.isOptional() || t.getUnionTypes().some((u) => u.isUndefined());
|
|
83
|
-
const propType = createType(language, t, isOptional);
|
|
83
|
+
const propType = createType(language, t, isOptional, declaration.getTypeNode());
|
|
84
84
|
properties.push(new Property(prop.getName(), propType, declaration.isReadonly()));
|
|
85
85
|
}
|
|
86
86
|
else if (Node.isMethodSignature(declaration)) {
|
|
87
87
|
const returnType = declaration.getReturnType();
|
|
88
88
|
const isOptional = returnType.getUnionTypes().some((t) => t.isUndefined());
|
|
89
|
-
const methodReturnType = createType(language, returnType, isOptional);
|
|
89
|
+
const methodReturnType = createType(language, returnType, isOptional, declaration.getReturnTypeNode());
|
|
90
90
|
const methodParameters = declaration
|
|
91
91
|
.getParameters()
|
|
92
92
|
.map((p) => new Parameter(p, language));
|
package/lib/syntax/Parameter.js
CHANGED
|
@@ -18,7 +18,7 @@ export class Parameter {
|
|
|
18
18
|
const name = param.getSymbolOrThrow().getEscapedName();
|
|
19
19
|
const type = param.getType();
|
|
20
20
|
const isOptional = param.hasQuestionToken() || param.isOptional() || type.isNullable();
|
|
21
|
-
this.type = createNamedType(language, name, type, isOptional);
|
|
21
|
+
this.type = createNamedType(language, name, type, isOptional, param.getTypeNode());
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
24
24
|
// constructor(...)???
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Type as TSMorphType } from 'ts-morph';
|
|
1
|
+
import { Node, ts, Type as TSMorphType } from 'ts-morph';
|
|
2
2
|
import type { Type } from './types/Type.js';
|
|
3
3
|
import { NamedWrappingType } from './types/NamedWrappingType.js';
|
|
4
4
|
import { type Language } from '../getPlatformSpecs.js';
|
|
5
|
-
|
|
5
|
+
type TypeNode = Node<ts.TypeNode>;
|
|
6
|
+
export declare function createNamedType(language: Language, name: string, type: TSMorphType, isOptional: boolean, typeNode?: TypeNode): NamedWrappingType<Type>;
|
|
6
7
|
export declare function createVoidType(): Type;
|
|
7
8
|
/**
|
|
8
9
|
* Get a list of all currently known complex types.
|
|
@@ -12,4 +13,5 @@ export declare function addKnownType(key: string, type: Type, language: Language
|
|
|
12
13
|
/**
|
|
13
14
|
* Create a new type (or return it from cache if it is already known)
|
|
14
15
|
*/
|
|
15
|
-
export declare function createType(language: Language, type: TSMorphType, isOptional: boolean): Type;
|
|
16
|
+
export declare function createType(language: Language, type: TSMorphType, isOptional: boolean, typeNode?: TypeNode): Type;
|
|
17
|
+
export {};
|
package/lib/syntax/createType.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ts, Type as TSMorphType } from 'ts-morph';
|
|
1
|
+
import { Node, ts, Type as TSMorphType } from 'ts-morph';
|
|
2
2
|
import { BooleanType } from './types/BooleanType.js';
|
|
3
3
|
import { NumberType } from './types/NumberType.js';
|
|
4
4
|
import { StringType } from './types/StringType.js';
|
|
@@ -51,6 +51,34 @@ function removeDuplicates(types) {
|
|
|
51
51
|
return firstIndexOfType === index;
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
+
function getAliasTypeNode(type) {
|
|
55
|
+
const symbol = type.getNonNullableType().getAliasSymbol();
|
|
56
|
+
const declaration = symbol?.getDeclarations()[0];
|
|
57
|
+
if (declaration != null && Node.isTypeAliasDeclaration(declaration)) {
|
|
58
|
+
return declaration.getTypeNode();
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
function getUnionTypeNodes(type, typeNode) {
|
|
63
|
+
if (typeNode != null && Node.isUnionTypeNode(typeNode)) {
|
|
64
|
+
return typeNode.getTypeNodes();
|
|
65
|
+
}
|
|
66
|
+
const aliasTypeNode = getAliasTypeNode(type);
|
|
67
|
+
if (aliasTypeNode != null && Node.isUnionTypeNode(aliasTypeNode)) {
|
|
68
|
+
return aliasTypeNode.getTypeNodes();
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
function getUnionConstituents(type, typeNode) {
|
|
73
|
+
const typeNodes = getUnionTypeNodes(type, typeNode);
|
|
74
|
+
if (typeNodes != null) {
|
|
75
|
+
return typeNodes.map((node) => ({
|
|
76
|
+
type: node.getType(),
|
|
77
|
+
typeNode: node,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
return type.getUnionTypes().map((unionType) => ({ type: unionType }));
|
|
81
|
+
}
|
|
54
82
|
function getArguments(type, typename, count) {
|
|
55
83
|
const typeArguments = type.getTypeArguments();
|
|
56
84
|
if (typeArguments.length === count) {
|
|
@@ -62,11 +90,11 @@ function getArguments(type, typename, count) {
|
|
|
62
90
|
}
|
|
63
91
|
throw new Error(`Type ${type.getText()} looks like a ${typename}, but has ${typeArguments.length} or ${aliasTypeArguments.length} type arguments instead of ${count}!`);
|
|
64
92
|
}
|
|
65
|
-
export function createNamedType(language, name, type, isOptional) {
|
|
93
|
+
export function createNamedType(language, name, type, isOptional, typeNode) {
|
|
66
94
|
if (name.startsWith('__')) {
|
|
67
95
|
throw new Error(`Name cannot start with two underscores (__) as this is reserved syntax for Nitrogen! (In ${type.getText()})`);
|
|
68
96
|
}
|
|
69
|
-
return new NamedWrappingType(name, createType(language, type, isOptional));
|
|
97
|
+
return new NamedWrappingType(name, createType(language, type, isOptional, typeNode));
|
|
70
98
|
}
|
|
71
99
|
export function createVoidType() {
|
|
72
100
|
return new VoidType();
|
|
@@ -110,7 +138,7 @@ export function addKnownType(key, type, language) {
|
|
|
110
138
|
/**
|
|
111
139
|
* Create a new type (or return it from cache if it is already known)
|
|
112
140
|
*/
|
|
113
|
-
export function createType(language, type, isOptional) {
|
|
141
|
+
export function createType(language, type, isOptional, typeNode) {
|
|
114
142
|
const key = getTypeId(type, isOptional);
|
|
115
143
|
if (key != null && knownTypes[language].has(key)) {
|
|
116
144
|
const known = knownTypes[language].get(key);
|
|
@@ -120,7 +148,7 @@ export function createType(language, type, isOptional) {
|
|
|
120
148
|
}
|
|
121
149
|
const get = () => {
|
|
122
150
|
if (isOptional) {
|
|
123
|
-
const wrapping = createType(language, type, false);
|
|
151
|
+
const wrapping = createType(language, type, false, typeNode);
|
|
124
152
|
return new OptionalType(wrapping);
|
|
125
153
|
}
|
|
126
154
|
if (type.isNull()) {
|
|
@@ -232,8 +260,10 @@ export function createType(language, type, isOptional) {
|
|
|
232
260
|
// - of string literals (then it's an enum)
|
|
233
261
|
// - of type `T | undefined` (then it's just optional `T`)
|
|
234
262
|
// - of different types (then it's a variant `A | B | C`)
|
|
235
|
-
const
|
|
236
|
-
const nonNullTypes =
|
|
263
|
+
const unionConstituents = getUnionConstituents(type, typeNode);
|
|
264
|
+
const nonNullTypes = unionConstituents
|
|
265
|
+
.map((c) => c.type)
|
|
266
|
+
.filter((t) => !t.isNull() && !t.isUndefined() && !t.isVoid());
|
|
237
267
|
const isEnumUnion = nonNullTypes.every((t) => t.isStringLiteral());
|
|
238
268
|
if (isEnumUnion) {
|
|
239
269
|
// It consists only of string literaly - that means it's describing an enum!
|
|
@@ -248,11 +278,10 @@ export function createType(language, type, isOptional) {
|
|
|
248
278
|
}
|
|
249
279
|
else {
|
|
250
280
|
// It consists of different types - that means it's a variant!
|
|
251
|
-
let variants =
|
|
252
|
-
.getUnionTypes()
|
|
281
|
+
let variants = unionConstituents
|
|
253
282
|
// Filter out any undefineds/voids, as those are already treated as `isOptional`.
|
|
254
|
-
.filter((t) => !t.isUndefined() && !t.isVoid())
|
|
255
|
-
.map((t) => createType(language, t, false))
|
|
283
|
+
.filter(({ type: t }) => !t.isUndefined() && !t.isVoid())
|
|
284
|
+
.map(({ type: t, typeNode: node }) => createType(language, t, false, node))
|
|
256
285
|
.toSorted(compareLooselyness);
|
|
257
286
|
variants = removeDuplicates(variants);
|
|
258
287
|
if (variants.length === 1) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ts, type Type } from 'ts-morph';
|
|
2
2
|
import type { NamedType } from './types/Type.js';
|
|
3
3
|
import type { Language } from '../getPlatformSpecs.js';
|
|
4
4
|
export declare function getInterfaceProperties(language: Language, interfaceType: Type<ts.ObjectType>): NamedType[];
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
1
2
|
import { createNamedType } from './createType.js';
|
|
2
3
|
export function getInterfaceProperties(language, interfaceType) {
|
|
3
4
|
const symbol = interfaceType.getAliasSymbol() ?? interfaceType.getSymbol();
|
|
4
5
|
if (symbol == null)
|
|
5
6
|
throw new Error(`Interface "${interfaceType.getText()}" does not have a Symbol!`);
|
|
6
7
|
return interfaceType.getProperties().map((prop) => {
|
|
8
|
+
const propDeclaration = prop
|
|
9
|
+
.getDeclarations()
|
|
10
|
+
.find((declaration) => Node.isPropertySignature(declaration));
|
|
7
11
|
let propType = prop.getDeclaredType();
|
|
8
12
|
if (propType.isAny() || propType.isUnknown()) {
|
|
9
13
|
// the interface is aliased/merged - we need to look into the actual declaration
|
|
@@ -15,7 +19,7 @@ export function getInterfaceProperties(language, interfaceType) {
|
|
|
15
19
|
}
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
|
-
const refType = createNamedType(language, prop.getName(), propType, prop.isOptional() || propType.isNullable());
|
|
22
|
+
const refType = createNamedType(language, prop.getName(), propType, prop.isOptional() || propType.isNullable(), propDeclaration?.getTypeNode());
|
|
19
23
|
return refType;
|
|
20
24
|
});
|
|
21
25
|
}
|
|
@@ -40,7 +40,7 @@ namespace ${cxxNamespace} {
|
|
|
40
40
|
using namespace facebook;
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* The C++ JNI bridge between the C++ enum "${enumType.enumName}" and the
|
|
43
|
+
* The C++ JNI bridge between the C++ enum "${enumType.enumName}" and the Kotlin enum "${enumType.enumName}".
|
|
44
44
|
*/
|
|
45
45
|
struct J${enumType.enumName} final: public jni::JavaClass<J${enumType.enumName}> {
|
|
46
46
|
public:
|
|
@@ -109,7 +109,7 @@ namespace ${cxxNamespace} {
|
|
|
109
109
|
using namespace facebook;
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
|
-
* The C++ JNI bridge between the C++ struct "${structType.structName}" and the
|
|
112
|
+
* The C++ JNI bridge between the C++ struct "${structType.structName}" and the Kotlin data class "${structType.structName}".
|
|
113
113
|
*/
|
|
114
114
|
struct J${structType.structName} final: public jni::JavaClass<J${structType.structName}> {
|
|
115
115
|
public:
|
|
@@ -210,7 +210,7 @@ namespace ${namespace} {
|
|
|
210
210
|
|
|
211
211
|
${descriptorClassName}::${descriptorClassName}(const react::ComponentDescriptorParameters& parameters)
|
|
212
212
|
: ConcreteComponentDescriptor(parameters,
|
|
213
|
-
react::RawPropsParser(
|
|
213
|
+
react::RawPropsParser()) {}
|
|
214
214
|
|
|
215
215
|
std::shared_ptr<const react::Props> ${descriptorClassName}::cloneProps(const react::PropsParserContext& context,
|
|
216
216
|
${descriptorIndent} const std::shared_ptr<const react::Props>& props,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitrogen",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.36.0",
|
|
4
|
+
"description": "Code generator for React Native Nitro Modules that turns TypeScript specs into C++, Swift, and Kotlin bindings.",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"source": "src/index",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"bugs": {
|
|
22
22
|
"url": "https://github.com/mrousavy/nitro/issues"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://
|
|
24
|
+
"homepage": "https://nitro.margelo.com/docs/concepts/nitrogen",
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"registry": "https://registry.npmjs.org/"
|
|
27
27
|
},
|
|
@@ -30,18 +30,18 @@
|
|
|
30
30
|
"start": "tsc && node lib/index.js",
|
|
31
31
|
"typecheck": "tsc --noEmit",
|
|
32
32
|
"lint": "eslint \"**/*.{js,ts,tsx}\" --fix",
|
|
33
|
-
"lint-ci": "eslint \"**/*.{js,ts,tsx}\" -f @jamesacarr/github-actions",
|
|
33
|
+
"lint-ci": "eslint \"**/*.{js,ts,tsx}\" -f @jamesacarr/github-actions --max-warnings 0",
|
|
34
34
|
"release": "release-it"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"chalk": "^5.3.0",
|
|
38
|
-
"react-native-nitro-modules": "^0.
|
|
38
|
+
"react-native-nitro-modules": "^0.36.0",
|
|
39
39
|
"ts-morph": "^28.0.0",
|
|
40
40
|
"yargs": "^18.0.0",
|
|
41
|
-
"zod": "^4.
|
|
41
|
+
"zod": "^4.4.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^
|
|
44
|
+
"@types/node": "^26.0.0"
|
|
45
45
|
},
|
|
46
46
|
"release-it": {
|
|
47
47
|
"npm": {
|
|
@@ -113,14 +113,24 @@ function getHybridObjectSpec(type: Type, language: Language): HybridObjectSpec {
|
|
|
113
113
|
const t = declaration.getType()
|
|
114
114
|
const isOptional =
|
|
115
115
|
prop.isOptional() || t.getUnionTypes().some((u) => u.isUndefined())
|
|
116
|
-
const propType = createType(
|
|
116
|
+
const propType = createType(
|
|
117
|
+
language,
|
|
118
|
+
t,
|
|
119
|
+
isOptional,
|
|
120
|
+
declaration.getTypeNode()
|
|
121
|
+
)
|
|
117
122
|
properties.push(
|
|
118
123
|
new Property(prop.getName(), propType, declaration.isReadonly())
|
|
119
124
|
)
|
|
120
125
|
} else if (Node.isMethodSignature(declaration)) {
|
|
121
126
|
const returnType = declaration.getReturnType()
|
|
122
127
|
const isOptional = returnType.getUnionTypes().some((t) => t.isUndefined())
|
|
123
|
-
const methodReturnType = createType(
|
|
128
|
+
const methodReturnType = createType(
|
|
129
|
+
language,
|
|
130
|
+
returnType,
|
|
131
|
+
isOptional,
|
|
132
|
+
declaration.getReturnTypeNode()
|
|
133
|
+
)
|
|
124
134
|
const methodParameters = declaration
|
|
125
135
|
.getParameters()
|
|
126
136
|
.map((p) => new Parameter(p, language))
|
package/src/syntax/Parameter.ts
CHANGED
|
@@ -26,7 +26,13 @@ export class Parameter implements CodeNode {
|
|
|
26
26
|
const type = param.getType()
|
|
27
27
|
const isOptional =
|
|
28
28
|
param.hasQuestionToken() || param.isOptional() || type.isNullable()
|
|
29
|
-
this.type = createNamedType(
|
|
29
|
+
this.type = createNamedType(
|
|
30
|
+
language,
|
|
31
|
+
name,
|
|
32
|
+
type,
|
|
33
|
+
isOptional,
|
|
34
|
+
param.getTypeNode()
|
|
35
|
+
)
|
|
30
36
|
} else {
|
|
31
37
|
// constructor(...)???
|
|
32
38
|
throw new Error(`Invalid constructor! Arguments: ${args}`)
|
package/src/syntax/createType.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ts, Type as TSMorphType, type Signature } from 'ts-morph'
|
|
1
|
+
import { Node, ts, Type as TSMorphType, type Signature } from 'ts-morph'
|
|
2
2
|
import type { Type } from './types/Type.js'
|
|
3
3
|
import { BooleanType } from './types/BooleanType.js'
|
|
4
4
|
import { NumberType } from './types/NumberType.js'
|
|
@@ -83,6 +83,54 @@ type Tuple<
|
|
|
83
83
|
N extends number,
|
|
84
84
|
R extends unknown[] = [],
|
|
85
85
|
> = R['length'] extends N ? R : Tuple<T, N, [T, ...R]>
|
|
86
|
+
|
|
87
|
+
type TypeNode = Node<ts.TypeNode>
|
|
88
|
+
|
|
89
|
+
interface UnionConstituent {
|
|
90
|
+
type: TSMorphType
|
|
91
|
+
typeNode?: TypeNode
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getAliasTypeNode(type: TSMorphType): TypeNode | undefined {
|
|
95
|
+
const symbol = type.getNonNullableType().getAliasSymbol()
|
|
96
|
+
const declaration = symbol?.getDeclarations()[0]
|
|
97
|
+
if (declaration != null && Node.isTypeAliasDeclaration(declaration)) {
|
|
98
|
+
return declaration.getTypeNode()
|
|
99
|
+
}
|
|
100
|
+
return undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getUnionTypeNodes(
|
|
104
|
+
type: TSMorphType,
|
|
105
|
+
typeNode?: TypeNode
|
|
106
|
+
): TypeNode[] | undefined {
|
|
107
|
+
if (typeNode != null && Node.isUnionTypeNode(typeNode)) {
|
|
108
|
+
return typeNode.getTypeNodes()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const aliasTypeNode = getAliasTypeNode(type)
|
|
112
|
+
if (aliasTypeNode != null && Node.isUnionTypeNode(aliasTypeNode)) {
|
|
113
|
+
return aliasTypeNode.getTypeNodes()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return undefined
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function getUnionConstituents(
|
|
120
|
+
type: TSMorphType,
|
|
121
|
+
typeNode?: TypeNode
|
|
122
|
+
): UnionConstituent[] {
|
|
123
|
+
const typeNodes = getUnionTypeNodes(type, typeNode)
|
|
124
|
+
if (typeNodes != null) {
|
|
125
|
+
return typeNodes.map((node) => ({
|
|
126
|
+
type: node.getType(),
|
|
127
|
+
typeNode: node,
|
|
128
|
+
}))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return type.getUnionTypes().map((unionType) => ({ type: unionType }))
|
|
132
|
+
}
|
|
133
|
+
|
|
86
134
|
function getArguments<N extends number>(
|
|
87
135
|
type: TSMorphType,
|
|
88
136
|
typename: string,
|
|
@@ -107,14 +155,18 @@ export function createNamedType(
|
|
|
107
155
|
language: Language,
|
|
108
156
|
name: string,
|
|
109
157
|
type: TSMorphType,
|
|
110
|
-
isOptional: boolean
|
|
158
|
+
isOptional: boolean,
|
|
159
|
+
typeNode?: TypeNode
|
|
111
160
|
) {
|
|
112
161
|
if (name.startsWith('__')) {
|
|
113
162
|
throw new Error(
|
|
114
163
|
`Name cannot start with two underscores (__) as this is reserved syntax for Nitrogen! (In ${type.getText()})`
|
|
115
164
|
)
|
|
116
165
|
}
|
|
117
|
-
return new NamedWrappingType(
|
|
166
|
+
return new NamedWrappingType(
|
|
167
|
+
name,
|
|
168
|
+
createType(language, type, isOptional, typeNode)
|
|
169
|
+
)
|
|
118
170
|
}
|
|
119
171
|
|
|
120
172
|
export function createVoidType(): Type {
|
|
@@ -171,7 +223,8 @@ export function addKnownType(
|
|
|
171
223
|
export function createType(
|
|
172
224
|
language: Language,
|
|
173
225
|
type: TSMorphType,
|
|
174
|
-
isOptional: boolean
|
|
226
|
+
isOptional: boolean,
|
|
227
|
+
typeNode?: TypeNode
|
|
175
228
|
): Type {
|
|
176
229
|
const key = getTypeId(type, isOptional)
|
|
177
230
|
if (key != null && knownTypes[language].has(key)) {
|
|
@@ -183,7 +236,7 @@ export function createType(
|
|
|
183
236
|
|
|
184
237
|
const get = () => {
|
|
185
238
|
if (isOptional) {
|
|
186
|
-
const wrapping = createType(language, type, false)
|
|
239
|
+
const wrapping = createType(language, type, false, typeNode)
|
|
187
240
|
return new OptionalType(wrapping)
|
|
188
241
|
}
|
|
189
242
|
|
|
@@ -286,10 +339,10 @@ export function createType(
|
|
|
286
339
|
// - of string literals (then it's an enum)
|
|
287
340
|
// - of type `T | undefined` (then it's just optional `T`)
|
|
288
341
|
// - of different types (then it's a variant `A | B | C`)
|
|
289
|
-
const
|
|
290
|
-
const nonNullTypes =
|
|
291
|
-
|
|
292
|
-
|
|
342
|
+
const unionConstituents = getUnionConstituents(type, typeNode)
|
|
343
|
+
const nonNullTypes = unionConstituents
|
|
344
|
+
.map((c) => c.type)
|
|
345
|
+
.filter((t) => !t.isNull() && !t.isUndefined() && !t.isVoid())
|
|
293
346
|
const isEnumUnion = nonNullTypes.every((t) => t.isStringLiteral())
|
|
294
347
|
if (isEnumUnion) {
|
|
295
348
|
// It consists only of string literaly - that means it's describing an enum!
|
|
@@ -305,11 +358,12 @@ export function createType(
|
|
|
305
358
|
return new EnumType(typename, type)
|
|
306
359
|
} else {
|
|
307
360
|
// It consists of different types - that means it's a variant!
|
|
308
|
-
let variants =
|
|
309
|
-
.getUnionTypes()
|
|
361
|
+
let variants = unionConstituents
|
|
310
362
|
// Filter out any undefineds/voids, as those are already treated as `isOptional`.
|
|
311
|
-
.filter((t) => !t.isUndefined() && !t.isVoid())
|
|
312
|
-
.map((
|
|
363
|
+
.filter(({ type: t }) => !t.isUndefined() && !t.isVoid())
|
|
364
|
+
.map(({ type: t, typeNode: node }) =>
|
|
365
|
+
createType(language, t, false, node)
|
|
366
|
+
)
|
|
313
367
|
.toSorted(compareLooselyness)
|
|
314
368
|
variants = removeDuplicates(variants)
|
|
315
369
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { Node, type ts, type Type } from 'ts-morph'
|
|
2
2
|
import type { NamedType } from './types/Type.js'
|
|
3
3
|
import { createNamedType } from './createType.js'
|
|
4
4
|
import type { Language } from '../getPlatformSpecs.js'
|
|
@@ -13,6 +13,9 @@ export function getInterfaceProperties(
|
|
|
13
13
|
`Interface "${interfaceType.getText()}" does not have a Symbol!`
|
|
14
14
|
)
|
|
15
15
|
return interfaceType.getProperties().map((prop) => {
|
|
16
|
+
const propDeclaration = prop
|
|
17
|
+
.getDeclarations()
|
|
18
|
+
.find((declaration) => Node.isPropertySignature(declaration))
|
|
16
19
|
let propType = prop.getDeclaredType()
|
|
17
20
|
if (propType.isAny() || propType.isUnknown()) {
|
|
18
21
|
// the interface is aliased/merged - we need to look into the actual declaration
|
|
@@ -29,7 +32,8 @@ export function getInterfaceProperties(
|
|
|
29
32
|
language,
|
|
30
33
|
prop.getName(),
|
|
31
34
|
propType,
|
|
32
|
-
prop.isOptional() || propType.isNullable()
|
|
35
|
+
prop.isOptional() || propType.isNullable(),
|
|
36
|
+
propDeclaration?.getTypeNode()
|
|
33
37
|
)
|
|
34
38
|
return refType
|
|
35
39
|
})
|
|
@@ -49,7 +49,7 @@ namespace ${cxxNamespace} {
|
|
|
49
49
|
using namespace facebook;
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* The C++ JNI bridge between the C++ enum "${enumType.enumName}" and the
|
|
52
|
+
* The C++ JNI bridge between the C++ enum "${enumType.enumName}" and the Kotlin enum "${enumType.enumName}".
|
|
53
53
|
*/
|
|
54
54
|
struct J${enumType.enumName} final: public jni::JavaClass<J${enumType.enumName}> {
|
|
55
55
|
public:
|
|
@@ -133,7 +133,7 @@ namespace ${cxxNamespace} {
|
|
|
133
133
|
using namespace facebook;
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
* The C++ JNI bridge between the C++ struct "${structType.structName}" and the
|
|
136
|
+
* The C++ JNI bridge between the C++ struct "${structType.structName}" and the Kotlin data class "${structType.structName}".
|
|
137
137
|
*/
|
|
138
138
|
struct J${structType.structName} final: public jni::JavaClass<J${structType.structName}> {
|
|
139
139
|
public:
|
|
@@ -257,7 +257,7 @@ namespace ${namespace} {
|
|
|
257
257
|
|
|
258
258
|
${descriptorClassName}::${descriptorClassName}(const react::ComponentDescriptorParameters& parameters)
|
|
259
259
|
: ConcreteComponentDescriptor(parameters,
|
|
260
|
-
react::RawPropsParser(
|
|
260
|
+
react::RawPropsParser()) {}
|
|
261
261
|
|
|
262
262
|
std::shared_ptr<const react::Props> ${descriptorClassName}::cloneProps(const react::PropsParserContext& context,
|
|
263
263
|
${descriptorIndent} const std::shared_ptr<const react::Props>& props,
|