Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
c1c0f16
Add mock generation for @Instantiable types
dfed Apr 1, 2026
c587910
Fix CI: deduplicate mocks, update configs, fix lint
dfed Apr 1, 2026
3cd7a0e
Disable mock gen for Xcode example projects
dfed Apr 1, 2026
11ca4d0
Add SafeDIConfiguration to ExampleProjectIntegration xcodeproj
dfed Apr 1, 2026
38d8ced
Remove dead code in MockGenerator to improve coverage
dfed Apr 1, 2026
bc29734
Rewrite tests with full output, add #Preview, handle non-@Instantiabl…
dfed Apr 1, 2026
d444825
Fix non-@Instantiable mock params: use non-optional closures
dfed Apr 1, 2026
b466954
Handle erasedToConcreteExistential in mock generation
dfed Apr 1, 2026
f824b93
Auto-wrap erased types for received deps, simplify #Previews, improve…
dfed Apr 1, 2026
4694d4f
Fix swiftformat: indent #Preview inside #if DEBUG
dfed Apr 1, 2026
608feb8
Fix erased type mocks: only expose @Received/@Instantiated params
dfed Apr 1, 2026
62ba557
Add comprehensive mock generation tests for complex configurations
dfed Apr 1, 2026
0e6ad45
Revert multi-project #Preview to manual construction
dfed Apr 1, 2026
55e8775
Disable mocks for multi-project example
dfed Apr 1, 2026
34a266e
Achieve 100% coverage on all new lines
dfed Apr 1, 2026
afa2fbb
Add Instantiator<T> mock support to MockGenerator
dfed Apr 1, 2026
c85877d
Add Instantiator mock generation tests
dfed Apr 1, 2026
a334b89
Default generateMocks to false when no @SafeDIConfiguration exists
dfed Apr 1, 2026
2ac283d
Document additionalDirectoriesToInclude mock limitation
dfed Apr 1, 2026
7e05fbd
Add multiple-forwarded-properties test, remove dead code, update docs
dfed Apr 1, 2026
8c3e50d
Restore guards instead of force unwraps in MockGenerator
dfed Apr 1, 2026
4f0cdff
Add edge case coverage tests for MockGenerator
dfed Apr 1, 2026
5ae3325
Add SafeDIGenerator plugin to Subproject target for per-module mocks
dfed Apr 1, 2026
9cc69c3
Improve additionalDirectoriesToInclude comment for clarity
dfed Apr 1, 2026
c9b36b7
Convert all contains assertions to exact == output comparisons
dfed Apr 1, 2026
316f949
Remove unreachable Instantiator !hasKnownMock branch
dfed Apr 1, 2026
ecf1998
Achieve 0 uncovered lines in MockGenerator
dfed Apr 1, 2026
4ca755d
Simplify mock file writing, fix nil-CC double-optional bug
dfed Apr 1, 2026
9e3c999
Remove all force unwraps from MockGenerator
dfed Apr 1, 2026
68d6bea
Apply suggestion from @dfed
dfed Apr 1, 2026
36c66df
Assert all mock files and counts, remove dead else branch
dfed Apr 1, 2026
5f7caf4
Add comprehensive mock tests for all code gen patterns
dfed Apr 1, 2026
9b4f4aa
Fix inline construction to thread all deps, sanitize type identifiers
dfed Apr 1, 2026
a2865d1
Add enumName conflict disambiguation
dfed Apr 1, 2026
038a4ed
Fix entry key collision and test disambiguation
dfed Apr 1, 2026
2191351
Fix test expectations after entry key change, convert disambiguation …
dfed Apr 1, 2026
dd2a1b7
Skip mock generation for types with existing static func mock()
dfed Apr 1, 2026
6186e8f
Fix aliased dep threading, detect class func mock, improve naming
dfed Apr 1, 2026
d28ca48
Fix topo sort to respect aliased dep ordering
dfed Apr 1, 2026
0d99083
Nest Instantiator defaults inside enclosing builder closures when needed
dfed Apr 1, 2026
9032e08
Always inline-construct deps instead of calling .mock()
dfed Apr 1, 2026
c57ec08
lint
dfed Apr 1, 2026
ee5dc28
Bubble up unresolved received deps as mock parameters
dfed Apr 1, 2026
e7e0d47
Fix extension instantiate, nesting for mockable forwarded types, sani…
dfed Apr 1, 2026
159f7de
Fix extension mockAttributes, recursive inline construction, bubble-u…
dfed Apr 1, 2026
d6f0fb8
Nest constant entries in builder closures, resolve deps via fulfillin…
dfed Apr 1, 2026
ec7a0c9
Wrap Instantiator deps in closures during recursive inline construction
dfed Apr 1, 2026
23c21ee
Fix @Sendable closure spacing in generated mock code
dfed Apr 1, 2026
e3f6aac
Add cycle detection, fix fulfilling type resolution, fix test expecta…
dfed Apr 1, 2026
a94dc5b
Add failing tests for known mock generation issues
dfed Apr 2, 2026
efd1b95
Rewrite mock generation to reuse ScopeGenerator's recursive tree
dfed Apr 2, 2026
db28e6a
Add parameter label disambiguation, path extension, and onlyIfAvailab…
dfed Apr 2, 2026
aa69814
Build mock trees with received deps as children, thread transitive deps
dfed Apr 2, 2026
6b324b6
Fix onlyIfAvailable handling: skip promotion, pass nil, compute unava…
dfed Apr 2, 2026
cb1bf07
Include fulfillingAdditionalTypes in constructedTypes for mock tree
dfed Apr 2, 2026
041b71a
Add required parameters for non-@Instantiable received dependencies
dfed Apr 2, 2026
8c258be
Replace abbreviations with full words in mock generation code
dfed Apr 2, 2026
2d95469
Thread onlyIfAvailable dependencies as optional mock parameters
dfed Apr 2, 2026
10e9b6f
Fix onlyIfAvailable return statement using variable instead of nil
dfed Apr 2, 2026
d610c48
Mark mock parameter closures @Sendable when captured by @Sendable fun…
dfed Apr 2, 2026
fdf5d3c
Skip non-reachable types in mock tree, make them required parameters
dfed Apr 2, 2026
7a7127a
Fix Instantiator sourceType and same-type different-label parameters
dfed Apr 2, 2026
2fd5197
Remove knownInstantiableTypes filter, trust typeDescriptionToFulfilli…
dfed Apr 2, 2026
26161c6
Resolve concrete existential wrappers via erasure map, remove knownIn…
dfed Apr 2, 2026
0bd8917
Remove dead code: unused instantiable accessor and requiredParameterL…
dfed Apr 2, 2026
2f6819a
Use production Scope tree for mock generation instead of custom tree …
dfed Apr 2, 2026
c0bb317
Promote received dependencies at root scope only, not on child scopes
dfed Apr 2, 2026
a2d5bf9
Use receivedProperties to determine unsatisfied dependencies for mock…
dfed Apr 2, 2026
6034b46
Iteratively promote transitive received dependencies at mock root
dfed Apr 2, 2026
d4badb2
Use ScopeGenerator.receivedProperties for mock root promotion (2-buil…
dfed Apr 2, 2026
0bc7f79
Add debug output messages to all 137 mock test assertions
dfed Apr 2, 2026
514b60b
Audit and correct LoggedInViewController and StringStorage test expec…
dfed Apr 2, 2026
c6ef978
Audit and correct mock test expectations (Phase 2 in progress)
dfed Apr 2, 2026
9c48e64
Fix onlyIfAvailable defaults, forwarded collisions, and iterative pro…
dfed Apr 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions Documentation/Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,91 @@ public struct ParentView: View, Instantiable {
}
```

## Mock generation

SafeDI can automatically generate `mock()` methods for every `@Instantiable` type, drastically simplifying testing and SwiftUI previews. Mock generation is enabled by default and controlled via `@SafeDIConfiguration`.

### Configuration

```swift
@SafeDIConfiguration
enum MyConfiguration {
static let additionalImportedModules: [StaticString] = []
static let additionalDirectoriesToInclude: [StaticString] = []
static let generateMocks: Bool = true
static let mockConditionalCompilation: StaticString? = "DEBUG"
}
```

- `generateMocks`: Set to `false` to disable mock generation entirely.
- `mockConditionalCompilation`: The `#if` flag wrapping generated mocks. Default is `"DEBUG"`. Set to `nil` to generate mocks without conditional compilation.

### Using generated mocks

Each `@Instantiable` type gets a `mock()` static method that builds its full dependency subtree. If the decorated type declaration already contains a `static func mock(...)` or `class func mock(...)` method, SafeDI will not generate one — your hand-written mock takes precedence. Note that mocks defined in separate extensions are not detected; the method must be in the `@Instantiable`-decorated declaration body.

```swift
#if DEBUG
#Preview {
MyView.mock()
}
#endif
```

Every dependency in the tree can be overridden via optional closure parameters:

```swift
let view = MyView.mock(
sharedThing: { _ in CustomSharedThing() }
)
```

### Path enums

Each `@Instantiable` type with dependencies gets a `SafeDIMockPath` enum containing nested enums per dependency type. These describe where in the tree each dependency is created:

- `case parent` — the dependency is received from the parent scope
- `case root` — the dependency is created at the top level of the mock
- `case childA` — the dependency is created for the `childA` property

This lets you differentiate when the same type is instantiated at multiple tree locations:

```swift
let root = Root.mock(
cache: { path in
switch path {
case .childA_cache: return Cache(size: 100)
case .childB_cache: return Cache(size: 200)
}
}
)
```

### @Forwarded properties in mocks

`@Forwarded` properties become required parameters on the mock method (no default value), since they represent runtime input:

```swift
let noteView = NoteView.mock(userName: "Preview User")
```

### The `mockAttributes` parameter

When a type's initializer is bound to a global actor that the plugin cannot detect (e.g. inherited `@MainActor`), use `mockAttributes` to annotate the generated mock:

```swift
@Instantiable(mockAttributes: "@MainActor")
public final class MyPresenter: Instantiable { ... }
```

### Multi-module mock generation

To generate mocks for non-root modules, add the `SafeDIGenerator` plugin to all first-party targets in your `Package.swift`. Each module's mocks are scoped to its own types to avoid duplicates.

Each module that generates mocks must have its own `@SafeDIConfiguration` with `generateMocks: true`. When no configuration exists, mock generation is disabled by default.

**Note:** Mock generation only creates mocks for types defined in the current module. Types from dependent modules or `additionalDirectoriesToInclude` are not mocked — each module must have its own `SafeDIGenerator` plugin to generate mocks for its types.

## Comparing SafeDI and Manual Injection: Key Differences

SafeDI is designed to be simple to adopt and minimize architectural changes required to get the benefits of a compile-time safe DI system. Despite this design goal, there are a few key differences between projects that utilize SafeDI and projects that don’t. As the benefits of this system are clearly outlined in the [Features](../README.md#features) section above, this section outlines the pattern changes required to utilize a DI system like SafeDI.
Expand Down
15 changes: 15 additions & 0 deletions Examples/Example Package Integration/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIGenerator", package: "SafeDI"),
],
),
.target(
name: "ChildBModule",
Expand All @@ -63,6 +66,9 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIGenerator", package: "SafeDI"),
],
),
.target(
name: "ChildCModule",
Expand All @@ -74,6 +80,9 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIGenerator", package: "SafeDI"),
],
),
.target(
name: "GrandchildrenModule",
Expand All @@ -84,13 +93,19 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIGenerator", package: "SafeDI"),
],
),
.target(
name: "SharedModule",
dependencies: ["SafeDI"],
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIGenerator", package: "SafeDI"),
],
),
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
3289B4082BF955720053F2E4 /* Subproject.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3289B4012BF955710053F2E4 /* Subproject.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3289B40D2BF955A10053F2E4 /* StringStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ECC2B314DB20001AC0C /* StringStorage.swift */; };
3289B40F2BF955A10053F2E4 /* UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324F1ECA2B314D8D0001AC0C /* UserService.swift */; };
BB000003BBBBBBBB00000001 /* SafeDIConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB000004BBBBBBBB00000001 /* SafeDIConfiguration.swift */; };
32B72E192D39763900F5EB6F /* SafeDI in Frameworks */ = {isa = PBXBuildFile; productRef = 32B72E182D39763900F5EB6F /* SafeDI */; };
32B72E1B2D39764200F5EB6F /* SafeDI in Frameworks */ = {isa = PBXBuildFile; productRef = 32B72E1A2D39764200F5EB6F /* SafeDI */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -47,9 +48,9 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
324F1EBF2B314E030001AC0C /* SafeDIConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeDIConfiguration.swift; sourceTree = "<group>"; };
324F1ECA2B314D8D0001AC0C /* UserService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserService.swift; sourceTree = "<group>"; };
324F1ECC2B314DB20001AC0C /* StringStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringStorage.swift; sourceTree = "<group>"; };
324F1EBF2B314E030001AC0C /* SafeDIConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeDIConfiguration.swift; sourceTree = "<group>"; };
324F1ECE2B314E030001AC0C /* NameEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameEntryView.swift; sourceTree = "<group>"; };
324F1ED12B3150480001AC0C /* NoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteView.swift; sourceTree = "<group>"; };
32756FE22B24C042006BDD24 /* ExampleMultiProjectIntegration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleMultiProjectIntegration.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -59,6 +60,7 @@
32756FED2B24C044006BDD24 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
3289B4012BF955710053F2E4 /* Subproject.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Subproject.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3289B4032BF955720053F2E4 /* Subproject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Subproject.h; sourceTree = "<group>"; };
BB000004BBBBBBBB00000001 /* SafeDIConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeDIConfiguration.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -134,6 +136,7 @@
3289B4022BF955720053F2E4 /* Subproject */ = {
isa = PBXGroup;
children = (
BB000004BBBBBBBB00000001 /* SafeDIConfiguration.swift */,
324F1ECA2B314D8D0001AC0C /* UserService.swift */,
324F1ECC2B314DB20001AC0C /* StringStorage.swift */,
3289B4032BF955720053F2E4 /* Subproject.h */,
Expand Down Expand Up @@ -197,6 +200,7 @@
buildRules = (
);
dependencies = (
BB000001BBBBBBBB00000001 /* PBXTargetDependency */,
);
name = Subproject;
packageProductDependencies = (
Expand Down Expand Up @@ -281,6 +285,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BB000003BBBBBBBB00000001 /* SafeDIConfiguration.swift in Sources */,
3289B40D2BF955A10053F2E4 /* StringStorage.swift in Sources */,
3289B40F2BF955A10053F2E4 /* UserService.swift in Sources */,
);
Expand All @@ -298,6 +303,10 @@
isa = PBXTargetDependency;
productRef = 32B72E1C2D39765B00F5EB6F /* SafeDIGenerator */;
};
BB000001BBBBBBBB00000001 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
productRef = BB000002BBBBBBBB00000001 /* SafeDIGenerator */;
};
/* End PBXTargetDependency section */

/* Begin XCBuildConfiguration section */
Expand Down Expand Up @@ -629,6 +638,11 @@
package = 32B72E172D39763900F5EB6F /* XCLocalSwiftPackageReference "../../../SafeDI" */;
productName = "plugin:SafeDIGenerator";
};
BB000002BBBBBBBB00000001 /* SafeDIGenerator */ = {
isa = XCSwiftPackageProductDependency;
package = 32B72E172D39763900F5EB6F /* XCLocalSwiftPackageReference "../../../SafeDI" */;
productName = "plugin:SafeDIGenerator";
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 32756FDA2B24C042006BDD24 /* Project object */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,13 @@ enum ExampleSafeDIConfiguration {

/// 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.
/// Needed for DI tree generation even though Subproject has its own plugin for mock generation.
static let additionalDirectoriesToInclude: [StaticString] = ["Subproject"]

/// Whether to generate `mock()` methods for `@Instantiable` types.
static let generateMocks: Bool = true

/// The conditional compilation flag to wrap generated mock code in.
/// Set to `nil` to generate mocks without conditional compilation.
static let mockConditionalCompilation: StaticString? = "DEBUG"
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public struct NameEntryView: Instantiable, View {
@Received private let userService: AnyUserService
}

#Preview {
NameEntryView(userService: .init(DefaultUserService(stringStorage: UserDefaults.standard)))
}
#if DEBUG
#Preview {
NameEntryView.mock()
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,8 @@ public struct NoteView: Instantiable, View {
@State private var note: String = ""
}

#Preview {
NoteView(
userName: "dfed",
userService: .init(DefaultUserService(stringStorage: UserDefaults.standard)),
stringStorage: UserDefaults.standard,
)
}
#if DEBUG
#Preview {
NoteView.mock(userName: "dfed")
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Distributed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import SafeDI

