diff --git a/.agents/roles.md b/.agents/roles.md index d1a64935..fa5fb32d 100644 --- a/.agents/roles.md +++ b/.agents/roles.md @@ -144,7 +144,7 @@ Planner must produce this packet before handing work to another role. - Stop conditions: ``` -Use `Architecture risk: possible` when the task touches module boundaries, imports, target dependencies, DI, repository or service contracts, Widget flow, Firebase or SDK placement, StorePattern boundaries, or architecture documentation. +Use `Architecture risk: possible` when the task touches module boundaries, imports, target dependencies, DI, repository or service contracts, Widget flow, `ThirdParty` package linkage, StorePattern boundaries, or architecture documentation. ## Role activation @@ -249,7 +249,7 @@ Output: Architecture Watcher is a read-only gate for DevLog boundaries. -Use it when a task touches module boundaries, file ownership, layer dependencies, DI assembly, repository or service contracts, widget data flow, Firebase dependency placement, external SDK placement, StorePattern responsibilities, or architecture documentation. +Use it when a task touches module boundaries, file ownership, layer dependencies, DI assembly, repository or service contracts, widget data flow, `ThirdParty` package linkage, StorePattern responsibilities, or architecture documentation. Must read before reviewing: @@ -263,7 +263,7 @@ Must inspect: - Source imports in changed Swift files. - Relevant `Project.swift`, `Workspace.swift`, or target dependency changes. - Layer ownership before and after the change. -- External SDK exposure. +- `ThirdParty` package product linkage and whether it remains free of DevLog application behavior. - Same-layer dependency injection. - Widget, WidgetCore, and WidgetExtension boundaries when widget flow is touched. - Presentation `StorePattern` responsibility boundaries when Presentation feature logic is touched. @@ -272,7 +272,7 @@ Must not: - Edit files. - Approve ambiguous ownership by assumption. -- Treat a manifest-only target dependency as permission for a source-level architecture dependency. +- Treat a manifest-only target dependency as permission for a source-level DevLog architecture dependency. A direct `ThirdParty` dependency permits only imports of its external package products. - Hide architecture decisions inside build-fix wording. Output: @@ -285,7 +285,7 @@ Output: - Owning target: - Dependency direction: - Target dependency impact: -- SDK placement: +- ThirdParty linkage: - Same-layer DI: - Widget boundary: - StorePattern: diff --git a/.agents/rules/architecture.md b/.agents/rules/architecture.md index a711bad8..661fa0ac 100644 --- a/.agents/rules/architecture.md +++ b/.agents/rules/architecture.md @@ -10,6 +10,8 @@ Use this reference with `AGENTS.md`, `.agents/rules/general.md`, and `.agents/ro This repository is a Tuist-generated, workspace-based modular iOS app. There is no root `Package.swift`; module projects are generated from `Workspace.swift` and each module's `Project.swift`. +`ThirdParty` is an external package registry, not a DevLog application layer. It owns Swift Package declarations and product linkage only, has no DevLog target dependency, and any target including `Domain` may depend on it when that target imports an external package product. + ## When to use Read this file before work that changes any of these areas: @@ -157,17 +159,18 @@ flowchart TD | Layer | Owns | Allowed direction | Ask before | | --- | --- | --- | --- | -| `Core` | DI primitives, logger, shared value/query types, display options, activity kinds, lightweight widget bridge values | No DevLog layer dependency | Moving domain entities into Core | -| `Domain` | entities, repository protocols, use cases | Core only | Adding Data, Infra, Persistence, Presentation, App, Widget UI, or SDK dependency | -| `Data` | repository implementations, DTOs, mappers, data protocols, widget repository/updater/sync contracts | Domain, Core | Adding concrete Firebase, GoogleSignIn, WidgetKit, storage, WidgetCore snapshot model/factory usage, or platform implementation details; moving concrete widget handlers into Data | -| `Infra` | Firebase, social login, network, metadata, messaging implementations | Data, Core | Moving SDK-specific behavior out of Infra; adding any Domain dependency, source import, or SDK service contract coupling | -| `Persistence` | local stores, image cache, non-widget app persistence | Data, Core | Adding WidgetCore, WidgetKit reload, Widget, widget snapshot generation, or widget bridge ownership | -| `Presentation` | UI, view models, coordinators, presentation state, narrow presentation-scoped platform side effects | Domain, Core | Adding Data, Infra, Persistence, or App dependency; expanding platform service ownership beyond UI-side effects | -| `MarkdownRenderer` | public SwiftUI renderer and reference value, internal WebKit bridge, renderer resources, TypeScript Tooling, renderer tests | system frameworks only | Adding a DevLog application layer dependency, exposing WebKit bridge types, adding another Presentation importer, or re-exporting the module | -| `Widget` | app-side widget bridge, sync bus implementation, sync/session handlers, snapshot generation/persistence orchestration, WidgetKit reload bridge, widget assembler | Data, Core, WidgetCore | Adding Domain, Infra, Persistence, Presentation, or App dependency | -| `App` | composition root, lifecycle, assembler wiring, app target ownership for widget extension embedding | Concrete app layers | Moving feature logic into App | -| `WidgetCore` | widget snapshot models, factories, app-group keys/defaults store, deep links, pure snapshot logic | Core | Adding Domain, Data, Infra, Persistence, Presentation, App, or Widget dependency | -| `WidgetExtension` | WidgetKit rendering and timeline plumbing | WidgetCore | Calling app/domain services directly | +| `ThirdParty` | external package declarations, product linkage, marker sources | No DevLog target dependency; may be depended on by any target | Adding DevLog feature, service, adapter, or layer dependency; changing package versions or products outside the requested scope | +| `Core` | DI primitives, logger, shared value/query types, display options, activity kinds, lightweight widget bridge values | No DevLog layer dependency; `ThirdParty` when needed | Moving domain entities into Core | +| `Domain` | entities, repository protocols, use cases | Core, `ThirdParty` when needed | Adding Data, Infra, Persistence, Presentation, App, or Widget UI dependency | +| `Data` | repository implementations, DTOs, mappers, data protocols, widget repository/updater/sync contracts | Domain, Core, `ThirdParty` when needed | Adding WidgetKit, storage, WidgetCore snapshot model/factory usage, or platform implementation details; moving concrete widget handlers into Data | +| `Infra` | application infrastructure service implementations for social login, network, metadata, and messaging | Data, Core, `ThirdParty` when needed | Adding any Domain dependency or SDK service contract coupling | +| `Persistence` | local stores, image cache, non-widget app persistence | Data, Core, `ThirdParty` when needed | Adding WidgetCore, WidgetKit reload, Widget, widget snapshot generation, or widget bridge ownership | +| `Presentation` | UI, view models, coordinators, presentation state, narrow presentation-scoped platform side effects | Domain, Core, `ThirdParty` when needed | Adding Data, Infra, Persistence, or App dependency; expanding platform service ownership beyond UI-side effects | +| `MarkdownRenderer` | public SwiftUI renderer and reference value, internal WebKit bridge, renderer resources, TypeScript Tooling, renderer tests | system frameworks, `ThirdParty` when needed | Adding a DevLog application layer dependency, exposing WebKit bridge types, adding another Presentation importer, or re-exporting the module | +| `Widget` | app-side widget bridge, sync bus implementation, sync/session handlers, snapshot generation/persistence orchestration, WidgetKit reload bridge, widget assembler | Data, Core, WidgetCore, `ThirdParty` when needed | Adding Domain, Infra, Persistence, Presentation, or App dependency | +| `App` | composition root, lifecycle, assembler wiring, app target ownership for widget extension embedding | Concrete app layers, `ThirdParty` for framework linking | Moving feature logic into App | +| `WidgetCore` | widget snapshot models, factories, app-group keys/defaults store, deep links, pure snapshot logic | Core, `ThirdParty` when needed | Adding Domain, Data, Infra, Persistence, Presentation, App, or Widget dependency | +| `WidgetExtension` | WidgetKit rendering and timeline plumbing | WidgetCore, `ThirdParty` when needed | Calling app/domain services directly | ## Presentation target structure @@ -286,29 +289,33 @@ flowchart TD OnlyShared -->|No| Ask ``` -## External dependency flow +## System framework and ThirdParty dependency flow -Use this flow before introducing or moving imports such as Firebase, GoogleSignIn, AuthenticationServices, UserNotifications, LinkPresentation, Network, or WidgetKit. +Use this flow before introducing or moving framework imports. A Swift Package product declared by `ThirdParty` is available to any target including `Domain`; it requires that target's direct `ThirdParty` dependency but does not change DevLog layer ownership. ```mermaid flowchart TD - Import["External framework import"] - Firebase{"Firebase/Auth/Firestore/Functions/Messaging?"} - SocialLogin{"GoogleSignIn or AuthenticationServices?"} + Import["Framework import"] + ThirdPartyProduct{"ThirdParty package product?"} + ThirdParty["Add direct ThirdParty target dependency"] + SystemFramework{"System framework?"} + SocialLogin{"AuthenticationServices?"} SocialLoginClassification{"Existing presentation/data cancellation/error classification?"} NetworkMeta{"Network or LinkPresentation implementation?"} UserNotifications{"UserNotifications?"} WidgetKit{"WidgetKit?"} - Infra["Prefer Infra"] + Infra["Prefer Infra implementation"] ErrorClassification["Keep narrow in Data or Presentation only when matching the existing cancellation-classification pattern"] PresentationBadge["Allow in Presentation only for established badge/UI side effects"] Widget["Allow in Widget for app-side snapshot update/reload orchestration"] WidgetExtension["Allow in WidgetExtension rendering/timeline code"] Ask["Ask user before crossing layer"] - Import --> Firebase - Firebase -->|Yes| Infra - Firebase -->|No| SocialLogin + Import --> ThirdPartyProduct + ThirdPartyProduct -->|Yes| ThirdParty + ThirdPartyProduct -->|No| SystemFramework + SystemFramework -->|No| Ask + SystemFramework -->|Yes| SocialLogin SocialLogin -->|Login implementation| Infra SocialLogin -->|Presentation/data error classification| SocialLoginClassification SocialLoginClassification -->|Matches existing pattern| ErrorClassification @@ -381,7 +388,7 @@ Before editing architecture code, the AI should be able to answer these question 2. What layer should own it after the change? 3. Which imports prove the current dependency direction? 4. Which target dependency will change? -5. Does the change expose an external SDK outside its current boundary? +5. Does the change add a `ThirdParty` dependency or move DevLog behavior into `ThirdParty`? 6. Does the change affect WidgetCore or WidgetExtension boundaries? 7. Is this change inside the current issue or PR scope? 8. Is user confirmation required before editing? @@ -391,6 +398,7 @@ Before editing architecture code, the AI should be able to answer these question - DevLog-specific rules were loaded. - Current files and imports were inspected. - Ambiguous architecture decisions were confirmed by the user. +- `ThirdParty` remains free of DevLog target dependencies and application behavior. - Swift logic was preserved unless explicitly approved. - Diff scope was checked. - Xcode Local MCP build was used for Swift/iOS code changes. diff --git a/.agents/workflows.md b/.agents/workflows.md index 6263f1a5..215121a3 100644 --- a/.agents/workflows.md +++ b/.agents/workflows.md @@ -140,7 +140,7 @@ Implementer must not proceed on `Block` or `Needs Owner Decision`. - Changed Swift imports. - `Workspace.swift` and relevant `Project.swift` files. - Current owner and proposed owner. -- External SDK placement. +- `ThirdParty` package linkage and external import policy. - Same-layer DI. - Widget and WidgetCore boundaries when touched. - StorePattern reducer, side effect, and run responsibility when Presentation feature logic is touched. diff --git a/Application/App/Project.swift b/Application/App/Project.swift index 08a77304..bdca564b 100644 --- a/Application/App/Project.swift +++ b/Application/App/Project.swift @@ -7,7 +7,7 @@ let project = Project( disableBundleAccessors: true, disableSynthesizedResourceAccessors: true ), - packages: DevLogPackages.defaultPackages, + packages: [], settings: .devlogProject(versionXcconfigPath: "../Shared/Version.xcconfig"), targets: [ .target( @@ -32,6 +32,7 @@ let project = Project( ], dependencies: [ .project(target: "Presentation", path: "../Presentation"), + .project(target: "ThirdParty", path: "../../Libraries/ThirdParty"), .project(target: "Persistence", path: "../Persistence"), .project(target: "Infra", path: "../Infra"), .project(target: "Widget", path: "../Widget"), diff --git a/Application/Core/Project.swift b/Application/Core/Project.swift index f9c1cd32..1eb835a6 100644 --- a/Application/Core/Project.swift +++ b/Application/Core/Project.swift @@ -7,6 +7,6 @@ let project = Project.devlogFramework( versionXcconfigPath: "../Shared/Version.xcconfig", frameworkInfoPlistPath: "../Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.defaultPackages, + packages: [], hasTests: false ) diff --git a/Application/Data/Project.swift b/Application/Data/Project.swift index c0800338..750ea655 100644 --- a/Application/Data/Project.swift +++ b/Application/Data/Project.swift @@ -7,7 +7,7 @@ let project = Project.devlogFramework( versionXcconfigPath: "../Shared/Version.xcconfig", frameworkInfoPlistPath: "../Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.defaultPackages, + packages: [], dependencies: [ .project(target: "Domain", path: "../Domain"), .project(target: "Core", path: "../Core"), diff --git a/Application/Domain/Project.swift b/Application/Domain/Project.swift index 9c417667..0c7d9f0d 100644 --- a/Application/Domain/Project.swift +++ b/Application/Domain/Project.swift @@ -7,7 +7,7 @@ let project = Project.devlogFramework( versionXcconfigPath: "../Shared/Version.xcconfig", frameworkInfoPlistPath: "../Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.defaultPackages, + packages: [], dependencies: [ .project(target: "Core", path: "../Core") ], diff --git a/Application/Infra/Project.swift b/Application/Infra/Project.swift index b3400b7c..1462b9f5 100644 --- a/Application/Infra/Project.swift +++ b/Application/Infra/Project.swift @@ -7,10 +7,14 @@ let project = Project.devlogFramework( versionXcconfigPath: "../Shared/Version.xcconfig", frameworkInfoPlistPath: "../Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.infraPackages, + packages: [], dependencies: [ .project(target: "Data", path: "../Data"), .project(target: "Core", path: "../Core"), - ] + DevLogPackages.infraPackageDependencies, + .project(target: "ThirdParty", path: "../../Libraries/ThirdParty"), + ], + testDependencies: [ + .project(target: "ThirdParty", path: "../../Libraries/ThirdParty"), + ], hasTests: true ) diff --git a/Application/Persistence/Project.swift b/Application/Persistence/Project.swift index 67ea93a4..f127ad70 100644 --- a/Application/Persistence/Project.swift +++ b/Application/Persistence/Project.swift @@ -7,7 +7,7 @@ let project = Project.devlogFramework( versionXcconfigPath: "../Shared/Version.xcconfig", frameworkInfoPlistPath: "../Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.defaultPackages, + packages: [], dependencies: [ .project(target: "Data", path: "../Data"), .project(target: "Core", path: "../Core"), diff --git a/Application/Presentation/Project.swift b/Application/Presentation/Project.swift index 102bc9cc..55af3554 100644 --- a/Application/Presentation/Project.swift +++ b/Application/Presentation/Project.swift @@ -13,13 +13,18 @@ let frameworkBuildSettings = Settings.devlog( ] ) +let thirdPartyDependency: TargetDependency = .project( + target: "ThirdParty", + path: "../../Libraries/ThirdParty" +) + let project = Project( name: "Presentation", options: .options( disableBundleAccessors: true, disableSynthesizedResourceAccessors: true ), - packages: DevLogPackages.presentationPackages, + packages: [], settings: .devlogProject(versionXcconfigPath: versionXcconfigPath), targets: [ .target( @@ -42,8 +47,7 @@ let project = Project( target: "MarkdownRenderer", path: "../../Libraries/MarkdownRenderer" ), - .package(product: "ComposableArchitecture"), - .package(product: "OrderedCollections") + thirdPartyDependency, ], settings: frameworkBuildSettings ), @@ -63,7 +67,8 @@ let project = Project( dependencies: [ .project(target: "Domain", path: "../Domain"), .project(target: "Core", path: "../Core"), - .target(name: "PresentationShared") + .target(name: "PresentationShared"), + thirdPartyDependency, ], settings: .devlog( base: [ @@ -107,7 +112,8 @@ let project = Project( ], dependencies: [ .target(name: "HomeTab"), - .target(name: "PresentationShared") + .target(name: "PresentationShared"), + thirdPartyDependency, ], settings: .devlog( base: [ @@ -151,7 +157,8 @@ let project = Project( ], dependencies: [ .target(name: "TodayTab"), - .target(name: "PresentationShared") + .target(name: "PresentationShared"), + thirdPartyDependency, ], settings: .devlog( base: [ @@ -197,7 +204,8 @@ let project = Project( .project(target: "Domain", path: "../Domain"), .project(target: "Core", path: "../Core"), .target(name: "NotificationTab"), - .target(name: "PresentationShared") + .target(name: "PresentationShared"), + thirdPartyDependency, ], settings: .devlog( base: [ @@ -243,7 +251,8 @@ let project = Project( .project(target: "Domain", path: "../Domain"), .project(target: "Core", path: "../Core"), .target(name: "ProfileTab"), - .target(name: "PresentationShared") + .target(name: "PresentationShared"), + thirdPartyDependency, ], settings: .devlog( base: [ @@ -293,7 +302,8 @@ let project = Project( .project(target: "Domain", path: "../Domain"), .project(target: "Core", path: "../Core"), .target(name: "Entry"), - .target(name: "PresentationShared") + .target(name: "PresentationShared"), + thirdPartyDependency, ], settings: .devlog( base: [ diff --git a/Application/Widget/Project.swift b/Application/Widget/Project.swift index ec687b4b..0a7ce72b 100644 --- a/Application/Widget/Project.swift +++ b/Application/Widget/Project.swift @@ -7,7 +7,7 @@ let project = Project.devlogFramework( versionXcconfigPath: "../Shared/Version.xcconfig", frameworkInfoPlistPath: "../Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.defaultPackages, + packages: [], dependencies: [ .project(target: "Data", path: "../Data"), .project(target: "Core", path: "../Core"), diff --git a/Libraries/ThirdParty/Project.swift b/Libraries/ThirdParty/Project.swift new file mode 100644 index 00000000..e604f271 --- /dev/null +++ b/Libraries/ThirdParty/Project.swift @@ -0,0 +1,72 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let deploymentSettings: SettingsDictionary = [ + "IPHONEOS_DEPLOYMENT_TARGET": "17.0", + "MARKETING_VERSION": "1.0.0", +] + +let project = Project( + name: "ThirdParty", + packages: [ + .package( + url: "https://github.com/firebase/firebase-ios-sdk", + .exact("11.15.0") + ), + .package( + url: "https://github.com/google/GoogleSignIn-iOS", + .revision("02616ac6b469e8f00212436d2cac16e6efad7954") + ), + .package( + url: "https://github.com/opficdev/Nexa", + .upToNextMinor(from: "1.1.1") + ), + .package( + url: "https://github.com/pointfreeco/swift-composable-architecture", + .exact("1.25.5") + ), + .package( + url: "https://github.com/apple/swift-collections.git", + .exact("1.3.0") + ), + ], + settings: .devlogProject(additionalBase: deploymentSettings), + targets: [ + .target( + name: "ThirdParty", + destinations: .iOS, + product: .framework, + bundleId: "com.opfic.DevLog.ThirdParty", + infoPlist: .extendingDefault( + with: [ + "CFBundlePackageType": "FMWK", + ] + ), + sources: [ + "Sources/**/*.swift", + ], + scripts: [ + DevLogScripts.swiftLint( + sourcePath: "Sources", + configPath: "Sources/.swiftlint.yml" + ), + ], + dependencies: [ + .package(product: "FirebaseAnalyticsCore"), + .package(product: "FirebaseCore"), + .package(product: "FirebaseFunctions"), + .package(product: "FirebaseAuth"), + .package(product: "FirebaseCrashlytics"), + .package(product: "FirebaseMessaging"), + .package(product: "FirebaseFirestore"), + .package(product: "GoogleSignIn"), + .package(product: "Nexa"), + .package(product: "ComposableArchitecture"), + .package(product: "OrderedCollections"), + ], + settings: .devlog( + base: deploymentSettings + ) + ), + ] +) diff --git a/Libraries/ThirdParty/Sources/.swiftlint.yml b/Libraries/ThirdParty/Sources/.swiftlint.yml new file mode 100644 index 00000000..1242ffca --- /dev/null +++ b/Libraries/ThirdParty/Sources/.swiftlint.yml @@ -0,0 +1 @@ +parent_config: ../../../.swiftlint.yml diff --git a/Libraries/ThirdParty/Sources/ThirdParty.swift b/Libraries/ThirdParty/Sources/ThirdParty.swift new file mode 100644 index 00000000..5150da06 --- /dev/null +++ b/Libraries/ThirdParty/Sources/ThirdParty.swift @@ -0,0 +1,10 @@ +// +// ThirdParty.swift +// ThirdParty +// +// Created by opfic on 2026/08/20. +// + +import Foundation + +public enum ThirdPartyModule { } diff --git a/README.md b/README.md index ada7acc5..95614090 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Todo, 저장 링크, 오늘 할 일, 받은 알림, 누적 활동을 하나의 - `DevLog.xcworkspace` 안에서 Application, Libraries, Widget 모듈을 분리하고 화면, 상태, 비즈니스 로직, 외부 의존성 경계를 나눈 `Clean Architecture` 기반 구성 - `Domain`을 중심으로 계층별 책임과 의존 방향을 분리해 비즈니스 규칙이 UI, 데이터 저장소, 외부 SDK 구현에 의존하지 않도록 구성 +- `ThirdParty` target은 Swift Package 선언과 product 링크만 소유하는 계층 외부 registry이며 필요한 target이 선택적으로 의존함 - `Presentation` target은 `App`의 기존 import를 유지하는 re-export 역할 - `Entry`: root/auth/tab shell/window 흐름 소유 - `PresentationShared`: 공통 Todo/Search/Loading 흐름 소유 @@ -254,7 +255,8 @@ DevLog_iOS/ │ │ └── ProfileTab/ # Profile/Settings 탭 화면, feature, coordinator, 테스트 │ └── Widget/ # 앱-위젯 브릿지, 위젯 동기화 이벤트, 스냅샷 갱신 ├── Libraries/ -│ └── MarkdownRenderer/ # 독립 Markdown 렌더링 화면, WebKit 연결, 자원, 테스트, Tooling +│ ├── MarkdownRenderer/ # 독립 Markdown 렌더링 화면, WebKit 연결, 자원, 테스트, Tooling +│ └── ThirdParty/ # 외부 Swift Package 선언과 product 링크 ├── Widget/ │ ├── WidgetCore/ # 위젯 스냅샷 모델, Factory, App Group 상수 │ └── WidgetExtension/ # WidgetKit UI, Provider, Timeline diff --git a/Tuist/ProjectDescriptionHelpers/Project+Packages.swift b/Tuist/ProjectDescriptionHelpers/Project+Packages.swift deleted file mode 100644 index 1b6657cc..00000000 --- a/Tuist/ProjectDescriptionHelpers/Project+Packages.swift +++ /dev/null @@ -1,99 +0,0 @@ -import ProjectDescription - -public enum DevLogPackages { - public static let swiftCollectionsPackage: Package = .package( - url: "https://github.com/apple/swift-collections.git", - .exact("1.3.0") - ) - public static let composableArchitecturePackage: Package = .package( - url: "https://github.com/pointfreeco/swift-composable-architecture", - .exact("1.25.5") - ) - public static let firebasePackage: Package = .package( - url: "https://github.com/firebase/firebase-ios-sdk", - .exact("11.15.0") - ) - public static let googleSignInPackage: Package = .package( - url: "https://github.com/google/GoogleSignIn-iOS", - .revision("02616ac6b469e8f00212436d2cac16e6efad7954") - ) - public static let nexaPackage: Package = .package( - url: "https://github.com/opficdev/Nexa", - .upToNextMinor(from: "1.1.1") - ) - - public static let presentationPackageDependencies: [TargetDependency] = [ - .package(product: "ComposableArchitecture"), - .package(product: "OrderedCollections"), - ] - - public static let infraPackageDependencies: [TargetDependency] = [ - .package(product: "FirebaseAnalyticsCore"), - .package(product: "FirebaseCore"), - .package(product: "FirebaseFunctions"), - .package(product: "FirebaseAuth"), - .package(product: "FirebaseCrashlytics"), - .package(product: "FirebaseMessaging"), - .package(product: "FirebaseFirestore"), - .package(product: "GoogleSignIn"), - .package(product: "Nexa"), - ] - - public static let defaultPackages: [Package] = [] - - public static let presentationPackages: [Package] = [ - composableArchitecturePackage, - swiftCollectionsPackage, - ] - - public static let infraPackages: [Package] = [ - firebasePackage, - googleSignInPackage, - nexaPackage, - ] -} - -public enum DevLogScripts { - public static func swiftLint( - sourcePath: String, - configPath: String = "../../.swiftlint.yml" - ) -> TargetScript { - TargetScript.pre( - script: """ - export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" - - swiftLintPath="$(command -v swiftlint || true)" - if [ -z "$swiftLintPath" ]; then - echo "error: SwiftLint is not installed. Run 'brew install swiftlint'." - exit 1 - fi - - configPath="${SRCROOT}/\(configPath)" - sourcePathName="\(sourcePath)" - lintSourcePath="${SRCROOT}/${sourcePathName}" - - if [ "$sourcePathName" != "." ]; then - "$swiftLintPath" lint --config "$configPath" "$lintSourcePath" - else - swiftFilePaths=() - while IFS= read -r -d '' swiftFilePath; do - swiftFilePaths+=("$swiftFilePath") - done < <(find "$lintSourcePath" -name "*.swift" -not -path "*/Derived/*" -not -name "Project.swift" -print0) - - if [ ${#swiftFilePaths[@]} -lt 1 ]; then - exit 0 - fi - - "$swiftLintPath" lint --config "$configPath" "${swiftFilePaths[@]}" - fi - """, - name: "SwiftLint", - inputPaths: [ - "$(SRCROOT)/\(configPath)", - "$(SRCROOT)/\(sourcePath)", - ], - basedOnDependencyAnalysis: false, - shellPath: "/bin/bash" - ) - } -} diff --git a/Tuist/ProjectDescriptionHelpers/Project+Scripts.swift b/Tuist/ProjectDescriptionHelpers/Project+Scripts.swift new file mode 100644 index 00000000..83151857 --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Project+Scripts.swift @@ -0,0 +1,46 @@ +import ProjectDescription + +public enum DevLogScripts { + public static func swiftLint( + sourcePath: String, + configPath: String = "../../.swiftlint.yml" + ) -> TargetScript { + TargetScript.pre( + script: """ + export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" + + swiftLintPath="$(command -v swiftlint || true)" + if [ -z "$swiftLintPath" ]; then + echo "error: SwiftLint is not installed. Run 'brew install swiftlint'." + exit 1 + fi + + configPath="${SRCROOT}/\(configPath)" + sourcePathName="\(sourcePath)" + lintSourcePath="${SRCROOT}/${sourcePathName}" + + if [ "$sourcePathName" != "." ]; then + "$swiftLintPath" lint --config "$configPath" "$lintSourcePath" + else + swiftFilePaths=() + while IFS= read -r -d '' swiftFilePath; do + swiftFilePaths+=("$swiftFilePath") + done < <(find "$lintSourcePath" -name "*.swift" -not -path "*/Derived/*" -not -name "Project.swift" -print0) + + if [ ${#swiftFilePaths[@]} -lt 1 ]; then + exit 0 + fi + + "$swiftLintPath" lint --config "$configPath" "${swiftFilePaths[@]}" + fi + """, + name: "SwiftLint", + inputPaths: [ + "$(SRCROOT)/\(configPath)", + "$(SRCROOT)/\(sourcePath)", + ], + basedOnDependencyAnalysis: false, + shellPath: "/bin/bash" + ) + } +} diff --git a/Tuist/ProjectDescriptionHelpers/Project+Templates.swift b/Tuist/ProjectDescriptionHelpers/Project+Templates.swift index f6a53760..5dab2127 100644 --- a/Tuist/ProjectDescriptionHelpers/Project+Templates.swift +++ b/Tuist/ProjectDescriptionHelpers/Project+Templates.swift @@ -7,8 +7,9 @@ public extension Project { versionXcconfigPath: Path, frameworkInfoPlistPath: Path, testsInfoPlistPath: Path, - packages: [Package] = DevLogPackages.defaultPackages, + packages: [Package] = [], dependencies: [TargetDependency] = [], + testDependencies: [TargetDependency] = [], hasTests: Bool ) -> Project { var targets: [Target] = [ @@ -52,7 +53,7 @@ public extension Project { ], dependencies: [ .target(name: name), - ], + ] + testDependencies, settings: .devlog( base: [ "ENABLE_USER_SCRIPT_SANDBOXING": "NO", diff --git a/Widget/WidgetCore/Project.swift b/Widget/WidgetCore/Project.swift index 36643d46..0f6f4246 100644 --- a/Widget/WidgetCore/Project.swift +++ b/Widget/WidgetCore/Project.swift @@ -7,7 +7,7 @@ let project = Project.devlogFramework( versionXcconfigPath: "../../Application/Shared/Version.xcconfig", frameworkInfoPlistPath: "../../Application/Shared/InfoPlists/Framework-Info.plist", testsInfoPlistPath: "../../Application/Shared/InfoPlists/UnitTests-Info.plist", - packages: DevLogPackages.defaultPackages, + packages: [], dependencies: [ .project(target: "Core", path: "../../Application/Core"), ], diff --git a/Workspace.swift b/Workspace.swift index 912ef51f..95aadfa0 100644 --- a/Workspace.swift +++ b/Workspace.swift @@ -13,6 +13,7 @@ let workspace = Workspace( "Application/Widget", "Libraries/CollectionUI", "Libraries/MarkdownRenderer", + "Libraries/ThirdParty", "Widget/WidgetCore", "Widget/WidgetExtension", ], diff --git a/docs/graph.png b/docs/graph.png index d98b1b78..3cc8ac90 100644 Binary files a/docs/graph.png and b/docs/graph.png differ