expo-modules-macros 0.21.0 → 0.22.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/.github/workflows/swift-format.yml +76 -0
- package/AGENTS.md +9 -4
- package/README.md +15 -2
- package/apple/ExpoModulesMacros +0 -0
- package/apple/Package.resolved +3 -3
- package/apple/Package.swift +1 -2
- package/apple/Sources/ExpoModulesMacros/ClosureArguments.swift +39 -14
- package/apple/Sources/ExpoModulesMacros/DecorateModuleBuilder.swift +113 -26
- package/apple/Sources/ExpoModulesMacros/EventMacro.swift +29 -15
- package/apple/Sources/ExpoModulesMacros/ExpoModuleMacro.swift +53 -45
- package/apple/Sources/ExpoModulesMacros/ExpoModulesOptimizedMacro.swift +2 -1
- package/apple/Sources/ExpoModulesMacros/FreeFormTypes.swift +2 -61
- package/apple/Sources/ExpoModulesMacros/JSConstructor.swift +6 -3
- package/apple/Sources/ExpoModulesMacros/JSMacro.swift +180 -44
- package/apple/Sources/ExpoModulesMacros/JSNameCollisions.swift +26 -6
- package/apple/Sources/ExpoModulesMacros/MacroHelpers.swift +163 -42
- package/apple/Sources/ExpoModulesMacros/RecordMacro.swift +285 -221
- package/apple/Sources/ExpoModulesMacros/SharedObjectMacro.swift +45 -32
- package/apple/Sources/ExpoModulesMacros/TypeConformanceAssertion.swift +57 -27
- package/apple/Sources/ExpoModulesMacros/UnionMacro.swift +23 -9
- package/apple/Sources/ExpoModulesMacros/ViewPropsMacro.swift +10 -5
- package/apple/Sources/ExpoModulesScanner/CLI.swift +3 -1
- package/apple/Sources/ExpoModulesScanner/Core/DetectionVisitor.swift +11 -7
- package/apple/Sources/ExpoModulesScanner/Core/ScanBuildConfiguration.swift +2 -1
- package/apple/Sources/ExpoModulesScanner/Core/SourceScan.swift +10 -7
- package/apple/Sources/ExpoModulesScanner/Exports/Availability.swift +6 -3
- package/apple/Sources/ExpoModulesScanner/Exports/ExportedSurface.swift +3 -2
- package/apple/Sources/ExpoModulesScanner/Exports/ResolveRefs.swift +15 -5
- package/apple/Sources/ExpoModulesScanner/Exports/ScanExports.swift +8 -3
- package/apple/Sources/ExpoModulesScanner/Exports/SurfaceVisitor.swift +127 -45
- package/apple/Sources/ExpoModulesScanner/Exports/TypeNode.swift +2 -1
- package/apple/Sources/ExpoModulesScanner/Modules/ScanModules.swift +8 -2
- package/build/types.d.ts +7 -1
- package/package.json +7 -5
|
@@ -54,7 +54,8 @@ public struct EventMacro: AccessorMacro {
|
|
|
54
54
|
// through the getter, so the body never has to spell the payload type. A sync event calls
|
|
55
55
|
// `emitSync` (inline dispatch, JS thread only); the default calls the scheduling `emit`.
|
|
56
56
|
let emitMethod = event.isSync ? "emitSync" : "emit"
|
|
57
|
-
let closure =
|
|
57
|
+
let closure =
|
|
58
|
+
event.hasPayload
|
|
58
59
|
? "{ [weak self] payload in self?.\(emitMethod)(event: \"\(event.jsName)\", payload: payload) }"
|
|
59
60
|
: "{ [weak self] in self?.\(emitMethod)(event: \"\(event.jsName)\") }"
|
|
60
61
|
return [
|
|
@@ -85,9 +86,10 @@ extension EventMacro: PeerMacro {
|
|
|
85
86
|
// and asserting the enclosing type by its spelled name so the conformance error names the
|
|
86
87
|
// user's type rather than 'Self'.
|
|
87
88
|
let name = event.swiftName
|
|
88
|
-
let payload = event.payloadType.flatMap(
|
|
89
|
+
let payload = event.payloadType.flatMap { assertableBoundaryType($0, constraint: jsConvertibleProtocolName) }
|
|
89
90
|
let owner = enclosingTypeName(in: context) ?? "Self"
|
|
90
|
-
let helper =
|
|
91
|
+
let helper =
|
|
92
|
+
payload != nil
|
|
91
93
|
? "func \(name)<P: \(jsConvertibleProtocolName), E: \(eventEmitterProtocolName)>(_: P.Type, _: E.Type) {}"
|
|
92
94
|
: "func \(name)<E: \(eventEmitterProtocolName)>(_: E.Type) {}"
|
|
93
95
|
let call = payload.map { "\(name)(\($0).self, \(owner).self)" } ?? "\(name)(\(owner).self)"
|
|
@@ -132,7 +134,8 @@ private func validatedEvent(
|
|
|
132
134
|
}
|
|
133
135
|
if varDecl.attributes.firstAttribute(named: "JS") != nil {
|
|
134
136
|
throw MacroExpansionErrorMessage(
|
|
135
|
-
"@Event and @JS cannot be combined on the same property; an event is exposed to JS on its own, so remove one of the attributes"
|
|
137
|
+
"@Event and @JS cannot be combined on the same property; an event is exposed to JS on its own, so remove one of the attributes"
|
|
138
|
+
)
|
|
136
139
|
}
|
|
137
140
|
// The compiler also rejects accessor macros on a `let`, but with a generic message; this one says
|
|
138
141
|
// what to do instead and carries the fix-it doing it. The synthesized property is getter-only, so
|
|
@@ -142,32 +145,40 @@ private func validatedEvent(
|
|
|
142
145
|
}
|
|
143
146
|
if varDecl.modifiers.contains(where: isTypeLevelModifier) {
|
|
144
147
|
throw MacroExpansionErrorMessage(
|
|
145
|
-
"@Event must be an instance property; events are emitted from a module or shared object instance."
|
|
148
|
+
"@Event must be an instance property; events are emitted from a module or shared object instance."
|
|
149
|
+
)
|
|
146
150
|
}
|
|
147
151
|
guard varDecl.bindings.count == 1, let binding = varDecl.bindings.first,
|
|
148
|
-
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)
|
|
152
|
+
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)
|
|
153
|
+
else {
|
|
149
154
|
throw MacroExpansionErrorMessage(
|
|
150
|
-
"@Event must be applied to a single named property; declare each event separately"
|
|
155
|
+
"@Event must be applied to a single named property; declare each event separately"
|
|
156
|
+
)
|
|
151
157
|
}
|
|
152
158
|
if binding.initializer != nil {
|
|
153
159
|
throw MacroExpansionErrorMessage(
|
|
154
|
-
"@Event property cannot have an initial value; the macro synthesizes the closure"
|
|
160
|
+
"@Event property cannot have an initial value; the macro synthesizes the closure"
|
|
161
|
+
)
|
|
155
162
|
}
|
|
156
163
|
if binding.accessorBlock != nil {
|
|
157
164
|
throw MacroExpansionErrorMessage(
|
|
158
|
-
"@Event property cannot declare its own accessors; the macro synthesizes the getter"
|
|
165
|
+
"@Event property cannot declare its own accessors; the macro synthesizes the getter"
|
|
166
|
+
)
|
|
159
167
|
}
|
|
160
168
|
guard let functionType = underlyingFunctionType(of: binding.typeAnnotation?.type) else {
|
|
161
169
|
throw MacroExpansionErrorMessage(
|
|
162
|
-
"@Event property must declare a function type, such as '(Payload) -> Void' or '() -> Void'"
|
|
170
|
+
"@Event property must declare a function type, such as '(Payload) -> Void' or '() -> Void'"
|
|
171
|
+
)
|
|
163
172
|
}
|
|
164
173
|
guard isVoidReturn(functionType.returnClause.type) else {
|
|
165
174
|
throw MacroExpansionErrorMessage(
|
|
166
|
-
"@Event function type must return 'Void'; an event dispatches to JS and has no return value"
|
|
175
|
+
"@Event function type must return 'Void'; an event dispatches to JS and has no return value"
|
|
176
|
+
)
|
|
167
177
|
}
|
|
168
178
|
guard functionType.parameters.count <= 1 else {
|
|
169
179
|
throw MacroExpansionErrorMessage(
|
|
170
|
-
"@Event function type takes at most one payload parameter; combine multiple values into a single record"
|
|
180
|
+
"@Event function type takes at most one payload parameter; combine multiple values into a single record"
|
|
181
|
+
)
|
|
171
182
|
}
|
|
172
183
|
// The payload is encoded to JavaScript, and a native closure can't be encoded.
|
|
173
184
|
if let payloadClosure = functionType.parameters.first.flatMap({ firstFunctionType(in: $0.type) }) {
|
|
@@ -177,7 +188,8 @@ private func validatedEvent(
|
|
|
177
188
|
message: EventDiagnosticMessage(
|
|
178
189
|
"@Event payload can't hold a closure: the payload is encoded to JavaScript, and a native closure can't be encoded.",
|
|
179
190
|
id: "event-closure-payload"
|
|
180
|
-
)
|
|
191
|
+
)
|
|
192
|
+
)
|
|
181
193
|
])
|
|
182
194
|
}
|
|
183
195
|
|
|
@@ -321,7 +333,8 @@ private func underlyingFunctionType(of type: TypeSyntax?) -> FunctionTypeSyntax?
|
|
|
321
333
|
return underlyingFunctionType(of: attributed.baseType)
|
|
322
334
|
}
|
|
323
335
|
if let tuple = type.as(TupleTypeSyntax.self),
|
|
324
|
-
tuple.elements.count == 1, let element = tuple.elements.first, element.firstName == nil
|
|
336
|
+
tuple.elements.count == 1, let element = tuple.elements.first, element.firstName == nil
|
|
337
|
+
{
|
|
325
338
|
return underlyingFunctionType(of: element.type)
|
|
326
339
|
}
|
|
327
340
|
return type.as(FunctionTypeSyntax.self)
|
|
@@ -334,7 +347,8 @@ private func underlyingFunctionType(of type: TypeSyntax?) -> FunctionTypeSyntax?
|
|
|
334
347
|
private func isVoidReturn(_ type: TypeSyntax) -> Bool {
|
|
335
348
|
// Peel single-element, unlabeled parentheses: `(Void)` and `(())` are the same type as their content.
|
|
336
349
|
if let tuple = type.as(TupleTypeSyntax.self), tuple.elements.count == 1,
|
|
337
|
-
let element = tuple.elements.first, element.firstName == nil
|
|
350
|
+
let element = tuple.elements.first, element.firstName == nil
|
|
351
|
+
{
|
|
338
352
|
return isVoidReturn(element.type)
|
|
339
353
|
}
|
|
340
354
|
let text = type.trimmedDescription
|
|
@@ -2,34 +2,32 @@ import SwiftSyntax
|
|
|
2
2
|
import SwiftSyntaxBuilder
|
|
3
3
|
import SwiftSyntaxMacros
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
*/
|
|
5
|
+
/// Macro applied to a module class. It plays three roles, each implemented in its own
|
|
6
|
+
/// extension below:
|
|
7
|
+
///
|
|
8
|
+
/// - `MemberMacro`: binds `@JS`-marked members directly into the module's JS object via the
|
|
9
|
+
/// synthesized `_decorateModule`, and emits the resolved module name as a non-optional
|
|
10
|
+
/// `_jsName` static (no `Name(…)` DSL element). It also synthesizes a
|
|
11
|
+
/// framework-internal `_synthesizedDefinition()` returning `[AnyDefinition]` (now carrying
|
|
12
|
+
/// only nested `classes` entries) that `expo-modules-core` merges into the module's
|
|
13
|
+
/// definition. When the class doesn't already inherit `Module`/`BaseModule`, it also
|
|
14
|
+
/// synthesizes the `appContext` storage and `init(appContext:)` those base classes provide.
|
|
15
|
+
/// - `MemberAttributeMacro`: stamps `@JavaScriptActor` on `@JS` sync members and
|
|
16
|
+
/// `@ModuleDefinitionBuilder` on a `definition()` method.
|
|
17
|
+
/// - `ExtensionMacro`: adds the `AnyModule` conformance when the class doesn't inherit it.
|
|
18
|
+
///
|
|
19
|
+
/// Inheriting from `Module` is therefore optional — a class can carry any superclass (or
|
|
20
|
+
/// none) and still be a module, because everything inheritance used to provide is synthesized.
|
|
21
|
+
///
|
|
22
|
+
/// @ExpoModule
|
|
23
|
+
/// public final class MyModule {
|
|
24
|
+
/// public func definition() -> ModuleDefinition {
|
|
25
|
+
/// Name("MyModule")
|
|
26
|
+
/// }
|
|
27
|
+
///
|
|
28
|
+
/// @JS
|
|
29
|
+
/// func greet(name: String) -> String { "Hi, \(name)" }
|
|
30
|
+
/// }
|
|
33
31
|
public struct ExpoModuleMacro: MemberMacro {
|
|
34
32
|
public static func expansion(
|
|
35
33
|
of node: AttributeSyntax,
|
|
@@ -62,13 +60,19 @@ public struct ExpoModuleMacro: MemberMacro {
|
|
|
62
60
|
let decl = member.decl
|
|
63
61
|
|
|
64
62
|
if let funcDecl = decl.as(FunctionDeclSyntax.self),
|
|
65
|
-
let attribute = funcDecl.attributes.firstAttribute(named: "JS")
|
|
66
|
-
|
|
63
|
+
let attribute = funcDecl.attributes.firstAttribute(named: "JS")
|
|
64
|
+
{
|
|
65
|
+
let function = JSFunction(funcDecl: funcDecl, attribute: attribute)
|
|
66
|
+
functions.append(function)
|
|
67
|
+
if let variant = function.asyncVariant {
|
|
68
|
+
functions.append(variant)
|
|
69
|
+
}
|
|
67
70
|
continue
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
if let varDecl = decl.as(VariableDeclSyntax.self),
|
|
71
|
-
let attribute = varDecl.attributes.firstAttribute(named: "JS")
|
|
74
|
+
let attribute = varDecl.attributes.firstAttribute(named: "JS")
|
|
75
|
+
{
|
|
72
76
|
properties.append(contentsOf: collectProperties(varDecl: varDecl, attribute: attribute))
|
|
73
77
|
}
|
|
74
78
|
}
|
|
@@ -154,12 +158,14 @@ extension ExpoModuleMacro: MemberAttributeMacro {
|
|
|
154
158
|
|
|
155
159
|
// `@JS` sync members run on the JS thread; stamp `@JavaScriptActor` so isolation is
|
|
156
160
|
// checked at compile time. Skipped when the member already chose an isolation
|
|
157
|
-
// (`
|
|
161
|
+
// (`nonisolated` or another global actor), or when `.concurrent` or `.withAsync("name")` runs
|
|
162
|
+
// it on the concurrent pool. See `shouldStampJavaScriptActor`.
|
|
158
163
|
// `@Event(sync: true)` members get the stamp too: a sync event dispatches inline, so the
|
|
159
164
|
// isolation forces its call site onto the JS thread. Async events (the default) are
|
|
160
165
|
// deliberately left unstamped — their `emit` schedules onto the JS thread itself.
|
|
161
166
|
if memberHasJSAttribute(member) || isSyncEventMember(member),
|
|
162
|
-
shouldStampJavaScriptActor(on: member, enclosedBy: declaration)
|
|
167
|
+
shouldStampJavaScriptActor(on: member, enclosedBy: declaration)
|
|
168
|
+
{
|
|
163
169
|
attributes.append("@JavaScriptActor")
|
|
164
170
|
}
|
|
165
171
|
|
|
@@ -174,7 +180,8 @@ extension ExpoModuleMacro: MemberAttributeMacro {
|
|
|
174
180
|
// they already wrote `@ModuleDefinitionBuilder` themselves, which would otherwise be
|
|
175
181
|
// a duplicate attribute.
|
|
176
182
|
if isModuleDefinitionFunction(member),
|
|
177
|
-
!memberAttributes(of: member).contains(where: { hasAttributeName($0, "ModuleDefinitionBuilder") })
|
|
183
|
+
!memberAttributes(of: member).contains(where: { hasAttributeName($0, "ModuleDefinitionBuilder") })
|
|
184
|
+
{
|
|
178
185
|
attributes.append("@ModuleDefinitionBuilder")
|
|
179
186
|
}
|
|
180
187
|
|
|
@@ -186,7 +193,8 @@ private func isModuleDefinitionFunction(_ member: some DeclSyntaxProtocol) -> Bo
|
|
|
186
193
|
guard let funcDecl = member.as(FunctionDeclSyntax.self),
|
|
187
194
|
funcDecl.name.text == "definition",
|
|
188
195
|
funcDecl.signature.parameterClause.parameters.isEmpty,
|
|
189
|
-
let returnType = funcDecl.signature.returnClause?.type
|
|
196
|
+
let returnType = funcDecl.signature.returnClause?.type
|
|
197
|
+
else {
|
|
190
198
|
return false
|
|
191
199
|
}
|
|
192
200
|
return baseIdentifier(of: returnType) == "ModuleDefinition"
|
|
@@ -215,7 +223,8 @@ extension ExpoModuleMacro: ExtensionMacro {
|
|
|
215
223
|
// These base types already supply `AnyModule`; emitting a second conformance here
|
|
216
224
|
// would be redundant and error.
|
|
217
225
|
if let classDecl = declaration.as(ClassDeclSyntax.self),
|
|
218
|
-
inheritsFromAny(classDecl, names: ["Module", "BaseModule", "AnyModule"])
|
|
226
|
+
inheritsFromAny(classDecl, names: ["Module", "BaseModule", "AnyModule"])
|
|
227
|
+
{
|
|
219
228
|
return []
|
|
220
229
|
}
|
|
221
230
|
let conformance: DeclSyntax = "extension \(type.trimmed): AnyModule {}"
|
|
@@ -232,7 +241,8 @@ private func hasStoredProperty(_ classDecl: ClassDeclSyntax, named name: String)
|
|
|
232
241
|
}
|
|
233
242
|
for binding in varDecl.bindings {
|
|
234
243
|
if let identifier = binding.pattern.as(IdentifierPatternSyntax.self),
|
|
235
|
-
identifier.identifier.text == name
|
|
244
|
+
identifier.identifier.text == name
|
|
245
|
+
{
|
|
236
246
|
return true
|
|
237
247
|
}
|
|
238
248
|
}
|
|
@@ -240,14 +250,12 @@ private func hasStoredProperty(_ classDecl: ClassDeclSyntax, named name: String)
|
|
|
240
250
|
return false
|
|
241
251
|
}
|
|
242
252
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
syntactic match on the spelled name.
|
|
250
|
-
*/
|
|
253
|
+
/// True if the class declares an initializer that satisfies the `init(appContext:)` protocol
|
|
254
|
+
/// requirement: a single parameter labeled `appContext` whose type is written as `AppContext`
|
|
255
|
+
/// (or `….AppContext`). Both must match — the label is part of the requirement, so
|
|
256
|
+
/// `init(c: AppContext)` does *not* satisfy it (we still synthesize ours), and the type guards
|
|
257
|
+
/// against a same-labeled init of an unrelated type. A macro can't resolve types, so this is a
|
|
258
|
+
/// syntactic match on the spelled name.
|
|
251
259
|
private func hasAppContextInitializer(_ classDecl: ClassDeclSyntax) -> Bool {
|
|
252
260
|
for member in classDecl.memberBlock.members {
|
|
253
261
|
guard let initDecl = member.decl.as(InitializerDeclSyntax.self) else {
|
|
@@ -34,7 +34,8 @@ public struct OptimizedFunctionAttachedMacro: PeerMacro {
|
|
|
34
34
|
) throws -> [DeclSyntax] {
|
|
35
35
|
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
|
|
36
36
|
throw MacroExpansionErrorMessage(
|
|
37
|
-
"@OptimizedFunction can only be attached to function declarations"
|
|
37
|
+
"@OptimizedFunction can only be attached to function declarations"
|
|
38
|
+
)
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
let functionName = funcDecl.name.text
|
|
@@ -178,72 +178,13 @@ internal func isAnyType(_ type: some SyntaxProtocol) -> Bool {
|
|
|
178
178
|
if let member = type.as(MemberTypeSyntax.self),
|
|
179
179
|
member.name.text == "Any",
|
|
180
180
|
member.genericArgumentClause == nil,
|
|
181
|
-
let base = member.baseType.as(IdentifierTypeSyntax.self)
|
|
181
|
+
let base = member.baseType.as(IdentifierTypeSyntax.self)
|
|
182
|
+
{
|
|
182
183
|
return base.name.text == "Swift"
|
|
183
184
|
}
|
|
184
185
|
return false
|
|
185
186
|
}
|
|
186
187
|
|
|
187
|
-
/// The element type of `[T]` or `Array<T>`, or `nil` for any other type.
|
|
188
|
-
private func arrayElementType(_ type: TypeSyntax) -> TypeSyntax? {
|
|
189
|
-
if let array = type.as(ArrayTypeSyntax.self) {
|
|
190
|
-
return array.element
|
|
191
|
-
}
|
|
192
|
-
guard let arguments = genericArguments(of: type, named: "Array"), arguments.count == 1 else {
|
|
193
|
-
return nil
|
|
194
|
-
}
|
|
195
|
-
return arguments[0]
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/// The value type of `[String: V]` or `Dictionary<String, V>`, or `nil` for any other type, including a
|
|
199
|
-
/// dictionary with a different key type.
|
|
200
|
-
private func stringKeyedDictionaryValueType(_ type: TypeSyntax) -> TypeSyntax? {
|
|
201
|
-
if let dictionary = type.as(DictionaryTypeSyntax.self) {
|
|
202
|
-
return isStringType(dictionary.key) ? dictionary.value : nil
|
|
203
|
-
}
|
|
204
|
-
guard let arguments = genericArguments(of: type, named: "Dictionary"), arguments.count == 2 else {
|
|
205
|
-
return nil
|
|
206
|
-
}
|
|
207
|
-
return isStringType(arguments[0]) ? arguments[1] : nil
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/// The type arguments of a generic type spelled `<name><…>` (or `Swift.<name><…>`), or `nil` when the
|
|
211
|
-
/// type has another name or no type arguments.
|
|
212
|
-
private func genericArguments(of type: TypeSyntax, named name: String) -> [TypeSyntax]? {
|
|
213
|
-
let clause: GenericArgumentClauseSyntax?
|
|
214
|
-
if let identifier = type.as(IdentifierTypeSyntax.self), identifier.name.text == name {
|
|
215
|
-
clause = identifier.genericArgumentClause
|
|
216
|
-
} else if let member = type.as(MemberTypeSyntax.self),
|
|
217
|
-
member.name.text == name,
|
|
218
|
-
member.baseType.as(IdentifierTypeSyntax.self)?.name.text == "Swift" {
|
|
219
|
-
clause = member.genericArgumentClause
|
|
220
|
-
} else {
|
|
221
|
-
return nil
|
|
222
|
-
}
|
|
223
|
-
guard let clause else {
|
|
224
|
-
return nil
|
|
225
|
-
}
|
|
226
|
-
var types: [TypeSyntax] = []
|
|
227
|
-
for argument in clause.arguments {
|
|
228
|
-
guard case .type(let type) = argument.argument else {
|
|
229
|
-
return nil
|
|
230
|
-
}
|
|
231
|
-
types.append(type)
|
|
232
|
-
}
|
|
233
|
-
return types
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/// True when the type is `String` or `Swift.String`.
|
|
237
|
-
private func isStringType(_ type: TypeSyntax) -> Bool {
|
|
238
|
-
if let identifier = type.as(IdentifierTypeSyntax.self) {
|
|
239
|
-
return identifier.name.text == "String" && identifier.genericArgumentClause == nil
|
|
240
|
-
}
|
|
241
|
-
if let member = type.as(MemberTypeSyntax.self), member.name.text == "String" {
|
|
242
|
-
return member.baseType.as(IdentifierTypeSyntax.self)?.name.text == "Swift"
|
|
243
|
-
}
|
|
244
|
-
return false
|
|
245
|
-
}
|
|
246
|
-
|
|
247
188
|
/// Walks a type looking for `Any` (or `Swift.Any`) anywhere inside it.
|
|
248
189
|
private final class AnyTypeFinder: SyntaxVisitor {
|
|
249
190
|
var found = false
|
|
@@ -23,7 +23,8 @@ internal struct JSConstructor {
|
|
|
23
23
|
guard arguments.count == \(parameters.count) else {
|
|
24
24
|
throw Exceptions.ArgumentsRangeMismatch((functionName: "\(typeName)", received: arguments.count, required: \(parameters.count), maximum: \(parameters.count)))
|
|
25
25
|
}
|
|
26
|
-
"""
|
|
26
|
+
"""
|
|
27
|
+
)
|
|
27
28
|
|
|
28
29
|
var callArguments: [String] = []
|
|
29
30
|
for (index, parameter) in parameters.enumerated() {
|
|
@@ -32,7 +33,8 @@ internal struct JSConstructor {
|
|
|
32
33
|
type: parameter.type,
|
|
33
34
|
into: "arg\(index)",
|
|
34
35
|
from: "arguments.unownedValue(at: \(index))"
|
|
35
|
-
)
|
|
36
|
+
)
|
|
37
|
+
)
|
|
36
38
|
|
|
37
39
|
let label = parameter.firstName.text
|
|
38
40
|
callArguments.append(label == "_" ? "arg\(index)" : "\(label): arg\(index)")
|
|
@@ -40,7 +42,8 @@ internal struct JSConstructor {
|
|
|
40
42
|
|
|
41
43
|
lines.append("return \(typeName)(\(callArguments.joined(separator: ", ")))")
|
|
42
44
|
|
|
43
|
-
return
|
|
45
|
+
return
|
|
46
|
+
lines
|
|
44
47
|
.flatMap { $0.split(separator: "\n", omittingEmptySubsequences: false) }
|
|
45
48
|
.map { indent + $0 }
|
|
46
49
|
.joined(separator: "\n")
|