Skip to content

Conversation

@NSFatalError
Copy link
Owner

@NSFatalError NSFatalError commented Aug 24, 2025

Summary by CodeRabbit

  • New Features

    • Add isolation support to Publishable via a new isolation parameter, enhancing actor-aware behavior.
  • Refactor

    • Simplified Publishable protocol to a leaner surface driven by macro-generated publishers.
  • Documentation

    • Updated guides and inline docs to reflect the new isolation-enabled initializer and publisher behavior.
  • Tests

    • Added extensive tests covering MainActor usage, property publishers, and change notifications.
  • Chores

    • Updated dependencies (including PrincipleMacros) and broadened compatibility ranges.
  • Style

    • Tweaked lint rules for annotation formatting.

@NSFatalError NSFatalError self-assigned this Aug 24, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 24, 2025

Walkthrough

This change updates lint rules, bumps dependencies, revises documentation, simplifies the Publishable protocol, adds a macro overload for explicit global-actor isolation, reworks the observation registrar API and generated code, threads isolation through macro builders, adds documentation comments, and introduces new tests covering MainActor-isolated macro expansion and publisher behavior.

Changes

Cohort / File(s) Summary
Lint config
\.swiftlint.yml
Tightened two custom_rules regexes to require a trailing space after @…Actor and @sendable.
Package management
Package.swift, Package.resolved
Updated PrincipleMacros to 2.0.4 and widened swift-syntax range to <604.0.0; resolved revisions updated accordingly.
Docs
Sources/Publishable/Documentation.docc/Publishable.md
Replaced reference to Publishable() with Publishable(isolation:).
Core protocol & macro API
Sources/Publishable/PropertyPublisher/Publishable.swift
Added public macro overload Publishable(isolation:); simplified public protocol Publishable to no associated types or publisher requirement; expanded macro docs.
Registrar protocol
Sources/Publishable/Registrars/PublishableObservationRegistrar.swift
Removed underlying property and didSet; added init(); renamed publishwillSet; kept access and withMutation as requirements; removed default implementations.
Macro builders — registrar
Sources/PublishableMacros/Builders/ObservationRegistrarDeclBuilder.swift
Threaded explicit global-actor isolation; adjusted generated types to unified trimmedType; added generated willSet/didSet/access/withMutation, isolation wrappers, and assumeIsolatedIfNeeded helpers; annotated functions with inherited global-actor attribute.
Macro builders — property publishers
Sources/PublishableMacros/Builders/PropertyPublisherDeclBuilder.swift
Added explicit isolation support; switched AnyPropertyPublisher generic to trimmedType; prefixed publishers with inherited global-actor attribute; used inlinable access control computation.
Macro builders — publisher doc
Sources/PublishableMacros/Builders/PublisherDeclBuilder.swift
Added documentation comment above publisher; no signature change.
Macro main
Sources/PublishableMacros/Main/PublishableMacro.swift
Updated expansion signature to name the AttributeSyntax parameter; extracted and propagated explicit global-actor isolation into builders.
Macro tests — expansion (MainActor)
Tests/PublishableMacrosTests/MainActorMacroTests.swift
New tests verifying macro expansion under @mainactor: generated PropertyPublisher, ObservationRegistrar with isolation handling, and conformance.
Macro tests — expansion
Tests/PublishableMacrosTests/PublishableMacroTests.swift
New tests asserting generated publisher surface, nested PropertyPublisher, and registrar lifecycle hooks.
Runtime tests — publishers (MainActor)
Tests/PublishableTests/Suites/MainActorTests.swift
New tests validating stored/computed property publishers, willChange/didChange behavior, and completion on deallocation for a @mainactor Person.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Person as Person (@MainActor, @Publishable, @Observable)
  participant Publisher as PropertyPublisher
  participant Registrar as ObservationRegistrar
  participant SwiftObs as SwiftObservationRegistrar
  participant Sub as Combine Subscriber

  Note over Person,Registrar: Generated by Publishable macro

  Client->>Person: mutate property
  Person->>Registrar: willSet(object, keyPath)
  Registrar->>SwiftObs: begin/access coordination
  Registrar->>Publisher: route keyPath (assumeIsolatedIfNeeded)
  Publisher-->>Sub: willChange emit (optional)

  Person->>Registrar: withMutation(of:keyPath) { ... }
  Registrar->>Registrar: assumeIsolatedIfNeeded(MainActor?)
  Registrar->>Person: perform mutation
  Registrar->>Publisher: publish(keyPath)
  Publisher-->>Sub: value emit

  Registrar->>SwiftObs: end coordination
  Note over Registrar: access(object,keyPath) used for reads
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