@SafeDIConfiguration
enum SubprojectSafeDIConfiguration {
/// The names of modules to import in the generated dependency tree.
static let additionalImportedModules: [StaticString] = []

/// Directories containing Swift files to include, relative to the executing directory.
static let additionalDirectoriesToInclude: [StaticString] = []

/// Whether to generate `mock()` methods for `@Instantiable` types.
static let generateMocks: Bool = true

/// The conditional compilation flag to wrap generated mock code in.
static let mockConditionalCompilation: StaticString? = "DEBUG"
}
15 changes: 15 additions & 0 deletions Examples/ExamplePrebuiltPackageIntegration/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIPrebuiltGenerator", package: "SafeDI"),
],
),
.target(
name: "ChildBModule",
Expand All @@ -63,6 +66,9 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIPrebuiltGenerator", package: "SafeDI"),
],
),
.target(
name: "ChildCModule",
Expand All @@ -74,6 +80,9 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIPrebuiltGenerator", package: "SafeDI"),
],
),
.target(
name: "GrandchildrenModule",
Expand All @@ -84,13 +93,19 @@ let package = Package(
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIPrebuiltGenerator", package: "SafeDI"),
],
),
.target(
name: "SharedModule",
dependencies: ["SafeDI"],
swiftSettings: [
.swiftLanguageMode(.v6),
],
plugins: [
.plugin(name: "SafeDIPrebuiltGenerator", package: "SafeDI"),
],
),
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
32756FE62B24C042006BDD24 /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32756FE52B24C042006BDD24 /* ExampleApp.swift */; };
32756FEA2B24C044006BDD24 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32756FE92B24C044006BDD24 /* Assets.xcassets */; };
32756FEE2B24C044006BDD24 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32756FED2B24C044006BDD24 /* Preview Assets.xcassets */; };
AA000001AAAAAAAA00000001 /* SafeDIConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA000002AAAAAAAA00000001 /* SafeDIConfiguration.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -27,6 +28,7 @@
32756FE92B24C044006BDD24 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
32756FEB2B24C044006BDD24 /* ExampleProjectIntegration.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ExampleProjectIntegration.entitlements; sourceTree = "<group>"; };
32756FED2B24C044006BDD24 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
AA000002AAAAAAAA00000001 /* SafeDIConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeDIConfiguration.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -82,6 +84,7 @@
children = (
324F1EDA2B315AB20001AC0C /* Views */,
324F1EDC2B315ABB0001AC0C /* Models */,
AA000002AAAAAAAA00000001 /* SafeDIConfiguration.swift */,
32756FE92B24C044006BDD24 /* Assets.xcassets */,
32756FEB2B24C044006BDD24 /* ExampleProjectIntegration.entitlements */,
32756FEC2B24C044006BDD24 /* Preview Content */,
Expand Down Expand Up @@ -186,6 +189,7 @@
32756FE62B24C042006BDD24 /* ExampleApp.swift in Sources */,
324F1ECD2B314DB20001AC0C /* StringStorage.swift in Sources */,
324F1ECB2B314D8D0001AC0C /* UserService.swift in Sources */,
AA000001AAAAAAAA00000001 /* SafeDIConfiguration.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Loading
Loading