From 89dfae078890bfbfc821cb3ecb9b0f4838d45e2e Mon Sep 17 00:00:00 2001 From: Dan Federman Date: Fri, 1 May 2026 21:57:15 -0700 Subject: [PATCH 1/3] Docs: flag additionalDirectoriesToInclude as SPM-Xcode only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flag walks directories at SafeDITool runtime, which the SPM build-tool plugin under Xcode allows but the Bazel and Tuist integrations don't — both enumerate every input up front (Bazel via declared rule inputs; Tuist via the build phase's `inputPaths`), so files reached only through `additionalDirectoriesToInclude` won't be visible at build time and won't trigger incremental rebuilds. Surface the limitation in three spots: - `Sources/SafeDI/Decorators/SafeDIConfiguration.swift` parameter doc - `Documentation/Manual.md` — the `additionalDirectoriesToInclude` prose section gets a callout note - `Documentation/Manual.md` — the `#SafeDIConfiguration` parameter list updates to match The existing language ("only applies to SafeDI repos that utilize the SPM plugin via an Xcode project") was already a negative claim about Bazel/Tuist by implication, but readers won't reliably make that leap. Calling out both integrations by name makes the incompatibility actionable. Co-Authored-By: Claude Opus 4.7 (1M context) --- Documentation/Manual.md | 4 +++- Sources/SafeDI/Decorators/SafeDIConfiguration.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/Manual.md b/Documentation/Manual.md index e79cf6ef..9c9c0497 100644 --- a/Documentation/Manual.md +++ b/Documentation/Manual.md @@ -42,6 +42,8 @@ import SafeDI The `additionalDirectoriesToInclude` parameter specifies folders outside of your module that SafeDI will scan for Swift source files. Paths must be relative to the executing directory (the directory containing the `.xcodeproj` for Xcode integrations). Use this parameter to specify the paths to dependent modules’ source directories, since Xcode project plugins cannot discover these automatically. You can see [an example of this configuration](../Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration/SafeDIConfiguration.swift) in the [ExampleMultiProjectIntegration](../Examples/ExampleMultiProjectIntegration) project. +> **Note:** `additionalDirectoriesToInclude` is only honored by the SPM build-tool plugin running inside an Xcode project. The Bazel and Tuist integrations enumerate every input up front (Bazel via declared rule inputs; Tuist via the build phase's `inputPaths`), so files reached only through `additionalDirectoriesToInclude` won't be visible to SafeDITool at build time and won't trigger incremental rebuilds. Under those integrations, list every Swift source you want SafeDI to see directly via the build target. + ##### Installing the prebuilt SafeDITool binary If you see a build warning that starts with **"SafeDI's build-tool plugin is falling back to a regex-based output scanner..."** — installing the prebuilt tool fixes it. @@ -439,7 +441,7 @@ public struct FeedView: Instantiable { **Parameters:** - `additionalImportedModules`: Module names to import in the generated dependency tree, in addition to the import statements found in files that declare `@Instantiable` types. Default: `[]`. -- `additionalDirectoriesToInclude`: Directories containing Swift files to include, relative to the executing directory. This parameter only applies to SafeDI repos that utilize the SPM plugin via an Xcode project. Default: `[]`. +- `additionalDirectoriesToInclude`: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin in an Xcode project. The Bazel and Tuist integrations enumerate inputs up front and ignore this parameter — list every Swift source via the build target itself instead. Default: `[]`. - `additionalMocksToGenerate`: Type names from dependent modules to generate `mock()` methods for in this module. The types must be `@Instantiable` in their home module. See [Cross-module mock generation](#cross-module-mock-generation). Default: `[]`. - `mockConditionalCompilation`: The conditional compilation flag to wrap generated mock code in (e.g. `"DEBUG"`). Set to `nil` to generate mocks without conditional compilation. Default: `"DEBUG"`. diff --git a/Sources/SafeDI/Decorators/SafeDIConfiguration.swift b/Sources/SafeDI/Decorators/SafeDIConfiguration.swift index 89b099bc..17e5264a 100644 --- a/Sources/SafeDI/Decorators/SafeDIConfiguration.swift +++ b/Sources/SafeDI/Decorators/SafeDIConfiguration.swift @@ -29,7 +29,7 @@ /// /// - Parameters: /// - additionalImportedModules: Module names to import in the generated dependency tree, in addition to the import statements found in files that declare `@Instantiable` types. -/// - additionalDirectoriesToInclude: Directories containing Swift files to include, relative to the executing directory. This property only applies to SafeDI repos that utilize the SPM plugin via an Xcode project. +/// - additionalDirectoriesToInclude: Directories containing Swift files to include, relative to the executing directory. Only supported when SafeDI runs via the SPM build-tool plugin in an Xcode project. The Bazel and Tuist integrations enumerate inputs up front and therefore cannot honor this parameter — list every Swift source via the build target itself instead. /// - additionalMocksToGenerate: Type names from dependent modules to generate `mock()` methods for in this module. The types must be decorated with `@Instantiable` in their home module. See the "Cross-module mock generation" section of the manual. /// - mockConditionalCompilation: The conditional compilation flag to wrap generated mock code in (e.g. `"DEBUG"`). Set to `nil` to generate mocks without conditional compilation. /// From 47c1377842d14c44aab1e8e8e8d8e6d222b4acf7 Mon Sep 17 00:00:00 2001 From: Dan Federman Date: Fri, 1 May 2026 21:58:43 -0700 Subject: [PATCH 2/3] Docs: drop incorrect "Xcode project" qualifier on additionalDirectoriesToInclude MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Earlier copy said the flag is "only honored by the SPM build-tool plugin running inside an Xcode project" — that's wrong. The flag is honored by the SPM build-tool plugin in any context (`swift build` on the CLI, Xcode building an SPM package, etc.). The relevant distinction is "SPM build-tool plugin" vs "different build system", not "Xcode" vs "not Xcode". Bazel and Tuist still don't honor it, since they invoke SafeDITool via their own input-enumeration models rather than going through the SPM plugin. --- Documentation/Manual.md | 4 ++-- Sources/SafeDI/Decorators/SafeDIConfiguration.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/Manual.md b/Documentation/Manual.md index 9c9c0497..afe05341 100644 --- a/Documentation/Manual.md +++ b/Documentation/Manual.md @@ -42,7 +42,7 @@ import SafeDI The `additionalDirectoriesToInclude` parameter specifies folders outside of your module that SafeDI will scan for Swift source files. Paths must be relative to the executing directory (the directory containing the `.xcodeproj` for Xcode integrations). Use this parameter to specify the paths to dependent modules’ source directories, since Xcode project plugins cannot discover these automatically. You can see [an example of this configuration](../Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration/SafeDIConfiguration.swift) in the [ExampleMultiProjectIntegration](../Examples/ExampleMultiProjectIntegration) project. -> **Note:** `additionalDirectoriesToInclude` is only honored by the SPM build-tool plugin running inside an Xcode project. The Bazel and Tuist integrations enumerate every input up front (Bazel via declared rule inputs; Tuist via the build phase's `inputPaths`), so files reached only through `additionalDirectoriesToInclude` won't be visible to SafeDITool at build time and won't trigger incremental rebuilds. Under those integrations, list every Swift source you want SafeDI to see directly via the build target. +> **Note:** `additionalDirectoriesToInclude` is only honored by the SPM build-tool plugin (i.e. `swift build` or Xcode building an SPM package). The Bazel and Tuist integrations enumerate every input up front (Bazel via declared rule inputs; Tuist via the build phase's `inputPaths`), so files reached only through `additionalDirectoriesToInclude` won't be visible to SafeDITool at build time and won't trigger incremental rebuilds. Under those integrations, list every Swift source you want SafeDI to see directly via the build target. ##### Installing the prebuilt SafeDITool binary @@ -441,7 +441,7 @@ public struct FeedView: Instantiable { **Parameters:** - `additionalImportedModules`: Module names to import in the generated dependency tree, in addition to the import statements found in files that declare `@Instantiable` types. Default: `[]`. -- `additionalDirectoriesToInclude`: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin in an Xcode project. The Bazel and Tuist integrations enumerate inputs up front and ignore this parameter — list every Swift source via the build target itself instead. Default: `[]`. +- `additionalDirectoriesToInclude`: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin (i.e. `swift build` or Xcode building an SPM package). The Bazel and Tuist integrations enumerate inputs up front and ignore this parameter — list every Swift source via the build target itself instead. Default: `[]`. - `additionalMocksToGenerate`: Type names from dependent modules to generate `mock()` methods for in this module. The types must be `@Instantiable` in their home module. See [Cross-module mock generation](#cross-module-mock-generation). Default: `[]`. - `mockConditionalCompilation`: The conditional compilation flag to wrap generated mock code in (e.g. `"DEBUG"`). Set to `nil` to generate mocks without conditional compilation. Default: `"DEBUG"`. diff --git a/Sources/SafeDI/Decorators/SafeDIConfiguration.swift b/Sources/SafeDI/Decorators/SafeDIConfiguration.swift index 17e5264a..9f18abf6 100644 --- a/Sources/SafeDI/Decorators/SafeDIConfiguration.swift +++ b/Sources/SafeDI/Decorators/SafeDIConfiguration.swift @@ -29,7 +29,7 @@ /// /// - Parameters: /// - additionalImportedModules: Module names to import in the generated dependency tree, in addition to the import statements found in files that declare `@Instantiable` types. -/// - additionalDirectoriesToInclude: Directories containing Swift files to include, relative to the executing directory. Only supported when SafeDI runs via the SPM build-tool plugin in an Xcode project. The Bazel and Tuist integrations enumerate inputs up front and therefore cannot honor this parameter — list every Swift source via the build target itself instead. +/// - additionalDirectoriesToInclude: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin (i.e. `swift build` or Xcode building an SPM package). The Bazel and Tuist integrations enumerate inputs up front and therefore ignore this parameter — list every Swift source via the build target itself instead. /// - additionalMocksToGenerate: Type names from dependent modules to generate `mock()` methods for in this module. The types must be decorated with `@Instantiable` in their home module. See the "Cross-module mock generation" section of the manual. /// - mockConditionalCompilation: The conditional compilation flag to wrap generated mock code in (e.g. `"DEBUG"`). Set to `nil` to generate mocks without conditional compilation. /// From 7b76925d9d2be65ffaf2ce574f02b1691d241dcc Mon Sep 17 00:00:00 2001 From: Dan Federman Date: Fri, 1 May 2026 21:59:44 -0700 Subject: [PATCH 3/3] Docs: drop unnecessary "i.e." parenthetical MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "the SPM build-tool plugin" already covers every context where the flag is honored — `swift build`, Xcode-of-an-SPM-package, and Xcode- of-an-Xcodeproj-with-an-SPM-dependency-via-the-plugin all route through the same plugin. The parenthetical was incomplete (omitted the third case) and noisy. --- Documentation/Manual.md | 4 ++-- Sources/SafeDI/Decorators/SafeDIConfiguration.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/Manual.md b/Documentation/Manual.md index afe05341..d05d328c 100644 --- a/Documentation/Manual.md +++ b/Documentation/Manual.md @@ -42,7 +42,7 @@ import SafeDI The `additionalDirectoriesToInclude` parameter specifies folders outside of your module that SafeDI will scan for Swift source files. Paths must be relative to the executing directory (the directory containing the `.xcodeproj` for Xcode integrations). Use this parameter to specify the paths to dependent modules’ source directories, since Xcode project plugins cannot discover these automatically. You can see [an example of this configuration](../Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration/SafeDIConfiguration.swift) in the [ExampleMultiProjectIntegration](../Examples/ExampleMultiProjectIntegration) project. -> **Note:** `additionalDirectoriesToInclude` is only honored by the SPM build-tool plugin (i.e. `swift build` or Xcode building an SPM package). The Bazel and Tuist integrations enumerate every input up front (Bazel via declared rule inputs; Tuist via the build phase's `inputPaths`), so files reached only through `additionalDirectoriesToInclude` won't be visible to SafeDITool at build time and won't trigger incremental rebuilds. Under those integrations, list every Swift source you want SafeDI to see directly via the build target. +> **Note:** `additionalDirectoriesToInclude` is only honored by the SPM build-tool plugin. The Bazel and Tuist integrations enumerate every input up front (Bazel via declared rule inputs; Tuist via the build phase's `inputPaths`), so files reached only through `additionalDirectoriesToInclude` won't be visible to SafeDITool at build time and won't trigger incremental rebuilds. Under those integrations, list every Swift source you want SafeDI to see directly via the build target. ##### Installing the prebuilt SafeDITool binary @@ -441,7 +441,7 @@ public struct FeedView: Instantiable { **Parameters:** - `additionalImportedModules`: Module names to import in the generated dependency tree, in addition to the import statements found in files that declare `@Instantiable` types. Default: `[]`. -- `additionalDirectoriesToInclude`: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin (i.e. `swift build` or Xcode building an SPM package). The Bazel and Tuist integrations enumerate inputs up front and ignore this parameter — list every Swift source via the build target itself instead. Default: `[]`. +- `additionalDirectoriesToInclude`: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin. The Bazel and Tuist integrations enumerate inputs up front and ignore this parameter — list every Swift source via the build target itself instead. Default: `[]`. - `additionalMocksToGenerate`: Type names from dependent modules to generate `mock()` methods for in this module. The types must be `@Instantiable` in their home module. See [Cross-module mock generation](#cross-module-mock-generation). Default: `[]`. - `mockConditionalCompilation`: The conditional compilation flag to wrap generated mock code in (e.g. `"DEBUG"`). Set to `nil` to generate mocks without conditional compilation. Default: `"DEBUG"`. diff --git a/Sources/SafeDI/Decorators/SafeDIConfiguration.swift b/Sources/SafeDI/Decorators/SafeDIConfiguration.swift index 9f18abf6..4db2d8c6 100644 --- a/Sources/SafeDI/Decorators/SafeDIConfiguration.swift +++ b/Sources/SafeDI/Decorators/SafeDIConfiguration.swift @@ -29,7 +29,7 @@ /// /// - Parameters: /// - additionalImportedModules: Module names to import in the generated dependency tree, in addition to the import statements found in files that declare `@Instantiable` types. -/// - additionalDirectoriesToInclude: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin (i.e. `swift build` or Xcode building an SPM package). The Bazel and Tuist integrations enumerate inputs up front and therefore ignore this parameter — list every Swift source via the build target itself instead. +/// - additionalDirectoriesToInclude: Directories containing Swift files to include, relative to the executing directory. Only honored by the SPM build-tool plugin. The Bazel and Tuist integrations enumerate inputs up front and therefore ignore this parameter — list every Swift source via the build target itself instead. /// - additionalMocksToGenerate: Type names from dependent modules to generate `mock()` methods for in this module. The types must be decorated with `@Instantiable` in their home module. See the "Cross-module mock generation" section of the manual. /// - mockConditionalCompilation: The conditional compilation flag to wrap generated mock code in (e.g. `"DEBUG"`). Set to `nil` to generate mocks without conditional compilation. ///