I thump my paws in actor time,
New macros hum in orderly rhyme.
With willSet whispers, changes flow,
Publishers pop—then off they go.
Lint is crisp, dependencies new—
A bunny bows: reviewed, pulled through. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/global-actor-isolation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link

codecov bot commented Aug 24, 2025

Codecov Report

❌ Patch coverage is 99.66942% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
Tests/PublishableTests/Suites/MainActorTests.swift 98.91% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (16)
.swiftlint.yml (1)

186-190: Tighten custom rule regexes to reduce backtracking and avoid requiring a trailing whitespace character

The current patterns rely on greedy .+/.* and require a trailing \s after the attribute. This can be brittle and slower on large files. Also, module-qualified actors (e.g., @MyModule.MainActor) aren’t explicitly handled.

Suggested more specific, faster patterns that don’t require trailing whitespace and correctly match module-qualified global actors:

-        regex: "(?-s)(@.+[^,\\s]\\s+@.*Actor\\s)"
+        regex: "(?-s)@[^,\\s]+\\s+@[\\w\\.]*Actor\\b"
-        regex: "(?-s)(@.+[^,\\s]\\s+@Sendable\\s)"
+        regex: "(?-s)@[^,\\s]+\\s+@Sendable\\b"

Notes:

  • @[^,\s]+ matches a single attribute token without overreaching.
  • @[\\w\\.]*Actor\\b matches @MainActor and @Module.MainActor while avoiding partials.
  • \b marks the end of the identifier (no need to require trailing whitespace).

If you want, I can add quick unit-style fixtures to validate these patterns against common attribute layouts (single-line, multi-line, module-qualified).

Sources/Publishable/Documentation.docc/Publishable.md (1)

10-10: Good addition; consider clarifying isolation semantics (nil vs actor) with a short example

The symbol link is great. A one-liner here (or on the macro’s dedicated page) stating that nil means nonisolated and a concrete example with MainActor.self would help readers adopt the new API faster.

For example (DocC snippet to add near this topic list or on the macro page):

// @Publishable(isolation: MainActor.self) // MainActor-isolated
// @Publishable(isolation: nil)            // nonisolated

I can draft a small “Discussion” section if you prefer to keep the Topics list terse.

Sources/PublishableMacros/Builders/PublisherDeclBuilder.swift (1)

23-29: Nice doc addition; minor wording polish and actor-isolation note

The warning is helpful. Suggested micro-edits for clarity and to acknowledge global-actor isolation of the enclosing type:

-            /// A ``PropertyPublisher`` which exposes `Combine` publishers for all mutable 
-            /// or computed instance properties of this object.
+            /// A ``PropertyPublisher`` that exposes `Combine` publishers for all mutable
+            /// or computed instance properties of this object. The property is isolated
+            /// to the same global actor as the enclosing type, if any.
@@
-            /// - Important: Don't store this instance in an external property. Accessing it after 
-            /// the original object has been deallocated may result in a crash. Always access it directly 
-            /// through the object that exposes it.
+            /// - Important: Don’t store this value outside the owning object. Accessing it
+            ///   after the owner has been deinitialized will crash (it keeps an unowned reference).
+            ///   Always access it directly through the object that exposes it.

If PropertyPublisher is type-aliased to AnyPropertyPublisher<…> elsewhere, consider cross-linking it with AnyPropertyPublisher in a See Also to aid doc navigation.

Sources/Publishable/Registrars/PublishableObservationRegistrar.swift (2)

16-16: Initializer requirement looks fine; consider clarifying isolation expectations in docs

Adding init() enables macro-generated registrars to be value types with default initialization. Minor ask: please document whether conformers are expected to be actor-isolated or nonisolated by default so downstream implementers don’t accidentally capture non-Sendable state across actors.


28-37: withMutation rethrows return pattern is good; consider making access semantics explicit

  • withMutation returning T and rethrows is appropriate.
  • For access, please document that it records dependency tracking only (no publishing), matching the Observation framework’s read-tracking semantics. This avoids misuse where callers expect emissions.

Happy to propose doc comment text if desired.

