Generate one output file per root @Instantiable#202
Draft
dfed wants to merge 19 commits intodfed/major-version-bumpfrom
Draft
Generate one output file per root @Instantiable#202dfed wants to merge 19 commits intodfed/major-version-bumpfrom
dfed wants to merge 19 commits intodfed/major-version-bumpfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dfed/major-version-bump #202 +/- ##
===========================================================
+ Coverage 99.88% 99.91% +0.03%
===========================================================
Files 36 37 +1
Lines 3452 3501 +49
===========================================================
+ Hits 3448 3498 +50
+ Misses 4 3 -1
🚀 New features to boost your workflow:
|
Replace --dependency-tree-output (single file) with --swift-output-directory
(directory). The build plugin uses regex to detect root types in source files
and declares one output file per root ({TypeName}+SafeDI.swift). The tool
writes per-root files with the same naming convention.
This improves incremental compilation: when one root's dependency tree changes,
only that root's generated file needs recompilation. Targets with no roots
produce no output files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce SafeDIToolManifest as the explicit contract between the plugin and SafeDITool. The manifest maps input file paths to output file paths, replacing the implicit naming convention where both sides independently computed filenames. The plugin now writes a JSON manifest and passes --swift-manifest to the tool. The tool validates the manifest against its parsed roots and writes to the specified output paths. This design scales to future output kinds (e.g. mock generation) without growing the CLI argument list, and uses relative paths for compatibility with remote build caches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add tests for both ManifestError cases: - Manifest lists a file that doesn't contain a root - Root exists in a file not listed in the manifest Also fix the empty-root test to expect a comment-only output file (matching the new behavior where manifest mode always writes output). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The regex was matching @INSTANTIABLE(isRoot: true) inside doc comment backtick-quoted code spans. Add a negative lookbehind for backtick to avoid matching inside markdown code references. Also rephrase SafeDIToolManifest doc comment to avoid containing the literal pattern that triggers false matches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Swift's Regex does not support lookbehind assertions, causing the previous regex to silently fail (try? returned nil). Instead, check that each match's line prefix doesn't contain '//' or '`' to filter out matches inside comments and doc comment code spans. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Test unexpected nodes with a root declared (covers errorContent write in manifest mode) - Test multiple roots in the same file (covers code combining path) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use Optional.map instead of guard-let-else-return-nil so the nil path is implicit in the optional chaining rather than an explicit branch that coverage tooling flags. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sourceFilePath is needed in .safedi cross-module files so the root module's tool invocation can match dependent module roots against the manifest. Remove unnecessary custom CodingKeys, ==, and hash. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Compute input file paths relative to the package/project root instead of using absolute paths. The tool's cwd is the package root (verified for both SPM and Xcode), so relative paths resolve correctly. Output paths remain absolute since they reference the build system's plugin work directory which is outside the project tree. This enables consistent cache keys across machines for build systems like Bazel and Buck that use remote caches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Provides concrete ordering and extensibility. Each entry is a struct with inputFilePath and outputFilePath, with doc comments explaining path semantics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No longer needed outside the module after removing the type-name-based output filename computation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GeneratedRoot.code now contains only the extension code, without the file header. The tool prepends the header once per output file when combining extensions. Previously each root's code included the header, causing duplication when multiple roots mapped to the same output. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No longer needed outside the module — fileHeader wraps it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ence - Test that running the tool twice with identical inputs does not rewrite the output file (verified via modification timestamp) - Test that --swift-manifest and --dot-file-output work together Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Disambiguate output filenames when multiple root files share the same base name (e.g. ModuleA/Root.swift and ModuleB/Root.swift now produce ModuleA_Root+SafeDI.swift and ModuleB_Root+SafeDI.swift). Sort extensions before joining when multiple roots share a source file, ensuring deterministic output regardless of task-group completion order. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2e474ed to
aeff016
Compare
The Xcode plugin variants (#if canImport(XcodeProjectPlugin)) were not updated when outputFileName was replaced with outputFileNames. Linux CI doesn't compile these blocks, so this went undetected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--dependency-tree-output(single file) with--swift-manifest(JSON manifest mapping input files to output files)@Instantiable(isRoot: true)root instead of a monolithicSafeDI.swiftSafeDIToolManifestCodable type as the explicit contract between plugin/build systems and the toolInputOutputMapstructs (not a dictionary) for concrete ordering and extensibilitysourceFilePathtoInstantiablefor tracking which file each root came fromMotivation
Test plan
swift test)./lint.sh)🤖 Generated with Claude Code