Repository navigation
Releases: nikolainobadi/NnFileKit
Release list
0.9.1
0.9.0
NnFileKit 0.9.0 adds Sendable requirements to its file system abstractions and synchronized state to its test doubles. This release includes breaking changes to deployment targets and public APIs.
Breaking changes and migration
- Deployment targets: The package previously declared no explicit platform minimums; it now requires macOS 15 or iOS 18. Raise consuming projects’ deployment targets accordingly.
- Custom conformers:
DirectoryandFileSystemnow inheritSendable. Update custom implementations to satisfy Swift’sSendablerequirements, including protecting mutable state where needed. - Test doubles:
MockDirectoryandMockFileSystemchanged from classes toSendablestructs. Replace class-only usage, such as identity comparisons and weak references, with assertions on exposed state. Copies share synchronized mutable state, so recorded calls and state changes remain visible through every copy; create a new mock when you need independent state. - File manager injection:
DefaultFileSystem(fileManager:)has been removed. Replace calls using the default manager withDefaultFileSystem(), which usesFileManager.default. If you depend on a custom file manager, provide a customFileSystemimplementation.
Concurrency support
Values typed as any Directory or any FileSystem can now cross concurrency boundaries. CopiedDirectory and CopiedFile also conform to Sendable, allowing recorded copy operations to be passed across those boundaries.
0.8.0
NnFileKit 0.8.0
This release adds copying, byte-level file comparison, and helpers for nested and absolute directory paths. It also makes named: parameters accept only a single path component. Code that passed nested paths through named:, code that implements Directory or FileSystem, and tests that use MockDirectory may need changes.
Breaking changes
New protocol requirements
Directory now requires copy(to:overwrite:), copyFile(named:to:overwrite:), and fileContentsEqual(named:in:). FileSystem now requires createDirectory(at:).
Who is affected: projects with their own types that conform to Directory or FileSystem. DefaultDirectory, DefaultFileSystem, and the NnFileTesting mocks already implement these methods.
Action: add the four methods to your conforming types.
named: parameters accept a single path component
Previously: a name containing /, such as subdirectory(named: "assets/images"), was appended to the directory's path, so the method reached the nested location.
Now: a name containing / makes throwing methods throw FileSystemError.invalidName, and makes containsFile(named:) and containsSubdirectory(named:) return false.
Action: switch nested lookups and creation to the relative-path methods:
// Before
let images = try directory.subdirectory(named: "assets/images")
// After
let images = try directory.subdirectory(atRelativePath: "assets/images")
let created = try directory.createSubdirectory(atRelativePath: "assets/images")For file operations such as readFile(named:) or createFile(named:contents:) on nested files, resolve the containing directory first, then pass only the file name.
New FileSystemError.invalidName case
FileSystemError has a new case. A switch over FileSystemError without a default clause will no longer compile.
Action: handle .invalidName(String) or add a default clause.
MockDirectory.createSubdirectory(named:) throws for existing names
Previously: the mock returned the existing subdirectory. Now: it throws, the same way DefaultDirectory does.
Action: tests that rely on get-or-create behavior should call createSubfolderIfNeeded(named:) instead.
Copying and comparing
copy(to:overwrite:)copies a directory, including nested contents and symlinks, into a parent directory under its own name. It returns the copy.copyFile(named:to:overwrite:)copies one file into another directory under the same name. It returns the new file's path.- In
DefaultDirectory, both methods throw if the destination already exists andoverwriteisfalse. Withoverwrite: true, the existing destination is deleted before the copy starts. That step is not atomic: if the copy fails afterward, the original destination is already gone. fileContentsEqual(named:in:)checks whether a file has the same bytes as the file with that name in another directory. Binary files work. It returnsfalseif the other directory doesn't have the file, and throwsFileSystemError.fileNotFoundif the receiving directory doesn't.
Nested and absolute paths
FileSystem.createDirectory(at:)returns the directory at an absolute path. If the directory or any parent is missing, it creates them first.Directory.subdirectory(atRelativePath:)opens a nested subdirectory.createSubdirectory(atRelativePath:)does the same but creates any missing folders along the way. Both throwFileSystemError.invalidNamefor a path that starts with/, and return the receiving directory when the path is empty.
Testing support
MockDirectory records directory copies in copiedToParents and file copies in copiedFiles, including the overwrite flag. Tests can assert on both. The mock doesn't enforce overwrite. When the destination is a MockDirectory, a successful copy also adds the copied item to it.
Full changelog: 0.7.0...0.8.0
0.7.0
NnFileKit 0.7.0
Testing-focused release. NnFileTesting's mocks gain error injection and write recording, and the NnFileKit skill now ships from this repo.
Added
throwErroronMockFileSystemandMockDirectory— one flag fails every throwing operation, for exercising error paths.fileContentsToReadonMockFileSystem— stubreadFile(at:)by absolute path, no directory wiring needed.writtenFilePath/writtenFileContentsonMockFileSystem— assert a write happened without configuring a directory.
Changed
⚠️ Breaking:MockDirectory(autoCreateSubdirectories:)now defaults tofalse.subdirectory(named:)throws for unknown names instead of synthesizing one, which keepscontainsSubdirectory(named:)honest. Passtrueto restore the old behavior.MockDirectory.createSubdirectory(named:)now registers the new subdirectory insubdirectories.
Fixed
NnFileKitTestswas missing itsNnFileTestingdependency, soswift testdid not compile. Adding it surfaced — and this release fixes — the mock gaps above.MockFileSystem.readFile(at:)throwsFileSystemError.fileNotFoundinstead of an opaqueNSError.
Upgrading
.package(url: "https://github.com/nikolainobadi/NnFileKit.git", from: "0.7.0")Tests relying on subdirectory(named:) always succeeding need autoCreateSubdirectories: true.
0.6.0
NnFileKit 0.6.0 Release Notes
NnConfigKit — a new module for type-safe JSON configuration management, built on NnFileKit's existing FileSystem and Directory protocols.
What's New
NnConfigManager<Config: Codable>— generic manager for loading, saving, and updating JSON config files at~/.config/NnConfigList/{projectName}/- Nested config file support — create, append, remove, and delete files within config directory hierarchies
- Fully testable — accepts an injected
FileSystem, works withMockFileSystem/MockDirectoryout of the box - Sendable — safe for Swift 6 strict concurrency
Quick Start
import NnConfigKit
struct AppConfig: Codable {
var theme: String
var maxRetries: Int
}
let manager = NnConfigManager<AppConfig>(projectName: "MyApp")
try manager.saveConfig(AppConfig(theme: "dark", maxRetries: 3))
let config = try manager.loadConfig()Installation
.product(name: "NnConfigKit", package: "NnFileKit")0.5.0
0.5.0
Initial release of NnFileKit.
Highlights
FileSystemandDirectoryprotocols for abstracting file system operationsDefaultFileSystemandDefaultDirectoryimplementations backed byFileManagerNnFileTestingmodule withMockFileSystemandMockDirectorytest doubles- Recursive file search with optional extension filtering
- Trash support, directory traversal, and file read/write operations
- Swift 6 strict concurrency support (
Sendableconformance)