Tests/PublishableMacrosTests/PublishableMacroTests.swift (3)

75-83: Helpful publisher docs; consider adding a note on actor isolation

Nice docblock. Since global-actor isolation is now supported, consider appending a one-liner that the publisher’s accessors may be actor-isolated (e.g., @MainActor) depending on macro parameters or containing type isolation.


181-186: Route access through the isolation shim for consistency

access currently calls underlying.access directly. For consistency with mutation hooks and to prevent accidental cross-actor access when explicit isolation is used, consider:

- nonisolated func access(
+ nonisolated func access(
     _ object: Person,
     keyPath: KeyPath<Person, some Any>
 ) {
-    underlying.access(object, keyPath: keyPath)
+    assumeIsolatedIfNeeded {
+        underlying.access(object, keyPath: keyPath)
+    }
 }

This keeps all registrar interactions consistently isolated.


207-211: Isolation shim is a no-op here; consider an inline annotation to make that explicit

The non-actor variant’s assumeIsolatedIfNeeded is a straight try operation(). That’s fine. A tiny readability tweak would be to add a comment explaining it’s intentionally a no-op when no global actor is configured.

Sources/PublishableMacros/Builders/PropertyPublisherDeclBuilder.swift (2)

65-65: Prepending inherited global-actor attribute to stored property publishers: good; extend to the publisher property too

Annotating individual publisher accessors is correct. Consider also annotating the top-level publisher property (emitted by PublisherDeclBuilder) with the same inheritedGlobalActorAttribute so accessing object.publisher itself is consistently actor-checked when explicit isolation is requested.

I can wire explicitGlobalActorIsolation into PublisherDeclBuilder and add the attribute there.


24-24: Remove superfluous SwiftLint disable

SwiftLint hints a superfluous disable for type_contents_order. Since the rule didn’t trigger, drop the inline disable to keep the code clean.

-    func build() -> [DeclSyntax] { // swiftlint:disable:this type_contents_order
+    func build() -> [DeclSyntax] {
Tests/PublishableMacrosTests/MainActorMacroTests.swift (3)

21-234: SwiftLint: function_body_length violation; move the multi-line strings out of the test method

The test method spans 200+ lines due to inline multi-line strings. Extract the input and expected expansion into static helpers to satisfy the rule and improve readability.

Example refactor:

-        func testExpansion() {
-            assertMacroExpansion(
-                #"""
-                @MainActor @Publishable @Observable
-                public final class Person {
-                ...
-                """#,
-                expandedSource:
-                #"""
-                @MainActor @Observable
-                public final class Person {
-                ...
-                """#,
-                macros: macros
-            )
-        }
+        private static let inputSource: String = #"""
+        @MainActor @Publishable @Observable
+        public final class Person {
+        ...
+        }
+        """#
+
+        private static let expectedExpansion: String = #"""
+        @MainActor @Observable
+        public final class Person {
+        ...
+        }
+        """#
+
+        func testExpansion() {
+            assertMacroExpansion(
+                Self.inputSource,
+                expandedSource: Self.expectedExpansion,
+                macros: macros
+            )
+        }

119-156: Actor-annotated helper methods: good shape; ensure Combine availability

The generated expansion references PassthroughSubject and AnyPublisher. In macro-only tests that’s fine (string compare), but consider adding an integration test in the runtime test target to type-check a sample expansion under import Combine to catch drift early.

I can outline a small type-check test that compiles an expanded sample.


207-224: Isolation shim implementation: solid, but consider adding a fast path when already on the correct actor

You could optionally guard with MainActor.assumeIsolated only when needed. Not necessary, but if this path is hot, a fast-path could help:

  • Attempt MainActor.preconditionIsolated() in debug to catch misuse.
  • Or early-exit if already isolated (if you have a cheap check).

Given this is test expectation, treat this as a note for the builder implementation rather than the test text.

Sources/Publishable/PropertyPublisher/Publishable.swift (1)

13-14: Consider clarifying the error scenario in the documentation.

The documentation mentions "If this causes compilation errors" but doesn't specify what types of errors users might encounter when isolation inference fails. It would be helpful to provide examples of specific compilation errors that would require using the explicit isolation overload.

-/// - Note: This macro infers the global actor isolation of the type and applies it to the generated declarations.
-/// If this causes compilation errors, use ``Publishable(isolation:)`` instead.
+/// - Note: This macro infers the global actor isolation of the type and applies it to the generated declarations.
+/// If this causes compilation errors (e.g., "Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context"),
+/// use ``Publishable(isolation:)`` instead to explicitly specify the isolation.
Tests/PublishableTests/Suites/MainActorTests.swift (1)

20-20: Consider adding a comment explaining the use of nonisolated(unsafe).

While the use of nonisolated(unsafe) is correct here for tracking observations across actor boundaries, a brief comment would help future maintainers understand why this approach is necessary.

-        nonisolated(unsafe) var observationsQueue: [Void] = []
+        // Using nonisolated(unsafe) to allow mutation from the onChange closure
+        // which may execute on a different isolation context
+        nonisolated(unsafe) var observationsQueue: [Void] = []
Sources/PublishableMacros/Builders/ObservationRegistrarDeclBuilder.swift (1)

169-170: Consider documenting the unsafe cast rationale.

While the unsafeBitCast usage is correct and necessary here to work around Swift's type system limitations, adding a brief comment would help future maintainers understand why this approach is needed.

+                    // Strip the global actor annotation from the closure type to allow passing it to assumeIsolated
                     typealias Nonisolated = () throws -> Void
                     let rawOperation = unsafeBitCast(operation, to: Nonisolated.self)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d76ced2 and 835dc26.

📒 Files selected for processing (13)
  • .swiftlint.yml (1 hunks)
  • Package.resolved (1 hunks)
  • Package.swift (1 hunks)
  • Sources/Publishable/Documentation.docc/Publishable.md (1 hunks)
  • Sources/Publishable/PropertyPublisher/Publishable.swift (2 hunks)
  • Sources/Publishable/Registrars/PublishableObservationRegistrar.swift (1 hunks)
  • Sources/PublishableMacros/Builders/ObservationRegistrarDeclBuilder.swift (6 hunks)
  • Sources/PublishableMacros/Builders/PropertyPublisherDeclBuilder.swift (3 hunks)
  • Sources/PublishableMacros/Builders/PublisherDeclBuilder.swift (1 hunks)
  • Sources/PublishableMacros/Main/PublishableMacro.swift (2 hunks)
  • Tests/PublishableMacrosTests/MainActorMacroTests.swift (1 hunks)
  • Tests/PublishableMacrosTests/PublishableMacroTests.swift (3 hunks)
  • Tests/PublishableTests/Suites/MainActorTests.swift (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
Tests/PublishableMacrosTests/MainActorMacroTests.swift (1)
Tests/PublishableMacrosTests/PublishableMacroTests.swift (1)
  • testExpansion (21-221)
Sources/PublishableMacros/Builders/PropertyPublisherDeclBuilder.swift (1)
Sources/PublishableMacros/Builders/PublisherDeclBuilder.swift (1)
  • build (20-33)
Tests/PublishableTests/Suites/MainActorTests.swift (1)
Tests/PublishableTests/Helpers/Array+PopFirst.swift (1)
  • popFirst (11-16)
🪛 SwiftLint (0.57.0)
Tests/PublishableMacrosTests/MainActorMacroTests.swift

[Error] 21-21: Function body should span 100 lines or less excluding comments and whitespace: currently spans 212 lines

(function_body_length)

Sources/PublishableMacros/Builders/PropertyPublisherDeclBuilder.swift

[Warning] 24-24: SwiftLint rule 'type_contents_order' did not trigger a violation in the disabled region; remove the disable command

(superfluous_disable_command)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-and-test (macos)
  • GitHub Check: build-and-test (watchos)
  • GitHub Check: build-and-test (ios)
  • GitHub Check: build-and-test (maccatalyst)
  • GitHub Check: build-and-test (tvos)
🔇 Additional comments (18)
Package.resolved (1)

2-11: Lockfile aligns with Package.swift changes

  • PrincipleMacros pinned to 2.0.4 (rev d55ddb9…).
  • swift-syntax remains at 601.0.1, which is within the declared "600.0.0" ..< "604.0.0" range.

No concerns here.

Sources/Publishable/Registrars/PublishableObservationRegistrar.swift (1)

18-27: Symmetric willSet/didSet hooks are clear; verify ordering guarantees with underlying registrar

The contract implies:

  • willSet before mutation, then
  • actual mutation, then
  • didSet.

If the underlying SwiftObservationRegistrar can throw or otherwise reentrantly notify during didSet, confirm that publish-side effects won’t be missed. If needed, specify ordering guarantees in doc comments (e.g., “didSet is invoked after mutation has completed and before publish events are dispatched”).

Do you want me to draft concise doc comments for these hooks?

Tests/PublishableMacrosTests/PublishableMacroTests.swift (1)

117-117: underlying lifetime and thread-safety

private let underlying = SwiftObservationRegistrar() is fine. Verify that every call to underlying that mutates registrar state runs under the intended actor (or via an isolation shim) to avoid data races. In this non-actor test fixture, that’s handled by the wrappers around willSet/didSet/withMutation; see follow-up on access below.

Sources/PublishableMacros/Builders/PropertyPublisherDeclBuilder.swift (4)

15-22: Threading explicit global-actor isolation through settings: LGTM

Passing explicitGlobalActorIsolation into DeclBuilderSettings looks correct and aligns with the updated tests. No issues.


27-27: Generic argument switch to trimmedType: good catch

Moving from AnyPropertyPublisher<\(trimmedTypeName)> to <\(trimmedType)> preserves generic sugar (e.g., module-qualified names) and avoids name-only collisions. Looks good.


57-61: Use of inlinableAccessControlLevel is appropriate

This will produce the expected access level for peer members and caps at public. Nice improvement over the previous method.


75-86: Computed publishers also correctly inherit actor attribute

Looks consistent with the stored publishers path. No issues.

Sources/PublishableMacros/Main/PublishableMacro.swift (1)

34-46: Extracting explicitGlobalActorIsolation: good placement and error handling

Parsing the isolation parameter before property parsing is sensible. The throwing API is fine because expansion already throws. No changes requested.

Sources/Publishable/PropertyPublisher/Publishable.swift (2)

44-77: LGTM! Well-designed macro overload for explicit isolation control.

The new Publishable<Isolation: GlobalActor>(isolation:) macro provides excellent flexibility for users who need explicit control over global actor isolation. The documentation clearly explains when to use this overload versus the inference-based version.


84-84: Clean protocol design after removing associated type requirements.

The simplified Publishable protocol, without the PropertyPublisher associated type and publisher property, aligns well with the macro-driven approach where these are generated rather than protocol-required. This reduces complexity for implementers.

Tests/PublishableTests/Suites/MainActorTests.swift (5)

16-54: Excellent test coverage for stored property publishers.

The test thoroughly validates the behavior of stored property publishers, including:

  • Initial value emission
  • Property-specific change tracking
  • Proper isolation of unrelated property changes
  • Completion handling on deallocation

56-99: Well-structured test for computed property dependencies.

The test effectively verifies that computed properties correctly track their dependencies (name and surname) while ignoring unrelated changes (age). Good coverage of the reactive behavior.


104-151: Comprehensive willChange publisher testing.

The test properly validates that willChange emits the object reference before mutations occur and tracks changes across multiple properties. Good use of identity comparison (===) to verify the same instance is emitted.


153-200: Good coverage of didChange publisher behavior.

The test correctly verifies that didChange emits after mutations complete, maintaining consistency with the willChange test structure for easy comparison.


203-222: Well-designed test model with varied access levels.

The Person class effectively tests the macro's handling of different property access levels (public, internal, package, fileprivate) and types (stored, computed). The @MainActor isolation properly exercises the new global actor isolation support.

Sources/PublishableMacros/Builders/ObservationRegistrarDeclBuilder.swift (3)

15-22: Good addition of explicit isolation parameter.

The explicitGlobalActorIsolation parameter is properly integrated into the builder settings, allowing for flexible isolation control in the generated code.


106-157: Well-designed observation lifecycle methods with proper isolation handling.

The implementation correctly handles the observation lifecycle with willSet, didSet, access, and withMutation methods. The use of nonisolated(unsafe) for capturing values before calling assumeIsolatedIfNeeded is appropriate for maintaining actor isolation boundaries.


159-191: Clever isolation assumption implementation.

The assumeIsolatedIfNeeded function elegantly handles both isolated and nonisolated cases. The use of unsafeBitCast to strip the global actor annotation is a necessary workaround, and the implementation properly uses assumeIsolated to maintain runtime safety.

@NSFatalError
Copy link
Owner Author

Resolved in #6

@NSFatalError NSFatalError deleted the feature/global-actor-isolation branch November 29, 2025 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants