### Installation & Setup
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Instructions for installing FengNiao using different methods.
```bash
brew install mint
mint install onevcat/fengniao
```
```bash
git clone https://github.com/onevcat/fengniao.git
cd fengniao
swift build -c release
sudo cp .build/release/FengNiao /usr/local/bin/fengniao
```
```swift
// Package.swift
.package(url: "https://github.com/onevcat/fengniao.git", from: "0.13.0")
```
--------------------------------
### Check Configuration
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of checking FengNiao configuration in Swift.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods"],
resourceExtensions: ["png"],
searchInFileExtensions: ["swift"]
)
print("Scanning: \(scanner.projectPath)")
print("Excluded: \(scanner.excludedPaths)")
print("Resources: \(scanner.resourceExtensions)")
print("Files: \(scanner.searchInFileExtensions)")
```
--------------------------------
### Test with Single File Type
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of testing with a single resource and file type.
```swift
FengNiao(
projectPath: ".",
excludedPaths: ["Pods"],
resourceExtensions: ["png"], // Only PNG
searchInFileExtensions: ["swift"] // Only Swift
)
```
--------------------------------
### Minimal Configuration (Swift-Only)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of a minimal FengNiao configuration for Swift projects.
```swift
FengNiao(
projectPath: ".",
excludedPaths: ["Pods"],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"])
```
--------------------------------
### Maximum Configuration (All Formats)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of a maximum FengNiao configuration including all supported formats and extensive exclusions.
```swift
FengNiao(
projectPath: "/absolute/path/to/project",
excludedPaths: [
"Pods", "Carthage", "Vendor", ".build",
"DerivedData", ".git", "build", "node_modules"
],
resourceExtensions: [
"imageset", "launchimage", "appiconset",
"png", "jpg", "jpeg", "gif", "pdf", "webp"
],
searchInFileExtensions: [
"swift", "m", "mm", "h",
"xib", "storyboard", "plist"
])
```
--------------------------------
### Standard Configuration
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of a standard FengNiao configuration covering common file types.
```swift
FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg", "gif", "pdf"],
searchInFileExtensions: ["swift", "m", "mm", "h", "xib", "storyboard", "plist"])
```
--------------------------------
### Exclude Test Files
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of paths to exclude for test files and directories.
```swift
excludedPaths: ["Tests", "tests", "Specs", "specs"]
```
--------------------------------
### Legacy Objective-C Project
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example FengNiao configuration tailored for legacy Objective-C projects.
```swift
FengNiao(
projectPath: ".",
excludedPaths: ["Pods"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["m", "mm", "h", "xib", "storyboard"])
```
--------------------------------
### Validate Configuration
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of validating configuration by checking if resource and file extensions are specified.
```swift
let resourceExts = ["png"]
let fileExts = ["swift"]
guard !resourceExts.isEmpty else {
print("Error: Must specify resource extensions")
return
}
guard !fileExts.isEmpty else {
print("Error: Must specify file extensions")
return
}
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: resourceExts,
searchInFileExtensions: fileExts
)
```
--------------------------------
### --project, -p Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Examples of using the --project or -p option.
```bash
fengniao --project /path/to/MyProject
fengniao -p .
```
--------------------------------
### Full Example - Code and CLI Equivalent
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Example of a full configuration using both the Swift API and its CLI equivalent.
```swift
let scanner = FengNiao(
projectPath: "/path/to/MyApp",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["swift", "xib"]
)
```
```bash
fengniao --project /path/to/MyApp --exclude Pods Carthage --resource-extensions imageset png jpg --file-extensions swift xib
```
--------------------------------
### --force Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Example of using the --force option with --project.
```bash
fengniao --project . --force
```
--------------------------------
### Install with Mint
Source: https://github.com/onevcat/fengniao/blob/master/README.md
Instructions for installing FengNiao using Mint.
```bash
> brew install mint
> mint install onevcat/fengniao
```
--------------------------------
### Exclude Dependency Managers
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of paths to exclude for common dependency managers.
```swift
excludedPaths: ["Pods", "Carthage", "Vendor", "node_modules"]
```
--------------------------------
### Exclude Build Artifacts
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of paths to exclude for build artifacts.
```swift
excludedPaths: [".build", "build", "DerivedData", ".swift-build"]
```
--------------------------------
### Exclude Version Control
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of paths to exclude for version control directories.
```swift
excludedPaths: [".git", ".svn", ".hg"]
```
--------------------------------
### FileType Initialization Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/types.md
Example of initializing FileType.
```swift
if let type = FileType(ext: "swift") {
print(type) // .swift
}
```
--------------------------------
### --resource-extensions, -r Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Examples of using the --resource-extensions or -r option.
```bash
fengniao --resource-extensions imageset png jpg
fengniao -r png jpg
```
--------------------------------
### Command Line Usage
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Examples of using the FengNiao command-line interface.
```bash
# Find unused files
fengniao --list-only
# Delete with confirmation
fengniao --exclude Pods
# Automatic deletion
fengniao --force
```
--------------------------------
### Generate Asset Symbols
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Examples of generating asset symbols in Swift and Objective-C.
```swift
"ic_flag".generatedAssetSymbolKey // ".icFlag" (Swift)
```
```objective-c
"ic_flag".objcGeneratedAssetSymbolKey // "ACImageNameIcFlag" (Objective-C)
```
--------------------------------
### Convert to Camel Case
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of converting a string to camel case.
```swift
"my_image_name".generatedAssetSymbolPathComponent // "myImageName"
```
--------------------------------
### --file-extensions, -f Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Examples of using the --file-extensions or -f option.
```bash
fengniao --file-extensions swift m mm xib
fengniao -f swift
```
--------------------------------
### Code Usage for Project Path
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Code examples demonstrating how to specify the project path in Swift.
```swift
// Current directory
let scanner1 = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"])
// Absolute path
let scanner2 = FengNiao(
projectPath: "/Users/username/Projects/MyApp",
excludedPaths: ["Pods"],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"])
```
--------------------------------
### Prompting Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/command-prompt.md
Example demonstrating how to use the promptResult function in a CLI context, including handling repeated listing.
```swift
import FengNio
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods"],
resourceExtensions: ["png", "jpg"],
searchInFileExtensions: ["swift"]
)
let unusedFiles = try scanner.unusedFiles()
// Prompt the user for action
var result = promptResult(files: unusedFiles)
while result == .list {
// Display the list again if requested
for file in unusedFiles.sorted(by: { $0.size > $1.size }) {
print("\(file.readableSize) \(file.path.string)")
}
result = promptResult(files: unusedFiles)
}
switch result {
case .list:
fatalError() // Should not reach here due to while loop
case .delete:
let (deleted, _) = FengNiao.delete(unusedFiles)
print("Deleted \(deleted.count) files")
case .ignore:
print("Operation cancelled")
}
```
--------------------------------
### Pattern 1: Find Unused Resources (List Only)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
CLI and Swift examples for listing unused resources without deleting them.
```bash
fengniao --list-only
```
```swift
import FengNiaoKit
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"])
do {
let unused = try scanner.unusedFiles()
for file in unused {
print("\(file.readableSize) - \(file.path)")
}
} catch {
print("Error: \(error)")
}
```
--------------------------------
### String plainFileName Usage Examples
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/types.md
Examples of using the plainFileName extension.
```swift
"myImage.png".plainFileName(extensions: ["png"]) // "myImage"
"icon@2x.png".plainFileName(extensions: ["png"]) // "icon"
"logo@3x.jpg".plainFileName(extensions: ["jpg"]) // "logo"
"filename".plainFileName(extensions: ["png"]) // "filename"
```
--------------------------------
### Exclude Generated Code
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of paths to exclude for generated code directories.
```swift
excludedPaths: ["Generated", ".generated", "Codegen"]
```
--------------------------------
### Pattern 3: Automatic Deletion (CI/CD)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
CLI and Swift examples for automatically deleting unused resources, suitable for CI/CD pipelines.
```bash
fengniao --force --exclude Pods Carthage
```
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["swift", "xib"])
let unused = try scanner.unusedFiles()
let (deleted, failed) = FengNiao.delete(unused)
print("Deleted \(deleted.count) of \(unused.count) files")
```
--------------------------------
### CLI Usage for Project Path
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Command-line interface usage examples for specifying the project path.
```bash
# Current directory (default)
fengniao
# Explicit current directory
fengniao --project .
# Absolute path
fengniao --project /path/to/MyProject
# Relative path
fengniao --project ./MyProject
# Home directory
fengniao --project ~/Projects/MyProject
```
--------------------------------
### --skip-proj-reference Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Example of using --skip-proj-reference with --force.
```bash
fengniao --force --skip-proj-reference
```
--------------------------------
### String fullRange Usage Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/types.md
Example of using the fullRange extension.
```swift
let content = "image: myImage"
let regex = try NSRegularExpression(pattern: "myImage")
let matches = regex.matches(in: content, options: [], range: content.fullRange)
```
--------------------------------
### --list-only Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Examples of using the --list-only option, including piping to grep.
```bash
fengniao --list-only
fengniao --list-only | grep ".png"
```
--------------------------------
### Basic Scan Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Scans the current directory and prompts for action.
```bash
fengniao
```
--------------------------------
### Integration Examples: Basic Scanning
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example of basic resource scanning using the FengNiao library.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["swift", "xib"]
)
let unused = try scanner.unusedFiles()
print("Found \(unused.count) unused files")
```
--------------------------------
### Configuration Files
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying configuration files (plist) to search within.
```swift
searchInFileExtensions: ["plist"]
```
--------------------------------
### Pattern 2: Interactive Deletion
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
CLI and Swift examples for interactively deleting unused resources after excluding specified paths.
```bash
fengniao --exclude Pods Carthage
```
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"])
let unused = try scanner.unusedFiles()
let action = promptResult(files: unused)
if action == .delete {
let (deleted, failed) = FengNiao.delete(unused)
if failed.isEmpty {
print("✓ Deleted \(deleted.count) files")
} else {
print("⚠ \(failed.count) files failed to delete")
}
}
```
--------------------------------
### Handle Deletion Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of handling errors that may occur during the deletion of unused files.
```swift
let (deleted, failed) = FengNiao.delete(unusedFiles)
print("✓ Deleted: \(deleted.count)")
if !failed.isEmpty {
print("✗ Failed: \(failed.count)")
for (file, error) in failed {
print(" - \(file.fileName): \(error)")
}
}
```
--------------------------------
### All Image Formats
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying a comprehensive list of image file formats to scan.
```swift
resourceExtensions: ["imageset", "png", "jpg", "gif", "pdf", "webp"]
```
--------------------------------
### Normalize Filenames
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of using the `plainFileName` extension to normalize filenames by removing common suffixes like '@2x'.
```swift
"myImage.png".plainFileName(extensions: ["png"]) // "myImage"
"icon@2x.png".plainFileName(extensions: ["png"]) // "icon"
```
--------------------------------
### Permission Error Recovery
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of identifying and handling permission errors during file deletion.
```swift
let (deleted, failed) = FengNiao.delete(unusedFiles)
let permissionErrors = failed.filter { _, error in
guard let nsError = error as? NSError else { return false }
return nsError.code == NSFileWriteNoPermissionError
}
if !permissionErrors.isEmpty {
print("Some files require elevated permissions. Retry with sudo?")
}
```
--------------------------------
### FileInfo Struct Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example showing how to iterate through unused files and print their details.
```swift
for file in unusedFiles {
print("\(file.readableSize) \(file.fileName)")
}
```
--------------------------------
### List Only Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Lists all unused files of specified extensions without deleting.
```bash
fengniao --list-only --resource-extensions png jpg
```
--------------------------------
### Objective-C Only (Legacy)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying Objective-C files (m, mm, h) as the only files to search within.
```swift
searchInFileExtensions: ["m", "mm", "h"]
```
--------------------------------
### Interface Files
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying interface files (XIB, Storyboard) to search within.
```swift
searchInFileExtensions: ["xib", "storyboard"]
```
--------------------------------
### Member Access Patterns
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Examples of how UIImage and Image resources can be accessed in Swift.
```swift
UIImage(.flagIcon) // Constructor parameter
UIImage(resource: .flagIcon) // Named parameter
Image(.Settings.Logo) // Complex type usage
let r: ImageResource = .flagIcon // Type-inferred
ImageResource.flagIcon // Direct access (deprecated)
```
--------------------------------
### --exclude, -e Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Examples of using the --exclude or -e option with multiple paths.
```bash
fengniao --exclude Pods Carthage Vendor
fengniao -e Pods Carthage
```
--------------------------------
### Common Exclusions in Code
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Code example demonstrating common path exclusions in Swift.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage", "Vendor", "node_modules"],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"])
```
--------------------------------
### Custom Extensions Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Scans for multiple image formats and searches only in specified file types.
```bash
fengniao --resource-extensions imageset png jpg gif webp --file-extensions swift
```
--------------------------------
### CLI Usage for Exclusions
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Command-line interface usage examples for excluding paths.
```bash
# Single exclusion
fengniao --exclude Pods
# Multiple exclusions
fengniao --exclude Pods Carthage Vendor
# With short option
fengniao -e Pods Carthage
```
--------------------------------
### Swift Only (Modern)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying Swift files as the only files to search within.
```swift
searchInFileExtensions: ["swift"]
```
--------------------------------
### As a Command-Line Tool
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Examples of using the FengNiao command-line tool for various operations.
```bash
# Find unused resources
fengniao --list-only
# Delete with confirmation prompt
fengniao --exclude Pods Carthage
# Automatic deletion
fengniao --force --exclude Pods Carthage
# Xcode integration
fengniao --xcode-warnings --exclude Pods
```
--------------------------------
### ObjCMemberAccessSearchRule Example Match
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/search-rules.md
Provides an example of how ObjCMemberAccessSearchRule detects Objective-C generated symbols from resource names.
```objc
// From resource "my_image.png", detects:
UIImage *img = [UIImage imageNamed:ACImageNameMyImage];
```
--------------------------------
### Usage with arguments
Source: https://github.com/onevcat/fengniao/blob/master/README.md
Example of using FengNiao with project path and exclude arguments.
```shell
> fengniao --project . --exclude Carthage Pods
```
--------------------------------
### --xcode-warnings Output Format
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Example output format when using the --xcode-warnings option.
```text
/path/to/file.png: warning: Unused resource of size 256 KB
/path/to/icon.imageset: warning: Unused resource of size 512 KB
```
--------------------------------
### Integration Examples: With User Interaction
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example of integrating FengNiao with user interaction for listing and deleting unused files.
```swift
let unused = try scanner.unusedFiles()
var result = promptResult(files: unused)
while result == .list {
for file in unused.sorted(by: { $0.size > $1.size }) {
print("\(file.readableSize) - \(file.path)")
}
result = promptResult(files: unused)
}
if result == .delete {
let (deleted, failed) = FengNiao.delete(unused)
print("Deleted \(deleted.count) files")
}
```
--------------------------------
### Integration with Git
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Command to find unused files and stage them for deletion using Git.
```bash
# Find unused files and stage them for deletion
fengniao --list-only | awk '{print $NF}' | xargs git rm
```
--------------------------------
### Review Before Deletion
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Two-step process to first list files that would be deleted and then perform the actual deletion.
```bash
# First, list what would be deleted
fengniao --list-only --exclude Pods
# Then delete
fengniao --force --exclude Pods
```
--------------------------------
### Integration with FengNiao Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/fileinfo.md
Demonstrates how to use FileInfo with FengNiao for finding and deleting unused files.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["png", "jpg"],
searchInFileExtensions: ["swift"]
)
let unusedFiles = try scanner.unusedFiles()
let totalSize = unusedFiles.reduce(0) { $0 + $1.size }
print("Found \(unusedFiles.count) unused files totaling \(totalSize.fn_readableSize)")
for file in unusedFiles.sorted(by: { $0.size > $1.size }) {
print("\(file.readableSize.padded(width: 10)) - \(file.path)")
}
let (deleted, failed) = FengNiao.delete(unusedFiles)
```
--------------------------------
### Search Rules Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Illustrates how FengNiao detects resource usage in different file types.
```text
Swift: UIImage(named: "myImage") → detects "myImage"
Objective-C: @"myImage" or ACImageNameMyImage → detects "myImage"
XIB: → detects "myImage"
```
--------------------------------
### FengNio Struct Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example demonstrating the usage of the FengNio struct for scanning and deleting unused resources.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"]
)
do {
let unused = try scanner.unusedFiles()
print("Found \(unused.count) unused resources")
let (deleted, failed) = FengNiao.delete(unused)
print("Deleted \(deleted.count) files")
} catch FengNiaoError.noResourceExtension {
print("Must specify resource extensions")
}
```
--------------------------------
### Use --list-only Mode for Review
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/errors.md
Command-line examples showing how to first list potential unused files without deleting them, and then proceed with deletion after satisfaction.
```bash
# Review first
fengniao --list-only --exclude Pods
# Then delete if satisfied
fengniao --force --exclude Pods
```
--------------------------------
### --list-only Output Format
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Example output format when using the --list-only option.
```text
2.50 MB /path/to/large_image.png
1.20 MB /path/to/another_image.jpg
512 KB /path/to/small_icon.png
5 unused files are found. Total Size: 5.00 MB
```
--------------------------------
### Asset Catalog Only
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying only asset catalog files as resources to scan.
```swift
resourceExtensions: ["imageset"]
```
--------------------------------
### Update Project References
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Programmatic workflow to update project references after deleting unused files, specifically targeting .pbxproj files.
```swift
let (deleted, _) = FengNiao.delete(unusedFiles)
// Update .pbxproj file
if let projectPath = try? Path(".").children()
.first(where: { $0.lastComponent.hasSuffix("xcodeproj") }) {
let pbxprojPath = projectPath + "project.pbxproj"
FengNiao.deleteReference(projectFilePath: pbxprojPath, deletedFiles: deleted)
}
```
--------------------------------
### Override Resource Extensions in Code
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Code example demonstrating how to override default resource extensions in Swift.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["imageset", "png", "jpg", "webp"],
searchInFileExtensions: ["swift"])
```
--------------------------------
### FileInfo Initialization Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/fileinfo.md
Initializes a FileInfo struct from a file path string and prints its filename and readable size.
```swift
let fileInfo = FileInfo(path: "/path/to/unused_image.png")
print("File: \(fileInfo.fileName)")
print("Size: \(fileInfo.readableSize)")
```
--------------------------------
### Xcode Build Phase Script
Source: https://github.com/onevcat/fengniao/blob/master/README.md
Example script to integrate FengNiao into Xcode build phases.
```bash
fengniao --exclude Carthage --force
```
--------------------------------
### Library Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Example of handling specific FengNiao library errors.
```swift
do {
let unused = try scanner.unusedFiles()
} catch FengNiaoError.noResourceExtension {
// Handle missing resource extensions
} catch FengNiaoError.noFileExtension {
// Handle missing file extensions
} catch {
// Handle other errors (file system, etc.)
}
```
--------------------------------
### Validate Project Path
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Command to validate the project path.
```bash
fengniao --project /path/to/project --list-only
# If empty result, path may be wrong
```
--------------------------------
### Override File Extensions to Search in Code
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Code example demonstrating how to override default file extensions to search in Swift.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift", "xib", "storyboard", "plist"])
```
--------------------------------
### CLI Integration Loop
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/command-prompt.md
Example of the loop used in the CLI to allow repeated listing of unused files based on user prompts.
```swift
var result = promptResult(files: unusedFiles)
while result == .list {
for file in unusedFiles.sorted(by: { $0.size > $1.size }) {
print("\(file.readableSize) \(file.path.string)")
}
result = promptResult(files: unusedFiles)
}
```
--------------------------------
### Direct Image Files Only
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying only direct image files (PNG, JPG) as resources to scan.
```swift
resourceExtensions: ["png", "jpg"]
```
--------------------------------
### Scan with Exclusions Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Scans the current directory excluding specified folders.
```bash
fengniao --project . --exclude Pods Carthage
```
--------------------------------
### As a Library (FengNiaoKit)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example of using FengNiaoKit as a Swift library to scan and delete unused resources.
```swift
import FengNiaoKit
let scanner = FengNiao(
projectPath: "/path/to/MyApp",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["swift", "xib"]
)
let unusedFiles = try scanner.unusedFiles()
let (deleted, failed) = FengNiao.delete(unusedFiles)
```
--------------------------------
### Automatic Cleanup Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Automatically deletes unused files without confirmation.
```bash
fengniao --project . --force --exclude Pods
```
--------------------------------
### String Normalization Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/search-rules.md
Demonstrates the string normalization process applied by search rules, which includes stripping extensions, removing scale modifiers, and returning the base resource name.
```swift
"myImage.png" → "myImage"
"icon@2x.png" → "icon"
"buttonBackground@3x" → "buttonBackground"
```
--------------------------------
### Batch Processing Multiple Projects
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Programmatic workflow to process multiple projects, scanning and deleting unused files in each.
```swift
let projectPaths = [
"/path/to/Project1",
"/path/to/Project2",
"/path/to/Project3"
]
for projectPath in projectPaths {
let scanner = FengNiao(
projectPath: projectPath,
excludedPaths: ["Pods"],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"]
)
let unused = try scanner.unusedFiles()
let (deleted, _) = FengNiao.delete(unused)
print("\(projectPath): Deleted \(deleted.count) files")
}
```
--------------------------------
### Size Report
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Command to generate a report of the top 20 largest unused files.
```bash
fengniao --list-only | sort -k1 -rn | head -20
```
--------------------------------
### Handle Scan Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Example of handling potential errors during the file scanning process.
```swift
do {
let unused = try scanner.unusedFiles()
print("Found \(unused.count) unused files")
} catch FengNiaoError.noResourceExtension {
print("Error: No resource extensions specified")
} catch FengNiaoError.noFileExtension {
print("Error: No file extensions specified")
} catch {
print("Unexpected error: \(error.localizedDescription)")
}
```
--------------------------------
### Scan and Report
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Programmatic workflow to scan a project, report unused files, and display the total size and largest files.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods"],
resourceExtensions: ["imageset", "png"],
searchInFileExtensions: ["swift"]
)
let unused = try scanner.unusedFiles()
let totalSize = unused.reduce(0) { $0 + $1.size }
print("""\
Found \(unused.count) unused resources
Total size: \(totalSize.fn_readableSize)
Top 5 largest:
""")
unused.sorted(by: { $0.size > $1.size }).prefix(5).forEach { file in
print(" \(file.readableSize) - \(file.fileName)")
}
```
--------------------------------
### Mixed Languages
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Configuration snippet for specifying a mix of Swift and Objective-C files to search within.
```swift
searchInFileExtensions: ["swift", "m", "mm", "h"]
```
--------------------------------
### Pattern 5: Generate Xcode Warnings
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
CLI command to generate Xcode warnings for unused resources.
```bash
fengniao --xcode-warnings --exclude Pods
```
--------------------------------
### Xcode Integration Script
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
A bash script to integrate FengNiao into Xcode build phases, ensuring it's installed and running the cleanup command.
```bash
if which fengniao >/dev/null; then
fengniao --exclude Pods Carthage --force
else
echo "FengNiao not installed. Install via: brew install fengniao or mint install onevcat/fengniao"
fi
```
--------------------------------
### Pattern 4: Xcode Build Phase
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Bash script to integrate FengNiao into an Xcode build phase for automatic cleanup.
```bash
#!/bin/bash
if which fengniao >/dev/null; then
fengniao --force --exclude Pods Carthage || true
else
echo "warning: FengNiao not installed"
fi
```
--------------------------------
### Handling Path Resolution Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/errors.md
Example of how to catch and handle path resolution errors when initializing FengNiao.
```swift
let projectPath = "/invalid/path"
let scanner = FengNiao(
projectPath: projectPath,
excludedPaths: [],
resourceExtensions: ["png"],
searchInFileExtensions: ["swift"]
)
do {
let unused = try scanner.unusedFiles()
} catch {
print("Error scanning project: \(error)")
if let nsError = error as? NSError {
if nsError.code == NSFileNoSuchFileError {
print("Project directory does not exist: \(projectPath)")
}
}
}
```
--------------------------------
### Find Smallest Unused Files
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Swift code to filter and count unused files smaller than 100 KB.
```swift
let small = unused.filter { $0.size < 100_000 } // < 100 KB
print("Found \(small.count) small unused files")
```
--------------------------------
### Exit Code Usage in Scripts
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Example of how to use FengNiao's exit codes in a bash script to check for unused resources.
```bash
#!/bin/bash
fengniao --list-only
if [ $? -eq 0 ]; then
echo "No unused resources found"
else
echo "Unused resources detected"
fi
```
--------------------------------
### Handling CLI-Specific Errors (Exit Code 1)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/errors.md
Example of outputting Xcode-compatible warnings when unused resources are found and the --xcode-warnings flag is used.
```swift
if xcodeWarnings {
for file in unusedFiles.sorted(by: { $0.size > $1.size }) {
print("\(file.path.string): warning: Unused resource of size \(file.readableSize)")
}
throw ExitCode(Self.exitUnusedResources)
}
```
--------------------------------
### Compile from source
Source: https://github.com/onevcat/fengniao/blob/master/README.md
Instructions for compiling FengNiao from source.
```bash
> git clone https://github.com/onevcat/FengNiao.git
> cd FengNiao
> swift build -c release
# Then copy the executable to your PATH, such as `/usr/local/bin`
> sudo cp .build/release/FengNiao /usr/local/bin/fengniao
```
--------------------------------
### Using FengNiao CLI
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Command to invoke the FengNiao CLI tool.
```bash
fengniao [options]
```
--------------------------------
### Deletion Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Example of handling errors during file deletion.
```swift
let (deleted, failed) = FengNiao.delete(unusedFiles)
for (file, error) in failed {
print("Failed to delete \(file.fileName): \(error)")
}
```
--------------------------------
### Handling noFileExtension Error
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/types.md
Example of how to handle the noFileExtension error.
```swift
do {
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["png"],
searchInFileExtensions: [] // Empty!
)
let unused = try scanner.unusedFiles()
} catch FengNiaoError.noFileExtension {
print("Must specify file extensions to search in like 'swift', 'm', 'xib'")
} catch {
print("Other error: \(error)")
}
```
--------------------------------
### Handling noResourceExtension Error
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/types.md
Example of how to handle the noResourceExtension error.
```swift
do {
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: [], // Empty!
searchInFileExtensions: ["swift"]
)
let unused = try scanner.unusedFiles()
} catch FengNiaoError.noResourceExtension {
print("Must specify resource extensions like 'png', 'jpg', 'imageset'")
} catch {
print("Other error: \(error)")
}
```
--------------------------------
### FengNiaoError.noFileExtension How to Catch
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/errors.md
Example of how to catch the FengNiaoError.noFileExtension error when calling unusedFiles().
```swift
do {
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["png"],
searchInFileExtensions: [] // Empty!
)
let unused = try scanner.unusedFiles()
} catch FengNiaoError.noFileExtension {
print("Error: Must specify file extensions to search in")
print("Example: searchInFileExtensions: [\"swift\", \"m\", \"xib\"]")
} catch {
print("Unexpected error: (error)")
}
```
--------------------------------
### Comprehensive Initialization
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Comprehensive initialization of FengNiao with a wide range of paths and extensions.
```swift
FengNiao(
projectPath: "/path/to/project",
excludedPaths: ["Pods", "Carthage", "Vendor", ".build", "DerivedData"],
resourceExtensions: ["imageset", "png", "jpg", "gif", "pdf", "webp"],
searchInFileExtensions: ["swift", "m", "mm", "h", "xib", "storyboard", "plist"]
)
```
--------------------------------
### FengNiaoError.noResourceExtension How to Catch
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/errors.md
Example of how to catch the FengNiaoError.noResourceExtension error when calling unusedFiles().
```swift
do {
let scanner = FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: [], // Empty!
searchInFileExtensions: ["swift"]
)
let unused = try scanner.unusedFiles()
} catch FengNiaoError.noResourceExtension {
print("Error: Must specify resource file extensions")
print("Example: resourceExtensions: [\"png\", \"jpg\", \"imageset\"]")
} catch {
print("Unexpected error: (error)")
}
```
--------------------------------
### Error Handling: Deletion Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example of handling deletion errors.
```swift
let (deleted, failed) = FengNiao.delete(unusedFiles)
if !failed.isEmpty {
for (file, error) in failed {
print("Failed: \(file.fileName): \(error)")
}
}
```
--------------------------------
### Enable Verbose Output
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Command to enable verbose output for debugging.
```bash
# Show each file as it's being deleted
fengniao --list-only | head -20
```
--------------------------------
### Help Command
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Displays help message with all available options.
```bash
fengniao --help
fengniao -h
```
--------------------------------
### Minimal Configuration (Swift-only)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Configuration for Swift-only projects.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["swift"]
)
```
```bash
fengniao --exclude Pods Carthage --resource-extensions imageset png jpg --file-extensions swift
```
--------------------------------
### Full Configuration
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Comprehensive scanning configuration.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage", "Vendor", ".build", "DerivedData"],
resourceExtensions: ["imageset", "png", "jpg", "gif", "pdf", "webp"],
searchInFileExtensions: ["swift", "m", "mm", "h", "xib", "storyboard", "plist"]
)
```
```bash
fengniao \
--exclude Pods Carthage Vendor .build DerivedData \
--resource-extensions imageset png jpg gif pdf webp \
--file-extensions swift m mm h xib storyboard plist
```
--------------------------------
### Integrated with Xcode Build Phase
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example of integrating FengNiao into an Xcode build phase.
```bash
fengniao --force --exclude Pods Carthage
```
--------------------------------
### --project, -p Option Syntax
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Syntax for specifying the project path using --project or -p.
```bash
fengniao --project
fengniao -p
```
--------------------------------
### Import FengNiaoKit
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Import statement for using FengNiaoKit.
```swift
import FengNiaoKit
// Now available:
// - FengNiao
// - FileInfo
// - FengNiaoError
// - Action
// - promptResult(files:)
// - String extensions
// - Int extensions
```
--------------------------------
### Error Handling: Library Errors
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Example of handling library errors using do-catch blocks.
```swift
do {
let unused = try scanner.unusedFiles()
} catch FengNiaoError.noResourceExtension {
print("Must specify resource extensions")
} catch FengNiaoError.noFileExtension {
print("Must specify file extensions")
} catch {
print("Unexpected error: \(error)")
}
```
--------------------------------
### Version Command
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Prints the version number of FengNiao.
```bash
fengniao --version
```
--------------------------------
### CLI Options
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/README.md
Command-line interface options for FengNiao.
```bash
fengniao [OPTIONS]
--project PATH Project root directory (default: .)
--exclude PATH ... Paths to exclude
--resource-extensions EXT ... File extensions to search for (default: imageset jpg png gif pdf)
--file-extensions EXT ... File extensions to search in (default: h m mm swift xib storyboard plist)
--force Delete without confirmation
--list-only List unused files and exit
--xcode-warnings Output as Xcode warnings
--skip-proj-reference Don't update .pbxproj file
--version Show version
--help Show help
```
--------------------------------
### Legacy Objective-C Project Configuration
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Configuration for projects with Objective-C code.
```swift
let scanner = FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["m", "mm", "h", "xib", "storyboard"]
)
```
```bash
fengniao \
--exclude Pods Carthage \
--resource-extensions imageset png jpg \
--file-extensions m mm h xib storyboard
```
--------------------------------
### --resource-extensions, -r Option Syntax
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Syntax for specifying resource file extensions using --resource-extensions or -r.
```bash
fengniao --resource-extensions ...
fengniao -r ...
```
--------------------------------
### FileInfo ReadableSize Property Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/fileinfo.md
Prints the human-readable representation of a file's size.
```swift
let fileInfo = FileInfo(path: "/path/to/image.png")
print(fileInfo.readableSize) // "2.50 MB" or "512 KB"
// Formatting rules:
// - Files under 1000 bytes: "N B"
// - 1000 - 999,999 bytes: "X.XX KB"
// - 1,000,000 - 999,999,999 bytes: "X.XX MB"
// - 1,000,000,000+ bytes: "X.XX GB"
```
--------------------------------
### File Extensions to Search (Default)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Default file extensions to search within by FengNiao CLI when not specified.
```swift
["h", "m", "mm", "swift", "xib", "storyboard", "plist"]
```
--------------------------------
### FengNiao Constructor Signature
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
The primary way to configure FengNio is through the initializer of the `FengNiao` struct.
```swift
public init(projectPath: String,
excludedPaths: [String],
resourceExtensions: [String],
searchInFileExtensions: [String])
```
--------------------------------
### Conditional Deletion
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Programmatic workflow to delete unused files only if they exceed a certain size threshold.
```swift
let unused = try scanner.unusedFiles()
let largeFiles = unused.filter { $0.size > 5_000_000 } // > 5 MB
if largeFiles.isEmpty {
print("No large unused files found")
} else {
print("Found \(largeFiles.count) large unused files")
let (deleted, _) = FengNiao.delete(largeFiles)
print("Deleted \(deleted.count) files, freed \((deleted.reduce(0) { $0 + $1.size }).fn_readableSize)")
}
```
--------------------------------
### Calculate Total Unused Size
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/quick-reference.md
Swift code to calculate the total size of all unused files.
```swift
let totalSize = unused.reduce(0) { $0 + $1.size }
print("Total unused space: \(totalSize.fn_readableSize)")
```
--------------------------------
### Minimal Initialization
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Basic initialization of the FengNiao class with essential parameters.
```swift
FengNiao(
projectPath: ".",
excludedPaths: [],
resourceExtensions: ["imageset"],
searchInFileExtensions: ["swift"]
)
```
--------------------------------
### FileInfo FileName Property Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/fileinfo.md
Retrieves and prints the filename component of a given file path.
```swift
let fileInfo = FileInfo(path: "/path/to/unused_image.png")
print(fileInfo.fileName) // "unused_image.png"
```
--------------------------------
### --xcode-warnings Option Syntax
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/cli.md
Syntax for using the --xcode-warnings option.
```bash
fengniao --xcode-warnings
```
--------------------------------
### FileInfo Size Property Example
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/fileinfo.md
Checks if a file is larger than 1MB and prints its size in bytes.
```swift
let fileInfo = FileInfo(path: "/path/to/image.png")
if fileInfo.size > 1_000_000 {
print("Large file: \(fileInfo.size) bytes")
}
```
--------------------------------
### CLI Command Structure
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
The general structure of the FengNiao command-line interface command.
```bash
fengniao [OPTIONS]
```
--------------------------------
### Standard Initialization
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/api-reference/overview.md
Standard initialization of FengNiao with common exclusions and extensions.
```swift
FengNiao(
projectPath: ".",
excludedPaths: ["Pods", "Carthage"],
resourceExtensions: ["imageset", "png", "jpg"],
searchInFileExtensions: ["swift", "xib", "storyboard"]
)
```
--------------------------------
### Resource Extensions (Default)
Source: https://github.com/onevcat/fengniao/blob/master/_autodocs/configuration.md
Default resource extensions used by FengNiao CLI when not specified.
```swift
["imageset", "jpg", "png", "gif", "pdf"]
```