nitrogen 0.2.24 → 0.29.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -108
- package/lib/Logger.js +56 -0
- package/lib/autolinking/Autolinking.js +1 -0
- package/lib/autolinking/android/createCMakeExtension.js +109 -0
- package/lib/autolinking/android/createGradleExtension.js +36 -0
- package/lib/autolinking/android/createHybridObjectInitializer.js +159 -0
- package/lib/autolinking/createAndroidAutolinking.js +13 -0
- package/lib/autolinking/createIOSAutolinking.js +19 -0
- package/lib/autolinking/ios/createHybridObjectInitializer.js +97 -0
- package/lib/autolinking/ios/createPodspecRubyExtension.js +69 -0
- package/lib/autolinking/ios/createSwiftCxxBridge.js +117 -0
- package/lib/autolinking/ios/createSwiftUmbrellaHeader.js +74 -0
- package/lib/config/NitroConfig.js +112 -0
- package/lib/config/NitroUserConfig.js +88 -0
- package/lib/config/getConfig.js +84 -0
- package/lib/createGitAttributes.js +11 -0
- package/lib/createPlatformSpec.js +127 -0
- package/lib/getFiles.js +28 -0
- package/lib/getPlatformSpecs.js +153 -0
- package/lib/index.js +113 -10
- package/lib/init.js +123 -0
- package/lib/nitrogen.js +165 -0
- package/lib/prettifyDirectory.js +27 -0
- package/lib/syntax/BridgedType.js +1 -0
- package/lib/syntax/CodeNode.js +1 -0
- package/lib/syntax/HybridObjectSpec.js +1 -0
- package/lib/syntax/Method.js +108 -0
- package/lib/syntax/Parameter.js +65 -0
- package/lib/syntax/Property.js +147 -0
- package/lib/syntax/SourceFile.js +7 -0
- package/lib/syntax/c++/CppEnum.js +110 -0
- package/lib/syntax/c++/CppHybridObject.js +146 -0
- package/lib/syntax/c++/CppHybridObjectRegistration.js +18 -0
- package/lib/syntax/c++/CppStruct.js +108 -0
- package/lib/syntax/c++/CppUnion.js +88 -0
- package/lib/syntax/c++/getForwardDeclaration.js +14 -0
- package/lib/syntax/c++/includeNitroHeader.js +34 -0
- package/lib/syntax/createType.js +303 -0
- package/lib/syntax/getAllTypes.js +11 -0
- package/lib/syntax/getCustomTypeConfig.js +53 -0
- package/lib/syntax/getHybridObjectName.d.ts +36 -0
- package/lib/syntax/getHybridObjectName.js +10 -0
- package/lib/syntax/getInterfaceProperties.js +9 -0
- package/lib/syntax/getReferencedTypes.js +47 -0
- package/lib/syntax/helpers.js +53 -0
- package/lib/syntax/isCoreType.js +47 -0
- package/lib/syntax/kotlin/FbjniHybridObject.js +261 -0
- package/lib/syntax/kotlin/JNINativeRegistrations.js +7 -0
- package/lib/syntax/kotlin/KotlinBoxedPrimitive.js +17 -0
- package/lib/syntax/kotlin/KotlinCxxBridgedType.js +893 -0
- package/lib/syntax/kotlin/KotlinEnum.js +113 -0
- package/lib/syntax/kotlin/KotlinFunction.js +256 -0
- package/lib/syntax/kotlin/KotlinHybridObject.js +177 -0
- package/lib/syntax/kotlin/KotlinHybridObjectRegistration.js +26 -0
- package/lib/syntax/kotlin/KotlinStruct.js +172 -0
- package/lib/syntax/kotlin/KotlinVariant.js +191 -0
- package/lib/syntax/swift/SwiftCxxBridgedType.js +819 -0
- package/lib/syntax/swift/SwiftCxxTypeHelper.js +613 -0
- package/lib/syntax/swift/SwiftEnum.js +52 -0
- package/lib/syntax/swift/SwiftFunction.js +83 -0
- package/lib/syntax/swift/SwiftHybridObject.js +103 -0
- package/lib/syntax/swift/SwiftHybridObjectBridge.js +451 -0
- package/lib/syntax/swift/SwiftHybridObjectRegistration.js +42 -0
- package/lib/syntax/swift/SwiftStruct.js +75 -0
- package/lib/syntax/swift/SwiftVariant.js +58 -0
- package/lib/syntax/types/ArrayBufferType.js +37 -0
- package/lib/syntax/types/ArrayType.d.ts +12 -0
- package/lib/syntax/types/ArrayType.js +52 -0
- package/lib/syntax/types/BigIntType.js +27 -0
- package/lib/syntax/types/BooleanType.js +27 -0
- package/lib/syntax/types/CustomType.d.ts +14 -0
- package/lib/syntax/types/CustomType.js +36 -0
- package/lib/syntax/types/DateType.js +35 -0
- package/lib/syntax/types/EnumType.js +101 -0
- package/lib/syntax/types/ErrorType.js +37 -0
- package/lib/syntax/types/FunctionType.js +147 -0
- package/lib/syntax/types/HybridObjectBaseType.js +38 -0
- package/lib/syntax/types/HybridObjectType.js +131 -0
- package/lib/syntax/types/MapType.js +37 -0
- package/lib/syntax/types/NamedWrappingType.js +27 -0
- package/lib/syntax/types/NullType.js +23 -0
- package/lib/syntax/types/NumberType.js +27 -0
- package/lib/syntax/types/OptionalType.js +59 -0
- package/lib/syntax/types/PromiseType.js +62 -0
- package/lib/syntax/types/RecordType.js +47 -0
- package/lib/syntax/types/ResultWrappingType.js +44 -0
- package/lib/syntax/types/StringType.js +35 -0
- package/lib/syntax/types/StructType.js +61 -0
- package/lib/syntax/types/TupleType.js +39 -0
- package/lib/syntax/types/Type.js +1 -0
- package/lib/syntax/types/VariantType.js +75 -0
- package/lib/syntax/types/VoidType.js +27 -0
- package/lib/syntax/types/getTypeAs.js +12 -0
- package/lib/utils.js +126 -0
- package/lib/views/CppHybridViewComponent.js +256 -0
- package/lib/views/createHostComponentJs.js +27 -0
- package/lib/views/kotlin/KotlinHybridViewManager.js +229 -0
- package/lib/views/swift/SwiftHybridViewManager.js +131 -0
- package/lib/writeFile.js +19 -0
- package/package.json +58 -29
- package/src/Logger.ts +63 -0
- package/src/autolinking/Autolinking.ts +9 -0
- package/src/autolinking/android/createCMakeExtension.ts +126 -0
- package/src/autolinking/android/createGradleExtension.ts +43 -0
- package/src/autolinking/android/createHybridObjectInitializer.ts +174 -0
- package/src/autolinking/createAndroidAutolinking.ts +28 -0
- package/src/autolinking/createIOSAutolinking.ts +24 -0
- package/src/autolinking/ios/createHybridObjectInitializer.ts +112 -0
- package/src/autolinking/ios/createPodspecRubyExtension.ts +76 -0
- package/src/autolinking/ios/createSwiftCxxBridge.ts +137 -0
- package/src/autolinking/ios/createSwiftUmbrellaHeader.ts +90 -0
- package/src/config/NitroConfig.ts +139 -0
- package/src/config/NitroUserConfig.ts +105 -0
- package/src/config/getConfig.ts +91 -0
- package/src/createGitAttributes.ts +15 -0
- package/src/createPlatformSpec.ts +176 -0
- package/src/getFiles.ts +31 -0
- package/src/getPlatformSpecs.ts +202 -0
- package/src/index.ts +146 -0
- package/src/init.ts +186 -0
- package/src/nitrogen.ts +246 -0
- package/src/prettifyDirectory.ts +32 -0
- package/src/syntax/BridgedType.ts +59 -0
- package/src/syntax/CodeNode.ts +24 -0
- package/src/syntax/HybridObjectSpec.ts +14 -0
- package/src/syntax/Method.ts +154 -0
- package/src/syntax/Parameter.ts +81 -0
- package/src/syntax/Property.ts +203 -0
- package/src/syntax/SourceFile.ts +80 -0
- package/src/syntax/c++/CppEnum.ts +128 -0
- package/src/syntax/c++/CppHybridObject.ts +165 -0
- package/src/syntax/c++/CppHybridObjectRegistration.ts +39 -0
- package/src/syntax/c++/CppStruct.ts +129 -0
- package/src/syntax/c++/CppUnion.ts +105 -0
- package/src/syntax/c++/getForwardDeclaration.ts +19 -0
- package/src/syntax/c++/includeNitroHeader.ts +40 -0
- package/src/syntax/createType.ts +365 -0
- package/src/syntax/getAllTypes.ts +18 -0
- package/src/syntax/getCustomTypeConfig.ts +71 -0
- package/src/syntax/getHybridObjectName.ts +48 -0
- package/src/syntax/getInterfaceProperties.ts +21 -0
- package/src/syntax/getReferencedTypes.ts +57 -0
- package/src/syntax/helpers.ts +79 -0
- package/src/syntax/isCoreType.ts +60 -0
- package/src/syntax/kotlin/FbjniHybridObject.ts +313 -0
- package/src/syntax/kotlin/JNINativeRegistrations.ts +19 -0
- package/src/syntax/kotlin/KotlinBoxedPrimitive.ts +19 -0
- package/src/syntax/kotlin/KotlinCxxBridgedType.ts +942 -0
- package/src/syntax/kotlin/KotlinEnum.ts +130 -0
- package/src/syntax/kotlin/KotlinFunction.ts +277 -0
- package/src/syntax/kotlin/KotlinHybridObject.ts +205 -0
- package/src/syntax/kotlin/KotlinHybridObjectRegistration.ts +51 -0
- package/src/syntax/kotlin/KotlinStruct.ts +198 -0
- package/src/syntax/kotlin/KotlinVariant.ts +212 -0
- package/src/syntax/swift/SwiftCxxBridgedType.ts +874 -0
- package/src/syntax/swift/SwiftCxxTypeHelper.ts +674 -0
- package/src/syntax/swift/SwiftEnum.ts +65 -0
- package/src/syntax/swift/SwiftFunction.ts +91 -0
- package/src/syntax/swift/SwiftHybridObject.ts +121 -0
- package/src/syntax/swift/SwiftHybridObjectBridge.ts +522 -0
- package/src/syntax/swift/SwiftHybridObjectRegistration.ts +75 -0
- package/src/syntax/swift/SwiftStruct.ts +85 -0
- package/src/syntax/swift/SwiftVariant.ts +67 -0
- package/src/syntax/types/ArrayBufferType.ts +49 -0
- package/src/syntax/types/ArrayType.ts +62 -0
- package/src/syntax/types/BigIntType.ts +35 -0
- package/src/syntax/types/BooleanType.ts +35 -0
- package/src/syntax/types/CustomType.ts +47 -0
- package/src/syntax/types/DateType.ts +43 -0
- package/src/syntax/types/EnumType.ts +130 -0
- package/src/syntax/types/ErrorType.ts +44 -0
- package/src/syntax/types/FunctionType.ts +167 -0
- package/src/syntax/types/HybridObjectBaseType.ts +54 -0
- package/src/syntax/types/HybridObjectType.ts +198 -0
- package/src/syntax/types/MapType.ts +49 -0
- package/src/syntax/types/NamedWrappingType.ts +33 -0
- package/src/syntax/types/NullType.ts +30 -0
- package/src/syntax/types/NumberType.ts +34 -0
- package/src/syntax/types/OptionalType.ts +66 -0
- package/src/syntax/types/PromiseType.ts +72 -0
- package/src/syntax/types/RecordType.ts +56 -0
- package/src/syntax/types/ResultWrappingType.ts +53 -0
- package/src/syntax/types/StringType.ts +44 -0
- package/src/syntax/types/StructType.ts +83 -0
- package/src/syntax/types/TupleType.ts +53 -0
- package/src/syntax/types/Type.ts +82 -0
- package/src/syntax/types/VariantType.ts +92 -0
- package/src/syntax/types/VoidType.ts +34 -0
- package/src/syntax/types/getTypeAs.ts +15 -0
- package/src/utils.ts +162 -0
- package/src/views/CppHybridViewComponent.ts +304 -0
- package/src/views/createHostComponentJs.ts +34 -0
- package/src/views/kotlin/KotlinHybridViewManager.ts +258 -0
- package/src/views/swift/SwiftHybridViewManager.ts +153 -0
- package/src/writeFile.ts +27 -0
- package/.jshintignore +0 -6
- package/.jshintrc +0 -3
- package/.npmignore +0 -3
- package/.travis.yml +0 -13
- package/LICENSE +0 -13
- package/browser/nitrogen-min.js +0 -3
- package/browser/nitrogen.js +0 -6369
- package/lib/apiKey.js +0 -67
- package/lib/blob.js +0 -57
- package/lib/commandManager.js +0 -350
- package/lib/device.js +0 -19
- package/lib/memoryStore.js +0 -24
- package/lib/message.js +0 -298
- package/lib/permission.js +0 -121
- package/lib/principal.js +0 -330
- package/lib/service.js +0 -347
- package/lib/session.js +0 -494
- package/lib/user.js +0 -20
- package/publish +0 -2
- package/scripts/build-documentation +0 -4
- package/scripts/build-module +0 -27
- package/scripts/module.js +0 -12
- package/scripts/postamble.js +0 -1
- package/scripts/preamble.js +0 -2
- package/scripts/run-test-server +0 -9
- package/test/config.js +0 -12
- package/test/fixtures/images/image.jpg +0 -0
- package/test/fixtures/images/motion0.jpg +0 -0
- package/test/fixtures/images/motion1.jpg +0 -0
- package/test/fixtures/images/motion2.jpg +0 -0
- package/test/fixtures/index.js +0 -76
- package/test/main.js +0 -5
- package/test/memoryStore.js +0 -22
- package/test/mocha.opts +0 -3
- package/test/units/apiKey.js +0 -46
- package/test/units/blob.js +0 -35
- package/test/units/commandManager.js +0 -67
- package/test/units/device.js +0 -26
- package/test/units/heartbeat.js +0 -28
- package/test/units/message.js +0 -79
- package/test/units/permissions.js +0 -43
- package/test/units/principal.js +0 -116
- package/test/units/service.js +0 -92
- package/test/units/session.js +0 -97
- package/test/units/user.js +0 -48
- package/yuidoc.json +0 -8
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { CodeNode } from './CodeNode.js'
|
|
2
|
+
import { capitalizeName } from '../utils.js'
|
|
3
|
+
import { type SourceFile, type SourceImport } from './SourceFile.js'
|
|
4
|
+
import type { Language } from '../getPlatformSpecs.js'
|
|
5
|
+
import type { Type } from './types/Type.js'
|
|
6
|
+
import { Method } from './Method.js'
|
|
7
|
+
import { VoidType } from './types/VoidType.js'
|
|
8
|
+
import { Parameter } from './Parameter.js'
|
|
9
|
+
import { isBooleanPropertyPrefix } from './helpers.js'
|
|
10
|
+
|
|
11
|
+
export interface PropertyBody {
|
|
12
|
+
getter: string
|
|
13
|
+
setter: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type LanguageEnvironment = 'jvm' | 'swift' | 'other'
|
|
17
|
+
|
|
18
|
+
export interface PropertyModifiers {
|
|
19
|
+
/**
|
|
20
|
+
* The name of the class that defines this C++ property getter/setter method.
|
|
21
|
+
* Example: `Person` -> `int Person::getAge()`
|
|
22
|
+
*/
|
|
23
|
+
classDefinitionName?: string
|
|
24
|
+
/**
|
|
25
|
+
* Whether the property should be marked as inlineable.
|
|
26
|
+
*/
|
|
27
|
+
inline?: boolean
|
|
28
|
+
/*+
|
|
29
|
+
* Whether the property is a pure virtual C++ property (getter + setter).
|
|
30
|
+
*/
|
|
31
|
+
virtual?: boolean
|
|
32
|
+
/**
|
|
33
|
+
* Whether the property is marked as `noexcept` (doesn't throw) or not.
|
|
34
|
+
*/
|
|
35
|
+
noexcept?: boolean
|
|
36
|
+
/**
|
|
37
|
+
* Whether this property overrides a base/super property.
|
|
38
|
+
*/
|
|
39
|
+
override?: boolean
|
|
40
|
+
/**
|
|
41
|
+
* Whether this property has a `@DoNotStrip` and `@Keep` attribute to avoid
|
|
42
|
+
* it from being stripped from the binary by the Java compiler or ProGuard.
|
|
43
|
+
*/
|
|
44
|
+
doNotStrip?: boolean
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class Property implements CodeNode {
|
|
48
|
+
readonly name: string
|
|
49
|
+
readonly type: Type
|
|
50
|
+
readonly isReadonly: boolean
|
|
51
|
+
|
|
52
|
+
constructor(name: string, type: Type, isReadonly: boolean) {
|
|
53
|
+
this.name = name
|
|
54
|
+
this.type = type
|
|
55
|
+
this.isReadonly = isReadonly
|
|
56
|
+
if (this.name.startsWith('__')) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Property names are not allowed to start with two underscores (__)! (In ${this.jsSignature})`
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get jsSignature(): string {
|
|
64
|
+
return `${this.name}: ${this.type.kind}`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getExtraFiles(): SourceFile[] {
|
|
68
|
+
return this.type.getExtraFiles()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getRequiredImports(language: Language): SourceImport[] {
|
|
72
|
+
return this.type.getRequiredImports(language)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getGetterName(environment: LanguageEnvironment): string {
|
|
76
|
+
if (this.type.kind === 'boolean' && isBooleanPropertyPrefix(this.name)) {
|
|
77
|
+
// Boolean accessors where the property starts with "is" or "has" are renamed in JVM and Swift
|
|
78
|
+
switch (environment) {
|
|
79
|
+
case 'jvm':
|
|
80
|
+
case 'swift':
|
|
81
|
+
// isSomething -> isSomething()
|
|
82
|
+
return this.name
|
|
83
|
+
default:
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// isSomething -> getIsSomething()
|
|
88
|
+
return `get${capitalizeName(this.name)}`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getSetterName(environment: LanguageEnvironment): string {
|
|
92
|
+
if (this.type.kind === 'boolean' && this.name.startsWith('is')) {
|
|
93
|
+
// Boolean accessors where the property starts with "is" are renamed in JVM
|
|
94
|
+
if (environment === 'jvm') {
|
|
95
|
+
// isSomething -> setSomething()
|
|
96
|
+
const cleanName = this.name.replace('is', '')
|
|
97
|
+
return `set${capitalizeName(cleanName)}`
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// isSomething -> setIsSomething()
|
|
101
|
+
return `set${capitalizeName(this.name)}`
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get cppGetter(): Method {
|
|
105
|
+
return new Method(this.getGetterName('other'), this.type, [])
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get cppSetter(): Method | undefined {
|
|
109
|
+
if (this.isReadonly) return undefined
|
|
110
|
+
const parameter = new Parameter(this.name, this.type)
|
|
111
|
+
return new Method(this.getSetterName('other'), new VoidType(), [parameter])
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
getCppMethods(): [getter: Method] | [getter: Method, setter: Method] {
|
|
115
|
+
if (this.cppSetter != null) {
|
|
116
|
+
// get + set
|
|
117
|
+
return [this.cppGetter, this.cppSetter]
|
|
118
|
+
} else {
|
|
119
|
+
// get
|
|
120
|
+
return [this.cppGetter]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getCode(
|
|
125
|
+
language: Language,
|
|
126
|
+
modifiers?: PropertyModifiers,
|
|
127
|
+
body?: PropertyBody
|
|
128
|
+
): string {
|
|
129
|
+
if (body != null) {
|
|
130
|
+
body.getter = body.getter.trim()
|
|
131
|
+
body.setter = body.setter.trim()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
switch (language) {
|
|
135
|
+
case 'c++': {
|
|
136
|
+
const methods = this.getCppMethods()
|
|
137
|
+
const [getter, setter] = methods
|
|
138
|
+
const lines: string[] = []
|
|
139
|
+
lines.push(getter.getCode('c++', modifiers, body?.getter))
|
|
140
|
+
if (setter != null) {
|
|
141
|
+
lines.push(setter.getCode('c++', modifiers, body?.setter))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return lines.join('\n')
|
|
145
|
+
}
|
|
146
|
+
case 'swift': {
|
|
147
|
+
const type = this.type.getCode('swift')
|
|
148
|
+
let accessors: string
|
|
149
|
+
if (body == null) {
|
|
150
|
+
accessors = this.isReadonly ? `get` : `get set`
|
|
151
|
+
} else {
|
|
152
|
+
const lines: string[] = []
|
|
153
|
+
lines.push(`
|
|
154
|
+
get {
|
|
155
|
+
${body.getter}
|
|
156
|
+
}
|
|
157
|
+
`)
|
|
158
|
+
if (!this.isReadonly) {
|
|
159
|
+
lines.push(`
|
|
160
|
+
set {
|
|
161
|
+
${body.setter}
|
|
162
|
+
}
|
|
163
|
+
`)
|
|
164
|
+
}
|
|
165
|
+
accessors = '\n' + lines.join('\n') + '\n'
|
|
166
|
+
}
|
|
167
|
+
return `var ${this.name}: ${type} { ${accessors} }`
|
|
168
|
+
}
|
|
169
|
+
case 'kotlin': {
|
|
170
|
+
const type = this.type.getCode('kotlin')
|
|
171
|
+
let keyword = this.isReadonly ? 'val' : 'var'
|
|
172
|
+
if (modifiers?.virtual) keyword = `abstract ${keyword}`
|
|
173
|
+
const lines: string[] = []
|
|
174
|
+
if (modifiers?.doNotStrip) {
|
|
175
|
+
lines.push('@get:DoNotStrip', '@get:Keep')
|
|
176
|
+
if (!this.isReadonly) {
|
|
177
|
+
lines.push('@set:DoNotStrip', '@set:Keep')
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
lines.push(`${keyword} ${this.name}: ${type}`)
|
|
181
|
+
if (body != null) {
|
|
182
|
+
lines.push(`
|
|
183
|
+
get() {
|
|
184
|
+
${body.getter}
|
|
185
|
+
}
|
|
186
|
+
`)
|
|
187
|
+
if (!this.isReadonly) {
|
|
188
|
+
lines.push(`
|
|
189
|
+
set(value) {
|
|
190
|
+
${body.setter}
|
|
191
|
+
}
|
|
192
|
+
`)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return lines.join('\n')
|
|
196
|
+
}
|
|
197
|
+
default:
|
|
198
|
+
throw new Error(
|
|
199
|
+
`Language ${language} is not yet supported for properties!`
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Language, Platform } from '../getPlatformSpecs.js'
|
|
2
|
+
import type { Type } from './types/Type.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a file with source code, in a specific programming language.
|
|
6
|
+
*/
|
|
7
|
+
export interface SourceFile {
|
|
8
|
+
/**
|
|
9
|
+
* The name of the file with extension (e.g. `Image.hpp`)
|
|
10
|
+
*/
|
|
11
|
+
name: string
|
|
12
|
+
/**
|
|
13
|
+
* The subdirectory/subdirectories of the file, or empty (`[]`) if none.
|
|
14
|
+
*/
|
|
15
|
+
subdirectory: string[]
|
|
16
|
+
/**
|
|
17
|
+
* The full content of the file.
|
|
18
|
+
*/
|
|
19
|
+
content: string
|
|
20
|
+
/**
|
|
21
|
+
* The language the {@linkcode content} is written in (e.g. `c++`)
|
|
22
|
+
*/
|
|
23
|
+
language: Language
|
|
24
|
+
/**
|
|
25
|
+
* The platform this file can be used on or is created for. (e.g. `ios`)
|
|
26
|
+
*/
|
|
27
|
+
platform: Platform | 'shared'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Represents a {@linkcode SourceFile} that also references other types.
|
|
32
|
+
*/
|
|
33
|
+
export interface FileWithReferencedTypes extends SourceFile {
|
|
34
|
+
/**
|
|
35
|
+
* All external types this {@linkcode SourceFile} references,
|
|
36
|
+
* either as return types, parameter types, or member types.
|
|
37
|
+
*/
|
|
38
|
+
referencedTypes: Type[]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Represents an import for a specific header or module.
|
|
43
|
+
*
|
|
44
|
+
* E.g. `include "Image.hpp"`, or `import NitroModules`
|
|
45
|
+
*/
|
|
46
|
+
export interface SourceImport {
|
|
47
|
+
/**
|
|
48
|
+
* The name of the header or module to import (e.g. `Image.hpp`)
|
|
49
|
+
*/
|
|
50
|
+
name: string
|
|
51
|
+
/**
|
|
52
|
+
* If this is a C++ import, it could also be forward-declared.
|
|
53
|
+
* @example
|
|
54
|
+
* ```cpp
|
|
55
|
+
* namespace NitroTest {
|
|
56
|
+
* class HybridImage;
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
forwardDeclaration?: string
|
|
61
|
+
/**
|
|
62
|
+
* The language this file is written in (e.g. `c++`)
|
|
63
|
+
*/
|
|
64
|
+
language: Language
|
|
65
|
+
/**
|
|
66
|
+
* Whether the import is a user-defined header (something local, like `"MyObject.hpp"`)
|
|
67
|
+
* or a shared system header (like `<NitroModules/HybridObject.hpp>`)
|
|
68
|
+
*/
|
|
69
|
+
space: 'user' | 'system'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type GroupedFiles = Record<SourceFile['platform'], SourceFile[]>
|
|
73
|
+
|
|
74
|
+
export function groupByPlatform(files: SourceFile[]): GroupedFiles {
|
|
75
|
+
const result: GroupedFiles = { shared: [], ios: [], android: [] }
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
result[file.platform].push(file)
|
|
78
|
+
}
|
|
79
|
+
return result
|
|
80
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { NitroConfig } from '../../config/NitroConfig.js'
|
|
2
|
+
import { indent, toLowerCamelCase } from '../../utils.js'
|
|
3
|
+
import type { SourceFile } from '../SourceFile.js'
|
|
4
|
+
import { createFileMetadataString } from '../helpers.js'
|
|
5
|
+
import type { EnumMember } from '../types/EnumType.js'
|
|
6
|
+
import { includeNitroHeader } from './includeNitroHeader.js'
|
|
7
|
+
|
|
8
|
+
function getEnumMinValue(enumMembers: EnumMember[]): number {
|
|
9
|
+
return Math.min(...enumMembers.map((m) => m.value))
|
|
10
|
+
}
|
|
11
|
+
function getEnumMaxValue(enumMembers: EnumMember[]): number {
|
|
12
|
+
return Math.max(...enumMembers.map((m) => m.value))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isIncrementingEnum(enumMembers: EnumMember[]): boolean {
|
|
16
|
+
let lastValue = getEnumMinValue(enumMembers) - 1
|
|
17
|
+
for (const enumMember of enumMembers) {
|
|
18
|
+
if (enumMember.value !== lastValue + 1) {
|
|
19
|
+
// it is not just one higher than the last value!
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
lastValue = enumMember.value
|
|
23
|
+
}
|
|
24
|
+
// all enum values were incrementing!
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a C++ enum that converts to a JS enum (aka just int)
|
|
30
|
+
*/
|
|
31
|
+
export function createCppEnum(
|
|
32
|
+
typename: string,
|
|
33
|
+
enumMembers: EnumMember[]
|
|
34
|
+
): SourceFile {
|
|
35
|
+
// Namespace typename
|
|
36
|
+
const fullyQualifiedTypename = NitroConfig.current.getCxxNamespace(
|
|
37
|
+
'c++',
|
|
38
|
+
typename
|
|
39
|
+
)
|
|
40
|
+
// Map enum to C++ code
|
|
41
|
+
const cppEnumMembers = enumMembers
|
|
42
|
+
.map(
|
|
43
|
+
(m) =>
|
|
44
|
+
`${m.name} SWIFT_NAME(${toLowerCamelCase(m.name)}) = ${m.value},`
|
|
45
|
+
)
|
|
46
|
+
.join('\n')
|
|
47
|
+
const cxxNamespace = NitroConfig.current.getCxxNamespace('c++')
|
|
48
|
+
|
|
49
|
+
let isInsideValidValues: string | undefined
|
|
50
|
+
if (isIncrementingEnum(enumMembers)) {
|
|
51
|
+
// It's just incrementing one after another, so we can simplify this to a bounds check
|
|
52
|
+
const minValue = getEnumMinValue(enumMembers)
|
|
53
|
+
const maxValue = getEnumMaxValue(enumMembers)
|
|
54
|
+
isInsideValidValues = `
|
|
55
|
+
// Check if we are within the bounds of the enum.
|
|
56
|
+
return integer >= ${minValue} && integer <= ${maxValue};
|
|
57
|
+
`.trim()
|
|
58
|
+
} else {
|
|
59
|
+
const cases = enumMembers.map(
|
|
60
|
+
(m) => `case ${m.value} /* ${m.name} */: return true;`
|
|
61
|
+
)
|
|
62
|
+
isInsideValidValues = `
|
|
63
|
+
switch (integer) {
|
|
64
|
+
${indent(cases.join('\n'), ' ')}
|
|
65
|
+
default: return false;
|
|
66
|
+
}
|
|
67
|
+
`.trim()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Create entire C++ file
|
|
71
|
+
const cppCode = `
|
|
72
|
+
${createFileMetadataString(`${typename}.hpp`)}
|
|
73
|
+
|
|
74
|
+
#pragma once
|
|
75
|
+
|
|
76
|
+
${includeNitroHeader('JSIConverter.hpp')}
|
|
77
|
+
${includeNitroHeader('NitroDefines.hpp')}
|
|
78
|
+
|
|
79
|
+
namespace ${cxxNamespace} {
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* An enum which can be represented as a JavaScript enum (${typename}).
|
|
83
|
+
*/
|
|
84
|
+
enum class ${typename} {
|
|
85
|
+
${indent(cppEnumMembers, ' ')}
|
|
86
|
+
} CLOSED_ENUM;
|
|
87
|
+
|
|
88
|
+
} // namespace ${cxxNamespace}
|
|
89
|
+
|
|
90
|
+
namespace margelo::nitro {
|
|
91
|
+
|
|
92
|
+
// C++ ${typename} <> JS ${typename} (enum)
|
|
93
|
+
template <>
|
|
94
|
+
struct JSIConverter<${fullyQualifiedTypename}> final {
|
|
95
|
+
static inline ${fullyQualifiedTypename} fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
96
|
+
int enumValue = JSIConverter<int>::fromJSI(runtime, arg);
|
|
97
|
+
return static_cast<${fullyQualifiedTypename}>(enumValue);
|
|
98
|
+
}
|
|
99
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, ${fullyQualifiedTypename} arg) {
|
|
100
|
+
int enumValue = static_cast<int>(arg);
|
|
101
|
+
return JSIConverter<int>::toJSI(runtime, enumValue);
|
|
102
|
+
}
|
|
103
|
+
static inline bool canConvert(jsi::Runtime&, const jsi::Value& value) {
|
|
104
|
+
if (!value.isNumber()) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
double number = value.getNumber();
|
|
108
|
+
int integer = static_cast<int>(number);
|
|
109
|
+
if (number != integer) {
|
|
110
|
+
// The integer is not the same value as the double - we truncated floating points.
|
|
111
|
+
// Enums are all integers, so the input floating point number is obviously invalid.
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
${indent(isInsideValidValues, ' ')}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
} // namespace margelo::nitro
|
|
119
|
+
`
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
content: cppCode,
|
|
123
|
+
subdirectory: [],
|
|
124
|
+
name: `${typename}.hpp`,
|
|
125
|
+
language: 'c++',
|
|
126
|
+
platform: 'shared',
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { SourceFile } from '../SourceFile.js'
|
|
2
|
+
import { createFileMetadataString, isNotDuplicate } from '../helpers.js'
|
|
3
|
+
import { indent } from '../../utils.js'
|
|
4
|
+
import type { HybridObjectSpec } from '../HybridObjectSpec.js'
|
|
5
|
+
import { includeHeader, includeNitroHeader } from './includeNitroHeader.js'
|
|
6
|
+
import { getHybridObjectName } from '../getHybridObjectName.js'
|
|
7
|
+
import { HybridObjectType } from '../types/HybridObjectType.js'
|
|
8
|
+
|
|
9
|
+
export function createCppHybridObject(spec: HybridObjectSpec): SourceFile[] {
|
|
10
|
+
// Extra includes
|
|
11
|
+
const extraFiles = [
|
|
12
|
+
...spec.properties.flatMap((p) => p.getExtraFiles()),
|
|
13
|
+
...spec.methods.flatMap((m) => m.getExtraFiles()),
|
|
14
|
+
]
|
|
15
|
+
const extraIncludes = [
|
|
16
|
+
...spec.properties.flatMap((p) => p.getRequiredImports('c++')),
|
|
17
|
+
...spec.methods.flatMap((m) => m.getRequiredImports('c++')),
|
|
18
|
+
...spec.baseTypes.flatMap((b) =>
|
|
19
|
+
new HybridObjectType(b).getRequiredImports('c++')
|
|
20
|
+
),
|
|
21
|
+
]
|
|
22
|
+
const cppForwardDeclarations = extraIncludes
|
|
23
|
+
.map((i) => i.forwardDeclaration)
|
|
24
|
+
.filter((v) => v != null)
|
|
25
|
+
.filter(isNotDuplicate)
|
|
26
|
+
const cppExtraIncludes = extraIncludes
|
|
27
|
+
.map((i) => includeHeader(i))
|
|
28
|
+
.filter(isNotDuplicate)
|
|
29
|
+
const cxxNamespace = spec.config.getCxxNamespace('c++')
|
|
30
|
+
const name = getHybridObjectName(spec.name)
|
|
31
|
+
|
|
32
|
+
const bases = ['public virtual HybridObject']
|
|
33
|
+
for (const base of spec.baseTypes) {
|
|
34
|
+
const baseName = getHybridObjectName(base.name).HybridTSpec
|
|
35
|
+
const fullName = base.config.isExternalConfig
|
|
36
|
+
? base.config.getCxxNamespace('c++', baseName)
|
|
37
|
+
: baseName
|
|
38
|
+
bases.push(`public virtual ${fullName}`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Generate the full header / code
|
|
42
|
+
const cppHeaderCode = `
|
|
43
|
+
${createFileMetadataString(`${name.HybridTSpec}.hpp`)}
|
|
44
|
+
|
|
45
|
+
#pragma once
|
|
46
|
+
|
|
47
|
+
${includeNitroHeader('HybridObject.hpp')}
|
|
48
|
+
|
|
49
|
+
${cppForwardDeclarations.join('\n')}
|
|
50
|
+
|
|
51
|
+
${cppExtraIncludes.join('\n')}
|
|
52
|
+
|
|
53
|
+
namespace ${cxxNamespace} {
|
|
54
|
+
|
|
55
|
+
using namespace margelo::nitro;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* An abstract base class for \`${spec.name}\`
|
|
59
|
+
* Inherit this class to create instances of \`${name.HybridTSpec}\` in C++.
|
|
60
|
+
* You must explicitly call \`HybridObject\`'s constructor yourself, because it is virtual.
|
|
61
|
+
* @example
|
|
62
|
+
* \`\`\`cpp
|
|
63
|
+
* class ${name.HybridT}: public ${name.HybridTSpec} {
|
|
64
|
+
* public:
|
|
65
|
+
* ${name.HybridT}(...): HybridObject(TAG) { ... }
|
|
66
|
+
* // ...
|
|
67
|
+
* };
|
|
68
|
+
* \`\`\`
|
|
69
|
+
*/
|
|
70
|
+
class ${name.HybridTSpec}: ${bases.join(', ')} {
|
|
71
|
+
public:
|
|
72
|
+
// Constructor
|
|
73
|
+
explicit ${name.HybridTSpec}(): HybridObject(TAG) { }
|
|
74
|
+
|
|
75
|
+
// Destructor
|
|
76
|
+
~${name.HybridTSpec}() override = default;
|
|
77
|
+
|
|
78
|
+
public:
|
|
79
|
+
// Properties
|
|
80
|
+
${indent(spec.properties.map((p) => p.getCode('c++', { virtual: true })).join('\n'), ' ')}
|
|
81
|
+
|
|
82
|
+
public:
|
|
83
|
+
// Methods
|
|
84
|
+
${indent(spec.methods.map((m) => m.getCode('c++', { virtual: true })).join('\n'), ' ')}
|
|
85
|
+
|
|
86
|
+
protected:
|
|
87
|
+
// Hybrid Setup
|
|
88
|
+
void loadHybridMethods() override;
|
|
89
|
+
|
|
90
|
+
protected:
|
|
91
|
+
// Tag for logging
|
|
92
|
+
static constexpr auto TAG = "${spec.name}";
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
} // namespace ${cxxNamespace}
|
|
96
|
+
`
|
|
97
|
+
|
|
98
|
+
// Each C++ method needs to be registered in the HybridObject - that's getters, setters and normal methods.
|
|
99
|
+
const registrations: string[] = []
|
|
100
|
+
for (const property of spec.properties) {
|
|
101
|
+
const getterMethod = property.getGetterName('other')
|
|
102
|
+
const setterMethod = property.getSetterName('other')
|
|
103
|
+
// getter
|
|
104
|
+
registrations.push(
|
|
105
|
+
`prototype.registerHybridGetter("${property.name}", &${name.HybridTSpec}::${getterMethod});`
|
|
106
|
+
)
|
|
107
|
+
if (!property.isReadonly) {
|
|
108
|
+
// setter
|
|
109
|
+
registrations.push(
|
|
110
|
+
`prototype.registerHybridSetter("${property.name}", &${name.HybridTSpec}::${setterMethod});`
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const method of spec.methods) {
|
|
115
|
+
// method
|
|
116
|
+
registrations.push(
|
|
117
|
+
`prototype.registerHybridMethod("${method.name}", &${name.HybridTSpec}::${method.name});`
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const basePrototypeRegistrations = ['HybridObject::loadHybridMethods();']
|
|
122
|
+
for (const base of spec.baseTypes) {
|
|
123
|
+
const hybridObjectName = getHybridObjectName(base.name)
|
|
124
|
+
basePrototypeRegistrations.push(
|
|
125
|
+
`${hybridObjectName.HybridTSpec}::loadHybridMethods();`
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const cppBodyCode = `
|
|
130
|
+
${createFileMetadataString(`${name.HybridTSpec}.cpp`)}
|
|
131
|
+
|
|
132
|
+
#include "${name.HybridTSpec}.hpp"
|
|
133
|
+
|
|
134
|
+
namespace ${cxxNamespace} {
|
|
135
|
+
|
|
136
|
+
void ${name.HybridTSpec}::loadHybridMethods() {
|
|
137
|
+
// load base methods/properties
|
|
138
|
+
${indent(basePrototypeRegistrations.join('\n'), ' ')}
|
|
139
|
+
// load custom methods/properties
|
|
140
|
+
registerHybrids(this, [](Prototype& prototype) {
|
|
141
|
+
${indent(registrations.join('\n'), ' ')}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace ${cxxNamespace}
|
|
146
|
+
`
|
|
147
|
+
|
|
148
|
+
const files: SourceFile[] = []
|
|
149
|
+
files.push({
|
|
150
|
+
content: cppHeaderCode,
|
|
151
|
+
name: `${name.HybridTSpec}.hpp`,
|
|
152
|
+
subdirectory: [],
|
|
153
|
+
language: 'c++',
|
|
154
|
+
platform: 'shared',
|
|
155
|
+
})
|
|
156
|
+
files.push({
|
|
157
|
+
content: cppBodyCode,
|
|
158
|
+
name: `${name.HybridTSpec}.cpp`,
|
|
159
|
+
subdirectory: [],
|
|
160
|
+
language: 'c++',
|
|
161
|
+
platform: 'shared',
|
|
162
|
+
})
|
|
163
|
+
files.push(...extraFiles)
|
|
164
|
+
return files
|
|
165
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SourceImport } from '../SourceFile.js'
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
/**
|
|
5
|
+
* The name of the Hybrid Object under which it should be registered and exposed to JS to.
|
|
6
|
+
*/
|
|
7
|
+
hybridObjectName: string
|
|
8
|
+
/**
|
|
9
|
+
* The name of the C++ class that will be default-constructed
|
|
10
|
+
*/
|
|
11
|
+
cppClassName: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CppHybridObjectRegistration {
|
|
15
|
+
cppCode: string
|
|
16
|
+
requiredImports: SourceImport[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createCppHybridObjectRegistration({
|
|
20
|
+
hybridObjectName,
|
|
21
|
+
cppClassName,
|
|
22
|
+
}: Props): CppHybridObjectRegistration {
|
|
23
|
+
return {
|
|
24
|
+
requiredImports: [
|
|
25
|
+
{ name: `${cppClassName}.hpp`, language: 'c++', space: 'user' },
|
|
26
|
+
],
|
|
27
|
+
cppCode: `
|
|
28
|
+
HybridObjectRegistry::registerHybridObjectConstructor(
|
|
29
|
+
"${hybridObjectName}",
|
|
30
|
+
[]() -> std::shared_ptr<HybridObject> {
|
|
31
|
+
static_assert(std::is_default_constructible_v<${cppClassName}>,
|
|
32
|
+
"The HybridObject \\"${cppClassName}\\" is not default-constructible! "
|
|
33
|
+
"Create a public constructor that takes zero arguments to be able to autolink this HybridObject.");
|
|
34
|
+
return std::make_shared<${cppClassName}>();
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
`.trim(),
|
|
38
|
+
}
|
|
39
|
+
}
|