@expo/expo-modules-macros-plugin 0.6.0 → 0.6.2

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.
Binary file
@@ -60,7 +60,7 @@ internal struct JSFunction {
60
60
  let maximum = parameters.count
61
61
  var lines: [String] = []
62
62
 
63
- if let unwrap = receiver.unwrapStatement {
63
+ if let unwrap = receiver.unwrapStatement(isAsync: isAsync) {
64
64
  lines.append(unwrap)
65
65
  }
66
66
 
@@ -90,23 +90,21 @@ internal struct JSFunction {
90
90
  // No omittable trailing run: a single flat call with every argument decoded.
91
91
  lines.append(contentsOf: callAndEncodeLines(receiver: receiver, arity: maximum, decodingFrom: required))
92
92
  } else {
93
- // One call shape per accepted arity. Each branch decodes only the trailing slots it has and
94
- // fills the rest (defaulted params drop their label so Swift applies the default; optional
95
- // params are passed `nil`). A value-returning function binds the result from a `switch`
96
- // expression and encodes once after it; a no-return one calls inline in a `switch` statement
97
- // and returns `.undefined`.
98
- if returnType != nil {
99
- lines.append("let result = switch arguments.count {")
100
- } else {
101
- lines.append("switch arguments.count {")
93
+ // One call shape per accepted arity, branching on `arguments.count`. A branch decodes a
94
+ // trailing slot before the call, so this is a `switch` statement (not an expression): a
95
+ // value-returning function declares `result` up front and each branch assigns it.
96
+ if let returnType {
97
+ lines.append("let result: \(expressionType(returnType))")
102
98
  }
99
+ lines.append("switch arguments.count {")
103
100
  for arity in required...maximum {
104
101
  let label = arity == maximum ? "default:" : "case \(arity):"
105
102
  lines.append(label)
106
103
  for index in required..<arity {
107
104
  lines.append(" " + decodeStatement(at: index))
108
105
  }
109
- lines.append(" \(callExpression(receiver: receiver, arity: arity))")
106
+ let assignment = returnType != nil ? "result = " : ""
107
+ lines.append(" \(assignment)\(callExpression(receiver: receiver, arity: arity))")
110
108
  }
111
109
  lines.append("}")
112
110
  lines.append(contentsOf: encodeResultLines())
@@ -255,8 +253,9 @@ internal struct JSProperty {
255
253
  let callee = receiver.callee
256
254
  let object = receiver.decoratedObject
257
255
  // A shared object's accessors unwrap the JS `this` into `_self` before reading/writing; a module
258
- // reads `self` directly. The unwrap leads each accessor body.
259
- let unwrap = receiver.unwrapStatement.map { "\($0)\n" } ?? ""
256
+ // reads `self` directly. The unwrap leads each accessor body. Property accessors are synchronous, so
257
+ // they take the borrowed unowned `this`.
258
+ let unwrap = receiver.unwrapStatement(isAsync: false).map { "\($0)\n" } ?? ""
260
259
  var lines: [String] = []
261
260
 
262
261
  lines.append("let \(descriptorName) = runtime.createObject()")
@@ -340,7 +339,7 @@ internal func buildDecorateJavaScriptObject(functions: [JSFunction], properties:
340
339
  let body = decorateBody(functions: functions, properties: properties, receiver: .module)
341
340
  return """
342
341
  @JavaScriptActor
343
- public func _decorateModule(object: borrowing JavaScriptObject, in runtime: JavaScriptRuntime, appContext: AppContext) throws {
342
+ public func _decorateModule(object: borrowing JavaScriptObject, in runtime: JavaScriptRuntime) throws {
344
343
  \(raw: body)
345
344
  }
346
345
  """
@@ -361,7 +360,7 @@ internal func buildDecorateSharedObject(
361
360
  let body = decorateBody(functions: functions, properties: properties, receiver: .sharedObject(typeName: typeName))
362
361
  return """
363
362
  @JavaScriptActor
364
- public override class func _decorateSharedObject(prototype: borrowing JavaScriptObject, in runtime: JavaScriptRuntime, appContext: AppContext) throws {
363
+ public override class func _decorateSharedObject(prototype: borrowing JavaScriptObject, in runtime: JavaScriptRuntime) throws {
365
364
  \(raw: body)
366
365
  }
367
366
  """
@@ -42,14 +42,12 @@ internal struct JSConstructor {
42
42
  .joined(separator: "\n")
43
43
  }
44
44
 
45
- /// The `_constructSharedObject` entry point the runtime calls to build an instance from JS
46
- /// arguments. Overrides the base `SharedObject` class method so core can dispatch to it through the
47
- /// concrete type's metatype; the body returns the concrete instance, which promotes to the base
48
- /// `SharedObject?` return type. `this`/`appContext` may go unreferenced, which is harmless.
45
+ /// Builds an instance from the JS arguments. Overrides the base `SharedObject` class method; returns
46
+ /// the concrete instance, which promotes to the base `SharedObject?` return type.
49
47
  func buildConstructor(typeName: String) -> DeclSyntax {
50
48
  return """
51
49
  @JavaScriptActor
52
- public override class func _constructSharedObject(this: JavaScriptValue, arguments: borrowing JavaScriptValuesBuffer, in runtime: JavaScriptRuntime, appContext: AppContext) throws -> SharedObject? {
50
+ public override class func _constructSharedObject(this: JavaScriptValue, arguments: borrowing JavaScriptValuesBuffer, in runtime: JavaScriptRuntime) throws -> SharedObject? {
53
51
  \(raw: bodyStatements(typeName: typeName, indent: " "))
54
52
  }
55
53
  """
@@ -145,14 +145,13 @@ internal func memberHasJSAttribute(_ decl: DeclSyntaxProtocol) -> Bool {
145
145
  return false
146
146
  }
147
147
 
148
- /**
149
- Decides whether the macro should stamp `@JavaScriptActor` on a `@JS`-marked member.
150
- The macro defers to the user when they've already chosen an isolation:
151
- - the `nonisolated` modifier is present on the member
152
- - any attribute whose name matches a known global actor (`@MainActor`, `@JavaScriptActor`)
153
- or follows the `*Actor` naming convention is present on the member or its enclosing type
154
- Async members never get the stamp because `AsyncFunction` controls their dispatch separately.
155
- */
148
+ /// Decides whether the macro should stamp `@JavaScriptActor` on a `@JS`-marked member.
149
+ /// The macro defers to the user when they've already chosen an isolation:
150
+ /// - the `nonisolated` modifier is present on the member
151
+ /// - any attribute whose name matches a known global actor (`@MainActor`, `@JavaScriptActor`)
152
+ /// or follows the `*Actor` naming convention is present on the member or its enclosing type
153
+ /// `async` members are stamped too: an `async` function starts its execution on the JS thread and
154
+ /// stays there until the first suspension point, where it may hop to another executor.
156
155
  internal func shouldStampJavaScriptActor(
157
156
  on member: DeclSyntaxProtocol,
158
157
  enclosedBy enclosing: some DeclGroupSyntax
@@ -162,11 +161,6 @@ internal func shouldStampJavaScriptActor(
162
161
  return false
163
162
  }
164
163
 
165
- if let funcDecl = member.as(FunctionDeclSyntax.self),
166
- funcDecl.signature.effectSpecifiers?.asyncSpecifier != nil {
167
- return false
168
- }
169
-
170
164
  let memberAttributes = memberAttributes(of: member)
171
165
  if memberAttributes.contains(where: hasGlobalActorShape) {
172
166
  return false
@@ -33,14 +33,19 @@ internal enum Receiver {
33
33
  }
34
34
 
35
35
  /// The leading body line binding the receiver, or `nil` for a module (it reads `self` directly). For a
36
- /// shared object, `native(from:as:)` recovers the typed instance from the borrowed `this`, throwing on
37
- /// a foreign object or a type mismatch.
38
- var unwrapStatement: String? {
36
+ /// shared object, `native(from:as:)` recovers the typed instance from `this`, throwing on a foreign
37
+ /// object or a type mismatch.
38
+ ///
39
+ /// The `this` object comes from the borrowed `JavaScriptUnownedValue` in a sync binding (`asObject(in:)`)
40
+ /// and from the owning `JavaScriptValue` in an async one (`asObject()`). An async binding must take an
41
+ /// owning `this` because a borrowed unowned value can't survive the closure's suspension points.
42
+ func unwrapStatement(isAsync: Bool) -> String? {
39
43
  switch self {
40
44
  case .module:
41
45
  return nil
42
46
  case .sharedObject(let typeName):
43
- return "let _self = try SharedObject.native(from: this.asObject(in: runtime), as: \(typeName).self)"
47
+ let thisObject = isAsync ? "this.asObject()" : "this.asObject(in: runtime)"
48
+ return "let _self = try SharedObject.native(from: \(thisObject), as: \(typeName).self)"
44
49
  }
45
50
  }
46
51
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/expo-modules-macros-plugin",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Swift macro plugin for Expo modules",
5
5
  "license": "MIT",
6
6
  "author": "650 Industries, Inc.",