From b0858e53ab0756f7f178d24e441efe1a27e11538 Mon Sep 17 00:00:00 2001 From: maximkrouk Date: Wed, 28 Feb 2024 03:09:04 +0100 Subject: [PATCH] feat: Add macros from `combine-interception-macros` package - Setup CI --- .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/swiftpm/Package.resolved | 32 ++++ .../xcschemes/CombineInterception.xcscheme | 66 +++++++ .../CombineInterceptionMacros.xcscheme | 66 +++++++ .../CombineInterceptionMacrosTests.xcscheme | 53 ++++++ .../CombineInterceptionTests.xcscheme | 53 ++++++ .../combine-interception-Package.xcscheme | 130 +++++++++++++ .../xcschemes/combine-interception.xcscheme | 116 ++++++++++++ .github/workflows/ci.yml | 34 ++++ .gitignore | 4 +- .../xcschemes/CombineInterception.xcscheme | 66 +++++++ .../CombineInterceptionMacros.xcscheme | 66 +++++++ .../CombineInterceptionMacrosTests.xcscheme | 53 ++++++ .../CombineInterceptionTests.xcscheme | 53 ++++++ .../combine-interception-Package.xcscheme | 130 +++++++++++++ .../xcschemes/combine-interception.xcscheme | 116 ++++++++++++ Makefile | 62 ++++++- Package.resolved | 32 ++++ Package.swift | 24 ++- README.md | 35 +++- .../CombineInterceptionMacros/Exports.swift | 2 + .../InterceptionMacrosTests.swift | 173 ++++++++++++++++++ 23 files changed, 1370 insertions(+), 11 deletions(-) create mode 100644 .github/package.xcworkspace/contents.xcworkspacedata create mode 100644 .github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 .github/package.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/CombineInterception.xcscheme create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/combine-interception-Package.xcscheme create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/combine-interception.xcscheme create mode 100644 .github/workflows/ci.yml create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/CombineInterception.xcscheme create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/combine-interception-Package.xcscheme create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/combine-interception.xcscheme create mode 100644 Package.resolved create mode 100644 Sources/CombineInterceptionMacros/Exports.swift create mode 100644 Tests/CombineInterceptionMacrosTests/InterceptionMacrosTests.swift diff --git a/.github/package.xcworkspace/contents.xcworkspacedata b/.github/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..0fd0bc3 --- /dev/null +++ b/.github/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/.github/package.xcworkspace/xcshareddata/swiftpm/Package.resolved b/.github/package.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..12fe5cc --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,32 @@ +{ + "pins" : [ + { + "identity" : "swift-interception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/capturecontext/swift-interception.git", + "state" : { + "revision" : "8e6231d629a3cb04b929c5a3ba2ea2797151d0b6", + "version" : "0.3.0" + } + }, + { + "identity" : "swift-macro-toolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/stackotter/swift-macro-toolkit.git", + "state" : { + "revision" : "106daeb38eb3f52b1540aed981fc63fa22274576", + "version" : "0.3.1" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "74203046135342e4a4a627476dd6caf8b28fe11b", + "version" : "509.0.0" + } + } + ], + "version" : 2 +} diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterception.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterception.xcscheme new file mode 100644 index 0000000..ae1057d --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterception.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme new file mode 100644 index 0000000..0f7d1d8 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme new file mode 100644 index 0000000..b7c57a7 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme new file mode 100644 index 0000000..32425e1 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/combine-interception-Package.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/combine-interception-Package.xcscheme new file mode 100644 index 0000000..710fed6 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/combine-interception-Package.xcscheme @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/combine-interception.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/combine-interception.xcscheme new file mode 100644 index 0000000..40777d2 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/combine-interception.xcscheme @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2cc0f43 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + library-swift-latest: + name: Library + if: | + !contains(github.event.head_commit.message, '[ci skip]') && + !contains(github.event.head_commit.message, '[ci skip test]') && + !contains(github.event.head_commit.message, '[ci skip library-swift-latest]') + runs-on: macos-13 + timeout-minutes: 30 + strategy: + matrix: + config: + - debug + - release + steps: + - uses: actions/checkout@v4 + - name: Select Xcode 15.2 + run: sudo xcode-select -s /Applications/Xcode_15.2.app + - name: Run test + run: make test diff --git a/.gitignore b/.gitignore index 59e2947..0023a53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ .DS_Store /.build /Packages -/*.xcodeproj xcuserdata/ DerivedData/ +.swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata -Package.resolved +.netrc diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterception.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterception.xcscheme new file mode 100644 index 0000000..ae1057d --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterception.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme new file mode 100644 index 0000000..0f7d1d8 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacros.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme new file mode 100644 index 0000000..b7c57a7 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionMacrosTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme new file mode 100644 index 0000000..32425e1 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/CombineInterceptionTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/combine-interception-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/combine-interception-Package.xcscheme new file mode 100644 index 0000000..710fed6 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/combine-interception-Package.xcscheme @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/combine-interception.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/combine-interception.xcscheme new file mode 100644 index 0000000..40777d2 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/combine-interception.xcscheme @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Makefile b/Makefile index 65574b9..e05199d 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,59 @@ -format: - swift format --in-place --recursive \ - ./Package.swift ./Sources/CombineExtensions \ No newline at end of file +CONFIG = debug +PLATFORM_IOS = iOS Simulator,id=$(call udid_for,iOS 17.2,iPhone \d\+ Pro [^M]) +PLATFORM_MACOS = macOS +PLATFORM_MAC_CATALYST = macOS,variant=Mac Catalyst +PLATFORM_TVOS = tvOS Simulator,id=$(call udid_for,tvOS 17,TV) +PLATFORM_WATCHOS = watchOS Simulator,id=$(call udid_for,watchOS 10,Watch) + +default: test-all + +test-all: + $(MAKE) test + $(MAKE) test-docs + +test: + $(MAKE) CONFIG=debug test-library + $(MAKE) CONFIG=debug test-library-macros + +test-library: + for platform in "$(PLATFORM_IOS)" "$(PLATFORM_MACOS)" "$(PLATFORM_MAC_CATALYST)" "$(PLATFORM_TVOS)" "$(PLATFORM_WATCHOS)"; do \ + echo "\nTesting library on $$platform\n" && \ + (xcodebuild test \ + -skipMacroValidation \ + -configuration $(CONFIG) \ + -workspace .github/package.xcworkspace \ + -scheme CombineInterceptionTests \ + -destination platform="$$platform" | xcpretty && exit 0 \ + ) \ + || exit 1; \ + done; + +test-library-macros: + for platform in "$(PLATFORM_IOS)" "$(PLATFORM_MACOS)" "$(PLATFORM_MAC_CATALYST)" "$(PLATFORM_TVOS)" "$(PLATFORM_WATCHOS)"; do \ + echo "\nTesting library-macros on $$platform\n" && \ + (xcodebuild test \ + -skipMacroValidation \ + -configuration $(CONFIG) \ + -workspace .github/package.xcworkspace \ + -scheme CombineInterceptionMacrosTests \ + -destination platform="$$platform" | xcpretty && exit 0 \ + ) \ + || exit 1; \ + done; + +DOC_WARNINGS = $(shell xcodebuild clean docbuild \ + -scheme Interception \ + -destination platform="$(PLATFORM_IOS)" \ + -quiet \ + 2>&1 \ + | grep "couldn't be resolved to known documentation" \ + | sed 's|$(PWD)|.|g' \ + | tr '\n' '\1') +test-docs: + @test "$(DOC_WARNINGS)" = "" \ + || (echo "xcodebuild docbuild failed:\n\n$(DOC_WARNINGS)" | tr '\1' '\n' \ + && exit 1) + +define udid_for +$(shell xcrun simctl list devices available '$(1)' | grep '$(2)' | sort -r | head -1 | awk -F '[()]' '{ print $$(NF-3) }') +endef diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..12fe5cc --- /dev/null +++ b/Package.resolved @@ -0,0 +1,32 @@ +{ + "pins" : [ + { + "identity" : "swift-interception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/capturecontext/swift-interception.git", + "state" : { + "revision" : "8e6231d629a3cb04b929c5a3ba2ea2797151d0b6", + "version" : "0.3.0" + } + }, + { + "identity" : "swift-macro-toolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/stackotter/swift-macro-toolkit.git", + "state" : { + "revision" : "106daeb38eb3f52b1540aed981fc63fa22274576", + "version" : "0.3.1" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "74203046135342e4a4a627476dd6caf8b28fe11b", + "version" : "509.0.0" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift index 9a4eef5..5d90cb4 100644 --- a/Package.swift +++ b/Package.swift @@ -17,12 +17,17 @@ let package = Package( name: "CombineInterception", type: .static, targets: ["CombineInterception"] - ) + ), + .library( + name: "CombineInterceptionMacros", + type: .static, + targets: ["CombineInterceptionMacros"] + ), ], dependencies: [ .package( url: "https://github.com/capturecontext/swift-interception.git", - .upToNextMinor(from: "0.2.0") + .upToNextMinor(from: "0.3.0") ) ], targets: [ @@ -35,11 +40,26 @@ let package = Package( ) ] ), + .target( + name: "CombineInterceptionMacros", + dependencies: [ + .product( + name: "_InterceptionMacros", + package: "swift-interception" + ) + ] + ), .testTarget( name: "CombineInterceptionTests", dependencies: [ .target(name: "CombineInterception"), ] ), + .testTarget( + name: "CombineInterceptionMacrosTests", + dependencies: [ + .target(name: "CombineInterceptionMacros"), + ] + ), ] ) diff --git a/README.md b/README.md index 458bfe8..e53bb48 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ Combine API for interception of objc selectors in Swift. -Macros: [`combine-interception-macros`](https://github.com/capturecontext/combine-interception-macros) - ## Usage ### Basic @@ -15,7 +13,7 @@ Observe selectors on NSObject instances ```swift navigationController.intercept(_makeMethodSelector( selector: UINavigationController.popViewController, - signature: UINavigationController.popViewController + signature: navigationController.popViewController )) .sink { result in print(result.args) // `animated` flag @@ -23,6 +21,19 @@ navigationController.intercept(_makeMethodSelector( } ``` +You can also simplify creating method selector with `CombineInterceptionMacros` if you are open for macros + +```swift +navigationController.intercept( + #methodSelector(UINavigationController.popViewController) +).sink { result in + print(result.args) // `animated` flag + print(result.output) // popped `UIViewController?` +} +``` + +> Macros require `swift-syntax` compilation, so it will affect cold compilation time + ### Library If you use it to create a library it may be a good idea to export this one implicitly @@ -32,6 +43,13 @@ If you use it to create a library it may be a good idea to export this one impli @_exported import CombineInterception ``` +It's a good idea to add a separate macros target to your library as well + +```swift +// Exports.swift +@_exported import CombineInterceptionMacros +``` + ## Installation ### Basic @@ -49,7 +67,7 @@ If you use SwiftPM for your project, you can add CombineInterception to your pac ```swift .package( url: "https://github.com/capturecontext/combine-interception.git", - .upToNextMinor(from: "0.2.0") + .upToNextMinor(from: "0.3.0") ) ``` @@ -62,6 +80,15 @@ Do not forget about target dependencies: ) ``` +```swift +.product( + name: "CombineInterceptionMacros", + package: "combine-interception" +) +``` + + + ## License This library is released under the MIT license. See [LICENCE](LICENCE) for details. diff --git a/Sources/CombineInterceptionMacros/Exports.swift b/Sources/CombineInterceptionMacros/Exports.swift new file mode 100644 index 0000000..6a9be07 --- /dev/null +++ b/Sources/CombineInterceptionMacros/Exports.swift @@ -0,0 +1,2 @@ +@_exported import _InterceptionMacros +@_exported import CombineInterception diff --git a/Tests/CombineInterceptionMacrosTests/InterceptionMacrosTests.swift b/Tests/CombineInterceptionMacrosTests/InterceptionMacrosTests.swift new file mode 100644 index 0000000..beac43f --- /dev/null +++ b/Tests/CombineInterceptionMacrosTests/InterceptionMacrosTests.swift @@ -0,0 +1,173 @@ +import XCTest +@testable import CombineInterceptionMacros + +final class InterceptionMacrosTests: XCTestCase { + func testNoInputWithOutput() { + let object = Object() + var _args: [Void] = [] + var _outputs: [Int] = [] + var _expectedOutputs: [Int] = [] + var _count = 0 + + let cancellable = object.intercept(#methodSelector(Object.zero)).sink { result in + _args.append(result.args) + _outputs.append(result.output) + _count += 1 + } + + let runs = 3 + for _ in 0.. Int { 0 } + + @objc dynamic + func discard(_ value: Int) {} + + @discardableResult + @objc dynamic + func booleanForInteger(_ value: Int) -> Bool { + value != 0 + } + + @objc dynamic + func booleanAndForTwoIntegers(_ first: Int, _ second: Int) -> Bool { + booleanForInteger(first) && booleanForInteger(second) + } + + @objc dynamic + func toString(_ first: Int, _ second: Bool) -> String { + String(describing: (first, second)) + } +} + +fileprivate struct Pair: Equatable { + var left: Left + var right: Right + + init(_ pair: (Left, Right)) { + self.left = pair.0 + self.right = pair.1 + } +}