expo-modules-macros 0.19.1 → 0.21.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/linux.yml +132 -0
- package/.github/workflows/publish.yml +160 -11
- package/.github/workflows/windows.yml +3 -28
- package/AGENTS.md +11 -6
- package/README.md +15 -9
- package/apple/ExpoModulesMacros +0 -0
- package/apple/Sources/ExpoModulesMacros/ClosureArguments.swift +1 -1
- package/apple/Sources/ExpoModulesMacros/DecorateModuleBuilder.swift +23 -10
- package/apple/Sources/ExpoModulesMacros/EventMacro.swift +12 -1
- package/apple/Sources/ExpoModulesMacros/ExpoModuleMacro.swift +2 -0
- package/apple/Sources/ExpoModulesMacros/JSNameCollisions.swift +64 -0
- package/apple/Sources/ExpoModulesMacros/MacroHelpers.swift +2 -1
- package/apple/Sources/ExpoModulesMacros/RecordMacro.swift +176 -91
- package/apple/Sources/ExpoModulesMacros/SharedObjectMacro.swift +3 -0
- package/apple/Sources/ExpoModulesMacros/UnionMacro.swift +14 -1
- package/apple/Sources/ExpoModulesScanner/Exports/Availability.swift +259 -0
- package/apple/Sources/ExpoModulesScanner/Exports/ExportedSurface.swift +151 -32
- package/apple/Sources/ExpoModulesScanner/Exports/ResolveRefs.swift +48 -65
- package/apple/Sources/ExpoModulesScanner/Exports/ScanExports.swift +1 -1
- package/apple/Sources/ExpoModulesScanner/Exports/SurfaceVisitor.swift +179 -46
- package/build/index.d.ts +16 -6
- package/build/index.js +51 -28
- package/build/types.d.ts +86 -19
- package/build/types.js +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import SwiftIfConfig
|
|
2
|
+
import SwiftSyntax
|
|
3
|
+
|
|
4
|
+
/// The Apple OSes `scan-exports` attributes declarations to, in the order they are reported. Spelled
|
|
5
|
+
/// as `os(...)` spells them.
|
|
6
|
+
let applePlatforms = ["iOS", "macOS", "tvOS", "watchOS", "visionOS"]
|
|
7
|
+
|
|
8
|
+
/// The platform names `@available` accepts for each reported OS, including the legacy `OSX`. Other
|
|
9
|
+
/// names (`iOSApplicationExtension`, `macCatalyst`, `swift`, …) do not change where a declaration is
|
|
10
|
+
/// built for an app, so they are ignored.
|
|
11
|
+
private let availabilityPlatformNames: [String: String] = [
|
|
12
|
+
"iOS": "iOS",
|
|
13
|
+
"macOS": "macOS",
|
|
14
|
+
"OSX": "macOS",
|
|
15
|
+
"tvOS": "tvOS",
|
|
16
|
+
"watchOS": "watchOS",
|
|
17
|
+
"visionOS": "visionOS",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
/// Answers which platforms build a declaration in one file: those whose `#if` evaluation keeps it,
|
|
21
|
+
/// less those an `@available` attribute on it or on an enclosing type makes unavailable. The `#if`
|
|
22
|
+
/// regions are evaluated once per platform for the whole file. Each platform also carries the
|
|
23
|
+
/// deprecation the declaration's own `@available` attributes give it there.
|
|
24
|
+
///
|
|
25
|
+
/// A condition the scan cannot answer (`#if DEBUG`, `targetEnvironment`, a non-SDK `canImport`)
|
|
26
|
+
/// makes its region inactive on every platform, so a declaration under one is built nowhere.
|
|
27
|
+
struct PlatformResolver {
|
|
28
|
+
private let regions: [(platform: String, regions: ConfiguredRegions)]
|
|
29
|
+
|
|
30
|
+
init(tree: SourceFileSyntax) {
|
|
31
|
+
regions = applePlatforms.map { platform in
|
|
32
|
+
(platform, tree.configuredRegions(in: ScanBuildConfiguration(platform: platform, defines: [])))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// The platforms that build `node`, in `applePlatforms` order. Empty when none does.
|
|
37
|
+
func platforms(of node: some SyntaxProtocol) -> [ExportedPlatform] {
|
|
38
|
+
let availability = Availability(of: node)
|
|
39
|
+
return regions.compactMap { platform, regions in
|
|
40
|
+
guard regions.isActive(node) == .active, !availability.isUnavailable(on: platform) else {
|
|
41
|
+
return nil
|
|
42
|
+
}
|
|
43
|
+
return ExportedPlatform(
|
|
44
|
+
name: platform,
|
|
45
|
+
introduced: availability.introduced[platform],
|
|
46
|
+
deprecated: availability.deprecation(on: platform)
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// What the `@available` attributes on a declaration and its enclosing declarations say. A member
|
|
53
|
+
/// cannot be more available than the type it is declared in, so the attributes combine: a platform
|
|
54
|
+
/// any of them makes unavailable is unavailable, and the latest introduced version wins.
|
|
55
|
+
/// Deprecations are read from the declaration's own attributes only.
|
|
56
|
+
private struct Availability {
|
|
57
|
+
private var unavailable: Set<String> = []
|
|
58
|
+
private var isUnavailableEverywhere = false
|
|
59
|
+
private(set) var introduced: [String: String] = [:]
|
|
60
|
+
/// The deprecation from `@available(*, deprecated, ...)`, which applies on every platform.
|
|
61
|
+
private var deprecatedEverywhere: ExportedDeprecation?
|
|
62
|
+
/// The deprecations from attributes that name a platform.
|
|
63
|
+
private var deprecated: [String: ExportedDeprecation] = [:]
|
|
64
|
+
|
|
65
|
+
init(of node: some SyntaxProtocol) {
|
|
66
|
+
var current: Syntax? = Syntax(node)
|
|
67
|
+
var isOwn = true
|
|
68
|
+
while let decl = current {
|
|
69
|
+
if let attributes = decl.asProtocol(WithAttributesSyntax.self)?.attributes {
|
|
70
|
+
for element in attributes {
|
|
71
|
+
if let attribute = element.as(AttributeSyntax.self),
|
|
72
|
+
attribute.attributeName.trimmedDescription == "available",
|
|
73
|
+
case .availability(let arguments) = attribute.arguments {
|
|
74
|
+
read(arguments, readsDeprecation: isOwn)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
isOwn = false
|
|
79
|
+
current = decl.parent
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func isUnavailable(on platform: String) -> Bool {
|
|
84
|
+
return isUnavailableEverywhere || unavailable.contains(platform)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// The deprecation on `platform`: the platform's own, with any field it leaves out taken from the
|
|
88
|
+
/// `*` one.
|
|
89
|
+
func deprecation(on platform: String) -> ExportedDeprecation? {
|
|
90
|
+
switch (deprecated[platform], deprecatedEverywhere) {
|
|
91
|
+
case (nil, let everywhere):
|
|
92
|
+
return everywhere
|
|
93
|
+
case (let own?, nil):
|
|
94
|
+
return own
|
|
95
|
+
case (let own?, let everywhere?):
|
|
96
|
+
return own.filling(from: everywhere)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Reads one attribute. The long form names one platform (or `*`) first and then what applies to
|
|
101
|
+
/// it: `@available(iOS, introduced: 16)`, `@available(tvOS, unavailable)`,
|
|
102
|
+
/// `@available(*, deprecated, renamed: "other")`. The shorthand lists platforms with versions:
|
|
103
|
+
/// `@available(iOS 17, macOS 14, *)`.
|
|
104
|
+
///
|
|
105
|
+
/// A long-form attribute deprecates its platform when it writes `deprecated` (bare or with a
|
|
106
|
+
/// version) or `obsoleted:`. `message:` and `renamed:` describe that deprecation, and are ignored
|
|
107
|
+
/// when the attribute deprecates nothing.
|
|
108
|
+
private mutating func read(_ arguments: AvailabilityArgumentListSyntax, readsDeprecation: Bool) {
|
|
109
|
+
guard case .token(let first) = arguments.first?.argument else {
|
|
110
|
+
for argument in arguments {
|
|
111
|
+
if case .availabilityVersionRestriction(let restriction) = argument.argument,
|
|
112
|
+
let platform = availabilityPlatformNames[restriction.platform.text],
|
|
113
|
+
let version = restriction.version {
|
|
114
|
+
raiseIntroduced(on: platform, to: version.trimmedDescription)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
let isWildcard = first.tokenKind == .binaryOperator("*")
|
|
120
|
+
let platform = availabilityPlatformNames[first.text]
|
|
121
|
+
guard isWildcard || platform != nil else {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
var deprecation = ExportedDeprecation()
|
|
125
|
+
var isDeprecated = false
|
|
126
|
+
for argument in arguments.dropFirst() {
|
|
127
|
+
switch argument.argument {
|
|
128
|
+
case .token(let token) where token.text == "unavailable":
|
|
129
|
+
if let platform {
|
|
130
|
+
unavailable.insert(platform)
|
|
131
|
+
} else {
|
|
132
|
+
isUnavailableEverywhere = true
|
|
133
|
+
}
|
|
134
|
+
case .token(let token) where token.text == "deprecated":
|
|
135
|
+
isDeprecated = true
|
|
136
|
+
case .availabilityLabeledArgument(let labeled):
|
|
137
|
+
switch (labeled.label.text, labeled.value) {
|
|
138
|
+
case ("introduced", .version(let version)):
|
|
139
|
+
if let platform {
|
|
140
|
+
raiseIntroduced(on: platform, to: version.trimmedDescription)
|
|
141
|
+
}
|
|
142
|
+
case ("deprecated", .version(let version)):
|
|
143
|
+
isDeprecated = true
|
|
144
|
+
deprecation.since = version.trimmedDescription
|
|
145
|
+
case ("obsoleted", .version(let version)):
|
|
146
|
+
isDeprecated = true
|
|
147
|
+
deprecation.obsoleted = version.trimmedDescription
|
|
148
|
+
case ("message", .string(let literal)):
|
|
149
|
+
deprecation.message = decodedText(of: literal)
|
|
150
|
+
case ("renamed", .string(let literal)):
|
|
151
|
+
deprecation.renamed = decodedText(of: literal)
|
|
152
|
+
default:
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
default:
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
guard readsDeprecation, isDeprecated else {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
if let platform {
|
|
163
|
+
deprecated[platform] = deprecated[platform].map { deprecation.filling(from: $0) } ?? deprecation
|
|
164
|
+
} else {
|
|
165
|
+
deprecatedEverywhere = deprecatedEverywhere.map { deprecation.filling(from: $0) } ?? deprecation
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private mutating func raiseIntroduced(on platform: String, to version: String) {
|
|
170
|
+
if let current = introduced[platform], !isVersion(version, laterThan: current) {
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
introduced[platform] = version
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
extension ExportedDeprecation {
|
|
178
|
+
/// This deprecation with each field it leaves out taken from `other`.
|
|
179
|
+
fileprivate func filling(from other: ExportedDeprecation) -> ExportedDeprecation {
|
|
180
|
+
return ExportedDeprecation(
|
|
181
|
+
since: since ?? other.since,
|
|
182
|
+
obsoleted: obsoleted ?? other.obsoleted,
|
|
183
|
+
message: message ?? other.message,
|
|
184
|
+
renamed: renamed ?? other.renamed
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// The value of a string literal in an attribute, with its escape sequences decoded: `\"` reads as
|
|
190
|
+
/// `"`, `\n` as a line break, and `\u{2192}` as `→`. An escaped line break in a multi-line literal
|
|
191
|
+
/// joins the lines, as in Swift. An escape that isn't valid is kept as written.
|
|
192
|
+
private func decodedText(of literal: SimpleStringLiteralExprSyntax) -> String {
|
|
193
|
+
let text = literal.segments.map(\.content.text).joined()
|
|
194
|
+
var result = ""
|
|
195
|
+
var index = text.startIndex
|
|
196
|
+
while index < text.endIndex {
|
|
197
|
+
let character = text[index]
|
|
198
|
+
index = text.index(after: index)
|
|
199
|
+
guard character == "\\", index < text.endIndex else {
|
|
200
|
+
result.append(character)
|
|
201
|
+
continue
|
|
202
|
+
}
|
|
203
|
+
let escaped = text[index]
|
|
204
|
+
index = text.index(after: index)
|
|
205
|
+
switch escaped {
|
|
206
|
+
case "0":
|
|
207
|
+
result.append("\0")
|
|
208
|
+
case "n":
|
|
209
|
+
result.append("\n")
|
|
210
|
+
case "r":
|
|
211
|
+
result.append("\r")
|
|
212
|
+
case "t":
|
|
213
|
+
result.append("\t")
|
|
214
|
+
case "\"", "'", "\\":
|
|
215
|
+
result.append(escaped)
|
|
216
|
+
case "\n", "\r\n":
|
|
217
|
+
continue
|
|
218
|
+
case "u":
|
|
219
|
+
if text[index...].hasPrefix("{"), let close = text[index...].firstIndex(of: "}"),
|
|
220
|
+
let scalarValue = UInt32(text[text.index(after: index)..<close], radix: 16),
|
|
221
|
+
let scalar = Unicode.Scalar(scalarValue) {
|
|
222
|
+
result.unicodeScalars.append(scalar)
|
|
223
|
+
index = text.index(after: close)
|
|
224
|
+
} else {
|
|
225
|
+
result.append("\\u")
|
|
226
|
+
}
|
|
227
|
+
default:
|
|
228
|
+
result.append("\\")
|
|
229
|
+
result.append(escaped)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return result
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/// Compares two dotted version spellings component by component, treating a missing component as
|
|
236
|
+
/// `0`, so `17` and `17.0` are equal.
|
|
237
|
+
private func isVersion(_ lhs: String, laterThan rhs: String) -> Bool {
|
|
238
|
+
let left = lhs.split(separator: ".").map { Int($0) ?? 0 }
|
|
239
|
+
let right = rhs.split(separator: ".").map { Int($0) ?? 0 }
|
|
240
|
+
for index in 0..<max(left.count, right.count) {
|
|
241
|
+
let l = index < left.count ? left[index] : 0
|
|
242
|
+
let r = index < right.count ? right[index] : 0
|
|
243
|
+
if l != r {
|
|
244
|
+
return l > r
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return false
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/// The spelled access modifier of a declaration (`open`, `public`, `package`, `internal`,
|
|
251
|
+
/// `fileprivate`, `private`), or `nil` when none is written. A modifier with a detail, like the
|
|
252
|
+
/// `private` in `private(set)`, limits only the setter, so it is not the declaration's.
|
|
253
|
+
func spelledAccessLevel(of modifiers: DeclModifierListSyntax) -> String? {
|
|
254
|
+
return modifiers.first { modifier in
|
|
255
|
+
modifier.detail == nil && accessModifierNames.contains(modifier.name.text)
|
|
256
|
+
}?.name.text
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private let accessModifierNames: Set<String> = ["open", "public", "package", "internal", "fileprivate", "private"]
|
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
/// `@Record` type, with the per-member detail a TypeScript type generator needs. Read syntactically
|
|
3
3
|
/// (like the macros): each boundary type becomes a structured `TypeNode` tree so the consumer walks a
|
|
4
4
|
/// tagged tree rather than re-parsing Swift type syntax.
|
|
5
|
+
///
|
|
6
|
+
/// Every declaration and member carries the `platforms` that build it, and the ones that can be
|
|
7
|
+
/// written with an access modifier carry the `accessLevel` they spell. A declaration no platform
|
|
8
|
+
/// builds is not reported.
|
|
9
|
+
|
|
10
|
+
/// One Apple OS that builds a declaration.
|
|
11
|
+
struct ExportedPlatform: Encodable, Equatable {
|
|
12
|
+
/// The OS, spelled as `os(...)` spells it: `iOS`, `macOS`, `tvOS`, `watchOS`, or `visionOS`.
|
|
13
|
+
let name: String
|
|
14
|
+
|
|
15
|
+
/// The version spelled in `@available` (`17.0` in `@available(iOS 17.0, *)`), or `nil` when no
|
|
16
|
+
/// attribute on the declaration or its enclosing types names one. The latest version wins when
|
|
17
|
+
/// several do.
|
|
18
|
+
let introduced: String?
|
|
19
|
+
|
|
20
|
+
/// How the declaration's own `@available` attributes deprecate it on this OS, or `nil` when they
|
|
21
|
+
/// don't. Enclosing types are not read: a member of a deprecated type is not itself reported as
|
|
22
|
+
/// deprecated.
|
|
23
|
+
var deprecated: ExportedDeprecation? = nil
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// A deprecation from `@available`: `@available(*, deprecated, ...)` on every OS, or
|
|
27
|
+
/// `@available(iOS, deprecated: 16, obsoleted: 18, ...)` on one. Each field is `nil` when not written.
|
|
28
|
+
struct ExportedDeprecation: Encodable, Equatable {
|
|
29
|
+
/// The version from `deprecated: 16`; `nil` for a bare `deprecated`.
|
|
30
|
+
var since: String? = nil
|
|
31
|
+
|
|
32
|
+
/// The version from `obsoleted: 18`, from which the declaration is no longer available. A
|
|
33
|
+
/// declaration that is only obsoleted is still reported as deprecated.
|
|
34
|
+
var obsoleted: String? = nil
|
|
35
|
+
|
|
36
|
+
/// The `message:` text.
|
|
37
|
+
var message: String? = nil
|
|
38
|
+
|
|
39
|
+
/// The `renamed:` text: the Swift name of the replacement, as written (`newName`,
|
|
40
|
+
/// `other(value:)`). It is not resolved to a JS name.
|
|
41
|
+
var renamed: String? = nil
|
|
42
|
+
}
|
|
5
43
|
|
|
6
44
|
/// One parameter of a `@JS` function or `@JS init`.
|
|
7
45
|
struct ExportedParameter: Encodable, Equatable {
|
|
@@ -11,14 +49,18 @@ struct ExportedParameter: Encodable, Equatable {
|
|
|
11
49
|
/// The internal parameter name (the `second` name, else the same as `label`): `point` above.
|
|
12
50
|
let name: String
|
|
13
51
|
|
|
14
|
-
|
|
52
|
+
var type: TypeNode
|
|
15
53
|
|
|
16
54
|
/// True when the caller may omit it: a default value or an optional type. Distinct from the type
|
|
17
55
|
/// being `.optional` (a defaulted non-optional is also omittable). Encoded as `optional`.
|
|
18
56
|
let isOptional: Bool
|
|
19
57
|
|
|
58
|
+
/// The default value expression as source text (`1`, `"x"`, `.fast`), or `nil` when none is
|
|
59
|
+
/// written. Not evaluated: it may be any expression.
|
|
60
|
+
let defaultValue: String?
|
|
61
|
+
|
|
20
62
|
private enum CodingKeys: String, CodingKey {
|
|
21
|
-
case label, name, type
|
|
63
|
+
case label, name, type, defaultValue
|
|
22
64
|
case isOptional = "optional"
|
|
23
65
|
}
|
|
24
66
|
}
|
|
@@ -31,10 +73,10 @@ struct ExportedFunction: Encodable, Equatable {
|
|
|
31
73
|
/// The JS name it binds under: the `@JS("x")` override, else `name`.
|
|
32
74
|
let jsName: String
|
|
33
75
|
|
|
34
|
-
|
|
76
|
+
var parameters: [ExportedParameter]
|
|
35
77
|
|
|
36
78
|
/// The return type, or `nil` for `Void`. Named `returns` to pair with `parameters`.
|
|
37
|
-
|
|
79
|
+
var returns: TypeNode?
|
|
38
80
|
|
|
39
81
|
/// `async` (an async function is promise-returning in JS).
|
|
40
82
|
let isAsync: Bool
|
|
@@ -45,9 +87,14 @@ struct ExportedFunction: Encodable, Equatable {
|
|
|
45
87
|
/// `static`/`class` member.
|
|
46
88
|
let isStatic: Bool
|
|
47
89
|
|
|
90
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
91
|
+
let accessLevel: String?
|
|
92
|
+
|
|
93
|
+
let platforms: [ExportedPlatform]
|
|
94
|
+
|
|
48
95
|
/// The flags are encoded under their TS-keyword spellings.
|
|
49
96
|
private enum CodingKeys: String, CodingKey {
|
|
50
|
-
case name, jsName, parameters, returns
|
|
97
|
+
case name, jsName, parameters, returns, accessLevel, platforms
|
|
51
98
|
case isAsync = "async"
|
|
52
99
|
case isThrowing = "throws"
|
|
53
100
|
case isStatic = "static"
|
|
@@ -64,7 +111,7 @@ struct ExportedProperty: Encodable, Equatable {
|
|
|
64
111
|
|
|
65
112
|
/// The value type, or `nil` when undeterminable syntactically (no annotation and no literal
|
|
66
113
|
/// default), the case the macro binds getter-only.
|
|
67
|
-
|
|
114
|
+
var type: TypeNode?
|
|
68
115
|
|
|
69
116
|
/// True when JS can assign to it: a stored `var` or a computed `var` with a `set`. Encoded as its
|
|
70
117
|
/// inverse, `readonly`.
|
|
@@ -73,8 +120,17 @@ struct ExportedProperty: Encodable, Equatable {
|
|
|
73
120
|
/// `static`/`class` member. Encoded as `static`.
|
|
74
121
|
let isStatic: Bool
|
|
75
122
|
|
|
123
|
+
/// The initial value of a stored property as source text, or `nil` when none is written.
|
|
124
|
+
let defaultValue: String?
|
|
125
|
+
|
|
126
|
+
/// The spelled access modifier, or `nil` when none is written. A setter-only modifier like
|
|
127
|
+
/// `private(set)` is not the property's access level.
|
|
128
|
+
let accessLevel: String?
|
|
129
|
+
|
|
130
|
+
let platforms: [ExportedPlatform]
|
|
131
|
+
|
|
76
132
|
private enum CodingKeys: String, CodingKey {
|
|
77
|
-
case name, jsName, type
|
|
133
|
+
case name, jsName, type, defaultValue, accessLevel, platforms
|
|
78
134
|
case isReadonly = "readonly"
|
|
79
135
|
case isStatic = "static"
|
|
80
136
|
}
|
|
@@ -86,6 +142,9 @@ struct ExportedProperty: Encodable, Equatable {
|
|
|
86
142
|
try container.encodeIfPresent(type, forKey: .type)
|
|
87
143
|
try container.encode(!isSettable, forKey: .isReadonly)
|
|
88
144
|
try container.encode(isStatic, forKey: .isStatic)
|
|
145
|
+
try container.encodeIfPresent(defaultValue, forKey: .defaultValue)
|
|
146
|
+
try container.encodeIfPresent(accessLevel, forKey: .accessLevel)
|
|
147
|
+
try container.encode(platforms, forKey: .platforms)
|
|
89
148
|
}
|
|
90
149
|
}
|
|
91
150
|
|
|
@@ -96,23 +155,28 @@ struct ExportedRecordProperty: Encodable, Equatable {
|
|
|
96
155
|
let name: String
|
|
97
156
|
|
|
98
157
|
/// `@Record` requires a determinable type on every property, so this is never `nil`.
|
|
99
|
-
|
|
158
|
+
var type: TypeNode
|
|
100
159
|
|
|
101
160
|
/// Optional-typed. Encoded as `optional`.
|
|
102
161
|
let isOptional: Bool
|
|
103
162
|
|
|
104
|
-
///
|
|
105
|
-
|
|
106
|
-
|
|
163
|
+
/// The default value as source text, or `nil` when none is written. A field JS leaves out takes it.
|
|
164
|
+
let defaultValue: String?
|
|
165
|
+
|
|
166
|
+
/// The spelled access modifier, or `nil` when none is written. Never `private` or `fileprivate`,
|
|
167
|
+
/// since those exclude a property from the record.
|
|
168
|
+
let accessLevel: String?
|
|
169
|
+
|
|
170
|
+
let platforms: [ExportedPlatform]
|
|
107
171
|
|
|
108
172
|
/// Whether JS must supply this property, matching the macro's `RecordProperty.isRequired`. Encoded
|
|
109
173
|
/// as `required`.
|
|
110
174
|
var isRequired: Bool {
|
|
111
|
-
return
|
|
175
|
+
return defaultValue == nil && !isOptional
|
|
112
176
|
}
|
|
113
177
|
|
|
114
178
|
private enum CodingKeys: String, CodingKey {
|
|
115
|
-
case name, type
|
|
179
|
+
case name, type, defaultValue, accessLevel, platforms
|
|
116
180
|
case isOptional = "optional"
|
|
117
181
|
case isRequired = "required"
|
|
118
182
|
}
|
|
@@ -123,6 +187,9 @@ struct ExportedRecordProperty: Encodable, Equatable {
|
|
|
123
187
|
try container.encode(type, forKey: .type)
|
|
124
188
|
try container.encode(isOptional, forKey: .isOptional)
|
|
125
189
|
try container.encode(isRequired, forKey: .isRequired)
|
|
190
|
+
try container.encodeIfPresent(defaultValue, forKey: .defaultValue)
|
|
191
|
+
try container.encodeIfPresent(accessLevel, forKey: .accessLevel)
|
|
192
|
+
try container.encode(platforms, forKey: .platforms)
|
|
126
193
|
}
|
|
127
194
|
}
|
|
128
195
|
|
|
@@ -137,13 +204,18 @@ struct ExportedEvent: Encodable, Equatable {
|
|
|
137
204
|
let jsName: String
|
|
138
205
|
|
|
139
206
|
/// The single payload parameter's type, or `nil` for a no-payload `() -> Void` event.
|
|
140
|
-
|
|
207
|
+
var payload: TypeNode?
|
|
141
208
|
|
|
142
209
|
/// `@Event(sync: true)`, dispatching inline on the JS thread instead of scheduling.
|
|
143
210
|
let isSync: Bool
|
|
144
211
|
|
|
212
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
213
|
+
let accessLevel: String?
|
|
214
|
+
|
|
215
|
+
let platforms: [ExportedPlatform]
|
|
216
|
+
|
|
145
217
|
private enum CodingKeys: String, CodingKey {
|
|
146
|
-
case name, jsName, payload
|
|
218
|
+
case name, jsName, payload, accessLevel, platforms
|
|
147
219
|
case isSync = "sync"
|
|
148
220
|
}
|
|
149
221
|
|
|
@@ -153,6 +225,8 @@ struct ExportedEvent: Encodable, Equatable {
|
|
|
153
225
|
try container.encode(jsName, forKey: .jsName)
|
|
154
226
|
try container.encodeIfPresent(payload, forKey: .payload)
|
|
155
227
|
try container.encode(isSync, forKey: .isSync)
|
|
228
|
+
try container.encodeIfPresent(accessLevel, forKey: .accessLevel)
|
|
229
|
+
try container.encode(platforms, forKey: .platforms)
|
|
156
230
|
}
|
|
157
231
|
}
|
|
158
232
|
|
|
@@ -165,13 +239,18 @@ struct ExportedModule: Encodable, Equatable {
|
|
|
165
239
|
/// The JS module name: `@ExpoModule("Foo")` override, else the class name.
|
|
166
240
|
let jsName: String
|
|
167
241
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
242
|
+
var functions: [ExportedFunction]
|
|
243
|
+
var properties: [ExportedProperty]
|
|
244
|
+
var events: [ExportedEvent]
|
|
171
245
|
|
|
172
246
|
/// The classes listed in `@ExpoModule(classes: [...])`, in source order. Each is reachable from JS
|
|
173
247
|
/// as a member of the module.
|
|
174
|
-
|
|
248
|
+
var classes: [ExportedClass]
|
|
249
|
+
|
|
250
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
251
|
+
let accessLevel: String?
|
|
252
|
+
|
|
253
|
+
let platforms: [ExportedPlatform]
|
|
175
254
|
|
|
176
255
|
/// Absolute source path, matching `scan-modules`.
|
|
177
256
|
let file: String
|
|
@@ -190,6 +269,16 @@ struct ExportedClass: Encodable, Equatable {
|
|
|
190
269
|
let jsName: String?
|
|
191
270
|
}
|
|
192
271
|
|
|
272
|
+
/// The `@JS init` of a shared object: the constructor JS calls with `new`.
|
|
273
|
+
struct ExportedInitializer: Encodable, Equatable {
|
|
274
|
+
var parameters: [ExportedParameter]
|
|
275
|
+
|
|
276
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
277
|
+
let accessLevel: String?
|
|
278
|
+
|
|
279
|
+
let platforms: [ExportedPlatform]
|
|
280
|
+
}
|
|
281
|
+
|
|
193
282
|
/// A `@SharedObject` type: a JS class with an optional `@JS init` constructor plus its `@JS` members.
|
|
194
283
|
struct ExportedSharedObject: Encodable, Equatable {
|
|
195
284
|
/// The Swift class name, qualified with the types it is nested in (`Outer.Player`).
|
|
@@ -199,12 +288,18 @@ struct ExportedSharedObject: Encodable, Equatable {
|
|
|
199
288
|
/// types.
|
|
200
289
|
let jsName: String
|
|
201
290
|
|
|
202
|
-
/// The `@JS init
|
|
203
|
-
|
|
291
|
+
/// The `@JS init`, or `nil` when there's none. A shared object has at most one; the first is kept
|
|
292
|
+
/// if a malformed source has more. Not named `constructor`, which every JS object inherits.
|
|
293
|
+
var initializer: ExportedInitializer?
|
|
294
|
+
|
|
295
|
+
var functions: [ExportedFunction]
|
|
296
|
+
var properties: [ExportedProperty]
|
|
297
|
+
var events: [ExportedEvent]
|
|
204
298
|
|
|
205
|
-
|
|
206
|
-
let
|
|
207
|
-
|
|
299
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
300
|
+
let accessLevel: String?
|
|
301
|
+
|
|
302
|
+
let platforms: [ExportedPlatform]
|
|
208
303
|
|
|
209
304
|
let file: String
|
|
210
305
|
}
|
|
@@ -215,7 +310,12 @@ struct ExportedRecord: Encodable, Equatable {
|
|
|
215
310
|
/// (`Outer.Options`).
|
|
216
311
|
let name: String
|
|
217
312
|
|
|
218
|
-
|
|
313
|
+
var properties: [ExportedRecordProperty]
|
|
314
|
+
|
|
315
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
316
|
+
let accessLevel: String?
|
|
317
|
+
|
|
318
|
+
let platforms: [ExportedPlatform]
|
|
219
319
|
|
|
220
320
|
let file: String
|
|
221
321
|
}
|
|
@@ -237,14 +337,17 @@ struct ExportedEnumCase: Encodable, Equatable {
|
|
|
237
337
|
/// above.
|
|
238
338
|
let rawValue: String?
|
|
239
339
|
|
|
340
|
+
let platforms: [ExportedPlatform]
|
|
341
|
+
|
|
240
342
|
private enum CodingKeys: String, CodingKey {
|
|
241
|
-
case name, rawValue
|
|
343
|
+
case name, rawValue, platforms
|
|
242
344
|
}
|
|
243
345
|
|
|
244
346
|
func encode(to encoder: Encoder) throws {
|
|
245
347
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
246
348
|
try container.encode(name, forKey: .name)
|
|
247
349
|
try container.encodeIfPresent(rawValue, forKey: .rawValue)
|
|
350
|
+
try container.encode(platforms, forKey: .platforms)
|
|
248
351
|
}
|
|
249
352
|
}
|
|
250
353
|
|
|
@@ -264,10 +367,15 @@ struct ExportedEnum: Encodable, Equatable {
|
|
|
264
367
|
|
|
265
368
|
let cases: [ExportedEnumCase]
|
|
266
369
|
|
|
370
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
371
|
+
let accessLevel: String?
|
|
372
|
+
|
|
373
|
+
let platforms: [ExportedPlatform]
|
|
374
|
+
|
|
267
375
|
let file: String
|
|
268
376
|
|
|
269
377
|
private enum CodingKeys: String, CodingKey {
|
|
270
|
-
case name, rawType, cases, file
|
|
378
|
+
case name, rawType, cases, accessLevel, platforms, file
|
|
271
379
|
}
|
|
272
380
|
|
|
273
381
|
func encode(to encoder: Encoder) throws {
|
|
@@ -275,6 +383,8 @@ struct ExportedEnum: Encodable, Equatable {
|
|
|
275
383
|
try container.encode(name, forKey: .name)
|
|
276
384
|
try container.encodeIfPresent(rawType, forKey: .rawType)
|
|
277
385
|
try container.encode(cases, forKey: .cases)
|
|
386
|
+
try container.encodeIfPresent(accessLevel, forKey: .accessLevel)
|
|
387
|
+
try container.encode(platforms, forKey: .platforms)
|
|
278
388
|
try container.encode(file, forKey: .file)
|
|
279
389
|
}
|
|
280
390
|
}
|
|
@@ -288,10 +398,12 @@ struct ExportedUnionMember: Encodable, Equatable {
|
|
|
288
398
|
|
|
289
399
|
/// The associated value's type: what this alternative decodes from. Named `type` like every other
|
|
290
400
|
/// type-valued field here; `payload` already means an event's argument type on `ExportedEvent`.
|
|
291
|
-
|
|
401
|
+
var type: TypeNode
|
|
402
|
+
|
|
403
|
+
let platforms: [ExportedPlatform]
|
|
292
404
|
|
|
293
405
|
private enum CodingKeys: String, CodingKey {
|
|
294
|
-
case name, type
|
|
406
|
+
case name, type, platforms
|
|
295
407
|
}
|
|
296
408
|
}
|
|
297
409
|
|
|
@@ -307,7 +419,12 @@ struct ExportedUnion: Encodable, Equatable {
|
|
|
307
419
|
/// name.
|
|
308
420
|
let name: String
|
|
309
421
|
|
|
310
|
-
|
|
422
|
+
var members: [ExportedUnionMember]
|
|
423
|
+
|
|
424
|
+
/// The spelled access modifier, or `nil` when none is written.
|
|
425
|
+
let accessLevel: String?
|
|
426
|
+
|
|
427
|
+
let platforms: [ExportedPlatform]
|
|
311
428
|
|
|
312
429
|
let file: String
|
|
313
430
|
}
|
|
@@ -328,8 +445,10 @@ struct ExportedSurface: Encodable, Equatable {
|
|
|
328
445
|
/// and change for different reasons. Version 2 added `events` to modules and shared objects; version 3
|
|
329
446
|
/// added `enums`; version 4 added `unions`; version 5 resolves refs, adding `refKind` and correcting
|
|
330
447
|
/// 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
|
-
|
|
448
|
+
/// qualified names and gives a resolved ref the name of its declaration; version 8 reports
|
|
449
|
+
/// declarations in `#if` blocks, adds `platforms` (with deprecations), `accessLevel`, and
|
|
450
|
+
/// `defaultValue`, and replaces `constructorParameters` with `initializer`.
|
|
451
|
+
let scanExportsSchemaVersion = 8
|
|
333
452
|
|
|
334
453
|
/// The `scan-exports` result: the surface plus the run's stats. A distinct envelope from
|
|
335
454
|
/// `ScanModulesResult` (different consumer: TS generation vs. autolinking).
|