expo-modules-macros 0.17.0 → 0.19.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/apple/ExpoModulesMacros +0 -0
- package/apple/Sources/ExpoModulesMacros/ClosureArguments.swift +12 -18
- package/apple/Sources/ExpoModulesMacros/DecorateModuleBuilder.swift +17 -9
- package/apple/Sources/ExpoModulesMacros/EventMacro.swift +3 -2
- package/apple/Sources/ExpoModulesMacros/ExpoModuleMacro.swift +1 -1
- package/apple/Sources/ExpoModulesMacros/FreeFormTypes.swift +101 -52
- package/apple/Sources/ExpoModulesMacros/JSMacro.swift +80 -83
- package/apple/Sources/ExpoModulesMacros/MacroHelpers.swift +82 -8
- package/apple/Sources/ExpoModulesMacros/RecordMacro.swift +19 -62
- package/apple/Sources/ExpoModulesMacros/SharedObjectMacro.swift +1 -1
- package/apple/Sources/ExpoModulesMacros/TypeConformanceAssertion.swift +7 -5
- package/apple/Sources/ExpoModulesMacros/ViewPropsMacro.swift +0 -12
- package/apple/Sources/ExpoModulesScanner/Exports/ExportedSurface.swift +19 -11
- package/apple/Sources/ExpoModulesScanner/Exports/ResolveRefs.swift +101 -67
- package/apple/Sources/ExpoModulesScanner/Exports/SurfaceVisitor.swift +117 -36
- package/apple/Sources/ExpoModulesScanner/Exports/TypeNode.swift +4 -2
- package/build/types.d.ts +18 -3
- package/build/types.js +1 -1
- package/package.json +3 -3
|
@@ -72,6 +72,9 @@ internal func isConcurrentJSMember(_ decl: DeclSyntaxProtocol) -> Bool {
|
|
|
72
72
|
/// True if the type is written as an optional: `T?`, `T!`, or the explicit `Optional<T>`. Used to
|
|
73
73
|
/// decide argument requiredness (an optional parameter may be omitted) and record-field nullability.
|
|
74
74
|
internal func isOptionalType(_ type: TypeSyntax) -> Bool {
|
|
75
|
+
if let attributed = type.as(AttributedTypeSyntax.self) {
|
|
76
|
+
return isOptionalType(attributed.baseType)
|
|
77
|
+
}
|
|
75
78
|
if type.is(OptionalTypeSyntax.self) || type.is(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
|
|
76
79
|
return true
|
|
77
80
|
}
|
|
@@ -81,6 +84,39 @@ internal func isOptionalType(_ type: TypeSyntax) -> Bool {
|
|
|
81
84
|
return false
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
/// A parameter's type split from the specifiers written in front of it (`borrowing`, `consuming`,
|
|
88
|
+
/// `sending`, `inout`, `isolated`, ...). The specifiers aren't part of the type: the decode call and
|
|
89
|
+
/// the conformance assertion need the bare type (`borrowing Point.decode(...)` isn't valid Swift), and
|
|
90
|
+
/// a decoded argument is a fresh owned value, so it can be passed under any ownership convention.
|
|
91
|
+
internal struct SpecifiedType {
|
|
92
|
+
/// The type without its specifiers.
|
|
93
|
+
let type: TypeSyntax
|
|
94
|
+
/// The specifiers written before the type, in source order.
|
|
95
|
+
let specifiers: [String]
|
|
96
|
+
|
|
97
|
+
init(_ type: TypeSyntax) {
|
|
98
|
+
if let attributed = type.as(AttributedTypeSyntax.self), !attributed.specifiers.isEmpty {
|
|
99
|
+
self.specifiers = attributed.specifiers.map(\.trimmedDescription)
|
|
100
|
+
self.type =
|
|
101
|
+
attributed.attributes.isEmpty
|
|
102
|
+
? attributed.baseType : TypeSyntax(attributed.with(\.specifiers, []))
|
|
103
|
+
} else {
|
|
104
|
+
self.specifiers = []
|
|
105
|
+
self.type = type
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/// The first specifier a decoded argument can't honor: `inout` (JavaScript can't observe a write
|
|
110
|
+
/// back) or `isolated` (the argument doesn't carry an isolation).
|
|
111
|
+
var unsupportedSpecifier: String? {
|
|
112
|
+
return specifiers.first { !ownershipSpecifiers.contains($0) }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// The ownership specifiers a parameter may carry. They only change how the argument is passed, which
|
|
117
|
+
/// a fresh decoded value satisfies either way.
|
|
118
|
+
internal let ownershipSpecifiers: Set<String> = ["borrowing", "consuming", "sending", "__shared", "__owned"]
|
|
119
|
+
|
|
84
120
|
/// The type wrapped by one optional layer (`T?`, `T!` or `Optional<T>`), or `nil` when the type isn't
|
|
85
121
|
/// optional.
|
|
86
122
|
internal func optionalWrappedType(_ type: TypeSyntax) -> TypeSyntax? {
|
|
@@ -330,17 +366,53 @@ internal func expressionType(_ type: String) -> String {
|
|
|
330
366
|
}
|
|
331
367
|
|
|
332
368
|
/// The decode expression for a boundary type read from `valueExpression` (a `JavaScriptUnownedValue`),
|
|
333
|
-
/// as it appears after `try`. A
|
|
334
|
-
///
|
|
335
|
-
///
|
|
336
|
-
///
|
|
337
|
-
internal func decodeCall(_ type: String, from valueExpression: String) -> String {
|
|
338
|
-
if let
|
|
339
|
-
return
|
|
369
|
+
/// as it appears after `try`. A type that mentions `Any` can't conform to `JavaScriptDecodable`, so it
|
|
370
|
+
/// decodes through the `JavaScriptValue` free-form methods its `freeForm` conversion names; every other
|
|
371
|
+
/// type decodes through its own static `decode`, spelled in expression position (`T!` rewritten to
|
|
372
|
+
/// `T?`).
|
|
373
|
+
internal func decodeCall(_ type: String, freeForm: FreeFormConversion?, from valueExpression: String) -> String {
|
|
374
|
+
if let freeForm {
|
|
375
|
+
return freeForm.decodeExpression(of: valueExpression, as: expressionType(type))
|
|
340
376
|
}
|
|
341
377
|
return "\(expressionType(type)).decode(\(valueExpression), in: runtime)"
|
|
342
378
|
}
|
|
343
379
|
|
|
380
|
+
/// The encode expression for the native value `valueExpression` of a boundary type, as it appears
|
|
381
|
+
/// after `try`. The counterpart of `decodeCall`: a type that mentions `Any` encodes through the
|
|
382
|
+
/// `JavaScriptValue` free-form methods, and every other type through its own static `encode`.
|
|
383
|
+
internal func encodeCall(_ type: String, freeForm: FreeFormConversion?, of valueExpression: String) -> String {
|
|
384
|
+
if let freeForm {
|
|
385
|
+
return freeForm.encodeExpression(of: valueExpression)
|
|
386
|
+
}
|
|
387
|
+
return "\(expressionType(type)).encode(\(valueExpression), in: runtime)"
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// MARK: - Escaped names
|
|
391
|
+
|
|
392
|
+
/// `name` without the backticks that escape it: `` `default` `` becomes `default`. Swift needs the
|
|
393
|
+
/// backticks in every identifier position, but a name JavaScript sees (a JS member name, an event
|
|
394
|
+
/// name, a record key) is the bare name.
|
|
395
|
+
internal func withoutBackticks(_ name: String) -> String {
|
|
396
|
+
var name = Substring(name)
|
|
397
|
+
while name.first == "`" {
|
|
398
|
+
name.removeFirst()
|
|
399
|
+
}
|
|
400
|
+
while name.last == "`" {
|
|
401
|
+
name.removeLast()
|
|
402
|
+
}
|
|
403
|
+
return String(name)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/// A generated identifier built from a member's name, such as `countDescriptor` from `count`. The
|
|
407
|
+
/// affixes join the bare name, and an escaped name keeps the backticks around the whole result
|
|
408
|
+
/// (`` `class` `` gives `` `classDescriptor` ``), since the bare name may not be an identifier on
|
|
409
|
+
/// its own.
|
|
410
|
+
internal func derivedIdentifier(from name: String, prefix: String = "", suffix: String = "") -> String {
|
|
411
|
+
let bareName = withoutBackticks(name)
|
|
412
|
+
let identifier = prefix + bareName + suffix
|
|
413
|
+
return bareName == name ? identifier : "`\(identifier)`"
|
|
414
|
+
}
|
|
415
|
+
|
|
344
416
|
// MARK: - @JS property collection
|
|
345
417
|
|
|
346
418
|
/// Collects the `@JS var` bindings of a declaration into `JSProperty` values for direct JSI binding.
|
|
@@ -365,8 +437,10 @@ internal func collectProperties(
|
|
|
365
437
|
?? binding.initializer.flatMap { inferredLiteralType(of: $0.value) }
|
|
366
438
|
return JSProperty(
|
|
367
439
|
swiftName: swiftName,
|
|
368
|
-
jsName: jsNameOverride ?? swiftName,
|
|
440
|
+
jsName: jsNameOverride ?? withoutBackticks(swiftName),
|
|
369
441
|
valueType: valueType,
|
|
442
|
+
// A literal-inferred type never mentions `Any`, so only an explicit annotation can be free-form.
|
|
443
|
+
freeForm: binding.typeAnnotation.flatMap { freeFormConversion(of: $0.type) },
|
|
370
444
|
isSettable: isVar && bindingIsSettable(binding)
|
|
371
445
|
)
|
|
372
446
|
}
|
|
@@ -95,7 +95,7 @@ public struct RecordMacro: MemberMacro, ExtensionMacro {
|
|
|
95
95
|
members.append(defaultInit)
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
if !existingInitLabels.contains(properties.map { $0.
|
|
98
|
+
if !existingInitLabels.contains(properties.map { $0.key }) {
|
|
99
99
|
members.append(memberwiseInit(properties: properties))
|
|
100
100
|
}
|
|
101
101
|
members.append(fromJSObjectFactory(properties: properties))
|
|
@@ -143,62 +143,13 @@ public struct RecordMacro: MemberMacro, ExtensionMacro {
|
|
|
143
143
|
|
|
144
144
|
// MARK: - Property model
|
|
145
145
|
|
|
146
|
-
/**
|
|
147
|
-
How a property whose type mentions `Any` converts on the JS-value paths. Such a type can't conform to
|
|
148
|
-
the JS codable protocols, so the property converts through the `JavaScriptValue` free-form methods.
|
|
149
|
-
*/
|
|
150
|
-
private enum FreeFormConversion {
|
|
151
|
-
/// `Any`, `[Any]` or `[String: Any]`, wrapped in at most one optional: the dedicated methods for
|
|
152
|
-
/// that shape, named by `decodeMethod` and `encodeMethod`. The optional is handled around them.
|
|
153
|
-
case shape(decodeMethod: String, encodeMethod: String, isOptional: Bool, isBareAny: Bool)
|
|
154
|
-
/// Any other type that mentions `Any`: the generic `decodeAny(_:as:in:)` and `encodeAny(_:in:)`.
|
|
155
|
-
case generic
|
|
156
|
-
|
|
157
|
-
/// Classifies a type that mentions `Any`; the caller checks `isConvertibleFreeFormType` first.
|
|
158
|
-
init(type: TypeSyntax) {
|
|
159
|
-
let wrapped = optionalWrappedType(type)
|
|
160
|
-
switch freeFormShape(of: wrapped ?? type) {
|
|
161
|
-
case .any:
|
|
162
|
-
self = .shape(
|
|
163
|
-
decodeMethod: "decodeAny",
|
|
164
|
-
encodeMethod: "encodeAny",
|
|
165
|
-
isOptional: wrapped != nil,
|
|
166
|
-
isBareAny: true
|
|
167
|
-
)
|
|
168
|
-
case .array:
|
|
169
|
-
self = .shape(
|
|
170
|
-
decodeMethod: "decodeAnyArray",
|
|
171
|
-
encodeMethod: "encodeAnyArray",
|
|
172
|
-
isOptional: wrapped != nil,
|
|
173
|
-
isBareAny: false
|
|
174
|
-
)
|
|
175
|
-
case .dictionary:
|
|
176
|
-
self = .shape(
|
|
177
|
-
decodeMethod: "decodeAnyDictionary",
|
|
178
|
-
encodeMethod: "encodeAnyDictionary",
|
|
179
|
-
isOptional: wrapped != nil,
|
|
180
|
-
isBareAny: false
|
|
181
|
-
)
|
|
182
|
-
case nil:
|
|
183
|
-
self = .generic
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/// True for `Any` itself, optional or not.
|
|
188
|
-
var isBareAny: Bool {
|
|
189
|
-
guard case .shape(_, _, _, let isBareAny) = self else {
|
|
190
|
-
return false
|
|
191
|
-
}
|
|
192
|
-
return isBareAny
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
146
|
/**
|
|
197
147
|
A single record property discovered on the type, paired with everything the synthesized
|
|
198
|
-
conversions need: its property name
|
|
199
|
-
source may omit it.
|
|
148
|
+
conversions need: its property name, its written type, and how the source may omit it.
|
|
200
149
|
*/
|
|
201
150
|
private struct RecordProperty {
|
|
151
|
+
/// The property name as written, backticks included for an escaped name (`` `default` ``), since
|
|
152
|
+
/// every identifier position in the generated code needs them.
|
|
202
153
|
let name: String
|
|
203
154
|
/// The property's declared type, verbatim (e.g. `String`, `Int`, `String?`). Used to build the
|
|
204
155
|
/// memberwise-init parameter and as the receiver of the per-property `decode`/`encode` (and, on the
|
|
@@ -222,6 +173,12 @@ private struct RecordProperty {
|
|
|
222
173
|
var isRequired: Bool {
|
|
223
174
|
return !hasDefault && !isOptional
|
|
224
175
|
}
|
|
176
|
+
|
|
177
|
+
/// The key the property reads from and writes to, in both the JS object and the dictionary: the
|
|
178
|
+
/// name without escaping backticks.
|
|
179
|
+
var key: String {
|
|
180
|
+
return withoutBackticks(name)
|
|
181
|
+
}
|
|
225
182
|
}
|
|
226
183
|
|
|
227
184
|
/**
|
|
@@ -414,7 +371,7 @@ private func factoryBody(properties: [RecordProperty], readLines: [String]) -> S
|
|
|
414
371
|
private func jsObjectReadLines(properties: [RecordProperty]) -> [String] {
|
|
415
372
|
var lines: [String] = []
|
|
416
373
|
for property in properties {
|
|
417
|
-
let valueVar =
|
|
374
|
+
let valueVar = derivedIdentifier(from: property.name, suffix: "JSValue")
|
|
418
375
|
let exprType = expressionType(property.type)
|
|
419
376
|
let decode: String
|
|
420
377
|
switch property.freeForm {
|
|
@@ -426,10 +383,10 @@ private func jsObjectReadLines(properties: [RecordProperty]) -> [String] {
|
|
|
426
383
|
case nil:
|
|
427
384
|
decode = "try \(exprType).decode(\(valueVar), in: runtime)"
|
|
428
385
|
}
|
|
429
|
-
lines.append(" let \(valueVar) = object.getProperty(\"\(property.
|
|
386
|
+
lines.append(" let \(valueVar) = object.getProperty(\"\(property.key)\")")
|
|
430
387
|
if property.isRequired {
|
|
431
388
|
lines.append(" guard !\(valueVar).isUndefined() else {")
|
|
432
|
-
lines.append(" throw RecordPropertyRequiredException(\"\(property.
|
|
389
|
+
lines.append(" throw RecordPropertyRequiredException(\"\(property.key)\")")
|
|
433
390
|
lines.append(" }")
|
|
434
391
|
lines.append(" let \(property.name) = \(decode)")
|
|
435
392
|
} else if property.isOptional {
|
|
@@ -449,16 +406,16 @@ private func jsObjectReadLines(properties: [RecordProperty]) -> [String] {
|
|
|
449
406
|
private func dictionaryReadLines(properties: [RecordProperty]) -> [String] {
|
|
450
407
|
var lines: [String] = []
|
|
451
408
|
for property in properties {
|
|
452
|
-
let valueVar =
|
|
409
|
+
let valueVar = derivedIdentifier(from: property.name, suffix: "Value")
|
|
453
410
|
let exprType = expressionType(property.type)
|
|
454
411
|
let isBareAny = property.freeForm?.isBareAny == true
|
|
455
412
|
let cast = isBareAny
|
|
456
413
|
? valueVar
|
|
457
414
|
: "try \(exprType).getDynamicType().cast(\(valueVar), appContext: appContext) as! \(exprType)"
|
|
458
|
-
lines.append(" let \(valueVar) = dictionary[\"\(property.
|
|
415
|
+
lines.append(" let \(valueVar) = dictionary[\"\(property.key)\"]")
|
|
459
416
|
if property.isRequired {
|
|
460
417
|
lines.append(" guard let \(valueVar) else {")
|
|
461
|
-
lines.append(" throw RecordPropertyRequiredException(\"\(property.
|
|
418
|
+
lines.append(" throw RecordPropertyRequiredException(\"\(property.key)\")")
|
|
462
419
|
lines.append(" }")
|
|
463
420
|
lines.append(" let \(property.name) = \(cast)")
|
|
464
421
|
} else if property.isOptional {
|
|
@@ -483,7 +440,7 @@ private func toDictionaryMethod(properties: [RecordProperty], inheritsRecord: Bo
|
|
|
483
440
|
lines.append(" var dictionary: [String: Any] = [:]")
|
|
484
441
|
}
|
|
485
442
|
for property in properties {
|
|
486
|
-
lines.append(" dictionary[\"\(property.
|
|
443
|
+
lines.append(" dictionary[\"\(property.key)\"] = self.\(property.name)")
|
|
487
444
|
}
|
|
488
445
|
lines.append(" return dictionary")
|
|
489
446
|
let body = lines.joined(separator: "\n")
|
|
@@ -537,7 +494,7 @@ private func toObjectMethod(properties: [RecordProperty], inheritsRecord: Bool)
|
|
|
537
494
|
case nil:
|
|
538
495
|
encode = "try \(exprType).encode(self.\(property.name), in: runtime)"
|
|
539
496
|
}
|
|
540
|
-
lines.append(" object.setProperty(\"\(property.
|
|
497
|
+
lines.append(" object.setProperty(\"\(property.key)\", value: \(encode))")
|
|
541
498
|
}
|
|
542
499
|
lines.append(" return object")
|
|
543
500
|
let body = lines.joined(separator: "\n")
|
|
@@ -567,7 +524,7 @@ private func initializerParameterLabels(of declaration: some DeclGroupSyntax) ->
|
|
|
567
524
|
}
|
|
568
525
|
let labels = initDecl.signature.parameterClause.parameters.map { parameter in
|
|
569
526
|
// `firstName` is the external label (or `_`); fall back to the internal name when omitted.
|
|
570
|
-
let label = parameter.firstName.text
|
|
527
|
+
let label = withoutBackticks(parameter.firstName.text)
|
|
571
528
|
return label == "_" ? "" : label
|
|
572
529
|
}
|
|
573
530
|
signatures.append(labels)
|
|
@@ -39,7 +39,7 @@ public struct SharedObjectMacro: MemberMacro {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
let typeName = classDecl.name.text
|
|
42
|
-
let jsName = jsNameArgument(of: node) ?? typeName
|
|
42
|
+
let jsName = jsNameArgument(of: node) ?? withoutBackticks(typeName)
|
|
43
43
|
|
|
44
44
|
// `@JS func`s/`var`s and the `@JS init` are bound directly into the shared object's JS object by
|
|
45
45
|
// the synthesized `_decorateSharedObject(prototype:)` / `_decorateSharedObject(constructor:)` / `_constructSharedObject`
|
|
@@ -111,8 +111,9 @@ internal func directionalConformanceAssertion(
|
|
|
111
111
|
let helper = "func \(name)<\(parameters.joined(separator: ", "))>(\(typeParameters.joined(separator: ", "))) {}"
|
|
112
112
|
let call = "\(name)(\(arguments.joined(separator: ", ")))"
|
|
113
113
|
let staticKeyword = isStatic ? "static " : ""
|
|
114
|
+
let peerName = derivedIdentifier(from: name, prefix: "_assertTypesConformance_")
|
|
114
115
|
return """
|
|
115
|
-
private \(raw: staticKeyword)func
|
|
116
|
+
private \(raw: staticKeyword)func \(raw: peerName)() {
|
|
116
117
|
\(raw: helper)
|
|
117
118
|
\(raw: call)
|
|
118
119
|
}
|
|
@@ -142,10 +143,11 @@ internal func typeConformanceAssertions(
|
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
/// The type to assert for a boundary type as written, or `nil` when nothing needs asserting: an
|
|
145
|
-
/// exactly-free-form type (
|
|
146
|
-
/// primitive both return `nil`; everything else is unwrapped of trailing optionals
|
|
147
|
-
/// *optional* free-form (`[String: Any]?`)
|
|
148
|
-
/// asserted for a clean diagnostic.
|
|
146
|
+
/// exactly-free-form type (converted through the `JavaScriptValue` free-form methods) and a
|
|
147
|
+
/// known-conforming primitive both return `nil`; everything else is unwrapped of trailing optionals
|
|
148
|
+
/// and asserted. Shared with `@Event`, where an *optional* free-form type (`[String: Any]?`) is kept
|
|
149
|
+
/// and asserted for a clean diagnostic. `@JS` leaves out every type that mentions `Any` before it gets
|
|
150
|
+
/// here.
|
|
149
151
|
internal func assertableBoundaryType(_ type: String) -> String? {
|
|
150
152
|
guard !isFreeFormBoundaryType(type) else {
|
|
151
153
|
return nil
|
|
@@ -251,18 +251,6 @@ private struct ViewProp {
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
/// `name` without the backticks that escape it: `` `default` `` becomes `default`.
|
|
255
|
-
private func withoutBackticks(_ name: String) -> String {
|
|
256
|
-
var name = Substring(name)
|
|
257
|
-
while name.first == "`" {
|
|
258
|
-
name.removeFirst()
|
|
259
|
-
}
|
|
260
|
-
while name.last == "`" {
|
|
261
|
-
name.removeLast()
|
|
262
|
-
}
|
|
263
|
-
return String(name)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
254
|
private struct ViewPropsModel {
|
|
267
255
|
/// Value props, in declaration order. The order is the bit order, so it is part of the ABI
|
|
268
256
|
/// between a compiled view and the runtime that fills the mask.
|
|
@@ -158,7 +158,8 @@ struct ExportedEvent: Encodable, Equatable {
|
|
|
158
158
|
|
|
159
159
|
/// A `@ExpoModule` type and its `@JS` surface.
|
|
160
160
|
struct ExportedModule: Encodable, Equatable {
|
|
161
|
-
/// The Swift class name.
|
|
161
|
+
/// The Swift class name. A module is always declared at file scope, since autolinking registers no
|
|
162
|
+
/// other.
|
|
162
163
|
let name: String
|
|
163
164
|
|
|
164
165
|
/// The JS module name: `@ExpoModule("Foo")` override, else the class name.
|
|
@@ -178,7 +179,9 @@ struct ExportedModule: Encodable, Equatable {
|
|
|
178
179
|
|
|
179
180
|
/// One entry of `@ExpoModule(classes: [...])`.
|
|
180
181
|
struct ExportedClass: Encodable, Equatable {
|
|
181
|
-
/// The
|
|
182
|
+
/// The `name` of the matching `@SharedObject`, which is qualified when the class is nested
|
|
183
|
+
/// (`Outer.Statement`). The Swift name as spelled in the argument when the scan found no
|
|
184
|
+
/// `@SharedObject` with this name.
|
|
182
185
|
let name: String
|
|
183
186
|
|
|
184
187
|
/// The name of the module member JS reads the class from: the matching `@SharedObject`'s `jsName`.
|
|
@@ -189,10 +192,11 @@ struct ExportedClass: Encodable, Equatable {
|
|
|
189
192
|
|
|
190
193
|
/// A `@SharedObject` type: a JS class with an optional `@JS init` constructor plus its `@JS` members.
|
|
191
194
|
struct ExportedSharedObject: Encodable, Equatable {
|
|
192
|
-
/// The Swift class name.
|
|
195
|
+
/// The Swift class name, qualified with the types it is nested in (`Outer.Player`).
|
|
193
196
|
let name: String
|
|
194
197
|
|
|
195
|
-
/// The JS class name: `@SharedObject("Foo")` override, else the class name
|
|
198
|
+
/// The JS class name: `@SharedObject("Foo")` override, else the class name without the enclosing
|
|
199
|
+
/// types.
|
|
196
200
|
let jsName: String
|
|
197
201
|
|
|
198
202
|
/// The `@JS init` parameters, or `nil` when there's none. A shared object has at most one.
|
|
@@ -207,7 +211,8 @@ struct ExportedSharedObject: Encodable, Equatable {
|
|
|
207
211
|
|
|
208
212
|
/// A `@Record` type and its properties (data only: no functions, accessors, or constructor).
|
|
209
213
|
struct ExportedRecord: Encodable, Equatable {
|
|
210
|
-
/// The Swift type name (struct or class)
|
|
214
|
+
/// The Swift type name (struct or class), qualified with the types it is nested in
|
|
215
|
+
/// (`Outer.Options`).
|
|
211
216
|
let name: String
|
|
212
217
|
|
|
213
218
|
let properties: [ExportedRecordProperty]
|
|
@@ -247,8 +252,9 @@ struct ExportedEnumCase: Encodable, Equatable {
|
|
|
247
252
|
/// Detected by conformance, not by a macro attribute, because core converts it through its
|
|
248
253
|
/// `RawRepresentable`/`Enumerable` conformance (`Coding/…+Enumerable`) with no macro involved.
|
|
249
254
|
struct ExportedEnum: Encodable, Equatable {
|
|
250
|
-
/// The Swift enum name
|
|
251
|
-
/// reaches JS as its raw values, not under
|
|
255
|
+
/// The Swift enum name, qualified with the types it is nested in (`Options.Encoding`). No `jsName`:
|
|
256
|
+
/// an enum carries no macro to spell an override on, and it reaches JS as its raw values, not under
|
|
257
|
+
/// a bound name.
|
|
252
258
|
let name: String
|
|
253
259
|
|
|
254
260
|
/// The raw value type as written (`String`, `Int`, …), or `nil` for a bare `Enumerable` conformance
|
|
@@ -296,8 +302,9 @@ struct ExportedUnionMember: Encodable, Equatable {
|
|
|
296
302
|
/// `Double`, two compatible records) the earlier case wins. Reordering them describes a different
|
|
297
303
|
/// union than the one the module runs.
|
|
298
304
|
struct ExportedUnion: Encodable, Equatable {
|
|
299
|
-
/// The Swift enum name
|
|
300
|
-
/// payload types rather than under a bound
|
|
305
|
+
/// The Swift enum name, qualified with the types it is nested in (`Options.Value`). No `jsName`:
|
|
306
|
+
/// `@Union` takes no arguments, and a union reaches JS as its payload types rather than under a bound
|
|
307
|
+
/// name.
|
|
301
308
|
let name: String
|
|
302
309
|
|
|
303
310
|
let members: [ExportedUnionMember]
|
|
@@ -320,8 +327,9 @@ struct ExportedSurface: Encodable, Equatable {
|
|
|
320
327
|
/// Versioned independently of `scanModulesSchemaVersion`: the two commands serve different consumers
|
|
321
328
|
/// and change for different reasons. Version 2 added `events` to modules and shared objects; version 3
|
|
322
329
|
/// added `enums`; version 4 added `unions`; version 5 resolves refs, adding `refKind` and correcting
|
|
323
|
-
/// an enum ref's `typeof`; version 6 added `classes` to modules
|
|
324
|
-
|
|
330
|
+
/// an enum ref's `typeof`; version 6 added `classes` to modules; version 7 reports nested types under
|
|
331
|
+
/// qualified names and gives a resolved ref the name of its declaration.
|
|
332
|
+
let scanExportsSchemaVersion = 7
|
|
325
333
|
|
|
326
334
|
/// The `scan-exports` result: the surface plus the run's stats. A distinct envelope from
|
|
327
335
|
/// `ScanModulesResult` (different consumer: TS generation vs. autolinking).
|