### 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"] ```