Repository: mac-cain13/R.swift Branch: main Commit: f0a0d5316861 Files: 385 Total size: 890.5 KB Directory structure: gitextract_98a7l1sm/ ├── .github/ │ └── workflows/ │ ├── checks.yml │ └── release.yml ├── .gitignore ├── Documentation/ │ ├── Contribute.md │ ├── Examples.md │ ├── Ignoring.md │ ├── Migration.md │ ├── QandA.md │ └── Readme.md ├── Examples/ │ ├── FileSystemSynchronized/ │ │ ├── FileSystemSynchronized.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── MainUI/ │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── hand.ignoreme.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ └── MyStoryboard.storyboard │ │ │ ├── ContentView.swift │ │ │ ├── Info.plist │ │ │ ├── MainUI.entitlements │ │ │ ├── MainUIApp.swift │ │ │ ├── Preview Content/ │ │ │ │ └── Preview Assets.xcassets/ │ │ │ │ └── Contents.json │ │ │ ├── View.xib │ │ │ └── nl.lproj/ │ │ │ └── MyStoryboard.strings │ │ └── TheAppClip/ │ │ ├── ClipAssets.xcassets/ │ │ │ ├── Contents.json │ │ │ └── MyColor.colorset/ │ │ │ └── Contents.json │ │ ├── ContentView.swift │ │ ├── Group1/ │ │ │ ├── Base.lproj/ │ │ │ │ └── MySiriIntents.intentdefinition │ │ │ ├── Folder1/ │ │ │ │ └── .gitkeep │ │ │ └── nl.lproj/ │ │ │ └── MySiriIntents.strings │ │ ├── Info.plist │ │ ├── Preview Content/ │ │ │ └── Preview Assets.xcassets/ │ │ │ └── Contents.json │ │ ├── TheAppClip.entitlements │ │ ├── TheAppClipApp.swift │ │ ├── en.lproj/ │ │ │ └── Localizable.strings │ │ └── nl.lproj/ │ │ └── Localizable.strings │ ├── LocalizedStringApp/ │ │ ├── LocalizedStringApp/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj/ │ │ │ │ ├── eight.strings │ │ │ │ └── nine.strings │ │ │ ├── Info.plist │ │ │ ├── ca.lproj/ │ │ │ │ └── four.strings │ │ │ ├── en-GB.lproj/ │ │ │ │ └── five.strings │ │ │ ├── en.lproj/ │ │ │ │ ├── MyStoryboard.storyboard │ │ │ │ ├── five.strings │ │ │ │ ├── nine.strings │ │ │ │ ├── seven.strings │ │ │ │ ├── three.strings │ │ │ │ └── two.strings │ │ │ ├── fr-CA.lproj/ │ │ │ │ ├── five.strings │ │ │ │ └── six.strings │ │ │ ├── fr.lproj/ │ │ │ │ ├── eight.strings │ │ │ │ ├── five.strings │ │ │ │ ├── nine.strings │ │ │ │ ├── seven.strings │ │ │ │ ├── six.strings │ │ │ │ └── ten.stringsdict │ │ │ ├── nl.lproj/ │ │ │ │ ├── eight.strings │ │ │ │ ├── four.strings │ │ │ │ ├── nine.strings │ │ │ │ ├── seven.strings │ │ │ │ ├── ten.stringsdict │ │ │ │ └── three.strings │ │ │ └── one.strings │ │ ├── LocalizedStringApp.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm/ │ │ │ │ └── Package.resolved │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── LocalizedStringApp Dutch.xcscheme │ │ │ ├── LocalizedStringApp English (GB).xcscheme │ │ │ ├── LocalizedStringApp English.xcscheme │ │ │ ├── LocalizedStringApp French (Canada).xcscheme │ │ │ ├── LocalizedStringApp French.xcscheme │ │ │ ├── LocalizedStringApp Turkish.xcscheme │ │ │ └── LocalizedStringApp.xcscheme │ │ └── LocalizedStringAppTests/ │ │ ├── Info.plist │ │ └── LocalizedStringAppTests.swift │ ├── ResourceApp/ │ │ ├── .rswiftignore │ │ ├── Podfile │ │ ├── ResourceApp/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.xib │ │ │ │ ├── Main.storyboard │ │ │ │ └── Secondary.storyboard │ │ │ ├── CellCollectionView.xib │ │ │ ├── CellView.xib │ │ │ ├── CustomSegue.swift │ │ │ ├── Duplicate/ │ │ │ │ ├── ADuplicateCellView.xib │ │ │ │ ├── duplicate.storyboard │ │ │ │ └── duplicate.xib │ │ │ ├── Duplicate.storyboard │ │ │ ├── Duplicate.xib │ │ │ ├── DuplicateCellView.xib │ │ │ ├── Files/ │ │ │ │ ├── #column │ │ │ │ ├── Duplicate.json │ │ │ │ ├── Some.json │ │ │ │ ├── __FILE__ │ │ │ │ ├── associatedtype │ │ │ │ └── duplicateJson │ │ │ ├── FirstViewController.swift │ │ │ ├── Images/ │ │ │ │ └── Sky.tiff │ │ │ ├── Images.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── My Red.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Namespace/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Second.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── first.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Second.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Some Folder/ │ │ │ │ │ ├── A Nested Folder/ │ │ │ │ │ │ ├── first nested.imageset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── second nested.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── eerste.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── second.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── TheAppIcon.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── first.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Images2.xcassets/ │ │ │ │ ├── Conflicting.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Namespace 1/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Inner/ │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ └── Namespace 2/ │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ └── Folder/ │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ └── first.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Second.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── third.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Namespace-/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Inner/ │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ └── Namespace/ │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ └── Folder/ │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ └── first.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Second.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── third.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── conflicting/ │ │ │ │ ├── Contents.json │ │ │ │ └── first.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── Localized/ │ │ │ │ ├── Base.lproj/ │ │ │ │ │ └── hello.txt │ │ │ │ ├── es.lproj/ │ │ │ │ │ └── hello.txt │ │ │ │ └── nl.lproj/ │ │ │ │ └── hello.txt │ │ │ ├── Media.xcassets/ │ │ │ │ ├── Contents.json │ │ │ │ ├── Folder/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── Not dupe.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Keyboard Focus Indicator color.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── My Red.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Not dupe.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── Slightly transparant.colorset/ │ │ │ │ └── Contents.json │ │ │ ├── My View.xib │ │ │ ├── MyViewController.swift │ │ │ ├── References.storyboard │ │ │ ├── Relative To Project/ │ │ │ │ └── RelativeToProject.xib │ │ │ ├── SceneDelegate.swift │ │ │ ├── SecondViewController.swift │ │ │ ├── SegueIdentifiers.storyboard │ │ │ ├── Settings.bundle/ │ │ │ │ ├── Root.plist │ │ │ │ └── en.lproj/ │ │ │ │ └── Root.strings │ │ │ ├── Specials.storyboard │ │ │ ├── Strings/ │ │ │ │ ├── @@.strings │ │ │ │ ├── Base.lproj/ │ │ │ │ │ ├── Settings.strings │ │ │ │ │ └── Settings.stringsdict │ │ │ │ ├── Duplicate#.strings │ │ │ │ ├── Duplicate.strings │ │ │ │ ├── Generic.strings │ │ │ │ ├── Generic.stringsdict │ │ │ │ ├── en.lproj/ │ │ │ │ │ └── Localizable.strings │ │ │ │ ├── es.lproj/ │ │ │ │ │ └── Localizable.strings │ │ │ │ ├── ja.lproj/ │ │ │ │ │ └── Localizable.strings │ │ │ │ └── nl.lproj/ │ │ │ │ ├── Settings.strings │ │ │ │ └── Settings.stringsdict │ │ │ ├── SupplementaryElement.xib │ │ │ ├── TabBarItem.storyboard │ │ │ ├── WhitespaceReuseIdentifer.xib │ │ │ └── Xib with ViewController.xib │ │ ├── ResourceApp.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm/ │ │ │ │ └── Package.resolved │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ └── ResourceApp.xcscheme │ │ ├── ResourceApp.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── swiftpm/ │ │ │ └── Package.resolved │ │ └── ResourceAppTests/ │ │ ├── FilesTests.swift │ │ ├── FontsTests.swift │ │ ├── IgnoreTests.swift │ │ ├── Info.plist │ │ ├── InfoPlistTests.swift │ │ ├── NibTests.swift │ │ ├── ResourceAppTests.swift │ │ ├── SegueTests.swift │ │ ├── StoryboardTests.swift │ │ ├── StringsTests.swift │ │ └── ValidationTests.swift │ ├── RswiftAppWithStaticFrameworks/ │ │ ├── App/ │ │ │ ├── Info.plist │ │ │ ├── Resources/ │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ ├── AccentColor.colorset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ └── Sources/ │ │ │ ├── AppDelegate.swift │ │ │ ├── SceneDelegate.swift │ │ │ └── ViewController.swift │ │ ├── AppTests/ │ │ │ └── AppTests.swift │ │ ├── Bar/ │ │ │ ├── Info.plist │ │ │ └── Sources/ │ │ │ └── Bar.swift │ │ ├── Foo/ │ │ │ ├── Info.plist │ │ │ └── Sources/ │ │ │ └── Foo.swift │ │ ├── RswiftAppWithStaticFrameworks.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm/ │ │ │ │ └── Package.resolved │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── App.xcscheme │ │ │ ├── Bar.xcscheme │ │ │ └── Foo.xcscheme │ │ └── copy_bundles.sh │ ├── RswiftUI/ │ │ ├── RswiftUI/ │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── hand.ignoreme.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── ContentView.swift │ │ │ ├── Info.plist │ │ │ ├── Preview Content/ │ │ │ │ └── Preview Assets.xcassets/ │ │ │ │ └── Contents.json │ │ │ └── RswiftUIApp.swift │ │ ├── RswiftUI.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── swiftpm/ │ │ │ └── Package.resolved │ │ └── RswiftUIAppClip/ │ │ ├── ClipAssets.xcassets/ │ │ │ ├── Contents.json │ │ │ └── MyColor.colorset/ │ │ │ └── Contents.json │ │ ├── ContentView.swift │ │ ├── Info.plist │ │ ├── Preview Content/ │ │ │ └── Preview Assets.xcassets/ │ │ │ └── Contents.json │ │ ├── RswiftUIAppClip.entitlements │ │ └── RswiftUIAppClipApp.swift │ ├── RtvApp/ │ │ ├── .rswiftignore │ │ ├── ResourceApp-tvOS/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── Brand Assets.brandassets/ │ │ │ │ │ ├── App Icon - Large.imagestack/ │ │ │ │ │ │ ├── Back.imagestacklayer/ │ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ ├── Front.imagestacklayer/ │ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Middle.imagestacklayer/ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── App Icon - Small.imagestack/ │ │ │ │ │ │ ├── Back.imagestacklayer/ │ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ ├── Contents.json │ │ │ │ │ │ ├── Front.imagestacklayer/ │ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Middle.imagestacklayer/ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Top Shelf Image Wide.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Top Shelf Image.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── BrightWhite.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── ImageStackAsset.imagestack/ │ │ │ │ │ ├── Back.imagestacklayer/ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Front.imagestacklayer/ │ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Middle.imagestacklayer/ │ │ │ │ │ ├── Content.imageset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.launchimage/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ └── Main.storyboard │ │ │ └── Info.plist │ │ ├── ResourceAppTests-tvOS/ │ │ │ ├── ImageTests.swift │ │ │ ├── Info.plist │ │ │ └── ValidationTests.swift │ │ └── RtvApp.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── swiftpm/ │ │ │ └── Package.resolved │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ ├── ResourceApp-tvOS.xcscheme │ │ └── ResourceAppTests-tvOS.xcscheme │ └── RwatchApp/ │ ├── .rswiftignore │ ├── ResourceApp-watchOS/ │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ └── Interface.storyboard │ │ └── Info.plist │ ├── ResourceApp-watchOS-Extension/ │ │ ├── Assets.xcassets/ │ │ │ ├── Complication.complicationset/ │ │ │ │ ├── Circular.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Extra Large.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Graphic Bezel.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Graphic Circular.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Graphic Corner.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Graphic Extra Large.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Graphic Large Rectangular.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Modular.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── Utilitarian.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── MyColor.colorset/ │ │ │ │ └── Contents.json │ │ │ └── hand.ignoreme.imageset/ │ │ │ └── Contents.json │ │ ├── ExtensionDelegate.swift │ │ ├── Info.plist │ │ ├── InterfaceController.swift │ │ ├── NotificationController.swift │ │ ├── PushNotificationPayload.apns │ │ └── Strings/ │ │ ├── en.lproj/ │ │ │ └── Localizable.strings │ │ ├── es.lproj/ │ │ │ └── Localizable.strings │ │ └── ja.lproj/ │ │ └── Localizable.strings │ └── RwatchApp.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm/ │ │ └── Package.resolved │ └── xcshareddata/ │ └── xcschemes/ │ ├── ResourceApp-watchOS (Notification).xcscheme │ └── ResourceApp-watchOS.xcscheme ├── License ├── Package.resolved ├── Package.swift ├── Plugins/ │ ├── RswiftGenerateInternalResources/ │ │ └── RswiftGenerateInternalResources.swift │ ├── RswiftGeneratePublicResources/ │ │ └── RswiftGeneratePublicResources.swift │ ├── RswiftGenerateResourcesCommand/ │ │ └── RswiftGenerateResourcesCommand.swift │ └── RswiftModifyXcodePackages/ │ └── RswiftModifyXcodePackages.swift ├── R.swift.podspec ├── README.md ├── Sources/ │ ├── RswiftGenerators/ │ │ ├── AccessibilityIdentifier+Generator.swift │ │ ├── AssetCatalog+Generator.swift │ │ ├── Extensions/ │ │ │ ├── Array+Extensions.swift │ │ │ └── String+Extensions.swift │ │ ├── FileResource+Generator.swift │ │ ├── FontResource+Generator.swift │ │ ├── Nib+Generator.swift │ │ ├── PropertyListResource+Generator.swift │ │ ├── ReuseIdentifier+Generator.swift │ │ ├── Segue+Generator.swift │ │ ├── Shared/ │ │ │ ├── AssetCatalogMergedNamespaces.swift │ │ │ ├── LocaleReference+Generator.swift │ │ │ ├── SwiftIdentifier.swift │ │ │ └── TypeReference+Generator.swift │ │ ├── Storyboard+Generator.swift │ │ ├── StringsTable+Generator.swift │ │ ├── SwiftSyntax/ │ │ │ ├── Struct.swift │ │ │ └── StructMembersBuilder.swift │ │ └── XcodeProject+Generator.swift │ ├── RswiftParsers/ │ │ ├── ProjectResources.swift │ │ ├── Resources/ │ │ │ ├── AssetCatalog+Parser.swift │ │ │ ├── FileResource+Parser.swift │ │ │ ├── FontResource+Parser.swift │ │ │ ├── ImageResource+Parser.swift │ │ │ ├── Nib+Parser.swift │ │ │ ├── PropertyList+Parser.swift │ │ │ ├── Storyboard+Parser.swift │ │ │ └── StringsTable+Parser.swift │ │ └── Shared/ │ │ ├── Bundle+Extensions.swift │ │ ├── DeploymentTarget+Parser.swift │ │ ├── FormatPart+Extensions.swift │ │ ├── GeneratedId.swift │ │ ├── Glob.swift │ │ ├── IgnoreFile.swift │ │ ├── ResourceParsingError.swift │ │ ├── SourceTreeURLs.swift │ │ ├── SupportedExtensions.swift │ │ ├── TypeReference+Extensions.swift │ │ ├── URL+Extensions.swift │ │ └── Xcodeproj.swift │ ├── RswiftResources/ │ │ ├── AssetCatalog.swift │ │ ├── ColorResource.swift │ │ ├── DataResource.swift │ │ ├── FileResource.swift │ │ ├── FontResource.swift │ │ ├── ImageResource.swift │ │ ├── Integrations/ │ │ │ ├── Bundle+Extensions.swift │ │ │ ├── ColorResource+Integrations.swift │ │ │ ├── DataResource+Integrations.swift │ │ │ ├── FileResource+Integrations.swift │ │ │ ├── FontResource+Integrations.swift │ │ │ ├── ImageResource+Integrations.swift │ │ │ ├── NibReference+Integrations.swift │ │ │ ├── ReuseIdentifier+Integrations.swift │ │ │ ├── SegueIdentifier+Integrations.swift │ │ │ ├── StoryboardReference+Integrations.swift │ │ │ └── StringResource+Integrations.swift │ │ ├── NibResource.swift │ │ ├── PropertyListResource.swift │ │ ├── Shared/ │ │ │ ├── DeploymentTarget.swift │ │ │ ├── LocaleReference.swift │ │ │ ├── ModuleReference.swift │ │ │ ├── NameCatalog.swift │ │ │ ├── Reusable.swift │ │ │ ├── StoryboardReference.swift │ │ │ ├── StringParam+Extensions.swift │ │ │ ├── StringParam.swift │ │ │ ├── StringsTable.swift │ │ │ ├── TypeReference.swift │ │ │ ├── Unifiable.swift │ │ │ └── ValidationError.swift │ │ ├── StoryboardResource.swift │ │ └── StringResource.swift │ └── rswift/ │ ├── App.swift │ ├── Config.swift │ └── RswiftCore.swift └── Tests/ ├── RswiftGeneratorsTests/ │ └── MainTests.swift └── RswiftParsersTests/ ├── GlobTests.swift └── NibParserDelegateTests.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/checks.yml ================================================ name: Checks on: push: branches: [ main ] pull_request: branches: '*' env: DEVELOPER_DIR: /Applications/Xcode-16.0.0.app/Contents/Developer jobs: unit-tests: runs-on: self-hosted steps: - name: Checkout uses: actions/checkout@v4 - name: Pull cache uses: actions/cache@v4 with: path: .build key: ${{ runner.os }}spm${{ hashFiles('**/Package.resolved') }} restore-keys: | ${{ runner.os }}spm - name: Test run: swift test -v test-iOS-ResourceApp: runs-on: self-hosted needs: build-rswift steps: - name: Checkout uses: actions/checkout@v4 - name: Download build uses: actions/download-artifact@v4.1.7 with: name: rswift-dev path: rswift-dev - name: Put build into place run: | mkdir -p .build/release mv rswift-dev/rswift .build/release/rswift chmod +x .build/release/rswift - name: Pull cache uses: actions/cache@v4 id: podcache-ios with: path: Examples/ResourceApp/Pods key: ${{ runner.os }}pods${{ hashFiles('**/Podfile.lock') }} restore-keys: | ${{ runner.os }}pods - name: Install pods if: steps.podcache-ios.outputs.cache-hit != 'true' run: pod install --project-directory=Examples/ResourceApp - name: Test #run: fastlane scan --workspace "Examples/ResourceApp/ResourceApp.xcworkspace" --scheme "ResourceApp" run: xcodebuild -workspace Examples/ResourceApp/ResourceApp.xcworkspace -scheme ResourceApp -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.0' test test-iOS-StaticFrameworks: runs-on: self-hosted needs: build-rswift steps: - name: Checkout uses: actions/checkout@v4 - name: Download build uses: actions/download-artifact@v4.1.7 with: name: rswift-dev path: rswift-dev - name: Put build into place run: | mkdir -p .build/release mv rswift-dev/rswift .build/release/rswift chmod +x .build/release/rswift - name: Test #run: fastlane scan --project "Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj" --scheme "App" run: xcodebuild -project Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj -scheme App -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.0' test test-iOS-LocalizedStringApp: runs-on: self-hosted needs: build-rswift steps: - name: Checkout uses: actions/checkout@v4 - name: Download build uses: actions/download-artifact@v4.1.7 with: name: rswift-dev path: rswift-dev - name: Put build into place run: | mkdir -p .build/release mv rswift-dev/rswift .build/release/rswift chmod +x .build/release/rswift - name: Test run: xcodebuild -project Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj -scheme LocalizedStringApp -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.0' test test-tvOS: runs-on: self-hosted needs: build-rswift steps: - name: Checkout uses: actions/checkout@v4 - name: Download build uses: actions/download-artifact@v4.1.7 with: name: rswift-dev path: rswift-dev - name: Put build into place run: | mkdir -p .build/release mv rswift-dev/rswift .build/release/rswift chmod +x .build/release/rswift - name: Test #run: fastlane scan --project "Examples/RtvApp/RtvApp.xcodeproj" --scheme "ResourceApp-tvOS" run: xcodebuild -project Examples/RtvApp/RtvApp.xcodeproj -scheme ResourceApp-tvOS -destination 'platform=tvOS Simulator,name=Apple TV,OS=18.0' test build-rswift: runs-on: self-hosted steps: - name: Checkout uses: actions/checkout@v4 - name: Pull cache uses: actions/cache@v4 with: path: .build key: ${{ runner.os }}spm${{ hashFiles('**/Package.resolved') }} restore-keys: | ${{ runner.os }}spm - name: Set version run: | sed -i "" "s/\(static let version = \"\)Unknown\(\"\)/\1Development build: ${GITHUB_SHA}\2/" Sources/rswift/Config.swift - name: Build run: swift build -v -c release - name: Store artifact uses: actions/upload-artifact@v4 with: name: rswift-dev path: .build/release/rswift ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: release: types: created env: DEVELOPER_DIR: /Applications/Xcode-16.0.0.app/Contents/Developer jobs: release-build: runs-on: self-hosted steps: - name: Checkout uses: actions/checkout@v4 - name: Set version run: | sed -i "" "s/\(static let version = \"\).*\(\"\)/\1${TAG}\2/" Sources/rswift/Config.swift env: TAG: ${{ github.event.release.tag_name }} - name: Tarball source run: | tar -zcvf $TARGET --exclude .git . env: TARGET: ${{ runner.temp }}/source.tar.gz - name: Attach tarball to release uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ${{ runner.temp }}/source.tar.gz asset_name: rswift-${{ github.event.release.tag_name }}-source.tar.gz asset_content_type: application/tar+gzip - name: Build universal binary run: | swift build -c release --arch x86_64 --arch arm64 - name: Delete temp keychain from previous run run: | /usr/bin/security delete-keychain signing_temp.keychain || true - name: Import Signing Certificates uses: apple-actions/import-codesign-certs@v3 with: p12-file-base64: ${{ secrets.APPLE_CERTIFICATES }} p12-password: ${{ secrets.APPLE_CERTIFICATES_PASSWORD }} - name: Code Sign run: | codesign --force --options runtime --sign "$IDENTITY" .build/apple/Products/Release/rswift env: IDENTITY: 'Developer ID Application: Nonstrict B.V. (WT5N9FK54M)' - name: Store build artifact uses: actions/upload-artifact@v4 with: name: rswift-${{ github.event.release.tag_name }} path: .build/apple/Products/Release/rswift - name: Archive ZIP run: zip --junk-paths $FILENAME .build/apple/Products/Release/rswift License && zip --recurse-paths $FILENAME Sources/RswiftResources env: FILENAME: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.zip - name: Notarize ZIP run: | xcrun notarytool submit $FILENAME --apple-id $APPLE_ID --password $APP_PASSWORD --team-id $TEAM_ID --wait env: BUNDLE_ID: com.nonstrict.rswift APPLE_ID: ${{ secrets.APPLE_IDENTIFIER }} APP_PASSWORD: ${{ secrets.APPLE_IDENTIFIER_PASSWORD }} TEAM_ID: WT5N9FK54M FILENAME: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.zip - name: Attach ZIP to release uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.zip asset_name: rswift-${{ github.event.release.tag_name }}.zip asset_content_type: application/zip - name: Make artifact bundle run: | set -ex mkdir -p $ARTIFACT_BUNDLE_DIR/rswift/bin cp .build/apple/Products/Release/rswift $ARTIFACT_BUNDLE_DIR/rswift/bin cp License $ARTIFACT_BUNDLE_DIR/rswift cat < $ARTIFACT_BUNDLE_DIR/info.json { "schemaVersion": "1.0", "artifacts": { "rswift": { "type": "executable", "version": "$VERSION", "variants": [ { "path": "rswift/bin/rswift", "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] }, ] } } } EOF pushd $ARTIFACT_BUNDLE_DIR zip -r $FILENAME . popd env: VERSION: ${{ github.event.release.tag_name }} ARTIFACT_BUNDLE_DIR: ${{ runner.temp }}/rswift.artifactbundle FILENAME: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.artifactbundle.zip - name: Notarize artifact bundle run: | xcrun notarytool submit $FILENAME --apple-id $APPLE_ID --password $APP_PASSWORD --team-id $TEAM_ID --wait env: BUNDLE_ID: com.nonstrict.rswift APPLE_ID: ${{ secrets.APPLE_IDENTIFIER }} APP_PASSWORD: ${{ secrets.APPLE_IDENTIFIER_PASSWORD }} TEAM_ID: WT5N9FK54M FILENAME: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.artifactbundle.zip - name: Attach artifact bundle to release uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.artifactbundle.zip asset_name: rswift-${{ github.event.release.tag_name }}.artifactbundle.zip asset_content_type: application/zip - name: Archive PKG run: | mkdir -p $PKG_ROOT/$BINARY_ROOT cp .build/apple/Products/Release/rswift $PKG_ROOT/$BINARY_ROOT pkgbuild --root $PKG_ROOT --identifier $BUNDLE_ID --version $TAG_NAME --install-location "/" --sign "$IDENTITY" $FILENAME env: TAG_NAME: ${{ github.event.release.tag_name }} FILENAME: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.pkg BUNDLE_ID: com.nonstrict.rswift IDENTITY: 'Developer ID Installer: Nonstrict B.V. (WT5N9FK54M)' PKG_ROOT: ${{ runner.temp }}/pkgroot BINARY_ROOT: /usr/local/bin - name: Notarize PKG run: | xcrun notarytool submit $FILENAME --apple-id $APPLE_ID --password $APP_PASSWORD --team-id $TEAM_ID --wait xcrun stapler staple $FILENAME env: BUNDLE_ID: com.nonstrict.rswift APPLE_ID: ${{ secrets.APPLE_IDENTIFIER }} APP_PASSWORD: ${{ secrets.APPLE_IDENTIFIER_PASSWORD }} TEAM_ID: WT5N9FK54M FILENAME: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.pkg - name: Attach PKG to release uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ${{ runner.temp }}/rswift-${{ github.event.release.tag_name }}.pkg asset_name: rswift-${{ github.event.release.tag_name }}.pkg asset_content_type: application/pkg - name: Delete temp keychain from this run if: always() run: | /usr/bin/security delete-keychain signing_temp.keychain || true - name: Publish to Cocoapods run: | export POD_VERSION=$TAG_NAME pod trunk push --allow-warnings env: TAG_NAME: ${{ github.event.release.tag_name }} COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} ================================================ FILE: .gitignore ================================================ .DS_Store xcuserdata DerivedData Pods *.xccheckout *.generated.swift fastlane/test_output fastlane/README.md fastlane/report.xml fastlane/settoken.sh build .build .swiftpm rswift.xcarchive rswift.xcodeproj rswift.log rswift-tv.log rswift-watchos.log ================================================ FILE: Documentation/Contribute.md ================================================ # Thank you! Thank you for taking some of your precious time helping this project move forward. Really great that you're showing interest in contributing. You don't have to be an expert to help us, every small tweak, crazy idea and/or bugreport is highly appreciated! # Contributing ## Questions, issues and ideas Most important is to read the docs and scan the issue tracker before so you're sure your question/idea/bugreport isn't already answered/in the make/being fixed: - [Read the Readme](/README.md) - [Read the other documentation](/Documentation) - [Check open pull requests](https://github.com/mac-cain13/R.swift/pulls) - [Search the issue tracker](https://github.com/mac-cain13/R.swift/issues) If you find your idea/bugreport feel free to comment with an emoji or text reaction to let us know that you'd like this to be implemented. Is your idea/bugreport not in there? Please submit it to the [issue tracker](https://github.com/mac-cain13/R.swift/issues)! ## Pull requests If you'd like to implement a feature: - Check [the steps above](#questions-issues-and-ideas) to make sure it isn't already being build - Feel free to discuss the change in an issue, this will increase the chance of it being merged in - Keep your PR small, so it's easy to review - Follow the coding guidelines below ### Coding guidelines Principles R.swift code should follow: - Follow existing patterns/code style; Pattern/style improvements should go in a seperate issue/PR - Warn the user if you're skipping items - Code defensively; most formats we parse are undocumented and will change without notice Principles generated code should follow: - Never crash; No use of ! for example. - Always compile; Rather skip an item than generate corrupt code. - Clarity over brevity; Don't use R.swift.Library methods for example ([Read more](https://github.com/mac-cain13/R.swift/issues/177)) - Generate inline comments where it's relevant ================================================ FILE: Documentation/Examples.md ================================================ # Examples On this page you'll find examples of the kind of resources R.swift supports and how you can use them. We aim to keep this page up to date and complete so this should be a overview of all possibilities. ## Runtime validation Call `R.validate()` to call all validation methods that R.swift generates, this will check: - If all images used in storyboards and nibs are available - If all view controllers with storyboard identifiers can be loaded - If all custom fonts can be loaded The `R.validate()` method will throw a detailed error about the problems that occur. Note that this method will always perform checks, even in release builds. It’s recommended that validation is done in a testcase. *Example testcase* ```swift XCTAssertNoThrow(try R.validate()) ``` ## Images R.swift will find both images from Asset Catalogs and image files in your bundle. *Vanilla* ```swift let settingsIcon = UIImage(named: "settings-icon") let gradientBackground = UIImage(named: "gradient.jpg") ``` *With R.swift* ```swift let settingsIcon = R.image.settingsIcon() let gradientBackground = R.image.gradientJpg() ``` ### Support for assets grouped in folders Selecting "Provides Namespace" results in grouping assets: ![Assets folders structure](Images/NamespacedSubfolders.png) Use like so: ```swift let image = R.image.menu.icons.first() ``` ## Custom fonts *Vanilla* ```swift let lightFontTitle = UIFont(name: "Acme-Light", size: 22) ``` *With R.swift* ```swift let lightFontTitle = R.font.acmeLight(size: 22) ``` **Tip:** Also want this for system fonts? Take a look at the [UIFontComplete](https://github.com/Nirma/UIFontComplete) library, has a similar solution for the fonts Apple ships with iOS. ## Resource files *Vanilla* ```swift let jsonURL = Bundle.main.url(forResource: "seed-data", withExtension: "json") let jsonPath = Bundle.main.path(forResource: "seed-data", ofType: "json") ``` *With R.swift* ```swift let jsonURL = R.file.seedDataJson() let jsonPath = R.file.seedDataJson.path() ``` ## Colors *Vanilla* ```swift view.backgroundColor = UIColor(named: "primary background") ``` *With R.swift* ```swift view.backgroundColor = R.color.primaryBackground() ``` ## Localized strings *Vanilla* ```swift let welcomeMessage = NSLocalizedString("welcome.message", comment: "") let settingsTitle = NSLocalizedString("title", tableName: "Settings", comment: "") // Formatted strings let welcomeName = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Alice") // Stringsdict files let progress = String(format: NSLocalizedString("copy.progress", comment: ""), locale: NSLocale.current, 4, 23) ``` *With R.swift* ```swift // Localized strings are grouped per table (.strings file) let welcomeMessage = R.string.localizable.welcomeMessage() let settingsTitle = R.string.settings.title() // Functions with parameters are generated for format strings let welcomeName = R.string.localizable.welcomeWithName("Alice") // Functions with named argument labels are generated for stringsdict keys let progress = R.string.localizable.copyProgress(completed: 4, total: 23) ``` ## Storyboards *Vanilla* ```swift let storyboard = UIStoryboard(name: "Main", bundle: nil) let initialTabBarController = storyboard.instantiateInitialViewController() as? UITabBarController let settingsController = storyboard.instantiateViewController(withIdentifier: "settingsController") as? SettingsController ``` *With R.swift* ```swift let storyboard = R.storyboard.main() let initialTabBarController = R.storyboard.main.initialViewController() let settingsController = R.storyboard.main.settingsController() ``` ## Segues *Vanilla* ```swift // Trigger segue with: performSegue(withIdentifier: "openSettings", sender: self) // And then prepare it: override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let settingsController = segue.destination as? SettingsController, let segue = segue as? CustomSettingsSegue, segue.identifier == "openSettings" { segue.animationType = .LockAnimation settingsController.lockSettings = true } } ``` *With R.swift* ```swift // Trigger segue with: performSegue(withIdentifier: R.segue.overviewController.openSettings, sender: self) // And then prepare it: override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let typedInfo = R.segue.overviewController.openSettings(segue: segue) { typedInfo.segue.animationType = .LockAnimation typedInfo.destinationViewController.lockSettings = true } } ``` **Tip:** Take a look at the [SegueManager](https://github.com/tomlokhorst/SegueManager) library, it makes segues block based and is compatible with R.swift. ## Nibs *Vanilla* ```swift let nameOfNib = "CustomView" let customViewNib = UINib(nibName: "CustomView", bundle: nil) let rootViews = customViewNib.instantiate(withOwner: nil, options: nil) let customView = rootViews[0] as? CustomView let viewControllerWithNib = CustomViewController(nibName: "CustomView", bundle: nil) ``` *With R.swift* ```swift let nameOfNib = R.nib.customView.name let customViewNib = R.nib.customView() let rootViews = R.nib.customView.instantiate(withOwner: nil) let customView = R.nib.customView.firstView(owner: nil) let viewControllerWithNib = CustomViewController(nib: R.nib.customView) ``` ## Reusable table view cells *Vanilla* ```swift class FaqAnswerController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() let textCellNib = UINib(nibName: "TextCell", bundle: nil) tableView.register(textCellNib, forCellReuseIdentifier: "TextCellIdentifier") } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let textCell = tableView.dequeueReusableCell(withIdentifier: "TextCellIdentifier", for: indexPath) as! TextCell textCell.mainLabel.text = "Hello World" return textCell } } ``` *With R.swift* On your reusable cell Interface Builder "Attributes" inspector panel, set the cell "Identifier" field to the same value you are going to register and dequeue. ```swift class FaqAnswerController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() tableView.register(R.nib.textCell) } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let textCell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.textCell, for: indexPath)! textCell.mainLabel.text = "Hello World" return textCell } } ``` ## Reusable collection view cells *Vanilla* ```swift class RecentsController: UICollectionViewController { override func viewDidLoad() { super.viewDidLoad() let talkCellNib = UINib(nibName: "TalkCell", bundle: nil) collectionView?.register(talkCellNib, forCellWithReuseIdentifier: "TalkCellIdentifier") } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TalkCellIdentifier", for: indexPath) as! TalkCell cell.configureCell("Item \(indexPath.item)") return cell } } ``` *With R.swift* On your reusable cell Interface Builder "Attributes" inspector panel, set the cell "Identifier" field to the same value you are going to register and dequeue. ```swift class RecentsController: UICollectionViewController { override func viewDidLoad() { super.viewDidLoad() collectionView?.register(R.nib.talkCell) } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.talkCell, for: indexPath)! cell.configureCell("Item \(indexPath.item)") return cell } } ``` ## Project *Vanilla* ```swift let developmentRegion = fatalError("Not available at runtime") let myTag = "myTag" ``` *With R.swift* Access the development region and any asset tags that are set on the project file. ```swift let developmentRegion = R.project.developmentRegion let myTag = R.project.knownAssetTags.myTag ``` ## Entitlements *With R.swift* Access the values in the entitlement file you embedded. This might differ from the entitlements your app actually has at runtime! But it's greate to get some identifiers in a consistent way. ```swift let appGroupIdentifier = R.entitlements.comAppleSecurityApplicationGroups.groupMyAppGroup ``` ## Info.plist Values under `UIApplicationShortcutItems`, `UIApplicationSceneManifest`, `NSUserActivityTypes`, `NSExtension` that are often needed in code are available directly through R.swift. *With R.swift* Access the values in the Info.plist file. ```swift let activity = NSUserActivity(activityType: R.info.nsUserActivityTypes.planTripIntent) ``` ================================================ FILE: Documentation/Ignoring.md ================================================ # Ignoring resources R.swift will discover resources used in your project automatically. To make sure you can continue to use R.swift in the rare case that a file gives problems it is possible to ignore resources. It is also possible to only run certain generators to skip other `R.something` items. ## How does it work? Create a `.rswiftignore` file in the source root of your project, this file will automatically be discovered by R.swift. The format of the file is nearly the same as [a `.gitignore` file](https://git-scm.com/docs/gitignore#_pattern_format). Wildcards like `*` and `**` are supported and you can add comments by starting a line with a `#`. Explicitly including single or multiple files that are otherwise globally ignored is also supported by starting a pattern with `!`. _Note:_ All patterns are file paths relative to the path of the `.rswiftignore` file. ### Example ``` # Ignore a specific font file fonts/myspecialfont.ttf # Ignore all tiff and tif files in the images folder images/*.tif images/*.tiff # Ignore all strings files wherever they are **/*.strings # Ignore all files containing '.ignore.' **/*.ignore.* # Explicitly include a single file !keepme.ignore.png # Explicitly include all files containing '.keepme.' !**/*.keepme.* ``` ## Custom file location It is also possible to call the binary with the `--rswiftignore` flag and give a custom location of the ignore file this way. ## Only run specific generators (exclude R.something) By default, R.swift runs all generators, for images, nibs, strings and many more. In some situations you may not want to generate R structs for all these types. You can choose to run only certain generators by adding a flag like this: `--generators image,string` to the call to the [Build Phase](/Documentation/Images/BuildPhaseExample.png) These are the available generators: - `image` - `string` - `color` - `file` - `font` - `nib` - `segue` - `storyboard` - `reuseIdentifier` - `entitlements` - `info` - `id` ================================================ FILE: Documentation/Migration.md ================================================ # Migration Pointers for migration between major versions. ## Upgrading to 7.0 [Demo video: Updating from R.swift 6 to Rswift 7](https://www.youtube.com/watch?v=icihJ_hin3I) #### R.string changes - Strings are always formatted using `String(format:)`, even strings without arguments, make sure to escape any percentage signs (`%`) with `%%` - Use a custom language: `R.string(preferredLanguages: ["fr"]).example.hello()` #### Running the executable If you're using Swift Package Manager: - Separate R.swift.Library is no longer needed, remove dependency on that package - `R.generated.swift` file is no longer needed in the project, delete the file - Remove custom Run Script Build Phase that invokes `rswift` binary - Add SPM dependency on `github.com/mac-cain13/R.swift.git` package - Add `RswiftLibrary` to your targets - Under "Run Build Tool Plug-ins" Build Phase, add `RswiftGenerateInternalResources` or `RswiftGeneratePublicResources` ([Screenshot](Images/RunBuildToolPluginsRswift.png)) - Right-click on your project, and run `RswiftXcodeModifyPackages` to modify your Xcode project so that the build tool plug-in will actually run during builds (this seems to fix a bug in Xcode?) ([Screenshot](Images/RunXcodeModifyPackages.png)) If you're using Mint or manual call `rswift` executable: - Separate R.swift.Library is no longer needed, remove dependency on that package - Add SPM dependency on `github.com/mac-cain13/R.swift.git` package - Add `RswiftLibrary` to your targets Changes to the commandline tool `rswift` (not relevant when using SPM): - Argument `accessLevel` renamed to `access-level` - Argument `generateUITestFile` removed, if you need a separate file with just ids, call rswift a second time with `--generators id` - Argument `hostingBundle` removed, bundle can be specified in code: `_R(bundle: someBundle)` - Arguments removed: `bundleIdentifier`, `productModuleName`, `infoPlistFile`, `codeSignEntitlements`, `builtProductsDir`, `developerDir`, `platformDir`, `sdkRoot`, `sourceRoot`. Use environment variables instead. #### Library changes Internal changes in the Rswift support library: - Support for `R.nib.XXX.secondView` to `.twentiethView` has been removed, only `.firstView` remains - Renamed internal module, update `import Rswift` to `import RswiftResources` - Removed protocols: `ColorResourceType`, `FileResourceType`, `FontResourceType`, `IdentifierType`, `ImageResourceType`, `StoryboardViewControllerResourceType`, `StringResourceType`, `Validatable` - Added `StringResource1` up to `StringResource9`, for strings with parameters - Renamed types: * `ReuseIdentifierType` to `ReuseIdentifierContainer` * `NibResourceType` to `NibReferenceContainer` * `StoryboardResourceType` to `StoryboardReference` * `StoryboardResourceWithInitialControllerType` to `InitialControllerContainer` * `TypedStoryboardSegueInfo` to `TypedSegue` * `StoryboardSegueIdentifier` to `SegueIdentifier` #### Configuring Continuous Integration system When using a Swift Package Manager Plugin on a Continuous Integration (CI) server, you may see the following error: > The following build commands failed: > Validate plug-in “RswiftGeneratePublicResources” in package “r.swift” To allow the running of plugins, pass `-skipPackagePluginValidation` to xcbuildtool. See also this discussion on the Swift forums: https://forums.swift.org/t/telling-xcode-14-beta-4-to-trust-build-tool-plugins-programatically/59305 For users of Fastlane, pass the extra argument like so: ``` build_app( ... xcargs: "-skipPackagePluginValidation" ... ) ``` ## Upgrading to 6.0 - In the Build Phase, some changes are needed, [see an example screenshot](Images/BuildPhaseExample.png): * Uncheck "Based on dependency analysis" so that R.swift is run on each build * Remove `$TEMP_DIR/rswift-lastrun` from the "Input Files" of the Build Phase * Keep `$SRCROOT/[YOUR_PATH]/R.generated.swift` in the "Output Files" of the Build Phase unchanged ## Upgrading to 5.0 - Make sure you use Xcode 10 since we've adjusted to the SDK changes - At the moment we are compatible with both Swift 4 and 4.2, this is more an accident then a feature, beware that we might drop Swift 4 support anytime. If you are using the "New Build System": - In the Build Phase you must perform some changes: * Change the script to give the explicit output file, for example: `"$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/[YOUR_PATH]/R.generated.swift"` * Add `$TEMP_DIR/rswift-lastrun` to the "Input Files" of the Build Phase * Add `$SRCROOT/[YOUR_PATH]/R.generated.swift` to the "Output Files" of the Build Phase If you are using the "Legacy Build System": - Add the flag `--disable-input-output-files-validation` and *do not* add input/output files to the Build Phase. ## Upgrading to 4.0 - Make sure you use Swift 4 / Xcode 9 since we've adjusted to the syntax and SDK changes. - Running R.swift now requires the `generate` command, check the error R.swift outputs for upgrade instructions - Capitalization of methods and properties might have changed, in these cases the compiler should generate a fix-it for you. - Support for CLR-files is deprecated, use the new named Color assets instead where possible. * CLR based colors are moved from `R.color.*` to `R.clr.*` * Support for CLR files will be removed in a later version - At the moment we are compatible with both Swift 3.2 and Swift 4, this is more an accident then a feature, beware that we might drop Swift 3.2 support anytime. - If you upgrade from Swift 2 we advise you to first migrate to Swift 3 / R.swift 3.0 and when that is done apply the migration to Swift 4 / R.swift 4.0 ## Upgrading to 3.0 - Make sure you use Swift 3 / Xcode 8 since we've adjusted to the syntax changes. - If you want to use Swift 2.3 / Xcode 8 use the latest R.swift 2 release. - Some methods are renamed to match the new Swift 3 naming conventions, there are annotations available so the compiler can help you migrate. ## Upgrading to 2.0 - Make sure you use Swift 2.2 / Xcode 7.3 since we've adjusted to the syntax changes. ## Upgrading to 1.0 - iOS 7 support is dropped, use [R.swift 0.13](https://github.com/mac-cain13/R.swift/releases/tag/v0.13.0) if you still have to support it. - Generated code now depends on the [R.swift.Library](https://github.com/mac-cain13/R.swift.Library), CocoaPods users don't need to do anything. Manual installation users need to include this library themselves, see the readme for instructions. - In general; properties that created new stuff are now functions to represent better that they actually create a new instance. * `R.image.settingsIcon` changed to `R.image.settingsIcon()` * `R.file.someJson` changed to `R.file.someJson()` * `R.storyboard.main.initialViewController` changed to `R.storyboard.main.initialViewController()` * `R.storyboard.main.someViewController` changed to `R.storyboard.main.someViewController()` - In general; Where you needed to use `.initialize()` to get the instance, a shorter function is available now: * `R.storyboard.main.initialize()` changed to `R.storyboard.main()` * `R.nib.someView.initiate()` changed to `R.nib.someView()` - Nib root view loading changed from `R.nib.someView.firstView(nil, options: nil)` to `R.nib.someView.firstView(owner: nil)` - Typed segue syntax changed from `segue.typedInfoWithIdentifier(R.segue.someViewController.someSegue)` to `R.segue.someViewController.someSegue(segue: segue)` - Runtime validation changed: * `R.validate()` now throws errors it encounters * `R.assertValid()` asserts on errors and only performs action in a debug/non-optimized build * For regular use cases using `R.assertValid()` is recommended ================================================ FILE: Documentation/QandA.md ================================================ # Questions and Answers ## Why was R.swift created? Swift is a beautiful language and one of it's main advantages is its increasing popularity. However, it can be frustrating to deal with errors that compile but fail during runtime due to missing resources. This makes refactoring difficult while making it easy to create bugs (e.g. missing images etc). Android tackles this problem by generating something called the R class. It inspired me to create this very project, R.swift, which, thankfully, was well received by colleagues, friends and Github stargazers, so here we are now. ## Why should I choose R.swift over alternative X or Y? There are many nice R.swift alternatives like [SwiftGen](https://github.com/AliSoftware/SwiftGen) and [Shark](https://github.com/kaandedeoglu/Shark). However, I believe R.swift has these important advantages: - R.swift inspects your Xcodeproj file for resources instead of scanning folders or asking you for files - R.swift supports a lot of different assets - R.swift stays very close to the vanilla Apple API's, having minimal code change with maximum impact ## What are the requirements to run R.swift? R.swift works with Xcode 10 for apps targetting iOS 8 and tvOS 9 and higher. ## How do I fix missing imports in the generated file? If you get errors like `Use of undeclared type 'SomeType'` in the `R.generated.swift` file, this can usually be fixed by [explicitly stating the module in your xib or storyboard](Images/ExplicitCustomModule.png). This will make R.swift recognize that an import is necessary. ## How do I use classes with the same name as their module? If you get errors like `'SomeType' is not a member type of 'SomeType'`, that means you are using a module that contains a class/struct/enum with the same name as the module itself. This is a known [Swift issue](https://bugs.swift.org/browse/SR-898). You can work around this problem by [*emptying* the module field in the xib or storyboard](Images/ExplicitCustomModule.png) and then [adding `--import SomeType` as a flag](Images/CustomImport.png) to the R.swift build phase to ensure R.swift imports the module in the generated file. ## Can I use R.swift in a library? Yes, just add R.swift as a buildstep in your library project and it will work just like normal. This works best if you have a dedicated Xcode project you can use to add the build script to. For Cocoapod users: this is [not the case](https://github.com/mac-cain13/R.swift/issues/430#issue-344112657) if you've used `pod lib create MyNewLib` to scaffold your library. If you want to expose the resources to users of your library, you have to make the generated code public, you can do this by adding `--accessLevel public` to the call to R.swift. For example, if you included R.swift as a cocoapod dependency to your library project, you would change your build step to: `"$PODS_ROOT/R.swift/rswift" generate --accessLevel public "$SRCROOT"` ## How does R.swift work? During installation you add R.swift as a Build phase to your target, basically this means that: - Every time you build R.swift will run - It takes a look at your Xcode project file and inspects all resources linked with the target currently build - It generates a `R.generated.swift` file that contains a struct with types references to all of your resources ================================================ FILE: Documentation/Readme.md ================================================ # Documentation for R.swift - [Questions and Answers](QandA.md) - [Usage examples](Examples.md) - [Ignoring resources](Ignoring.md) - [Pointers for migration between major versions](Migration.md) - [About contributing](Contribute.md) ================================================ FILE: Examples/FileSystemSynchronized/FileSystemSynchronized.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 74; objects = { /* Begin PBXBuildFile section */ E212C64E291BE24B000E4F65 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E212C64D291BE24B000E4F65 /* RswiftLibrary */; }; E212C650291BE252000E4F65 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E212C64F291BE252000E4F65 /* RswiftLibrary */; }; E22057AE2C9C71D70070148F /* Colors@3x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E22057AB2C9C71D70070148F /* Colors@3x.jpg */; }; E243EFB02510E08D00DC653F /* TheAppClipApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243EFAF2510E08D00DC653F /* TheAppClipApp.swift */; }; E243EFB22510E08D00DC653F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243EFB12510E08D00DC653F /* ContentView.swift */; }; E243EFB42510E08E00DC653F /* ClipAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EFB32510E08E00DC653F /* ClipAssets.xcassets */; }; E243EFB72510E08E00DC653F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EFB62510E08E00DC653F /* Preview Assets.xcassets */; }; E243EFBC2510E08E00DC653F /* TheAppClip.app in Embed App Clips */ = {isa = PBXBuildFile; fileRef = E243EFAD2510E08D00DC653F /* TheAppClip.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; E2A7F4732CD799F300FCB116 /* MySiriIntents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E2A7F4722CD799F300FCB116 /* MySiriIntents.intentdefinition */; }; E2A7F4742CD799F300FCB116 /* MySiriIntents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E2A7F4722CD799F300FCB116 /* MySiriIntents.intentdefinition */; }; E2A7F4B62CD7A25100FCB116 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2A7F4B42CD7A25100FCB116 /* Localizable.strings */; }; E2A7F4B72CD7A25100FCB116 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2A7F4B42CD7A25100FCB116 /* Localizable.strings */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ E243EFBA2510E08E00DC653F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E243EF892510DF9100DC653F /* Project object */; proxyType = 1; remoteGlobalIDString = E243EFAC2510E08D00DC653F; remoteInfo = TheAppClip; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ E243EFBD2510E08E00DC653F /* Embed App Clips */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "$(CONTENTS_FOLDER_PATH)/AppClips"; dstSubfolderSpec = 16; files = ( E243EFBC2510E08E00DC653F /* TheAppClip.app in Embed App Clips */, ); name = "Embed App Clips"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ E212C64C291BE1DB000E4F65 /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; E22057AB2C9C71D70070148F /* Colors@3x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "Colors@3x.jpg"; sourceTree = ""; }; E243EF912510DF9100DC653F /* MainUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MainUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; E243EFAD2510E08D00DC653F /* TheAppClip.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TheAppClip.app; sourceTree = BUILT_PRODUCTS_DIR; }; E243EFAF2510E08D00DC653F /* TheAppClipApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TheAppClipApp.swift; sourceTree = ""; }; E243EFB12510E08D00DC653F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; E243EFB32510E08E00DC653F /* ClipAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ClipAssets.xcassets; sourceTree = ""; }; E243EFB62510E08E00DC653F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; E243EFB82510E08E00DC653F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E243EFB92510E08E00DC653F /* TheAppClip.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TheAppClip.entitlements; sourceTree = ""; }; E243EFC22510E0D900DC653F /* Rswift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Rswift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E2A7F4712CD799F300FCB116 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/MySiriIntents.intentdefinition; sourceTree = ""; }; E2A7F47C2CD79A0F00FCB116 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/MySiriIntents.strings; sourceTree = ""; }; E2A7F4B52CD7A25100FCB116 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E2A7F4B82CD7A25500FCB116 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ E22058272C9CB6AE0070148F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Nogeeen/person.png, ); target = E243EF902510DF9100DC653F /* MainUI */; }; E220582B2C9CB71A0070148F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( User.png, ); target = E243EFAC2510E08D00DC653F /* TheAppClip */; }; E25226AE2C9C612000F32501 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Info.plist, ); target = E243EF902510DF9100DC653F /* MainUI */; }; E25226AF2C9C612000F32501 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( /Localized/MyStoryboard.storyboard, Assets.xcassets, ); target = E243EFAC2510E08D00DC653F /* TheAppClip */; }; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ E2187D462CCC4ED800F33259 /* Folder2 */ = { isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = { }; explicitFolders = ( ); path = Folder2; sourceTree = ""; }; E22057F22C9C95EC0070148F /* Folder1 */ = { isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = { }; explicitFolders = ( ); path = Folder1; sourceTree = ""; }; E22058252C9CB6A20070148F /* Inner group */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( E22058272C9CB6AE0070148F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E220582B2C9CB71A0070148F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = { }; explicitFolders = ( ); path = "Inner group"; sourceTree = ""; }; E25226A62C9C612000F32501 /* MainUI */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( E25226AE2C9C612000F32501 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E25226AF2C9C612000F32501 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = { }; explicitFolders = ( ); path = MainUI; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ E243EF8E2510DF9100DC653F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E212C64E291BE24B000E4F65 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E243EFAA2510E08D00DC653F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E212C650291BE252000E4F65 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ E212C64B291BE1DB000E4F65 /* Packages */ = { isa = PBXGroup; children = ( E212C64C291BE1DB000E4F65 /* R.swift */, ); name = Packages; sourceTree = ""; }; E22057AC2C9C71D70070148F /* Subdir */ = { isa = PBXGroup; children = ( E22057AB2C9C71D70070148F /* Colors@3x.jpg */, E22058252C9CB6A20070148F /* Inner group */, ); path = Subdir; sourceTree = ""; }; E22057F32C9C95F50070148F /* Group1 */ = { isa = PBXGroup; children = ( E2187D462CCC4ED800F33259 /* Folder2 */, E22057F22C9C95EC0070148F /* Folder1 */, E2A7F4722CD799F300FCB116 /* MySiriIntents.intentdefinition */, ); path = Group1; sourceTree = ""; }; E243EF882510DF9100DC653F = { isa = PBXGroup; children = ( E212C64B291BE1DB000E4F65 /* Packages */, E25226A62C9C612000F32501 /* MainUI */, E243EFAE2510E08D00DC653F /* TheAppClip */, E243EF922510DF9100DC653F /* Products */, E243EFC12510E0D900DC653F /* Frameworks */, ); sourceTree = ""; }; E243EF922510DF9100DC653F /* Products */ = { isa = PBXGroup; children = ( E243EF912510DF9100DC653F /* MainUI.app */, E243EFAD2510E08D00DC653F /* TheAppClip.app */, ); name = Products; sourceTree = ""; }; E243EFAE2510E08D00DC653F /* TheAppClip */ = { isa = PBXGroup; children = ( E22057F32C9C95F50070148F /* Group1 */, E22057AC2C9C71D70070148F /* Subdir */, E243EFAF2510E08D00DC653F /* TheAppClipApp.swift */, E243EFB12510E08D00DC653F /* ContentView.swift */, E243EFB32510E08E00DC653F /* ClipAssets.xcassets */, E243EFB82510E08E00DC653F /* Info.plist */, E243EFB92510E08E00DC653F /* TheAppClip.entitlements */, E243EFB52510E08E00DC653F /* Preview Content */, E2A7F4B42CD7A25100FCB116 /* Localizable.strings */, ); path = TheAppClip; sourceTree = ""; }; E243EFB52510E08E00DC653F /* Preview Content */ = { isa = PBXGroup; children = ( E243EFB62510E08E00DC653F /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; E243EFC12510E0D900DC653F /* Frameworks */ = { isa = PBXGroup; children = ( E243EFC22510E0D900DC653F /* Rswift.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ E243EF902510DF9100DC653F /* MainUI */ = { isa = PBXNativeTarget; buildConfigurationList = E243EFA02510DF9200DC653F /* Build configuration list for PBXNativeTarget "MainUI" */; buildPhases = ( E243EF8D2510DF9100DC653F /* Sources */, E243EF8E2510DF9100DC653F /* Frameworks */, E243EF8F2510DF9100DC653F /* Resources */, E243EFBD2510E08E00DC653F /* Embed App Clips */, ); buildRules = ( ); dependencies = ( E212C655291BE2D9000E4F65 /* PBXTargetDependency */, E243EFBB2510E08E00DC653F /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( E25226A62C9C612000F32501 /* MainUI */, ); name = MainUI; packageProductDependencies = ( E212C64D291BE24B000E4F65 /* RswiftLibrary */, ); productName = MainUI; productReference = E243EF912510DF9100DC653F /* MainUI.app */; productType = "com.apple.product-type.application"; }; E243EFAC2510E08D00DC653F /* TheAppClip */ = { isa = PBXNativeTarget; buildConfigurationList = E243EFC02510E08E00DC653F /* Build configuration list for PBXNativeTarget "TheAppClip" */; buildPhases = ( E243EFA92510E08D00DC653F /* Sources */, E243EFAA2510E08D00DC653F /* Frameworks */, E243EFAB2510E08D00DC653F /* Resources */, ); buildRules = ( ); dependencies = ( E212C652291BE2C0000E4F65 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( E2187D462CCC4ED800F33259 /* Folder2 */, E22057F22C9C95EC0070148F /* Folder1 */, ); name = TheAppClip; packageProductDependencies = ( E212C64F291BE252000E4F65 /* RswiftLibrary */, ); productName = TheAppClip; productReference = E243EFAD2510E08D00DC653F /* TheAppClip.app */; productType = "com.apple.product-type.application.on-demand-install-capable"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E243EF892510DF9100DC653F /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1200; LastUpgradeCheck = 1500; TargetAttributes = { E243EF902510DF9100DC653F = { CreatedOnToolsVersion = 12.0; }; E243EFAC2510E08D00DC653F = { CreatedOnToolsVersion = 12.0; }; }; }; buildConfigurationList = E243EF8C2510DF9100DC653F /* Build configuration list for PBXProject "FileSystemSynchronized" */; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, nl, ); mainGroup = E243EF882510DF9100DC653F; packageReferences = ( E2A7F4B12CD7A1D500FCB116 /* XCLocalSwiftPackageReference "../../../R.swift" */, ); preferredProjectObjectVersion = 50; productRefGroup = E243EF922510DF9100DC653F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E243EF902510DF9100DC653F /* MainUI */, E243EFAC2510E08D00DC653F /* TheAppClip */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ E243EF8F2510DF9100DC653F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E2A7F4B72CD7A25100FCB116 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; E243EFAB2510E08D00DC653F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E243EFB72510E08E00DC653F /* Preview Assets.xcassets in Resources */, E2A7F4B62CD7A25100FCB116 /* Localizable.strings in Resources */, E243EFB42510E08E00DC653F /* ClipAssets.xcassets in Resources */, E22057AE2C9C71D70070148F /* Colors@3x.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ E243EF8D2510DF9100DC653F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E2A7F4732CD799F300FCB116 /* MySiriIntents.intentdefinition in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E243EFA92510E08D00DC653F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E2A7F4742CD799F300FCB116 /* MySiriIntents.intentdefinition in Sources */, E243EFB22510E08D00DC653F /* ContentView.swift in Sources */, E243EFB02510E08D00DC653F /* TheAppClipApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ E212C652291BE2C0000E4F65 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E212C651291BE2C0000E4F65 /* RswiftGenerateInternalResources */; }; E212C655291BE2D9000E4F65 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E212C654291BE2D9000E4F65 /* RswiftGenerateInternalResources */; }; E243EFBB2510E08E00DC653F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E243EFAC2510E08D00DC653F /* TheAppClip */; targetProxy = E243EFBA2510E08E00DC653F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ E2A7F4722CD799F300FCB116 /* MySiriIntents.intentdefinition */ = { isa = PBXVariantGroup; children = ( E2A7F4712CD799F300FCB116 /* Base */, E2A7F47C2CD79A0F00FCB116 /* nl */, ); name = MySiriIntents.intentdefinition; sourceTree = ""; }; E2A7F4B42CD7A25100FCB116 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( E2A7F4B52CD7A25100FCB116 /* en */, E2A7F4B82CD7A25500FCB116 /* nl */, ); name = Localizable.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ E243EF9E2510DF9200DC653F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; E243EF9F2510DF9200DC653F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; }; E243EFA12510DF9200DC653F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"MainUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = MainUI/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.MainUI; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E243EFA22510DF9200DC653F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"MainUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = MainUI/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.MainUI; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; E243EFBE2510E08E00DC653F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = TheAppClip/TheAppClip.entitlements; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"TheAppClip/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = TheAppClip/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.MainUI.Clip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E243EFBF2510E08E00DC653F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = TheAppClip/TheAppClip.entitlements; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"TheAppClip/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = TheAppClip/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.MainUI.Clip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E243EF8C2510DF9100DC653F /* Build configuration list for PBXProject "FileSystemSynchronized" */ = { isa = XCConfigurationList; buildConfigurations = ( E243EF9E2510DF9200DC653F /* Debug */, E243EF9F2510DF9200DC653F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E243EFA02510DF9200DC653F /* Build configuration list for PBXNativeTarget "MainUI" */ = { isa = XCConfigurationList; buildConfigurations = ( E243EFA12510DF9200DC653F /* Debug */, E243EFA22510DF9200DC653F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E243EFC02510E08E00DC653F /* Build configuration list for PBXNativeTarget "TheAppClip" */ = { isa = XCConfigurationList; buildConfigurations = ( E243EFBE2510E08E00DC653F /* Debug */, E243EFBF2510E08E00DC653F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ E2A7F4B12CD7A1D500FCB116 /* XCLocalSwiftPackageReference "../../../R.swift" */ = { isa = XCLocalSwiftPackageReference; relativePath = ../../../R.swift; }; /* End XCLocalSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ E212C64D291BE24B000E4F65 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E212C64F291BE252000E4F65 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E212C651291BE2C0000E4F65 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; E212C654291BE2D9000E4F65 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = E243EF892510DF9100DC653F /* Project object */; } ================================================ FILE: Examples/FileSystemSynchronized/FileSystemSynchronized.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/FileSystemSynchronized/FileSystemSynchronized.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/FileSystemSynchronized/MainUI/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/MainUI/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/MainUI/Assets.xcassets/hand.ignoreme.imageset/Contents.json ================================================ { "images" : [ { "filename" : "hand.ignoreme.png", "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/MainUI/Base.lproj/MyStoryboard.storyboard ================================================ ================================================ FILE: Examples/FileSystemSynchronized/MainUI/ContentView.swift ================================================ // // ContentView.swift // MainUI // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI struct ContentView: View { var body: some View { Text("Hello, SwiftUI App!") .padding() Image(R.image.handIgnoreme) .resizable() .aspectRatio(1, contentMode: .fit) .frame(width: 140) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ================================================ FILE: Examples/FileSystemSynchronized/MainUI/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS NSUserActivityTypes FirstIntentIntent UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UIApplicationSupportsIndirectInputEvents UILaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/FileSystemSynchronized/MainUI/MainUI.entitlements ================================================ com.apple.security.application-groups ================================================ FILE: Examples/FileSystemSynchronized/MainUI/MainUIApp.swift ================================================ // // MainUIApp.swift // MainUI // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI @main struct MainUIApp: App { var body: some Scene { WindowGroup { ContentView() .onAppear { // From Assets (in this target) print(R.image.handIgnoreme()!) // From root folder (in this target) print(R.image.user1()!) print(R.storyboard.myStoryboard.instantiateInitialViewController()!) // From Folders3 copy (in this target) print(R.image.hand3Two()!) print(R.image.hand3Three()!) print(R.image.hand2Two()!) print(R.image.hand2Three()!) // From Subdir (in TheAppClip target) print(R.image.person()!) // From root folder (in TheAppClip target) print(R.string.localizable.helloWorld()) } } } } ================================================ FILE: Examples/FileSystemSynchronized/MainUI/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/MainUI/View.xib ================================================ ================================================ FILE: Examples/FileSystemSynchronized/MainUI/nl.lproj/MyStoryboard.strings ================================================ /* Class = "UILabel"; text = "Second label"; ObjectID = "cgd-Ta-I3o"; */ "cgd-Ta-I3o.text" = "Tweede label"; /* Class = "UILabel"; text = "The first"; ObjectID = "oox-ej-MK4"; */ "oox-ej-MK4.text" = "De eerste"; ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/ClipAssets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/ClipAssets.xcassets/MyColor.colorset/Contents.json ================================================ { "colors" : [ { "color" : { "platform" : "ios", "reference" : "systemTealColor" }, "idiom" : "universal" }, { "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "color" : { "platform" : "ios", "reference" : "systemOrangeColor" }, "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/ContentView.swift ================================================ // // ContentView.swift // TheAppClip // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI struct ContentView: View { var body: some View { Text("Hello, App Clip!") .padding() Image(R.image.handIgnoreme) .resizable() .aspectRatio(1, contentMode: .fit) .frame(width: 140) .border(Color(R.color.myColor)) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/Group1/Base.lproj/MySiriIntents.intentdefinition ================================================ INEnums INIntentDefinitionModelVersion 1.2 INIntentDefinitionNamespace CfVXCE INIntentDefinitionSystemVersion 24A348 INIntentDefinitionToolsBuildVersion 16A242d INIntentDefinitionToolsVersion 16.0 INIntents INIntentCategory generic INIntentConfigurable INIntentDescription the description INIntentDescriptionID 0yVZNa INIntentManagedParameterCombinations INIntentParameterCombinationSupportsBackgroundExecution INIntentParameterCombinationUpdatesLinked INIntentName FirstIntent INIntentParameterCombinations INIntentParameterCombinationIsPrimary INIntentParameterCombinationSupportsBackgroundExecution INIntentResponse INIntentResponseCodes INIntentResponseCodeName success INIntentResponseCodeSuccess INIntentResponseCodeName failure INIntentTitle First Intent INIntentTitleID YPNLgh INIntentType Custom INIntentVerb Do INTypes ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/Group1/Folder1/.gitkeep ================================================ ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/Group1/nl.lproj/MySiriIntents.strings ================================================ "0yVZNa" = "de omschrijving"; "YPNLgh" = "Eerste Intent"; ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName MainUI CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS NSUserActivityTypes FirstIntentIntent UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UIApplicationSupportsIndirectInputEvents UILaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/TheAppClip.entitlements ================================================ com.apple.developer.parent-application-identifiers $(AppIdentifierPrefix)nl.mathijskadijk.MainUI ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/TheAppClipApp.swift ================================================ // // TheAppClipApp.swift // TheAppClip // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI @main struct TheAppClipApp: App { var body: some Scene { WindowGroup { ContentView() .onAppear { // From ClipAssets (in this target) print(R.color.myColor()!) // From Group1 (in this target) print(R.image.handTwo()!) print(R.image.handThree()!) print(R.image.hand3Two()!) print(R.image.hand3Three()!) print(R.image.hand3Three()!) // From Subdir (in this target) print(R.image.colorsJpg()!) print(R.image.user()!) // From root folder (in this target) print(R.string.localizable.helloWorld()) // From Assets (in MainUI) print(R.image.handIgnoreme()!) // From root folder (in MainUI) print(R.storyboard.myStoryboard.instantiateInitialViewController()!) } } } } ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/en.lproj/Localizable.strings ================================================ /* Localizable.strings FileSystemSynchronized Created by Tom Lokhorst on 2024-11-03. */ "hello.world" = "Hello world"; ================================================ FILE: Examples/FileSystemSynchronized/TheAppClip/nl.lproj/Localizable.strings ================================================ /* Localizable.strings FileSystemSynchronized Created by Tom Lokhorst on 2024-11-03. */ "hello.world" = "Hallo wereld"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/AppDelegate.swift ================================================ // // AppDelegate.swift // LocalizedStringApp // // Created by Tom Lokhorst on 2019-08-30. // Copyright © 2019 R.swift. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { /* let myprefs: [String] = ["fr-CA"] print("Locale.preferredLanguages:") print(Locale.preferredLanguages) print() print("Bundle.main.preferredLocalizations:") print(Bundle.main.preferredLocalizations) print() print("Test:") print(NSLocalizedString("one1", tableName: "one", comment: "")) print(R.string.one.one1()) print(R.string.one.one1(preferredLanguages: myprefs)) print() print(NSLocalizedString("one2", tableName: "one", comment: "")) print(R.string.one.one2()) print(R.string.one.one2(preferredLanguages: myprefs)) print() print(NSLocalizedString("two1", tableName: "two", comment: "")) print(R.string.two.two1()) print(R.string.two.two1(preferredLanguages: myprefs)) print() print(String(format: NSLocalizedString("two2", tableName: "two", comment: ""), locale: Locale(identifier: myprefs.first!), "Hello")) print(R.string.two.two2("Hello")) print(R.string.two.two2("Hello", preferredLanguages: myprefs)) print() print(NSLocalizedString("three1", tableName: "three", comment: "")) print(R.string.three.three1()) print(R.string.three.three1(preferredLanguages: myprefs)) print() print(NSLocalizedString("three2", tableName: "three", comment: "")) print(R.string.three.three2()) print(R.string.three.three2(preferredLanguages: myprefs)) print() print(NSLocalizedString("three3", tableName: "three", comment: "")) print(R.string.three.three3()) print(R.string.three.three3(preferredLanguages: myprefs)) print() print(NSLocalizedString("four1", tableName: "four", comment: "")) print(R.string.four.four1()) print(R.string.four.four1(preferredLanguages: myprefs)) print() print(NSLocalizedString("five1", tableName: "five", comment: "")) print(R.string.five.five1()) print(R.string.five.five1(preferredLanguages: myprefs)) print() print(NSLocalizedString("five2", tableName: "five", comment: "")) print(R.string.five.five2()) print(R.string.five.five2(preferredLanguages: myprefs)) print() print(NSLocalizedString("five4", tableName: "five", comment: "")) print(R.string.five.five4()) print(R.string.five.five4(preferredLanguages: myprefs)) print() print(NSLocalizedString("six1", tableName: "six", comment: "")) print(R.string.six.six1()) print(R.string.six.six1(preferredLanguages: myprefs)) print() print(NSLocalizedString("six2", tableName: "six", comment: "")) print(R.string.six.six2()) print(R.string.six.six2(preferredLanguages: myprefs)) print() print(NSLocalizedString("seven1", tableName: "seven", comment: "")) print(R.string.seven.seven1()) print(R.string.seven.seven1(preferredLanguages: myprefs)) print() print(NSLocalizedString("seven2", tableName: "seven", comment: "")) print(R.string.seven.seven2()) print(R.string.seven.seven2(preferredLanguages: myprefs)) print() print(NSLocalizedString("seven3", tableName: "seven", comment: "")) print(R.string.seven.seven3()) print(R.string.seven.seven3(preferredLanguages: myprefs)) print() print(NSLocalizedString("seven4", tableName: "seven", comment: "")) print(R.string.seven.seven4()) print(R.string.seven.seven4(preferredLanguages: myprefs)) print() print(NSLocalizedString("eight1", tableName: "eight", comment: "")) print(R.string.eight.eight1()) print(R.string.eight.eight1(preferredLanguages: myprefs)) print() print(NSLocalizedString("eight2", tableName: "eight", comment: "")) print(R.string.eight.eight2()) print(R.string.eight.eight2(preferredLanguages: myprefs)) print() print(NSLocalizedString("eight3", tableName: "eight", comment: "")) print(R.string.eight.eight3()) print(R.string.eight.eight3(preferredLanguages: myprefs)) print() print(NSLocalizedString("nine1", tableName: "nine", comment: "")) print(R.string.nine.nine1()) print(R.string.nine.nine1(preferredLanguages: myprefs)) print() print(NSLocalizedString("nine2", tableName: "nine", comment: "")) print(R.string.nine.nine2()) print(R.string.nine.nine2(preferredLanguages: myprefs)) print() print(NSLocalizedString("nine", tableName: "nine", comment: "")) print(R.string.nine.nine3()) print(R.string.nine.nine3(preferredLanguages: myprefs)) print() */ return true } } ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/Base.lproj/eight.strings ================================================ /* eight.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-26. Copyright © 2019 R.swift. All rights reserved. */ "eight1" = "eight 1, localized base"; "eight2" = "eight 2, localized base"; "eight3" = "eight 3, localized base"; "eightArg1" = "eight 1 %@, localized base"; "eightArg2" = "eight 2 %@, localized base"; "eightArg3" = "eight 3 %@, localized base"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/Base.lproj/nine.strings ================================================ /* nine.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-31. Copyright © 2019 R.swift. All rights reserved. */ "nine1" = "nine 1, localized base"; "nine2" = "nine 2, localized base"; "nine3" = "nine 3, localized base"; "nineArg1" = "nine 1 %@, localized base"; "nineArg2" = "nine 2 %@, localized base"; "nineArg3" = "nine 3 %@, localized base"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSApplicationCategoryType LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/ca.lproj/four.strings ================================================ /* four.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "four1" = "four 1, localized catalan"; "fourArg" = "four %@, localized catalan"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en-GB.lproj/five.strings ================================================ /* five.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "five1" = "five 1, localized english gb"; "fiveArg1" = "five 1 %@, localized english gb"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en.lproj/MyStoryboard.storyboard ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en.lproj/five.strings ================================================ /* five.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "five1" = "five 1, localized english"; "five2" = "five 2, localized english"; "five3" = "five 3, localized english"; "fiveArg1" = "five 1 %@, localized english"; "fiveArg2" = "five 2 %@, localized english"; "fiveArg3" = "five 3 %@, localized english"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en.lproj/nine.strings ================================================ /* nine.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-31. Copyright © 2019 R.swift. All rights reserved. */ "nine1" = "nine 1, localized english"; "nine2" = "nine 2, localized english"; "nineArg1" = "nine 1 %@, localized english"; "nineArg2" = "nine 2 %@, localized english"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en.lproj/seven.strings ================================================ /* seven.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-22. Copyright © 2019 R.swift. All rights reserved. */ "seven1" = "seven 1, localized english"; "seven2" = "seven 2, localized english"; "sevenArg1" = "seven 1 %@, localized english"; "sevenArg2" = "seven 2 %@, localized english"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en.lproj/three.strings ================================================ /* three.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "three1" = "three 1, localized english"; "three2" = "three 2, localized english"; "threeArg1" = "three 1 %@, localized english"; "threeArg2" = "three 2 %@, localized english"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/en.lproj/two.strings ================================================ /* two.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "two1" = "two 1, localized english"; "two2" = "two 2, %@ localized english"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr-CA.lproj/five.strings ================================================ /* five.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "five1" = "five 1, localized french canada"; "fiveArg1" = "five 1 %@, localized french canada"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr-CA.lproj/six.strings ================================================ /* six.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "six1" = "six 1, localized french canada"; "sixArg1" = "six 1 %@, localized french canada"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr.lproj/eight.strings ================================================ /* eight.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-26. Copyright © 2019 R.swift. All rights reserved. */ "eight1" = "eight 1, localized french"; "eight2" = "eight 2, localized french"; "eightArg1" = "eight 1 %@, localized french"; "eightArg2" = "eight 2 %@, localized french"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr.lproj/five.strings ================================================ /* five.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "five1" = "five 1, localized french"; "five2" = "five 2, localized french"; "five4" = "five 4, localized french"; "fiveArg1" = "five 1 %@, localized french"; "fiveArg2" = "five 2 %@, localized french"; "fiveArg4" = "five 4 %@, localized french"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr.lproj/nine.strings ================================================ /* nine.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-31. Copyright © 2019 R.swift. All rights reserved. */ "nine1" = "nine 1, localized french"; "nine2" = "nine 2, localized french"; "nineArg1" = "nine 1 %@, localized french"; "nineArg2" = "nine 2 %@, localized french"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr.lproj/seven.strings ================================================ /* seven.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-22. Copyright © 2019 R.swift. All rights reserved. */ "seven1" = "seven 1, localized french"; "seven2" = "seven 2, localized french"; "seven3" = "seven 3, localized french"; "seven4" = "seven 4, localized french"; "sevenArg1" = "seven 1 %@, localized french"; "sevenArg2" = "seven 2 %@, localized french"; "sevenArg3" = "seven 3 %@, localized french"; "sevenArg4" = "seven 4 %@, localized french"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr.lproj/six.strings ================================================ /* six.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "six1" = "six 1, localized french"; "six2" = "six 2, localized french"; "sixArg1" = "six 1 %@, localized french"; "sixArg2" = "six 2 %@, localized french"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/fr.lproj/ten.stringsdict ================================================ ten1 NSStringLocalizedFormatKey ten 1 - %#@things@, localized french things NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one %d thing other %d things ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/nl.lproj/eight.strings ================================================ /* eight.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-26. Copyright © 2019 R.swift. All rights reserved. */ "eight1" = "eight 1, localized dutch"; "eight4" = "eight 4, localized dutch"; "eightArg1" = "eight 1 %@, localized dutch"; "eightArg4" = "eight 4 %@, localized dutch"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/nl.lproj/four.strings ================================================ /* four.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "four1" = "four 1, localized dutch"; "fourArg" = "four %@, localized dutch"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/nl.lproj/nine.strings ================================================ /* nine.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-31. Copyright © 2019 R.swift. All rights reserved. */ "nine1" = "nine 1, localized dutch"; "nine4" = "nine 4, localized dutch"; "nineArg1" = "nine 1 %@, localized dutch"; "nineArg4" = "nine 4 %@, localized dutch"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/nl.lproj/seven.strings ================================================ /* seven.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-22. Copyright © 2019 R.swift. All rights reserved. */ "seven1" = "seven 1, localized dutch"; "seven4" = "seven 4, localized dutch"; "sevenArg1" = "seven 1 %@, localized dutch"; "sevenArg4" = "seven 4 %@, localized dutch"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/nl.lproj/ten.stringsdict ================================================ ten1 NSStringLocalizedFormatKey ten 1 - %#@things@, localized dutch things NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one %d thing other %d things ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/nl.lproj/three.strings ================================================ /* three.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "three1" = "three 1, localized dutch"; "three3" = "three 3, localized dutch"; "threeArg1" = "three 1 %@, localized dutch"; "threeArg3" = "three 3 %@, localized dutch"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp/one.strings ================================================ /* one.strings LocalizedStringApp Created by Tom Lokhorst on 2019-08-21. Copyright © 2019 R.swift. All rights reserved. */ "one1" = "one 1, not localized"; "one2" = "one 2, not localized"; "oneArg" = "one %@, not localized"; ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 52; objects = { /* Begin PBXBuildFile section */ E258099B29325C1F008EA19C /* ten.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E258099929325C1F008EA19C /* ten.stringsdict */; }; E264FBA12319055A008E0DB5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E264FBA02319055A008E0DB5 /* AppDelegate.swift */; }; E264FBB82319055D008E0DB5 /* LocalizedStringAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E264FBB72319055D008E0DB5 /* LocalizedStringAppTests.swift */; }; E264FBCF2319082F008E0DB5 /* one.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBCE2319082E008E0DB5 /* one.strings */; }; E264FBD22319083B008E0DB5 /* two.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBD02319083B008E0DB5 /* two.strings */; }; E264FBD523190962008E0DB5 /* three.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBD323190962008E0DB5 /* three.strings */; }; E264FBD923190992008E0DB5 /* four.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBD723190992008E0DB5 /* four.strings */; }; E264FBDD231909F6008E0DB5 /* five.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBDB231909F6008E0DB5 /* five.strings */; }; E264FBE223190A19008E0DB5 /* six.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBE023190A19008E0DB5 /* six.strings */; }; E264FBE623190A2F008E0DB5 /* seven.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBE423190A2F008E0DB5 /* seven.strings */; }; E264FBEB23190A49008E0DB5 /* eight.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBE923190A49008E0DB5 /* eight.strings */; }; E264FBF4231A7335008E0DB5 /* nine.strings in Resources */ = {isa = PBXBuildFile; fileRef = E264FBF6231A7335008E0DB5 /* nine.strings */; }; E2E58371291D3AC2006E17D9 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E2E58370291D3AC2006E17D9 /* RswiftLibrary */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ E264FBB42319055D008E0DB5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E264FB952319055A008E0DB5 /* Project object */; proxyType = 1; remoteGlobalIDString = E264FB9C2319055A008E0DB5; remoteInfo = LocalizedStringApp; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ E258099A29325C1F008EA19C /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/ten.stringsdict; sourceTree = ""; }; E258099C29325C29008EA19C /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/ten.stringsdict; sourceTree = ""; }; E264FB9D2319055A008E0DB5 /* LocalizedStringApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LocalizedStringApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; E264FBA02319055A008E0DB5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; E264FBAE2319055D008E0DB5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E264FBB32319055D008E0DB5 /* LocalizedStringAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LocalizedStringAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E264FBB72319055D008E0DB5 /* LocalizedStringAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedStringAppTests.swift; sourceTree = ""; }; E264FBB92319055D008E0DB5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E264FBCE2319082E008E0DB5 /* one.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = one.strings; sourceTree = ""; }; E264FBD12319083B008E0DB5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/two.strings; sourceTree = ""; }; E264FBD423190962008E0DB5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/three.strings; sourceTree = ""; }; E264FBD62319096F008E0DB5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/three.strings; sourceTree = ""; }; E264FBD823190992008E0DB5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/four.strings; sourceTree = ""; }; E264FBDA231909D3008E0DB5 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/four.strings; sourceTree = ""; }; E264FBDC231909F6008E0DB5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/five.strings; sourceTree = ""; }; E264FBDE231909FD008E0DB5 /* fr-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-CA"; path = "fr-CA.lproj/five.strings"; sourceTree = ""; }; E264FBDF231909FF008E0DB5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/five.strings; sourceTree = ""; }; E264FBE123190A19008E0DB5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/six.strings; sourceTree = ""; }; E264FBE323190A1F008E0DB5 /* fr-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-CA"; path = "fr-CA.lproj/six.strings"; sourceTree = ""; }; E264FBE523190A2F008E0DB5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/seven.strings; sourceTree = ""; }; E264FBE723190A38008E0DB5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/seven.strings; sourceTree = ""; }; E264FBE823190A3C008E0DB5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/seven.strings; sourceTree = ""; }; E264FBEA23190A49008E0DB5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/eight.strings; sourceTree = ""; }; E264FBEC23190A5A008E0DB5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/eight.strings; sourceTree = ""; }; E264FBED23190A65008E0DB5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/eight.strings; sourceTree = ""; }; E264FBF1231A6984008E0DB5 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/five.strings"; sourceTree = ""; }; E264FBF5231A7335008E0DB5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/nine.strings; sourceTree = ""; }; E264FBF7231A7371008E0DB5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/nine.strings; sourceTree = ""; }; E264FBF8231A7392008E0DB5 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/nine.strings; sourceTree = ""; }; E264FBF9231A73BA008E0DB5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/nine.strings; sourceTree = ""; }; E2E5836E291D3AB5006E17D9 /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ E264FB9A2319055A008E0DB5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E2E58371291D3AC2006E17D9 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E264FBB02319055D008E0DB5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ E264FB942319055A008E0DB5 = { isa = PBXGroup; children = ( E2E5836D291D3AB5006E17D9 /* Packages */, E264FB9F2319055A008E0DB5 /* LocalizedStringApp */, E264FBB62319055D008E0DB5 /* LocalizedStringAppTests */, E264FB9E2319055A008E0DB5 /* Products */, E2E5836F291D3AC2006E17D9 /* Frameworks */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; }; E264FB9E2319055A008E0DB5 /* Products */ = { isa = PBXGroup; children = ( E264FB9D2319055A008E0DB5 /* LocalizedStringApp.app */, E264FBB32319055D008E0DB5 /* LocalizedStringAppTests.xctest */, ); name = Products; sourceTree = ""; }; E264FB9F2319055A008E0DB5 /* LocalizedStringApp */ = { isa = PBXGroup; children = ( E264FBA02319055A008E0DB5 /* AppDelegate.swift */, E264FBAE2319055D008E0DB5 /* Info.plist */, E264FBCE2319082E008E0DB5 /* one.strings */, E264FBD02319083B008E0DB5 /* two.strings */, E264FBD323190962008E0DB5 /* three.strings */, E264FBD723190992008E0DB5 /* four.strings */, E264FBDB231909F6008E0DB5 /* five.strings */, E264FBE023190A19008E0DB5 /* six.strings */, E264FBE423190A2F008E0DB5 /* seven.strings */, E264FBE923190A49008E0DB5 /* eight.strings */, E264FBF6231A7335008E0DB5 /* nine.strings */, E258099929325C1F008EA19C /* ten.stringsdict */, ); path = LocalizedStringApp; sourceTree = ""; }; E264FBB62319055D008E0DB5 /* LocalizedStringAppTests */ = { isa = PBXGroup; children = ( E264FBB72319055D008E0DB5 /* LocalizedStringAppTests.swift */, E264FBB92319055D008E0DB5 /* Info.plist */, ); path = LocalizedStringAppTests; sourceTree = ""; }; E2E5836D291D3AB5006E17D9 /* Packages */ = { isa = PBXGroup; children = ( E2E5836E291D3AB5006E17D9 /* R.swift */, ); name = Packages; sourceTree = ""; }; E2E5836F291D3AC2006E17D9 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ E264FB9C2319055A008E0DB5 /* LocalizedStringApp */ = { isa = PBXNativeTarget; buildConfigurationList = E264FBBC2319055D008E0DB5 /* Build configuration list for PBXNativeTarget "LocalizedStringApp" */; buildPhases = ( E264FB992319055A008E0DB5 /* Sources */, E264FB9A2319055A008E0DB5 /* Frameworks */, E264FB9B2319055A008E0DB5 /* Resources */, ); buildRules = ( ); dependencies = ( E2E58373291D3AD4006E17D9 /* PBXTargetDependency */, ); name = LocalizedStringApp; packageProductDependencies = ( E2E58370291D3AC2006E17D9 /* RswiftLibrary */, ); productName = LocalizedStringApp; productReference = E264FB9D2319055A008E0DB5 /* LocalizedStringApp.app */; productType = "com.apple.product-type.application"; }; E264FBB22319055D008E0DB5 /* LocalizedStringAppTests */ = { isa = PBXNativeTarget; buildConfigurationList = E264FBBF2319055D008E0DB5 /* Build configuration list for PBXNativeTarget "LocalizedStringAppTests" */; buildPhases = ( E264FBAF2319055D008E0DB5 /* Sources */, E264FBB02319055D008E0DB5 /* Frameworks */, E264FBB12319055D008E0DB5 /* Resources */, ); buildRules = ( ); dependencies = ( E264FBB52319055D008E0DB5 /* PBXTargetDependency */, ); name = LocalizedStringAppTests; productName = LocalizedStringAppTests; productReference = E264FBB32319055D008E0DB5 /* LocalizedStringAppTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E264FB952319055A008E0DB5 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1100; LastUpgradeCheck = 1410; ORGANIZATIONNAME = R.swift; TargetAttributes = { E264FB9C2319055A008E0DB5 = { CreatedOnToolsVersion = 11.0; }; E264FBB22319055D008E0DB5 = { CreatedOnToolsVersion = 11.0; TestTargetID = E264FB9C2319055A008E0DB5; }; }; }; buildConfigurationList = E264FB982319055A008E0DB5 /* Build configuration list for PBXProject "LocalizedStringApp" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = fr; hasScannedForEncodings = 0; knownRegions = ( ca, en, nl, fr, "fr-CA", Base, "en-GB", ); mainGroup = E264FB942319055A008E0DB5; productRefGroup = E264FB9E2319055A008E0DB5 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E264FB9C2319055A008E0DB5 /* LocalizedStringApp */, E264FBB22319055D008E0DB5 /* LocalizedStringAppTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ E264FB9B2319055A008E0DB5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E264FBD923190992008E0DB5 /* four.strings in Resources */, E264FBE223190A19008E0DB5 /* six.strings in Resources */, E264FBF4231A7335008E0DB5 /* nine.strings in Resources */, E264FBCF2319082F008E0DB5 /* one.strings in Resources */, E258099B29325C1F008EA19C /* ten.stringsdict in Resources */, E264FBD22319083B008E0DB5 /* two.strings in Resources */, E264FBDD231909F6008E0DB5 /* five.strings in Resources */, E264FBE623190A2F008E0DB5 /* seven.strings in Resources */, E264FBEB23190A49008E0DB5 /* eight.strings in Resources */, E264FBD523190962008E0DB5 /* three.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; E264FBB12319055D008E0DB5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ E264FB992319055A008E0DB5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E264FBA12319055A008E0DB5 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E264FBAF2319055D008E0DB5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E264FBB82319055D008E0DB5 /* LocalizedStringAppTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ E264FBB52319055D008E0DB5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E264FB9C2319055A008E0DB5 /* LocalizedStringApp */; targetProxy = E264FBB42319055D008E0DB5 /* PBXContainerItemProxy */; }; E2E58373291D3AD4006E17D9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E2E58372291D3AD4006E17D9 /* RswiftGenerateInternalResources */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ E258099929325C1F008EA19C /* ten.stringsdict */ = { isa = PBXVariantGroup; children = ( E258099A29325C1F008EA19C /* fr */, E258099C29325C29008EA19C /* nl */, ); name = ten.stringsdict; sourceTree = ""; }; E264FBD02319083B008E0DB5 /* two.strings */ = { isa = PBXVariantGroup; children = ( E264FBD12319083B008E0DB5 /* en */, ); name = two.strings; sourceTree = ""; }; E264FBD323190962008E0DB5 /* three.strings */ = { isa = PBXVariantGroup; children = ( E264FBD423190962008E0DB5 /* en */, E264FBD62319096F008E0DB5 /* nl */, ); name = three.strings; sourceTree = ""; }; E264FBD723190992008E0DB5 /* four.strings */ = { isa = PBXVariantGroup; children = ( E264FBD823190992008E0DB5 /* nl */, E264FBDA231909D3008E0DB5 /* ca */, ); name = four.strings; sourceTree = ""; }; E264FBDB231909F6008E0DB5 /* five.strings */ = { isa = PBXVariantGroup; children = ( E264FBDC231909F6008E0DB5 /* fr */, E264FBDE231909FD008E0DB5 /* fr-CA */, E264FBDF231909FF008E0DB5 /* en */, E264FBF1231A6984008E0DB5 /* en-GB */, ); name = five.strings; sourceTree = ""; }; E264FBE023190A19008E0DB5 /* six.strings */ = { isa = PBXVariantGroup; children = ( E264FBE123190A19008E0DB5 /* fr */, E264FBE323190A1F008E0DB5 /* fr-CA */, ); name = six.strings; sourceTree = ""; }; E264FBE423190A2F008E0DB5 /* seven.strings */ = { isa = PBXVariantGroup; children = ( E264FBE523190A2F008E0DB5 /* nl */, E264FBE723190A38008E0DB5 /* en */, E264FBE823190A3C008E0DB5 /* fr */, ); name = seven.strings; sourceTree = ""; }; E264FBE923190A49008E0DB5 /* eight.strings */ = { isa = PBXVariantGroup; children = ( E264FBEA23190A49008E0DB5 /* fr */, E264FBEC23190A5A008E0DB5 /* Base */, E264FBED23190A65008E0DB5 /* nl */, ); name = eight.strings; sourceTree = ""; }; E264FBF6231A7335008E0DB5 /* nine.strings */ = { isa = PBXVariantGroup; children = ( E264FBF5231A7335008E0DB5 /* fr */, E264FBF7231A7371008E0DB5 /* Base */, E264FBF8231A7392008E0DB5 /* nl */, E264FBF9231A73BA008E0DB5 /* en */, ); name = nine.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ E264FBBA2319055D008E0DB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; E264FBBB2319055D008E0DB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; }; E264FBBD2319055D008E0DB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = LC3Y92HQQ3; INFOPLIST_FILE = LocalizedStringApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.LocalizedStringApp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E264FBBE2319055D008E0DB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = LC3Y92HQQ3; INFOPLIST_FILE = LocalizedStringApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.LocalizedStringApp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; E264FBC02319055D008E0DB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = LocalizedStringAppTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.LocalizedStringAppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LocalizedStringApp.app/LocalizedStringApp"; }; name = Debug; }; E264FBC12319055D008E0DB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = LocalizedStringAppTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.LocalizedStringAppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LocalizedStringApp.app/LocalizedStringApp"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E264FB982319055A008E0DB5 /* Build configuration list for PBXProject "LocalizedStringApp" */ = { isa = XCConfigurationList; buildConfigurations = ( E264FBBA2319055D008E0DB5 /* Debug */, E264FBBB2319055D008E0DB5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E264FBBC2319055D008E0DB5 /* Build configuration list for PBXNativeTarget "LocalizedStringApp" */ = { isa = XCConfigurationList; buildConfigurations = ( E264FBBD2319055D008E0DB5 /* Debug */, E264FBBE2319055D008E0DB5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E264FBBF2319055D008E0DB5 /* Build configuration list for PBXNativeTarget "LocalizedStringAppTests" */ = { isa = XCConfigurationList; buildConfigurations = ( E264FBC02319055D008E0DB5 /* Debug */, E264FBC12319055D008E0DB5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ E2E58370291D3AC2006E17D9 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E2E58372291D3AD4006E17D9 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = E264FB952319055A008E0DB5 /* Project object */; } ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "cd466d6e8c5ffd2f2b61165d37b0646f09068e1e", "version" : "2.9.0" } } ], "version" : 2 } ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp Dutch.xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp English (GB).xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp English.xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp French (Canada).xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp French.xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp Turkish.xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringApp.xcodeproj/xcshareddata/xcschemes/LocalizedStringApp.xcscheme ================================================ ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringAppTests/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: Examples/LocalizedStringApp/LocalizedStringAppTests/LocalizedStringAppTests.swift ================================================ // // LocalizedStringAppTests.swift // LocalizedStringAppTests // // Created by Tom Lokhorst on 2019-08-30. // Copyright © 2019 R.swift. All rights reserved. // import XCTest @testable import LocalizedStringApp class LocalizedStringAppTests: XCTestCase { func testDefault() { /* one */ XCTAssertEqual( R.string.one.one1(), NSLocalizedString("one1", tableName: "one", comment: "") ) XCTAssertEqual( R.string.one.one2(), NSLocalizedString("one2", tableName: "one", comment: "") ) XCTAssertEqual( R.string.one.oneArg("ARG"), String(format: NSLocalizedString("oneArg", tableName: "one", comment: ""), "ARG") ) /* two */ XCTAssertEqual( R.string.two.two1(), NSLocalizedString("two1", tableName: "two", comment: "") ) XCTAssertEqual( R.string.two.two2("Hello"), String(format: NSLocalizedString("two2", tableName: "two", comment: ""), locale: Locale.current, "Hello") ) /* three */ XCTAssertEqual( R.string.three.three1(), NSLocalizedString("three1", tableName: "three", comment: "") ) XCTAssertEqual( R.string.three.three2(), NSLocalizedString("three2", tableName: "three", comment: "") ) XCTAssertEqual( R.string.three.three3(), NSLocalizedString("three3", tableName: "three", comment: "") ) XCTAssertEqual( R.string.three.threeArg1("ARG"), String(format: NSLocalizedString("threeArg1", tableName: "three", comment: ""), "ARG") ) XCTAssertEqual( R.string.three.threeArg2("ARG"), String(format: NSLocalizedString("threeArg2", tableName: "three", comment: ""), "ARG") ) XCTAssertEqual( R.string.three.threeArg3("ARG"), String(format: NSLocalizedString("threeArg3", tableName: "three", comment: ""), "ARG") ) /* four */ XCTAssertEqual( R.string.four.four1(), NSLocalizedString("four1", tableName: "four", comment: "") ) XCTAssertEqual( R.string.four.fourArg("ARG"), String(format: NSLocalizedString("fourArg", tableName: "four", comment: ""), "ARG") ) /* five */ XCTAssertEqual( R.string.five.five1(), NSLocalizedString("five1", tableName: "five", comment: "") ) XCTAssertEqual( R.string.five.five2(), NSLocalizedString("five2", tableName: "five", value: "five 2, localized french", comment: "") ) XCTAssertEqual( R.string.five.five4(), NSLocalizedString("five4", tableName: "five", value: "five 4, localized french", comment: "") ) XCTAssertEqual( R.string.five.fiveArg1("ARG"), String(format: NSLocalizedString("fiveArg1", tableName: "five", comment: ""), "ARG") ) XCTAssertEqual( R.string.five.fiveArg2("ARG"), String(format: NSLocalizedString("fiveArg2", tableName: "five", value: "five 2 %@, localized french", comment: ""), "ARG") ) XCTAssertEqual( R.string.five.fiveArg4("ARG"), String(format: NSLocalizedString("fiveArg4", tableName: "five", value: "five 4 %@, localized french", comment: ""), "ARG") ) /* six */ XCTAssertEqual( R.string.six.six1(), NSLocalizedString("six1", tableName: "six", comment: "") ) XCTAssertEqual( R.string.six.six2(), NSLocalizedString("six2", tableName: "six", value: "six 2, localized french", comment: "") ) XCTAssertEqual( R.string.six.sixArg1("ARG"), String(format: NSLocalizedString("sixArg1", tableName: "six", comment: ""), "ARG") ) XCTAssertEqual( R.string.six.sixArg2("ARG"), String(format: NSLocalizedString("sixArg2", tableName: "six", value: "six 2 %@, localized french", comment: ""), "ARG") ) /* seven */ XCTAssertEqual( R.string.seven.seven1(), NSLocalizedString("seven1", tableName: "seven", comment: "") ) XCTAssertEqual( R.string.seven.seven2(), NSLocalizedString("seven2", tableName: "seven", value: "seven 2, localized french", comment: "") ) XCTAssertEqual( R.string.seven.seven3(), NSLocalizedString("seven3", tableName: "seven", value: "seven 3, localized french", comment: "") ) XCTAssertEqual( R.string.seven.seven4(), NSLocalizedString("seven4", tableName: "seven", value: "seven 4, localized french", comment: "") ) XCTAssertEqual( R.string.seven.sevenArg1("ARG"), String(format: NSLocalizedString("sevenArg1", tableName: "seven", comment: ""), "ARG") ) XCTAssertEqual( R.string.seven.sevenArg2("ARG"), String(format: NSLocalizedString("sevenArg2", tableName: "seven", value: "seven 2 %@, localized french", comment: ""), "ARG") ) XCTAssertEqual( R.string.seven.sevenArg3("ARG"), String(format: NSLocalizedString("sevenArg3", tableName: "seven", value: "seven 3 %@, localized french", comment: ""), "ARG") ) XCTAssertEqual( R.string.seven.sevenArg4("ARG"), String(format: NSLocalizedString("sevenArg4", tableName: "seven", value: "seven 4 %@, localized french", comment: ""), "ARG") ) /* eight */ XCTAssertEqual( R.string.eight.eight1(), NSLocalizedString("eight1", tableName: "eight", comment: "") ) XCTAssertEqual( R.string.eight.eight2(), NSLocalizedString("eight2", tableName: "eight", value: "eight 2, localized french", comment: "") ) XCTAssertEqual( R.string.eight.eight3(), NSLocalizedString("eight3", tableName: "eight", comment: "") ) XCTAssertEqual( R.string.eight.eightArg1("ARG"), String(format: NSLocalizedString("eightArg1", tableName: "eight", comment: ""), "ARG") ) XCTAssertEqual( R.string.eight.eightArg2("ARG"), String(format: NSLocalizedString("eightArg2", tableName: "eight", value: "eight 2 %@, localized french", comment: ""), "ARG") ) XCTAssertEqual( R.string.eight.eightArg3("ARG"), String(format: NSLocalizedString("eightArg3", tableName: "eight", comment: ""), "ARG") ) /* nine */ XCTAssertEqual( R.string.nine.nine1(), NSLocalizedString("nine1", tableName: "nine", comment: "") ) XCTAssertEqual( R.string.nine.nine2(), NSLocalizedString("nine2", tableName: "nine", value: "nine 2, localized french", comment: "") ) XCTAssertEqual( R.string.nine.nine3(), NSLocalizedString("nine3", tableName: "nine", comment: "") ) XCTAssertEqual( R.string.nine.nineArg1("ARG"), String(format: NSLocalizedString("nineArg1", tableName: "nine", comment: ""), "ARG") ) XCTAssertEqual( R.string.nine.nineArg2("ARG"), String(format: NSLocalizedString("nineArg2", tableName: "nine", value: "nine 2 %@, localized french", comment: ""), "ARG") ) XCTAssertEqual( R.string.nine.nineArg3("ARG"), String(format: NSLocalizedString("nineArg3", tableName: "nine", comment: ""), "ARG") ) /* ten */ XCTAssertEqual( R.string.ten.ten1(things: 1), String(format: NSLocalizedString("ten1", tableName: "ten", comment: ""), 1) ) } func testTurkish() { let myprefs = ["tr"] testPrefferedLanguages(myprefs: myprefs) let strings = R.string(preferredLanguages: myprefs) /* one */ XCTAssertEqual(strings.one.one1(), "one 1, not localized") XCTAssertEqual(strings.one.one2(), "one 2, not localized") XCTAssertEqual(strings.one.oneArg("ARG"), "one ARG, not localized") /* two */ XCTAssertEqual(strings.two.two1(), "two1") XCTAssertEqual(strings.two.two2("Hello"), "two2") /* three */ XCTAssertEqual(strings.three.three1(), "three1") XCTAssertEqual(strings.three.three2(), "three2") XCTAssertEqual(strings.three.three3(), "three3") XCTAssertEqual(strings.three.threeArg1("ARG"), "threeArg1") XCTAssertEqual(strings.three.threeArg2("ARG"), "threeArg2") XCTAssertEqual(strings.three.threeArg3("ARG"), "threeArg3") /* four */ XCTAssertEqual(strings.four.four1(), "four1") XCTAssertEqual(strings.four.fourArg("ARG"), "fourArg") /* five */ XCTAssertEqual(strings.five.five1(), "five 1, localized french") XCTAssertEqual(strings.five.five2(), "five 2, localized french") XCTAssertEqual(strings.five.five4(), "five 4, localized french") XCTAssertEqual(strings.five.fiveArg1("ARG"), "five 1 ARG, localized french") XCTAssertEqual(strings.five.fiveArg2("ARG"), "five 2 ARG, localized french") XCTAssertEqual(strings.five.fiveArg4("ARG"), "five 4 ARG, localized french") /* six */ XCTAssertEqual(strings.six.six1(), "six 1, localized french") XCTAssertEqual(strings.six.six2(), "six 2, localized french") XCTAssertEqual(strings.six.sixArg1("ARG"), "six 1 ARG, localized french") XCTAssertEqual(strings.six.sixArg2("ARG"), "six 2 ARG, localized french") /* seven */ XCTAssertEqual(strings.seven.seven1(), "seven 1, localized french") XCTAssertEqual(strings.seven.seven2(), "seven 2, localized french") XCTAssertEqual(strings.seven.seven3(), "seven 3, localized french") XCTAssertEqual(strings.seven.seven4(), "seven 4, localized french") XCTAssertEqual(strings.seven.sevenArg1("ARG"), "seven 1 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg2("ARG"), "seven 2 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg3("ARG"), "seven 3 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg4("ARG"), "seven 4 ARG, localized french") /* eight */ XCTAssertEqual(strings.eight.eight1(), "eight 1, localized french") XCTAssertEqual(strings.eight.eight2(), "eight 2, localized french") XCTAssertEqual(strings.eight.eight3(), "eight3") XCTAssertEqual(strings.eight.eightArg1("ARG"), "eight 1 ARG, localized french") XCTAssertEqual(strings.eight.eightArg2("ARG"), "eight 2 ARG, localized french") XCTAssertEqual(strings.eight.eightArg3("ARG"), "eightArg3") /* nine */ XCTAssertEqual(strings.nine.nine1(), "nine 1, localized french") XCTAssertEqual(strings.nine.nine2(), "nine 2, localized french") XCTAssertEqual(strings.nine.nine3(), "nine3") XCTAssertEqual(strings.nine.nineArg1("ARG"), "nine 1 ARG, localized french") XCTAssertEqual(strings.nine.nineArg2("ARG"), "nine 2 ARG, localized french") XCTAssertEqual(strings.nine.nineArg3("ARG"), "nineArg3") /* ten */ XCTAssertEqual(strings.ten.ten1(things: 1), "ten 1 - 1 thing, localized french") } func testDutch() { let myprefs = ["nl"] testPrefferedLanguages(myprefs: myprefs) let strings = R.string(preferredLanguages: myprefs) /* one */ XCTAssertEqual(strings.one.one1(), "one 1, not localized") XCTAssertEqual(strings.one.one2(), "one 2, not localized") XCTAssertEqual(strings.one.oneArg("ARG"), "one ARG, not localized") /* two */ XCTAssertEqual(strings.two.two1(), "two1") XCTAssertEqual(strings.two.two2("Hello"), "two2") /* three */ XCTAssertEqual(strings.three.three1(), "three 1, localized dutch") XCTAssertEqual(strings.three.three2(), "three2") XCTAssertEqual(strings.three.three3(), "three 3, localized dutch") XCTAssertEqual(strings.three.threeArg1("ARG"), "three 1 ARG, localized dutch") XCTAssertEqual(strings.three.threeArg2("ARG"), "threeArg2") XCTAssertEqual(strings.three.threeArg3("ARG"), "three 3 ARG, localized dutch") /* four */ XCTAssertEqual(strings.four.four1(), "four 1, localized dutch") XCTAssertEqual(strings.four.fourArg("ARG"), "four ARG, localized dutch") /* five */ XCTAssertEqual(strings.five.five1(), "five 1, localized french") XCTAssertEqual(strings.five.five2(), "five 2, localized french") XCTAssertEqual(strings.five.five4(), "five 4, localized french") XCTAssertEqual(strings.five.fiveArg1("ARG"), "five 1 ARG, localized french") XCTAssertEqual(strings.five.fiveArg2("ARG"), "five 2 ARG, localized french") XCTAssertEqual(strings.five.fiveArg4("ARG"), "five 4 ARG, localized french") /* six */ XCTAssertEqual(strings.six.six1(), "six 1, localized french") XCTAssertEqual(strings.six.six2(), "six 2, localized french") XCTAssertEqual(strings.six.sixArg1("ARG"), "six 1 ARG, localized french") XCTAssertEqual(strings.six.sixArg2("ARG"), "six 2 ARG, localized french") /* seven */ XCTAssertEqual(strings.seven.seven1(), "seven 1, localized dutch") XCTAssertEqual(strings.seven.seven2(), "seven2") XCTAssertEqual(strings.seven.seven3(), "seven3") XCTAssertEqual(strings.seven.seven4(), "seven 4, localized dutch") XCTAssertEqual(strings.seven.sevenArg1("ARG"), "seven 1 ARG, localized dutch") XCTAssertEqual(strings.seven.sevenArg2("ARG"), "sevenArg2") XCTAssertEqual(strings.seven.sevenArg3("ARG"), "sevenArg3") XCTAssertEqual(strings.seven.sevenArg4("ARG"), "seven 4 ARG, localized dutch") /* eight */ XCTAssertEqual(strings.eight.eight1(), "eight 1, localized dutch") XCTAssertEqual(strings.eight.eight2(), "eight2") XCTAssertEqual(strings.eight.eight3(), "eight3") XCTAssertEqual(strings.eight.eightArg1("ARG"), "eight 1 ARG, localized dutch") XCTAssertEqual(strings.eight.eightArg2("ARG"), "eightArg2") XCTAssertEqual(strings.eight.eightArg3("ARG"), "eightArg3") /* nine */ XCTAssertEqual(strings.nine.nine1(), "nine 1, localized dutch") XCTAssertEqual(strings.nine.nine2(), "nine2") XCTAssertEqual(strings.nine.nine3(), "nine3") XCTAssertEqual(strings.nine.nineArg1("ARG"), "nine 1 ARG, localized dutch") XCTAssertEqual(strings.nine.nineArg2("ARG"), "nineArg2") XCTAssertEqual(strings.nine.nineArg3("ARG"), "nineArg3") /* ten */ XCTAssertEqual(strings.ten.ten1(things: 1), "ten 1 - 1 thing, localized dutch") } func testEnglish() { let myprefs = ["en"] testPrefferedLanguages(myprefs: myprefs) let strings = R.string(preferredLanguages: myprefs) /* one */ XCTAssertEqual(strings.one.one1(), "one 1, not localized") XCTAssertEqual(strings.one.one2(), "one 2, not localized") XCTAssertEqual(strings.one.oneArg("ARG"), "one ARG, not localized") /* two */ XCTAssertEqual(strings.two.two1(), "two 1, localized english") XCTAssertEqual(strings.two.two2("Hello"), "two 2, Hello localized english") /* three */ XCTAssertEqual(strings.three.three1(), "three 1, localized english") XCTAssertEqual(strings.three.three2(), "three 2, localized english") XCTAssertEqual(strings.three.three3(), "three3") XCTAssertEqual(strings.three.threeArg1("ARG"), "three 1 ARG, localized english") XCTAssertEqual(strings.three.threeArg2("ARG"), "three 2 ARG, localized english") XCTAssertEqual(strings.three.threeArg3("ARG"), "threeArg3") /* four */ XCTAssertEqual(strings.four.four1(), "four1") XCTAssertEqual(strings.four.fourArg("ARG"), "fourArg") /* five */ XCTAssertEqual(strings.five.five1(), "five 1, localized english") XCTAssertEqual(strings.five.five2(), "five 2, localized english") XCTAssertEqual(strings.five.five4(), "five4") XCTAssertEqual(strings.five.fiveArg1("ARG"), "five 1 ARG, localized english") XCTAssertEqual(strings.five.fiveArg2("ARG"), "five 2 ARG, localized english") XCTAssertEqual(strings.five.fiveArg4("ARG"), "fiveArg4") /* six */ XCTAssertEqual(strings.six.six1(), "six 1, localized french") XCTAssertEqual(strings.six.six2(), "six 2, localized french") XCTAssertEqual(strings.six.sixArg1("ARG"), "six 1 ARG, localized french") XCTAssertEqual(strings.six.sixArg2("ARG"), "six 2 ARG, localized french") /* seven */ XCTAssertEqual(strings.seven.seven1(), "seven 1, localized english") XCTAssertEqual(strings.seven.seven2(), "seven 2, localized english") XCTAssertEqual(strings.seven.seven3(), "seven3") XCTAssertEqual(strings.seven.seven4(), "seven4") XCTAssertEqual(strings.seven.sevenArg1("ARG"), "seven 1 ARG, localized english") XCTAssertEqual(strings.seven.sevenArg2("ARG"), "seven 2 ARG, localized english") XCTAssertEqual(strings.seven.sevenArg3("ARG"), "sevenArg3") XCTAssertEqual(strings.seven.sevenArg4("ARG"), "sevenArg4") /* eight */ XCTAssertEqual(strings.eight.eight1(), "eight 1, localized base") XCTAssertEqual(strings.eight.eight2(), "eight 2, localized base") XCTAssertEqual(strings.eight.eight3(), "eight 3, localized base") XCTAssertEqual(strings.eight.eightArg1("ARG"), "eight 1 ARG, localized base") XCTAssertEqual(strings.eight.eightArg2("ARG"), "eight 2 ARG, localized base") XCTAssertEqual(strings.eight.eightArg3("ARG"), "eight 3 ARG, localized base") /* nine */ XCTAssertEqual(strings.nine.nine1(), "nine 1, localized english") XCTAssertEqual(strings.nine.nine2(), "nine 2, localized english") XCTAssertEqual(strings.nine.nine3(), "nine3") XCTAssertEqual(strings.nine.nineArg1("ARG"), "nine 1 ARG, localized english") XCTAssertEqual(strings.nine.nineArg2("ARG"), "nine 2 ARG, localized english") XCTAssertEqual(strings.nine.nineArg3("ARG"), "nineArg3") /* ten */ XCTAssertEqual(strings.ten.ten1(things: 1), "ten 1 - 1 thing, localized french") } func testEnglishGB() { let myprefs = ["en-GB"] testPrefferedLanguages(myprefs: myprefs) let strings = R.string(preferredLanguages: myprefs) /* one */ XCTAssertEqual(strings.one.one1(), "one 1, not localized") XCTAssertEqual(strings.one.one2(), "one 2, not localized") XCTAssertEqual(strings.one.oneArg("ARG"), "one ARG, not localized") /* two */ XCTAssertEqual(strings.two.two1(), "two 1, localized english") XCTAssertEqual(strings.two.two2("Hello"), "two 2, Hello localized english") /* three */ XCTAssertEqual(strings.three.three1(), "three 1, localized english") XCTAssertEqual(strings.three.three2(), "three 2, localized english") XCTAssertEqual(strings.three.three3(), "three3") XCTAssertEqual(strings.three.threeArg1("ARG"), "three 1 ARG, localized english") XCTAssertEqual(strings.three.threeArg2("ARG"), "three 2 ARG, localized english") XCTAssertEqual(strings.three.threeArg3("ARG"), "threeArg3") /* four */ XCTAssertEqual(strings.four.four1(), "four1") XCTAssertEqual(strings.four.fourArg("ARG"), "fourArg") /* five */ XCTAssertEqual(strings.five.five1(), "five 1, localized english gb") XCTAssertEqual(strings.five.five2(), "five2") XCTAssertEqual(strings.five.five4(), "five4") XCTAssertEqual(strings.five.fiveArg1("ARG"), "five 1 ARG, localized english gb") XCTAssertEqual(strings.five.fiveArg2("ARG"), "fiveArg2") XCTAssertEqual(strings.five.fiveArg4("ARG"), "fiveArg4") /* six */ XCTAssertEqual(strings.six.six1(), "six 1, localized french") XCTAssertEqual(strings.six.six2(), "six 2, localized french") XCTAssertEqual(strings.six.sixArg1("ARG"), "six 1 ARG, localized french") XCTAssertEqual(strings.six.sixArg2("ARG"), "six 2 ARG, localized french") /* seven */ XCTAssertEqual(strings.seven.seven1(), "seven 1, localized english") XCTAssertEqual(strings.seven.seven2(), "seven 2, localized english") XCTAssertEqual(strings.seven.seven3(), "seven3") XCTAssertEqual(strings.seven.seven4(), "seven4") XCTAssertEqual(strings.seven.sevenArg1("ARG"), "seven 1 ARG, localized english") XCTAssertEqual(strings.seven.sevenArg2("ARG"), "seven 2 ARG, localized english") XCTAssertEqual(strings.seven.sevenArg3("ARG"), "sevenArg3") XCTAssertEqual(strings.seven.sevenArg4("ARG"), "sevenArg4") /* eight */ XCTAssertEqual(strings.eight.eight1(), "eight 1, localized base") XCTAssertEqual(strings.eight.eight2(), "eight 2, localized base") XCTAssertEqual(strings.eight.eight3(), "eight 3, localized base") XCTAssertEqual(strings.eight.eightArg1("ARG"), "eight 1 ARG, localized base") XCTAssertEqual(strings.eight.eightArg2("ARG"), "eight 2 ARG, localized base") XCTAssertEqual(strings.eight.eightArg3("ARG"), "eight 3 ARG, localized base") /* nine */ XCTAssertEqual(strings.nine.nine1(), "nine 1, localized base") XCTAssertEqual(strings.nine.nine2(), "nine 2, localized base") XCTAssertEqual(strings.nine.nine3(), "nine 3, localized base") XCTAssertEqual(strings.nine.nineArg1("ARG"), "nine 1 ARG, localized base") XCTAssertEqual(strings.nine.nineArg2("ARG"), "nine 2 ARG, localized base") XCTAssertEqual(strings.nine.nineArg3("ARG"), "nine 3 ARG, localized base") /* ten */ XCTAssertEqual(strings.ten.ten1(things: 1), "ten 1 - 1 thing, localized french") } func testFrench() { let myprefs = ["fr"] testPrefferedLanguages(myprefs: myprefs) let strings = R.string(preferredLanguages: myprefs) /* one */ XCTAssertEqual(strings.one.one1(), "one 1, not localized") XCTAssertEqual(strings.one.one2(), "one 2, not localized") XCTAssertEqual(strings.one.oneArg("ARG"), "one ARG, not localized") /* two */ XCTAssertEqual(strings.two.two1(), "two1") XCTAssertEqual(strings.two.two2("Hello"), "two2") /* three */ XCTAssertEqual(strings.three.three1(), "three1") XCTAssertEqual(strings.three.three2(), "three2") XCTAssertEqual(strings.three.three3(), "three3") XCTAssertEqual(strings.three.threeArg1("ARG"), "threeArg1") XCTAssertEqual(strings.three.threeArg2("ARG"), "threeArg2") XCTAssertEqual(strings.three.threeArg3("ARG"), "threeArg3") /* four */ XCTAssertEqual(strings.four.four1(), "four1") XCTAssertEqual(strings.four.fourArg("ARG"), "fourArg") /* five */ XCTAssertEqual(strings.five.five1(), "five 1, localized french") XCTAssertEqual(strings.five.five2(), "five 2, localized french") XCTAssertEqual(strings.five.five4(), "five 4, localized french") XCTAssertEqual(strings.five.fiveArg1("ARG"), "five 1 ARG, localized french") XCTAssertEqual(strings.five.fiveArg2("ARG"), "five 2 ARG, localized french") XCTAssertEqual(strings.five.fiveArg4("ARG"), "five 4 ARG, localized french") /* six */ XCTAssertEqual(strings.six.six1(), "six 1, localized french") XCTAssertEqual(strings.six.six2(), "six 2, localized french") XCTAssertEqual(strings.six.sixArg1("ARG"), "six 1 ARG, localized french") XCTAssertEqual(strings.six.sixArg2("ARG"), "six 2 ARG, localized french") /* seven */ XCTAssertEqual(strings.seven.seven1(), "seven 1, localized french") XCTAssertEqual(strings.seven.seven2(), "seven 2, localized french") XCTAssertEqual(strings.seven.seven3(), "seven 3, localized french") XCTAssertEqual(strings.seven.seven4(), "seven 4, localized french") XCTAssertEqual(strings.seven.sevenArg1("ARG"), "seven 1 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg2("ARG"), "seven 2 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg3("ARG"), "seven 3 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg4("ARG"), "seven 4 ARG, localized french") /* eight */ XCTAssertEqual(strings.eight.eight1(), "eight 1, localized french") XCTAssertEqual(strings.eight.eight2(), "eight 2, localized french") XCTAssertEqual(strings.eight.eight3(), "eight3") XCTAssertEqual(strings.eight.eightArg1("ARG"), "eight 1 ARG, localized french") XCTAssertEqual(strings.eight.eightArg2("ARG"), "eight 2 ARG, localized french") XCTAssertEqual(strings.eight.eightArg3("ARG"), "eightArg3") /* nine */ XCTAssertEqual(strings.nine.nine1(), "nine 1, localized french") XCTAssertEqual(strings.nine.nine2(), "nine 2, localized french") XCTAssertEqual(strings.nine.nine3(), "nine3") XCTAssertEqual(strings.nine.nineArg1("ARG"), "nine 1 ARG, localized french") XCTAssertEqual(strings.nine.nineArg2("ARG"), "nine 2 ARG, localized french") XCTAssertEqual(strings.nine.nineArg3("ARG"), "nineArg3") /* ten */ XCTAssertEqual(strings.ten.ten1(things: 1), "ten 1 - 1 thing, localized french") } func testFrenchCanada() { let myprefs = ["fr-CA"] testPrefferedLanguages(myprefs: myprefs) let strings = R.string(preferredLanguages: myprefs) /* one */ XCTAssertEqual(strings.one.one1(), "one 1, not localized") XCTAssertEqual(strings.one.one2(), "one 2, not localized") XCTAssertEqual(strings.one.oneArg("ARG"), "one ARG, not localized") /* two */ XCTAssertEqual(strings.two.two1(), "two1") XCTAssertEqual(strings.two.two2("Hello"), "two2") /* three */ XCTAssertEqual(strings.three.three1(), "three1") XCTAssertEqual(strings.three.three2(), "three2") XCTAssertEqual(strings.three.three3(), "three3") XCTAssertEqual(strings.three.threeArg1("ARG"), "threeArg1") XCTAssertEqual(strings.three.threeArg2("ARG"), "threeArg2") XCTAssertEqual(strings.three.threeArg3("ARG"), "threeArg3") /* four */ XCTAssertEqual(strings.four.four1(), "four1") XCTAssertEqual(strings.four.fourArg("ARG"), "fourArg") /* five */ XCTAssertEqual(strings.five.five1(), "five 1, localized french canada") XCTAssertEqual(strings.five.five2(), "five2") XCTAssertEqual(strings.five.five4(), "five4") XCTAssertEqual(strings.five.fiveArg1("ARG"), "five 1 ARG, localized french canada") XCTAssertEqual(strings.five.fiveArg2("ARG"), "fiveArg2") XCTAssertEqual(strings.five.fiveArg4("ARG"), "fiveArg4") /* six */ XCTAssertEqual(strings.six.six1(), "six 1, localized french canada") XCTAssertEqual(strings.six.six2(), "six2") XCTAssertEqual(strings.six.sixArg1("ARG"), "six 1 ARG, localized french canada") XCTAssertEqual(strings.six.sixArg2("ARG"), "sixArg2") /* seven */ XCTAssertEqual(strings.seven.seven1(), "seven 1, localized french") XCTAssertEqual(strings.seven.seven2(), "seven 2, localized french") XCTAssertEqual(strings.seven.seven3(), "seven 3, localized french") XCTAssertEqual(strings.seven.seven4(), "seven 4, localized french") XCTAssertEqual(strings.seven.sevenArg1("ARG"), "seven 1 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg2("ARG"), "seven 2 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg3("ARG"), "seven 3 ARG, localized french") XCTAssertEqual(strings.seven.sevenArg4("ARG"), "seven 4 ARG, localized french") /* eight */ XCTAssertEqual(strings.eight.eight1(), "eight 1, localized base") XCTAssertEqual(strings.eight.eight2(), "eight 2, localized base") XCTAssertEqual(strings.eight.eight3(), "eight 3, localized base") XCTAssertEqual(strings.eight.eightArg1("ARG"), "eight 1 ARG, localized base") XCTAssertEqual(strings.eight.eightArg2("ARG"), "eight 2 ARG, localized base") XCTAssertEqual(strings.eight.eightArg3("ARG"), "eight 3 ARG, localized base") /* nine */ XCTAssertEqual(strings.nine.nine1(), "nine 1, localized base") XCTAssertEqual(strings.nine.nine2(), "nine 2, localized base") XCTAssertEqual(strings.nine.nine3(), "nine 3, localized base") XCTAssertEqual(strings.nine.nineArg1("ARG"), "nine 1 ARG, localized base") XCTAssertEqual(strings.nine.nineArg2("ARG"), "nine 2 ARG, localized base") XCTAssertEqual(strings.nine.nineArg3("ARG"), "nine 3 ARG, localized base") /* ten */ XCTAssertEqual(strings.ten.ten1(things: 1), "ten 1 - 1 thing, localized french") } func testPrefferedLanguages(myprefs: [String]) { /* one */ XCTAssertEqual(R.string.one.one1(preferredLanguages: myprefs), R.string.one(preferredLanguages: myprefs).one1()) XCTAssertEqual(R.string.one.one2(preferredLanguages: myprefs), R.string.one(preferredLanguages: myprefs).one2()) XCTAssertEqual(R.string.one.oneArg("ARG", preferredLanguages: myprefs), R.string.one(preferredLanguages: myprefs).oneArg("ARG")) /* two */ XCTAssertEqual(R.string.two.two1(preferredLanguages: myprefs), R.string.two(preferredLanguages: myprefs).two1()) XCTAssertEqual(R.string.two.two2("Hello", preferredLanguages: myprefs), R.string.two(preferredLanguages: myprefs).two2("Hello")) /* three */ XCTAssertEqual(R.string.three.three1(preferredLanguages: myprefs), R.string.three(preferredLanguages: myprefs).three1()) XCTAssertEqual(R.string.three.three2(preferredLanguages: myprefs), R.string.three(preferredLanguages: myprefs).three2()) XCTAssertEqual(R.string.three.three3(preferredLanguages: myprefs), R.string.three(preferredLanguages: myprefs).three3()) XCTAssertEqual(R.string.three.threeArg1("ARG", preferredLanguages: myprefs), R.string.three(preferredLanguages: myprefs).threeArg1("ARG")) XCTAssertEqual(R.string.three.threeArg2("ARG", preferredLanguages: myprefs), R.string.three(preferredLanguages: myprefs).threeArg2("ARG")) XCTAssertEqual(R.string.three.threeArg3("ARG", preferredLanguages: myprefs), R.string.three(preferredLanguages: myprefs).threeArg3("ARG")) /* four */ XCTAssertEqual(R.string.four.four1(preferredLanguages: myprefs), R.string.four(preferredLanguages: myprefs).four1()) XCTAssertEqual(R.string.four.fourArg("ARG", preferredLanguages: myprefs), R.string.four(preferredLanguages: myprefs).fourArg("ARG")) /* five */ XCTAssertEqual(R.string.five.five1(preferredLanguages: myprefs), R.string.five(preferredLanguages: myprefs).five1()) XCTAssertEqual(R.string.five.five2(preferredLanguages: myprefs), R.string.five(preferredLanguages: myprefs).five2()) XCTAssertEqual(R.string.five.five4(preferredLanguages: myprefs), R.string.five(preferredLanguages: myprefs).five4()) XCTAssertEqual(R.string.five.fiveArg1("ARG", preferredLanguages: myprefs), R.string.five(preferredLanguages: myprefs).fiveArg1("ARG")) XCTAssertEqual(R.string.five.fiveArg2("ARG", preferredLanguages: myprefs), R.string.five(preferredLanguages: myprefs).fiveArg2("ARG")) XCTAssertEqual(R.string.five.fiveArg4("ARG", preferredLanguages: myprefs), R.string.five(preferredLanguages: myprefs).fiveArg4("ARG")) /* six */ XCTAssertEqual(R.string.six.six1(preferredLanguages: myprefs), R.string.six(preferredLanguages: myprefs).six1()) XCTAssertEqual(R.string.six.six2(preferredLanguages: myprefs), R.string.six(preferredLanguages: myprefs).six2()) XCTAssertEqual(R.string.six.sixArg1("ARG", preferredLanguages: myprefs), R.string.six(preferredLanguages: myprefs).sixArg1("ARG")) XCTAssertEqual(R.string.six.sixArg2("ARG", preferredLanguages: myprefs), R.string.six(preferredLanguages: myprefs).sixArg2("ARG")) /* seven */ XCTAssertEqual(R.string.seven.seven1(preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).seven1()) XCTAssertEqual(R.string.seven.seven2(preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).seven2()) XCTAssertEqual(R.string.seven.seven3(preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).seven3()) XCTAssertEqual(R.string.seven.seven4(preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).seven4()) XCTAssertEqual(R.string.seven.sevenArg1("ARG", preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).sevenArg1("ARG")) XCTAssertEqual(R.string.seven.sevenArg2("ARG", preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).sevenArg2("ARG")) XCTAssertEqual(R.string.seven.sevenArg3("ARG", preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).sevenArg3("ARG")) XCTAssertEqual(R.string.seven.sevenArg4("ARG", preferredLanguages: myprefs), R.string.seven(preferredLanguages: myprefs).sevenArg4("ARG")) /* eight */ XCTAssertEqual(R.string.eight.eight1(preferredLanguages: myprefs), R.string.eight(preferredLanguages: myprefs).eight1()) XCTAssertEqual(R.string.eight.eight2(preferredLanguages: myprefs), R.string.eight(preferredLanguages: myprefs).eight2()) XCTAssertEqual(R.string.eight.eight3(preferredLanguages: myprefs), R.string.eight(preferredLanguages: myprefs).eight3()) XCTAssertEqual(R.string.eight.eightArg1("ARG", preferredLanguages: myprefs), R.string.eight(preferredLanguages: myprefs).eightArg1("ARG")) XCTAssertEqual(R.string.eight.eightArg2("ARG", preferredLanguages: myprefs), R.string.eight(preferredLanguages: myprefs).eightArg2("ARG")) XCTAssertEqual(R.string.eight.eightArg3("ARG", preferredLanguages: myprefs), R.string.eight(preferredLanguages: myprefs).eightArg3("ARG")) /* nine */ XCTAssertEqual(R.string.nine.nine1(preferredLanguages: myprefs), R.string.nine(preferredLanguages: myprefs).nine1()) XCTAssertEqual(R.string.nine.nine2(preferredLanguages: myprefs), R.string.nine(preferredLanguages: myprefs).nine2()) XCTAssertEqual(R.string.nine.nine3(preferredLanguages: myprefs), R.string.nine(preferredLanguages: myprefs).nine3()) XCTAssertEqual(R.string.nine.nineArg1("ARG", preferredLanguages: myprefs), R.string.nine(preferredLanguages: myprefs).nineArg1("ARG")) XCTAssertEqual(R.string.nine.nineArg2("ARG", preferredLanguages: myprefs), R.string.nine(preferredLanguages: myprefs).nineArg2("ARG")) XCTAssertEqual(R.string.nine.nineArg3("ARG", preferredLanguages: myprefs), R.string.nine(preferredLanguages: myprefs).nineArg3("ARG")) /* ten */ XCTAssertEqual(R.string.ten.ten1(things: 1, preferredLanguages: myprefs), R.string.ten(preferredLanguages: myprefs).ten1(things: 1)) } } ================================================ FILE: Examples/ResourceApp/.rswiftignore ================================================ # Filtering single file ResourceApp/Images/Sky.tiff # Corrupt line # Ignore all files containing '.ignoreme.' **/*.ignoreme.* # Explicitly include single file !ResourceApp/ExplicitInclude.ignoreme.png # Explicitly include all files containing '.dont.ignoreme.' !**/*.dont.ignoreme.* ================================================ FILE: Examples/ResourceApp/Podfile ================================================ use_frameworks! workspace 'ResourceApp' target 'ResourceApp' do platform :ios, '12.0' project 'ResourceApp' pod 'SWRevealViewController' end post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' end end end ================================================ FILE: Examples/ResourceApp/ResourceApp/AppDelegate.swift ================================================ // // AppDelegate.swift // ResourceApp // // Created by Mathijs Kadijk on 20-07-15. // Copyright (c) 2015 Mathijs Kadijk. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool { // let defaults = UserDefaults.standard // defaults.setValue(["nl"], forKey: "AppleLanguages") // Override point for customization after application launch. return true } @available(iOS 13.0, *) func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. let sceneConfigurationName = R.info.uiApplicationSceneManifest.uiSceneConfigurations .uiWindowSceneSessionRoleApplication.defaultConfiguration.uiSceneConfigurationName return UISceneConfiguration(name: sceneConfigurationName, sessionRole: connectingSceneSession.role) } @available(iOS 13.0, *) func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Base.lproj/Main.storyboard ================================================ Helvetica ================================================ FILE: Examples/ResourceApp/ResourceApp/Base.lproj/Secondary.storyboard ================================================ Helvetica ================================================ FILE: Examples/ResourceApp/ResourceApp/CellCollectionView.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/CellView.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/CustomSegue.swift ================================================ // // CustomSegue.swift // ResourceApp // // Created by Tom Lokhorst on 2019-06-10. // Copyright © 2019 Mathijs Kadijk. All rights reserved. // import UIKit class CustomSegue: UIStoryboardSegue { } ================================================ FILE: Examples/ResourceApp/ResourceApp/Duplicate/ADuplicateCellView.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Duplicate/duplicate.storyboard ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Duplicate/duplicate.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Duplicate.storyboard ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Duplicate.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/DuplicateCellView.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Files/#column ================================================ #column is a Swift keyword as of Swift 2.2 ================================================ FILE: Examples/ResourceApp/ResourceApp/Files/Duplicate.json ================================================ { "some": "json" } ================================================ FILE: Examples/ResourceApp/ResourceApp/Files/Some.json ================================================ { "some": "json" } ================================================ FILE: Examples/ResourceApp/ResourceApp/Files/__FILE__ ================================================ __FILE__ is a reserved keyword in Swift ================================================ FILE: Examples/ResourceApp/ResourceApp/Files/associatedtype ================================================ associatedtype is a Swift keyword as of Swift 2.2 ================================================ FILE: Examples/ResourceApp/ResourceApp/Files/duplicateJson ================================================ { "some": "json" } ================================================ FILE: Examples/ResourceApp/ResourceApp/FirstViewController.swift ================================================ // // FirstViewController.swift // ResourceApp // // Created by Mathijs Kadijk on 20-07-15. // Copyright (c) 2015 Mathijs Kadijk. All rights reserved. // import UIKit class FirstViewController: UIViewController { @IBOutlet weak var titleLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. titleLabel.font = R.font.averiaLibreBoldItalic(size: 36) tabBarItem.image = R.image.userWhite() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "AppIcon.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "AppIcon-3.png", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "AppIcon-1.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "AppIcon-2.png", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/My Red.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "display-p3", "components" : { "red" : 0.8784313725, "alpha" : 1, "blue" : 0, "green" : 0.4392156863 } } } ] } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Namespace/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Namespace/Second.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "second.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Namespace/first.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Second.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "second.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Some Folder/A Nested Folder/first nested.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Some Folder/A Nested Folder/second nested.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "second.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Some Folder/eerste.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/Some Folder/second.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "second.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/TheAppIcon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "The App Icon.png", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images.xcassets/first.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Conflicting.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/Inner/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/Inner/Namespace 2/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/Inner/Namespace 2/Folder/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/Inner/Namespace 2/Folder/first.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/Second.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "second.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace 1/third.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/Inner/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/Inner/Namespace/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/Inner/Namespace/Folder/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/Inner/Namespace/Folder/first.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/Second.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "second.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/Namespace-/third.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/conflicting/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Images2.xcassets/conflicting/first.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "first.pdf" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDocumentTypes CFBundleTypeName MKDirectionsRequest LSItemContentTypes com.apple.maps.directionsrequest CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UIAppFonts AveriaLibre-B.ttf AveriaLibre-BI.ttf AveriaLibre-L.ttf AveriaLibre.ttf GdyBkltter1911.ttf UIApplicationShortcutItems UIApplicationShortcutItemIconFile ShortcutQrScanning UIApplicationShortcutItemTitle Scan QR-code UIApplicationShortcutItemType nl.mathijskadijk.shortcuts.qr-scanning UIApplicationShortcutItemIconFile ShortcutSendParcel UIApplicationShortcutItemTitle Send a Parcel UIApplicationShortcutItemType nl.mathijskadijk.shortcuts.send-parcel UIApplicationSupportsMultipleScenes UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate NSUserActivityTypes PlanTripIntent ShowDeparturesIntent DuplicatePlistValue DuplicatePlistValue NSExtension DuplicatePlistKey# Foo DuplicatePlistKey* Bar NSExtensionAttributes IntentsRestrictedWhileLocked IntentsRestrictedWhileProtectedDataUnavailable IntentsSupported PlanTripIntent ShowDeparturesIntent NSExtensionPointIdentifier com.apple.intents-service NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).IntentHandler UIStatusBarTintParameters UINavigationBar Style UIBarStyleDefault Translucent UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/ResourceApp/ResourceApp/Localized/Base.lproj/hello.txt ================================================ Hello, World! ================================================ FILE: Examples/ResourceApp/ResourceApp/Localized/es.lproj/hello.txt ================================================ ¡Hola Mundo! ================================================ FILE: Examples/ResourceApp/ResourceApp/Localized/nl.lproj/hello.txt ================================================ Hallo, Wereld! ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/Folder/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/Folder/Not dupe.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "srgb", "components" : { "red" : 0.7860491071, "alpha" : 1, "blue" : 1, "green" : 1 } } } ] } ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/Keyboard Focus Indicator color.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "srgb", "components" : { "red" : 0.2313725490196079, "alpha" : 1, "blue" : 0.9882352941176471, "green" : 0.6 } } } ] } ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/My Red.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "display-p3", "components" : { "red" : 0.7215686274999999, "alpha" : 1, "blue" : 0.1019607843, "green" : 0.02745098039 } } } ] } ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/Not dupe.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "display-p3", "components" : { "red" : 1, "alpha" : 1, "blue" : 1, "green" : 0.7767578125 } } } ] } ================================================ FILE: Examples/ResourceApp/ResourceApp/Media.xcassets/Slightly transparant.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "extended-gray", "components" : { "white" : 0, "alpha" : 0.4 } } } ] } ================================================ FILE: Examples/ResourceApp/ResourceApp/My View.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/MyViewController.swift ================================================ // // MyViewController.swift // ResourceApp // // Created by Mathijs Kadijk on 08-08-15. // Copyright © 2015 Mathijs Kadijk. All rights reserved. // import UIKit class MyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ } ================================================ FILE: Examples/ResourceApp/ResourceApp/References.storyboard ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Relative To Project/RelativeToProject.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/SceneDelegate.swift ================================================ // // SceneDelegate.swift // ResourceApp // // Created by Tom Lokhorst on 2020-04-20. // Copyright © 2020 Mathijs Kadijk. All rights reserved. // import UIKit @available(iOS 13.0, *) class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let tabController = R.storyboard.main.instantiateInitialViewController()! let window = UIWindow(windowScene: windowScene) window.rootViewController = tabController self.window = window window.makeKeyAndVisible() } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } } ================================================ FILE: Examples/ResourceApp/ResourceApp/SecondViewController.swift ================================================ // // SecondViewController.swift // ResourceApp // // Created by Mathijs Kadijk on 20-07-15. // Copyright (c) 2015 Mathijs Kadijk. All rights reserved. // import UIKit class SecondViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let _ = MyViewController(nib: R.nib.myView) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func unwindSomethingSomthing(_ segue: UIStoryboardSegue) { } } ================================================ FILE: Examples/ResourceApp/ResourceApp/SegueIdentifiers.storyboard ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Settings.bundle/Root.plist ================================================ StringsTable Root PreferenceSpecifiers Type PSGroupSpecifier Title Group Type PSTextFieldSpecifier Title Name Key name_preference DefaultValue IsSecure KeyboardType Alphabet AutocapitalizationType None AutocorrectionType No Type PSToggleSwitchSpecifier Title Enabled Key enabled_preference DefaultValue Type PSSliderSpecifier Key slider_preference DefaultValue 0.5 MinimumValue 0 MaximumValue 1 MinimumValueImage MaximumValueImage ================================================ FILE: Examples/ResourceApp/ResourceApp/Specials.storyboard ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/@@.strings ================================================ /* @@.strings ResourceApp Created by Tom Lokhorst on 2016-04-17. Copyright © 2016 Mathijs Kadijk. All rights reserved. */ "at" = "@"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/Base.lproj/Settings.strings ================================================ /* Settings.strings ResourceApp Created by Tom Lokhorst on 2016-04-17. Copyright © 2016 Mathijs Kadijk. All rights reserved. */ "Title" = "Settings"; "Not translated" = "Base language; Not translated"; "Multiline \\key/ \"weird\"?!" = "ABC \"\\DEF/\" GHI Base"; "Copy.Progress" = "%1$d of %2$i files copied, %3$f.2%% completed."; "We need a couple things\r\nbefore you get started." = "We need a couple things\r\nbefore you get started."; "FormatSpecifiers1" = "number 1: %d, number 2: %i, string 3: %@"; "FormatSpecifiers2" = "string 3: %3$@, number 2: %2$d, number 1: %1$i"; "FormatSpecifiers3" = "Nothing"; "FormatSpecifiers4" = "number 1: %1$d"; "FormatSpecifiers5" = "number 1: %d, string 3: %@"; "FormatSpecifiers6" = "number 1: %1$i, string 3: %3$@"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/Base.lproj/Settings.stringsdict ================================================ scope.%lu out of %lu runs NSStringLocalizedFormatKey %1$#@lu_completed_runs@ lu_completed_runs NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey lu zero No runs completed yet one One %2$#@lu_total_runs@ other %lu %2$#@lu_total_runs@ lu_total_runs NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey lu one run completed other of %lu runs completed mismatch NSStringLocalizedFormatKey Base %#@first@ first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d other %d incorrect in dutch NSStringLocalizedFormatKey Base %#@first@ first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d other %d ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/Duplicate#.strings ================================================ /* Duplicate_.strings ResourceApp Created by Tom Lokhorst on 2016-04-17. Copyright © 2016 Mathijs Kadijk. All rights reserved. */ "duplicate2" = "Duplicate 2"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/Duplicate.strings ================================================ /* Duplicate.strings ResourceApp Created by Tom Lokhorst on 2016-04-17. Copyright © 2016 Mathijs Kadijk. All rights reserved. */ "duplicate1" = "Duplicate 1"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/Generic.strings ================================================ /* Generic.strings ResourceApp Created by Tom Lokhorst on 2016-04-17. Copyright © 2016 Mathijs Kadijk. All rights reserved. */ "loremipsum" = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; "#" = "hashtag"; "precision1" = "one - %012.2f"; "precision2" = "two - %12.2f"; "precision3" = "three - %12.4f"; "precision4" = "four - %.2f"; "discount10" = "Today, 10%% off!"; "discountX" = "Today, %d%% off!"; "url" = "http%%3A%%2F%%2Fwww.abc.xyz"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/Generic.stringsdict ================================================ correct alpha NSStringLocalizedFormatKey Pre Alpha (| %#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Alpha one One Alpha other Other Alpha: %d correct beta NSStringLocalizedFormatKey Pre Beta (| %#@first@ x %#@second@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Beta.first other Other Beta.first: %d second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Beta.second other Other Beta.second: %d correct gamma NSStringLocalizedFormatKey Pre Gamma (| %2$#@second@ x %1$#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Gamma.first other Other Gamma.first: %d second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Gamma.second other Other Gamma.second: %d correct delta NSStringLocalizedFormatKey Pre Delta (| %#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Delta.first (%d). Second: %#@second@ other Other Delta.first: %d. Second: %#@second@ second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Delta.second other Other Delta.second: %d correct epsilon NSStringLocalizedFormatKey Pre Epsilon (| %#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Epsilon.first (%d). Second: %#@second@ other Other Epsilon.first: %d. Second: %#@second@ second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Epsilon.second other Other Epsilon.second: %d correct zeta NSStringLocalizedFormatKey Pre Zeta (| %@ %2$#@second@ |) second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Zeta.second. other Other Zeta.second: %d. correct eta NSStringLocalizedFormatKey Pre Eta (| %@ - %#@second@ - %d|) second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Eta.second. other Other Eta.second: %d. correct theta NSStringLocalizedFormatKey Pre Theta (| %#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Theta.first other Other Theta.first: %d. %#@second@ second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Theta.second other Other Theta.second: %d. %#@third@ third NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Theta.third other Other Theta.third: %d fault alpha NSStringLocalizedFormatKey Pre Alpha (| %#@missing@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Alpha one One Alpha other Other Alpha: %d fault beta NSStringLocalizedFormatKey Pre Beta (| %#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Beta.first %u other Other Beta.first: %d fault gamma NSStringLocalizedFormatKey Pre Gamma (| %1$#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Gamma.first other Other Gamma.first: %lu fault delta NSStringLocalizedFormatKey Pre Delta (| %#@first@ |) first NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d one One Delta.first. Second: %#@missing@ other Other Delta.first: %d. Second: %#@missing@ fault epsilon NSStringLocalizedFormatKey Pre Epsilon (| %#@second@ |) second NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d zero Zero Epsilon.second. First: %1$#@first_two@ other Other Epsilon.second: %d. First: %1$#@first_one@ Welcome NSStringVariableWidthRuleType 100 Hi 200 Welcome 300 Welcome to the store! ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/en.lproj/Localizable.strings ================================================ // // Localizable.strings // ResourceApp // // Created by Nolan Warner on 2016/03/01. // Copyright © 2016 Nolan Warner. All rights reserved. // one = Zero; // Duplicate keys are ignored, a warning from R.swift would be nice one = One; two = 2; "quote" = "There are %d lights!"; "discount10" = "Today, 10%% off!"; "discountX" = "Today, %d%% off!"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/es.lproj/Localizable.strings ================================================ // // Localizable.strings // ResourceApp // // Created by Nolan Warner on 2016/03/01. // Copyright © 2016 Nolan Warner. All rights reserved. // one = Uno; two = 2; "quote" = "Hay %d luces!"; "discount10" = "Today, 10%% off!"; "discountX" = "Today, %d%% off!"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/ja.lproj/Localizable.strings ================================================ // // Localizable.strings // ResourceApp // // Created by Nolan Warner on 2016/03/01. // Copyright © 2016 Nolan Warner. All rights reserved. // one = "一つ"; two = 2; "quote" = "%dつの光があります!"; "discount10" = "Today, 10%% off!"; "discountX" = "Today, %d%% off!"; "japanese only" = "Not translated in other languages, and there is no Base"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/nl.lproj/Settings.strings ================================================ /* Settings.strings ResourceApp Created by Tom Lokhorst on 2016-04-17. Copyright © 2016 Mathijs Kadijk. All rights reserved. */ "Title" = "Instellingen"; "Only Dutch" = "Alleen Nederlands. Doesn't apepar in Base translation"; "Multiline \\key/ \"weird\"?!" = "ABC \"\\DEF/\" GHI Dutch"; "Copy.Progress" = "Van de %2$d bestanden zijn er %1$d gekopieerd, %3$.2f%% compleet."; "We need a couple things\r\nbefore you get started." = "We hebben een aantal dingen nodig\r\nvoordat je begint."; "FormatSpecifiers1" = "number 1: %d, number 2: %i"; "FormatSpecifiers2" = "string 3: %3$@, number 1: %1$i"; "FormatSpecifiers3" = "number 2: %2$d, string 3: %3$@, number 1: %1$i"; "FormatSpecifiers4" = "number 1: %d, number 2: %i, string 3: %@"; "FormatSpecifiers5" = "number 1: %d, number 2: %i, string 3: %@"; "FormatSpecifiers6" = "number 1: %1$i, string 3: %3$@"; ================================================ FILE: Examples/ResourceApp/ResourceApp/Strings/nl.lproj/Settings.stringsdict ================================================ scope.%lu out of %lu runs NSStringLocalizedFormatKey %1$#@lu_completed_runs@ lu_completed_runs NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey lu zero Geen rondes afgerond one Één %2$#@lu_total_runs@ other %lu %2$#@lu_total_runs@ lu_total_runs NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey lu one ronde afgerond other van de %lu rondes afgerond mismatch NSStringLocalizedFormatKey Nederlands %#@eerste@ eerste NSStringFormatSpecTypeKey NSStringPluralRuleType NSStringFormatValueTypeKey d other %d incorrect in dutch NSStringLocalizedFormatKey Nederalnds %#@first@ ================================================ FILE: Examples/ResourceApp/ResourceApp/SupplementaryElement.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/TabBarItem.storyboard ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/WhitespaceReuseIdentifer.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp/Xib with ViewController.xib ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 5D1AFAB11C858637003FE7AB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5D1AFAAF1C858637003FE7AB /* Localizable.strings */; }; 5D9E41341C96918E002172D3 /* StringsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D9E41331C96918E002172D3 /* StringsTests.swift */; }; A3D0897420CF6FDA007ED462 /* Keep.dont.ignoreme.png in Resources */ = {isa = PBXBuildFile; fileRef = A3D0897320CF6FDA007ED462 /* Keep.dont.ignoreme.png */; }; A3D0897620CF6FE4007ED462 /* ExplicitInclude.ignoreme.png in Resources */ = {isa = PBXBuildFile; fileRef = A3D0897520CF6FE4007ED462 /* ExplicitInclude.ignoreme.png */; }; C30DF7218982DFFDAFAD2A11 /* Pods_ResourceApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1867ABA7936CAD2320B248E1 /* Pods_ResourceApp.framework */; }; C378DD7A1C68C2BF003598B8 /* SupplementaryElement.xib in Resources */ = {isa = PBXBuildFile; fileRef = C378DD791C68C2BF003598B8 /* SupplementaryElement.xib */; }; CCBC9CB91EC4809D002F3D0E /* Images2.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CCBC9CB81EC4809D002F3D0E /* Images2.xcassets */; }; CCBC9CBA1EC480A2002F3D0E /* Images2.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CCBC9CB81EC4809D002F3D0E /* Images2.xcassets */; }; D50175BE1B5FEFD000DB8314 /* Secondary.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D50175BC1B5FEFD000DB8314 /* Secondary.storyboard */; }; D5159E9E1BBC33680013F52A /* Colors@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D5159E9D1BBC33680013F52A /* Colors@2x.jpg */; }; D5159EA01BBC37BC0013F52A /* Colors@3x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D5159E9F1BBC37BC0013F52A /* Colors@3x.jpg */; }; D5159EA21BBD0BB40013F52A /* Colors~ipad@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D5159EA11BBD0BB40013F52A /* Colors~ipad@2x.jpg */; }; D51E60C11BB13626004BB376 /* Colors.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D51E60C01BB13626004BB376 /* Colors.jpg */; }; D51E60C51BB1E600004BB376 /* User@white.png in Resources */ = {isa = PBXBuildFile; fileRef = D51E60C21BB1E600004BB376 /* User@white.png */; }; D51E60C61BB1E600004BB376 /* User@white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D51E60C31BB1E600004BB376 /* User@white@2x.png */; }; D51E60C71BB1E600004BB376 /* User@white@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D51E60C41BB1E600004BB376 /* User@white@3x.png */; }; D51F47231B8FAF9F0028BAFD /* NibTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51F47221B8FAF9F0028BAFD /* NibTests.swift */; }; D52725FC1C4A7C6A0005C8D4 /* Sky.tiff in Resources */ = {isa = PBXBuildFile; fileRef = D52725FB1C4A7C6A0005C8D4 /* Sky.tiff */; }; D52725FE1C4BB6BC0005C8D4 /* References.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D52725FD1C4BB6BC0005C8D4 /* References.storyboard */; }; D55C6CC01B5D757300301B0D /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55C6CBF1B5D757300301B0D /* FirstViewController.swift */; }; D55C6CC21B5D757300301B0D /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55C6CC11B5D757300301B0D /* SecondViewController.swift */; }; D55C6CC51B5D757300301B0D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D55C6CC31B5D757300301B0D /* Main.storyboard */; }; D55C6CC71B5D757300301B0D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D55C6CC61B5D757300301B0D /* Images.xcassets */; }; D55C6CCA1B5D757300301B0D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = D55C6CC81B5D757300301B0D /* LaunchScreen.xib */; }; D55C6CD61B5D757300301B0D /* ResourceAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55C6CD51B5D757300301B0D /* ResourceAppTests.swift */; }; D56DC7701C42A5E700623437 /* StoryboardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56DC76F1C42A5E700623437 /* StoryboardTests.swift */; }; D575E25D1B766CD800C22F0B /* My View.xib in Resources */ = {isa = PBXBuildFile; fileRef = D575E25C1B766CD800C22F0B /* My View.xib */; }; D58AF2811B708CB300FB2A4E /* rswift.log in Resources */ = {isa = PBXBuildFile; fileRef = D50175BA1B5FEF6E00DB8314 /* rswift.log */; }; D59A04641DF3223800B9F65F /* icon.ignoreme.png in Resources */ = {isa = PBXBuildFile; fileRef = D59A04631DF3223800B9F65F /* icon.ignoreme.png */; }; D59A04661DF3225500B9F65F /* hand.ignoreme.png in Resources */ = {isa = PBXBuildFile; fileRef = D59A04651DF3225500B9F65F /* hand.ignoreme.png */; }; D5AD5C911B78FC0500A8B96C /* duplicate.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5C901B78FC0500A8B96C /* duplicate.xib */; }; D5AD5C941B78FC4E00A8B96C /* Duplicate.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5C931B78FC4E00A8B96C /* Duplicate.xib */; }; D5AD5C971B7A7CDA00A8B96C /* duplicate.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5C961B7A7CDA00A8B96C /* duplicate.storyboard */; }; D5AD5C991B7A7CE700A8B96C /* Duplicate.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5C981B7A7CE700A8B96C /* Duplicate.storyboard */; }; D5AD5C9B1B7A8F4300A8B96C /* CellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5C9A1B7A8F4300A8B96C /* CellView.xib */; }; D5AD5C9D1B7A901F00A8B96C /* ADuplicateCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5C9C1B7A901F00A8B96C /* ADuplicateCellView.xib */; }; D5AD5C9F1B7A924000A8B96C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AD5C9E1B7A924000A8B96C /* AppDelegate.swift */; }; D5AD5CA11B7A926200A8B96C /* DuplicateCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5AD5CA01B7A926200A8B96C /* DuplicateCellView.xib */; }; D5B799851C1B8DB6009EA901 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D5B799841C1B8DB6009EA901 /* Settings.bundle */; }; D5B799871C1B8DD2009EA901 /* Specials.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5B799861C1B8DD2009EA901 /* Specials.storyboard */; }; D5BA2E5F1C90086C0025C9E3 /* CellCollectionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5BA2E5E1C90086C0025C9E3 /* CellCollectionView.xib */; }; D5CBCE491B7682B800C5D96B /* MyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CBCE481B7682B800C5D96B /* MyViewController.swift */; }; D5D398EC20D43ADE00D67745 /* IgnoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D398EB20D43ADE00D67745 /* IgnoreTests.swift */; }; D5DE480E1B5E1CC7000F6A85 /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DE480D1B5E1CC7000F6A85 /* R.generated.swift */; }; D5E513BA1B8E111A0035ECAA /* AveriaLibre-B.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5E513B51B8E111A0035ECAA /* AveriaLibre-B.ttf */; }; D5E513BB1B8E111A0035ECAA /* AveriaLibre-BI.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5E513B61B8E111A0035ECAA /* AveriaLibre-BI.ttf */; }; D5E513BC1B8E111A0035ECAA /* AveriaLibre-L.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5E513B71B8E111A0035ECAA /* AveriaLibre-L.ttf */; }; D5E513BD1B8E111A0035ECAA /* AveriaLibre.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5E513B81B8E111A0035ECAA /* AveriaLibre.ttf */; }; D5E513BE1B8E111A0035ECAA /* GdyBkltter1911.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5E513B91B8E111A0035ECAA /* GdyBkltter1911.ttf */; }; D5E513C01B8E11810035ECAA /* FontsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E513BF1B8E11810035ECAA /* FontsTests.swift */; }; D5EB32701B63AD6B005C7B47 /* ValidationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EB326E1B63AD6B005C7B47 /* ValidationTests.swift */; }; D5EE1B5622DEEF3E00A901EC /* TabBarItem.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5EE1B5522DEEF3E00A901EC /* TabBarItem.storyboard */; }; D5F05D3F1BB3CDF3003AE55E /* The App Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = D5F05D3E1BB3CDF3003AE55E /* The App Icon.png */; }; D5F05D421BB52002003AE55E /* Some.json in Resources */ = {isa = PBXBuildFile; fileRef = D5F05D411BB52002003AE55E /* Some.json */; }; D5F05D441BB52063003AE55E /* Duplicate.json in Resources */ = {isa = PBXBuildFile; fileRef = D5F05D431BB52063003AE55E /* Duplicate.json */; }; D5F05D461BB52078003AE55E /* duplicateJson in Resources */ = {isa = PBXBuildFile; fileRef = D5F05D451BB52078003AE55E /* duplicateJson */; }; D5F05D481BB520B1003AE55E /* FilesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F05D471BB520B1003AE55E /* FilesTests.swift */; }; D5FAD9091B63B05700ECE230 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D55C6CC61B5D757300301B0D /* Images.xcassets */; }; DD0CD0C4232A950A00A555A3 /* SegueIdentifiers.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DD0CD0C3232A950A00A555A3 /* SegueIdentifiers.storyboard */; }; E20983241D585E78005ACBAA /* SegueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20983231D585E78005ACBAA /* SegueTests.swift */; }; E20983261D585F8C005ACBAA /* Xib with ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E20983251D585F8C005ACBAA /* Xib with ViewController.xib */; }; E2156B631CC4042900F341DC /* Settings.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2156B651CC4042900F341DC /* Settings.strings */; }; E2156B681CC41EB400F341DC /* Generic.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2156B671CC41EB400F341DC /* Generic.strings */; }; E2156B6A1CC4292600F341DC /* Duplicate.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2156B691CC4292600F341DC /* Duplicate.strings */; }; E2156B6C1CC4293000F341DC /* Duplicate#.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2156B6B1CC4293000F341DC /* Duplicate#.strings */; }; E2156B6E1CC42B6700F341DC /* @@.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2156B6D1CC42B6700F341DC /* @@.strings */; }; E22070771C92E137007A090B /* WhitespaceReuseIdentifer.xib in Resources */ = {isa = PBXBuildFile; fileRef = E22070761C92E137007A090B /* WhitespaceReuseIdentifer.xib */; }; E2562CD61EE70C68007D8938 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E2562CD51EE70C68007D8938 /* Media.xcassets */; }; E25984A122AEE89B00467E1E /* CustomSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25984A022AEE89B00467E1E /* CustomSegue.swift */; }; E2762AC01CCCDFDA0009BCAA /* Settings.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E2762AC21CCCDFDA0009BCAA /* Settings.stringsdict */; }; E2762AE01CCE62CC0009BCAA /* Generic.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E2762ADF1CCE62CC0009BCAA /* Generic.stringsdict */; }; E29693581CAD64B500401D53 /* __FILE__ in Resources */ = {isa = PBXBuildFile; fileRef = E29693571CAD64B500401D53 /* __FILE__ */; }; E296935A1CAD64D100401D53 /* associatedtype in Resources */ = {isa = PBXBuildFile; fileRef = E29693591CAD64D100401D53 /* associatedtype */; }; E296935C1CAD666200401D53 /* #column in Resources */ = {isa = PBXBuildFile; fileRef = E296935B1CAD666200401D53 /* #column */; }; E2A10EF81CD13779006BFC63 /* RelativeToProject.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2A10EF71CD13779006BFC63 /* RelativeToProject.xib */; }; E2C415D028EED7890028D537 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E2C415CF28EED7890028D537 /* RswiftLibrary */; }; E2CD68671D7CADEA00BEBE59 /* hello.txt in Resources */ = {isa = PBXBuildFile; fileRef = E2CD68641D7CACC100BEBE59 /* hello.txt */; }; E2DB0EB02334DCC100815AAF /* InfoPlistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2DB0EAF2334DCC100815AAF /* InfoPlistTests.swift */; }; E2F768FC244D92A200761E14 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F768FB244D92A200761E14 /* SceneDelegate.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ D55C6CD01B5D757300301B0D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D55C6CB01B5D757300301B0D /* Project object */; proxyType = 1; remoteGlobalIDString = D55C6CB71B5D757300301B0D; remoteInfo = ResourceApp; }; E22C7596251235D900124573 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E243EFA32510DFA600DC653F /* RswiftUI.xcodeproj */; proxyType = 2; remoteGlobalIDString = E243EFAD2510E08D00DC653F; remoteInfo = RswiftUIAppClip; }; E243EFA72510DFA600DC653F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E243EFA32510DFA600DC653F /* RswiftUI.xcodeproj */; proxyType = 2; remoteGlobalIDString = E243EF912510DF9100DC653F; remoteInfo = RswiftUI; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 2F5FBC3A2135561400A83A69 /* Embed Watch Content */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "$(CONTENTS_FOLDER_PATH)/Watch"; dstSubfolderSpec = 16; files = ( ); name = "Embed Watch Content"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1867ABA7936CAD2320B248E1 /* Pods_ResourceApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ResourceApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41D4DA51D96C4F7DDF13157E /* Pods-ResourceApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ResourceApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-ResourceApp/Pods-ResourceApp.release.xcconfig"; sourceTree = ""; }; 5D1AFAB01C858637003FE7AB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 5D1AFAB21C858647003FE7AB /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 5D1AFAB31C85864F003FE7AB /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; 5D9E41331C96918E002172D3 /* StringsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringsTests.swift; sourceTree = ""; }; A3D0897320CF6FDA007ED462 /* Keep.dont.ignoreme.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Keep.dont.ignoreme.png; sourceTree = ""; }; A3D0897520CF6FE4007ED462 /* ExplicitInclude.ignoreme.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ExplicitInclude.ignoreme.png; sourceTree = ""; }; BCFE901EE74D3A3CF9909E5D /* Pods-ResourceApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ResourceApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ResourceApp/Pods-ResourceApp.debug.xcconfig"; sourceTree = ""; }; C378DD791C68C2BF003598B8 /* SupplementaryElement.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SupplementaryElement.xib; sourceTree = ""; }; CCBC9CB81EC4809D002F3D0E /* Images2.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images2.xcassets; sourceTree = ""; }; D50175BA1B5FEF6E00DB8314 /* rswift.log */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rswift.log; sourceTree = SOURCE_ROOT; }; D50175BD1B5FEFD000DB8314 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Secondary.storyboard; sourceTree = ""; }; D5159E9D1BBC33680013F52A /* Colors@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "Colors@2x.jpg"; sourceTree = ""; }; D5159E9F1BBC37BC0013F52A /* Colors@3x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "Colors@3x.jpg"; sourceTree = ""; }; D5159EA11BBD0BB40013F52A /* Colors~ipad@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "Colors~ipad@2x.jpg"; sourceTree = ""; }; D51E60C01BB13626004BB376 /* Colors.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = Colors.jpg; sourceTree = ""; }; D51E60C21BB1E600004BB376 /* User@white.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "User@white.png"; sourceTree = ""; }; D51E60C31BB1E600004BB376 /* User@white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "User@white@2x.png"; sourceTree = ""; }; D51E60C41BB1E600004BB376 /* User@white@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "User@white@3x.png"; sourceTree = ""; }; D51F47221B8FAF9F0028BAFD /* NibTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NibTests.swift; sourceTree = ""; }; D52725FB1C4A7C6A0005C8D4 /* Sky.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Sky.tiff; sourceTree = ""; }; D52725FD1C4BB6BC0005C8D4 /* References.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = References.storyboard; sourceTree = ""; }; D55C6CB81B5D757300301B0D /* ResourceApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ResourceApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; D55C6CBC1B5D757300301B0D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D55C6CBF1B5D757300301B0D /* FirstViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController.swift; sourceTree = ""; }; D55C6CC11B5D757300301B0D /* SecondViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController.swift; sourceTree = ""; }; D55C6CC41B5D757300301B0D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; D55C6CC61B5D757300301B0D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; D55C6CC91B5D757300301B0D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; D55C6CCF1B5D757300301B0D /* ResourceAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResourceAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D55C6CD41B5D757300301B0D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D55C6CD51B5D757300301B0D /* ResourceAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceAppTests.swift; sourceTree = ""; }; D56DC76F1C42A5E700623437 /* StoryboardTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardTests.swift; sourceTree = ""; }; D575E25C1B766CD800C22F0B /* My View.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "My View.xib"; sourceTree = ""; }; D59A04631DF3223800B9F65F /* icon.ignoreme.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.ignoreme.png; sourceTree = ""; }; D59A04651DF3225500B9F65F /* hand.ignoreme.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = hand.ignoreme.png; sourceTree = ""; }; D5AD5C901B78FC0500A8B96C /* duplicate.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = duplicate.xib; path = Duplicate/duplicate.xib; sourceTree = ""; }; D5AD5C931B78FC4E00A8B96C /* Duplicate.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Duplicate.xib; sourceTree = ""; }; D5AD5C961B7A7CDA00A8B96C /* duplicate.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = duplicate.storyboard; path = Duplicate/duplicate.storyboard; sourceTree = ""; }; D5AD5C981B7A7CE700A8B96C /* Duplicate.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Duplicate.storyboard; sourceTree = ""; }; D5AD5C9A1B7A8F4300A8B96C /* CellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CellView.xib; sourceTree = ""; }; D5AD5C9C1B7A901F00A8B96C /* ADuplicateCellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ADuplicateCellView.xib; path = ResourceApp/Duplicate/ADuplicateCellView.xib; sourceTree = SOURCE_ROOT; }; D5AD5C9E1B7A924000A8B96C /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; D5AD5CA01B7A926200A8B96C /* DuplicateCellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DuplicateCellView.xib; sourceTree = ""; }; D5B799841C1B8DB6009EA901 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; D5B799861C1B8DD2009EA901 /* Specials.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Specials.storyboard; sourceTree = ""; }; D5B799881C1B8F0C009EA901 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; D5BA2E5E1C90086C0025C9E3 /* CellCollectionView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CellCollectionView.xib; sourceTree = ""; }; D5CBCE481B7682B800C5D96B /* MyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyViewController.swift; sourceTree = ""; }; D5D398EB20D43ADE00D67745 /* IgnoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IgnoreTests.swift; sourceTree = ""; }; D5DE480D1B5E1CC7000F6A85 /* R.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = SOURCE_ROOT; }; D5E513B51B8E111A0035ECAA /* AveriaLibre-B.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "AveriaLibre-B.ttf"; sourceTree = ""; }; D5E513B61B8E111A0035ECAA /* AveriaLibre-BI.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "AveriaLibre-BI.ttf"; sourceTree = ""; }; D5E513B71B8E111A0035ECAA /* AveriaLibre-L.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "AveriaLibre-L.ttf"; sourceTree = ""; }; D5E513B81B8E111A0035ECAA /* AveriaLibre.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = AveriaLibre.ttf; sourceTree = ""; }; D5E513B91B8E111A0035ECAA /* GdyBkltter1911.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = GdyBkltter1911.ttf; sourceTree = ""; }; D5E513BF1B8E11810035ECAA /* FontsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontsTests.swift; sourceTree = ""; }; D5EB326E1B63AD6B005C7B47 /* ValidationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationTests.swift; sourceTree = ""; }; D5EE1B5522DEEF3E00A901EC /* TabBarItem.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TabBarItem.storyboard; sourceTree = ""; }; D5EE1B5722DEEFBF00A901EC /* R.UITest.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = R.UITest.generated.swift; sourceTree = ""; }; D5F05D3E1BB3CDF3003AE55E /* The App Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "The App Icon.png"; sourceTree = ""; }; D5F05D411BB52002003AE55E /* Some.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Some.json; sourceTree = ""; }; D5F05D431BB52063003AE55E /* Duplicate.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Duplicate.json; sourceTree = ""; }; D5F05D451BB52078003AE55E /* duplicateJson */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = duplicateJson; sourceTree = ""; }; D5F05D471BB520B1003AE55E /* FilesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilesTests.swift; sourceTree = ""; }; DD0CD0C3232A950A00A555A3 /* SegueIdentifiers.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SegueIdentifiers.storyboard; sourceTree = ""; }; E20983231D585E78005ACBAA /* SegueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegueTests.swift; sourceTree = ""; }; E20983251D585F8C005ACBAA /* Xib with ViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "Xib with ViewController.xib"; sourceTree = ""; }; E2156B641CC4042900F341DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Settings.strings; sourceTree = ""; }; E2156B661CC4043C00F341DC /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Settings.strings; sourceTree = ""; }; E2156B671CC41EB400F341DC /* Generic.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Generic.strings; sourceTree = ""; }; E2156B691CC4292600F341DC /* Duplicate.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Duplicate.strings; sourceTree = ""; }; E2156B6B1CC4293000F341DC /* Duplicate#.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = "Duplicate#.strings"; sourceTree = ""; }; E2156B6D1CC42B6700F341DC /* @@.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = "@@.strings"; sourceTree = ""; }; E22070761C92E137007A090B /* WhitespaceReuseIdentifer.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WhitespaceReuseIdentifer.xib; sourceTree = ""; }; E243EFA32510DFA600DC653F /* RswiftUI.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RswiftUI.xcodeproj; path = ../RswiftUI/RswiftUI.xcodeproj; sourceTree = ""; }; E2562CD51EE70C68007D8938 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = ""; }; E25984A022AEE89B00467E1E /* CustomSegue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSegue.swift; sourceTree = ""; }; E2762AC11CCCDFDA0009BCAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = Base; path = Base.lproj/Settings.stringsdict; sourceTree = ""; }; E2762AC31CCCDFE10009BCAA /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Settings.stringsdict; sourceTree = ""; }; E2762ADF1CCE62CC0009BCAA /* Generic.stringsdict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.stringsdict; path = Generic.stringsdict; sourceTree = ""; }; E29693571CAD64B500401D53 /* __FILE__ */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = __FILE__; sourceTree = ""; }; E29693591CAD64D100401D53 /* associatedtype */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = associatedtype; sourceTree = ""; }; E296935B1CAD666200401D53 /* #column */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "#column"; sourceTree = ""; }; E2A10EF71CD13779006BFC63 /* RelativeToProject.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RelativeToProject.xib; sourceTree = ""; }; E2C415CE28EED7580028D537 /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; E2CD68631D7CACC100BEBE59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text; name = Base; path = Base.lproj/hello.txt; sourceTree = ""; }; E2CD68651D7CACCA00BEBE59 /* es */ = {isa = PBXFileReference; lastKnownFileType = text; name = es; path = es.lproj/hello.txt; sourceTree = ""; }; E2CD68661D7CACCB00BEBE59 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text; name = nl; path = nl.lproj/hello.txt; sourceTree = ""; }; E2DB0EAF2334DCC100815AAF /* InfoPlistTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPlistTests.swift; sourceTree = ""; }; E2F768FB244D92A200761E14 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ D55C6CB51B5D757300301B0D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( C30DF7218982DFFDAFAD2A11 /* Pods_ResourceApp.framework in Frameworks */, E2C415D028EED7890028D537 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D55C6CCC1B5D757300301B0D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 065D32753EEB6C7AE2FA201F /* Frameworks */ = { isa = PBXGroup; children = ( D5B799881C1B8F0C009EA901 /* AVKit.framework */, 1867ABA7936CAD2320B248E1 /* Pods_ResourceApp.framework */, ); name = Frameworks; sourceTree = ""; }; 5D1AFAAC1C85859D003FE7AB /* Strings */ = { isa = PBXGroup; children = ( E2156B6D1CC42B6700F341DC /* @@.strings */, E2156B691CC4292600F341DC /* Duplicate.strings */, E2156B6B1CC4293000F341DC /* Duplicate#.strings */, E2156B671CC41EB400F341DC /* Generic.strings */, E2762ADF1CCE62CC0009BCAA /* Generic.stringsdict */, 5D1AFAAF1C858637003FE7AB /* Localizable.strings */, E2156B651CC4042900F341DC /* Settings.strings */, E2762AC21CCCDFDA0009BCAA /* Settings.stringsdict */, ); path = Strings; sourceTree = ""; }; 6BD8864A6B6559C4D6F93D81 /* Pods */ = { isa = PBXGroup; children = ( BCFE901EE74D3A3CF9909E5D /* Pods-ResourceApp.debug.xcconfig */, 41D4DA51D96C4F7DDF13157E /* Pods-ResourceApp.release.xcconfig */, ); name = Pods; sourceTree = ""; }; D51E60BF1BB13612004BB376 /* Images */ = { isa = PBXGroup; children = ( A3D0897320CF6FDA007ED462 /* Keep.dont.ignoreme.png */, D59A04631DF3223800B9F65F /* icon.ignoreme.png */, D52725FB1C4A7C6A0005C8D4 /* Sky.tiff */, D5F05D3E1BB3CDF3003AE55E /* The App Icon.png */, D51E60C01BB13626004BB376 /* Colors.jpg */, D5159E9D1BBC33680013F52A /* Colors@2x.jpg */, D5159EA11BBD0BB40013F52A /* Colors~ipad@2x.jpg */, D5159E9F1BBC37BC0013F52A /* Colors@3x.jpg */, D51E60C21BB1E600004BB376 /* User@white.png */, D51E60C31BB1E600004BB376 /* User@white@2x.png */, D51E60C41BB1E600004BB376 /* User@white@3x.png */, ); path = Images; sourceTree = ""; }; D55C6CAF1B5D757300301B0D = { isa = PBXGroup; children = ( E2C415CD28EED7580028D537 /* Packages */, E243EFA32510DFA600DC653F /* RswiftUI.xcodeproj */, D5DE480D1B5E1CC7000F6A85 /* R.generated.swift */, D5EE1B5722DEEFBF00A901EC /* R.UITest.generated.swift */, D55C6CBA1B5D757300301B0D /* ResourceApp */, D55C6CD21B5D757300301B0D /* ResourceAppTests */, D55C6CB91B5D757300301B0D /* Products */, 6BD8864A6B6559C4D6F93D81 /* Pods */, 065D32753EEB6C7AE2FA201F /* Frameworks */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; D55C6CB91B5D757300301B0D /* Products */ = { isa = PBXGroup; children = ( D55C6CB81B5D757300301B0D /* ResourceApp.app */, D55C6CCF1B5D757300301B0D /* ResourceAppTests.xctest */, ); name = Products; sourceTree = ""; }; D55C6CBA1B5D757300301B0D /* ResourceApp */ = { isa = PBXGroup; children = ( D5B799841C1B8DB6009EA901 /* Settings.bundle */, A3D0897520CF6FE4007ED462 /* ExplicitInclude.ignoreme.png */, D59A04651DF3225500B9F65F /* hand.ignoreme.png */, D5AD5C961B7A7CDA00A8B96C /* duplicate.storyboard */, D5AD5C981B7A7CE700A8B96C /* Duplicate.storyboard */, D52725FD1C4BB6BC0005C8D4 /* References.storyboard */, D5B799861C1B8DD2009EA901 /* Specials.storyboard */, D5AD5C9E1B7A924000A8B96C /* AppDelegate.swift */, E25984A022AEE89B00467E1E /* CustomSegue.swift */, D55C6CBF1B5D757300301B0D /* FirstViewController.swift */, D5CBCE481B7682B800C5D96B /* MyViewController.swift */, DD0CD0C3232A950A00A555A3 /* SegueIdentifiers.storyboard */, D55C6CC11B5D757300301B0D /* SecondViewController.swift */, D55C6CC61B5D757300301B0D /* Images.xcassets */, CCBC9CB81EC4809D002F3D0E /* Images2.xcassets */, E2562CD51EE70C68007D8938 /* Media.xcassets */, D5AD5C9C1B7A901F00A8B96C /* ADuplicateCellView.xib */, D5BA2E5E1C90086C0025C9E3 /* CellCollectionView.xib */, D5AD5C9A1B7A8F4300A8B96C /* CellView.xib */, D5AD5C901B78FC0500A8B96C /* duplicate.xib */, D5AD5C931B78FC4E00A8B96C /* Duplicate.xib */, D5AD5CA01B7A926200A8B96C /* DuplicateCellView.xib */, D575E25C1B766CD800C22F0B /* My View.xib */, E2F768FB244D92A200761E14 /* SceneDelegate.swift */, C378DD791C68C2BF003598B8 /* SupplementaryElement.xib */, E22070761C92E137007A090B /* WhitespaceReuseIdentifer.xib */, E20983251D585F8C005ACBAA /* Xib with ViewController.xib */, D5EE1B5522DEEF3E00A901EC /* TabBarItem.storyboard */, D5F05D401BB51FEA003AE55E /* Files */, D5E513B41B8E10F90035ECAA /* Fonts */, D51E60BF1BB13612004BB376 /* Images */, D55C6CC81B5D757300301B0D /* LaunchScreen.xib */, E2CD68611D7CAC9200BEBE59 /* Localized */, D55C6CC31B5D757300301B0D /* Main.storyboard */, E2A10EF61CD13768006BFC63 /* Relative To Project */, D50175BC1B5FEFD000DB8314 /* Secondary.storyboard */, 5D1AFAAC1C85859D003FE7AB /* Strings */, D55C6CBB1B5D757300301B0D /* Supporting Files */, ); path = ResourceApp; sourceTree = ""; }; D55C6CBB1B5D757300301B0D /* Supporting Files */ = { isa = PBXGroup; children = ( D55C6CBC1B5D757300301B0D /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D55C6CD21B5D757300301B0D /* ResourceAppTests */ = { isa = PBXGroup; children = ( D5F05D471BB520B1003AE55E /* FilesTests.swift */, D5E513BF1B8E11810035ECAA /* FontsTests.swift */, D5D398EB20D43ADE00D67745 /* IgnoreTests.swift */, E2DB0EAF2334DCC100815AAF /* InfoPlistTests.swift */, D51F47221B8FAF9F0028BAFD /* NibTests.swift */, D55C6CD51B5D757300301B0D /* ResourceAppTests.swift */, E20983231D585E78005ACBAA /* SegueTests.swift */, D56DC76F1C42A5E700623437 /* StoryboardTests.swift */, 5D9E41331C96918E002172D3 /* StringsTests.swift */, D5EB326E1B63AD6B005C7B47 /* ValidationTests.swift */, D55C6CD31B5D757300301B0D /* Supporting Files */, ); path = ResourceAppTests; sourceTree = ""; }; D55C6CD31B5D757300301B0D /* Supporting Files */ = { isa = PBXGroup; children = ( D50175BA1B5FEF6E00DB8314 /* rswift.log */, D55C6CD41B5D757300301B0D /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D5E513B41B8E10F90035ECAA /* Fonts */ = { isa = PBXGroup; children = ( D5E513B51B8E111A0035ECAA /* AveriaLibre-B.ttf */, D5E513B61B8E111A0035ECAA /* AveriaLibre-BI.ttf */, D5E513B71B8E111A0035ECAA /* AveriaLibre-L.ttf */, D5E513B81B8E111A0035ECAA /* AveriaLibre.ttf */, D5E513B91B8E111A0035ECAA /* GdyBkltter1911.ttf */, ); path = Fonts; sourceTree = ""; }; D5F05D401BB51FEA003AE55E /* Files */ = { isa = PBXGroup; children = ( D5F05D451BB52078003AE55E /* duplicateJson */, D5F05D431BB52063003AE55E /* Duplicate.json */, D5F05D411BB52002003AE55E /* Some.json */, E29693571CAD64B500401D53 /* __FILE__ */, E29693591CAD64D100401D53 /* associatedtype */, E296935B1CAD666200401D53 /* #column */, ); path = Files; sourceTree = ""; }; E243EFA42510DFA600DC653F /* Products */ = { isa = PBXGroup; children = ( E243EFA82510DFA600DC653F /* RswiftUI.app */, E22C7597251235D900124573 /* RswiftUIAppClip.app */, ); name = Products; sourceTree = ""; }; E2A10EF61CD13768006BFC63 /* Relative To Project */ = { isa = PBXGroup; children = ( E2A10EF71CD13779006BFC63 /* RelativeToProject.xib */, ); name = "Relative To Project"; path = "ResourceApp/Relative To Project"; sourceTree = SOURCE_ROOT; }; E2C415CD28EED7580028D537 /* Packages */ = { isa = PBXGroup; children = ( E2C415CE28EED7580028D537 /* R.swift */, ); name = Packages; sourceTree = ""; }; E2CD68611D7CAC9200BEBE59 /* Localized */ = { isa = PBXGroup; children = ( E2CD68641D7CACC100BEBE59 /* hello.txt */, ); path = Localized; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ D55C6CB71B5D757300301B0D /* ResourceApp */ = { isa = PBXNativeTarget; buildConfigurationList = D55C6CD91B5D757300301B0D /* Build configuration list for PBXNativeTarget "ResourceApp" */; buildPhases = ( 978E4B8123C372F370555011 /* [CP] Check Pods Manifest.lock */, D55C6CED1B5E172900301B0D /* R.swift */, D55C6CB41B5D757300301B0D /* Sources */, D55C6CB51B5D757300301B0D /* Frameworks */, D55C6CB61B5D757300301B0D /* Resources */, 89BF8D4EC08D38DB6564C369 /* [CP] Embed Pods Frameworks */, 2F5FBC3A2135561400A83A69 /* Embed Watch Content */, ); buildRules = ( ); dependencies = ( ); name = ResourceApp; packageProductDependencies = ( E2C415CF28EED7890028D537 /* RswiftLibrary */, ); productName = ResourceApp; productReference = D55C6CB81B5D757300301B0D /* ResourceApp.app */; productType = "com.apple.product-type.application"; }; D55C6CCE1B5D757300301B0D /* ResourceAppTests */ = { isa = PBXNativeTarget; buildConfigurationList = D55C6CDC1B5D757300301B0D /* Build configuration list for PBXNativeTarget "ResourceAppTests" */; buildPhases = ( D55C6CCB1B5D757300301B0D /* Sources */, D55C6CCC1B5D757300301B0D /* Frameworks */, D55C6CCD1B5D757300301B0D /* Resources */, ); buildRules = ( ); dependencies = ( D55C6CD11B5D757300301B0D /* PBXTargetDependency */, ); name = ResourceAppTests; productName = ResourceAppTests; productReference = D55C6CCF1B5D757300301B0D /* ResourceAppTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D55C6CB01B5D757300301B0D /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; KnownAssetTags = ( one, two, ); LastSwiftMigration = 0700; LastSwiftUpdateCheck = 1000; LastUpgradeCheck = 1500; ORGANIZATIONNAME = "Mathijs Kadijk"; TargetAttributes = { D55C6CB71B5D757300301B0D = { CreatedOnToolsVersion = 6.4; LastSwiftMigration = 1140; }; D55C6CCE1B5D757300301B0D = { CreatedOnToolsVersion = 6.4; LastSwiftMigration = 1140; TestTargetID = D55C6CB71B5D757300301B0D; }; }; }; buildConfigurationList = D55C6CB31B5D757300301B0D /* Build configuration list for PBXProject "ResourceApp" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, en, Base, es, ja, nl, ); mainGroup = D55C6CAF1B5D757300301B0D; productRefGroup = D55C6CB91B5D757300301B0D /* Products */; projectDirPath = ""; projectReferences = ( { ProductGroup = E243EFA42510DFA600DC653F /* Products */; ProjectRef = E243EFA32510DFA600DC653F /* RswiftUI.xcodeproj */; }, ); projectRoot = ""; targets = ( D55C6CB71B5D757300301B0D /* ResourceApp */, D55C6CCE1B5D757300301B0D /* ResourceAppTests */, ); }; /* End PBXProject section */ /* Begin PBXReferenceProxy section */ E22C7597251235D900124573 /* RswiftUIAppClip.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; path = RswiftUIAppClip.app; remoteRef = E22C7596251235D900124573 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; E243EFA82510DFA600DC653F /* RswiftUI.app */ = { isa = PBXReferenceProxy; fileType = wrapper.application; path = RswiftUI.app; remoteRef = E243EFA72510DFA600DC653F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ D55C6CB61B5D757300301B0D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E296935C1CAD666200401D53 /* #column in Resources */, D5E513BB1B8E111A0035ECAA /* AveriaLibre-BI.ttf in Resources */, D5AD5C9B1B7A8F4300A8B96C /* CellView.xib in Resources */, D5159E9E1BBC33680013F52A /* Colors@2x.jpg in Resources */, D5E513BA1B8E111A0035ECAA /* AveriaLibre-B.ttf in Resources */, E2562CD61EE70C68007D8938 /* Media.xcassets in Resources */, D50175BE1B5FEFD000DB8314 /* Secondary.storyboard in Resources */, D5AD5C911B78FC0500A8B96C /* duplicate.xib in Resources */, D575E25D1B766CD800C22F0B /* My View.xib in Resources */, DD0CD0C4232A950A00A555A3 /* SegueIdentifiers.storyboard in Resources */, D5AD5C941B78FC4E00A8B96C /* Duplicate.xib in Resources */, E2CD68671D7CADEA00BEBE59 /* hello.txt in Resources */, D55C6CC51B5D757300301B0D /* Main.storyboard in Resources */, D5EE1B5622DEEF3E00A901EC /* TabBarItem.storyboard in Resources */, E29693581CAD64B500401D53 /* __FILE__ in Resources */, A3D0897420CF6FDA007ED462 /* Keep.dont.ignoreme.png in Resources */, A3D0897620CF6FE4007ED462 /* ExplicitInclude.ignoreme.png in Resources */, D5F05D461BB52078003AE55E /* duplicateJson in Resources */, E2156B6C1CC4293000F341DC /* Duplicate#.strings in Resources */, E2156B681CC41EB400F341DC /* Generic.strings in Resources */, E296935A1CAD64D100401D53 /* associatedtype in Resources */, D51E60C71BB1E600004BB376 /* User@white@3x.png in Resources */, D5B799851C1B8DB6009EA901 /* Settings.bundle in Resources */, D5B799871C1B8DD2009EA901 /* Specials.storyboard in Resources */, D5E513BD1B8E111A0035ECAA /* AveriaLibre.ttf in Resources */, D52725FE1C4BB6BC0005C8D4 /* References.storyboard in Resources */, E2156B6A1CC4292600F341DC /* Duplicate.strings in Resources */, E2762AE01CCE62CC0009BCAA /* Generic.stringsdict in Resources */, D5159EA01BBC37BC0013F52A /* Colors@3x.jpg in Resources */, D5F05D3F1BB3CDF3003AE55E /* The App Icon.png in Resources */, 5D1AFAB11C858637003FE7AB /* Localizable.strings in Resources */, D5E513BC1B8E111A0035ECAA /* AveriaLibre-L.ttf in Resources */, D51E60C51BB1E600004BB376 /* User@white.png in Resources */, D55C6CCA1B5D757300301B0D /* LaunchScreen.xib in Resources */, C378DD7A1C68C2BF003598B8 /* SupplementaryElement.xib in Resources */, E2762AC01CCCDFDA0009BCAA /* Settings.stringsdict in Resources */, D5AD5C991B7A7CE700A8B96C /* Duplicate.storyboard in Resources */, D5BA2E5F1C90086C0025C9E3 /* CellCollectionView.xib in Resources */, D5AD5CA11B7A926200A8B96C /* DuplicateCellView.xib in Resources */, E2A10EF81CD13779006BFC63 /* RelativeToProject.xib in Resources */, E20983261D585F8C005ACBAA /* Xib with ViewController.xib in Resources */, D5F05D421BB52002003AE55E /* Some.json in Resources */, E2156B631CC4042900F341DC /* Settings.strings in Resources */, D5F05D441BB52063003AE55E /* Duplicate.json in Resources */, D59A04641DF3223800B9F65F /* icon.ignoreme.png in Resources */, D5159EA21BBD0BB40013F52A /* Colors~ipad@2x.jpg in Resources */, D5AD5C971B7A7CDA00A8B96C /* duplicate.storyboard in Resources */, CCBC9CB91EC4809D002F3D0E /* Images2.xcassets in Resources */, D59A04661DF3225500B9F65F /* hand.ignoreme.png in Resources */, D5AD5C9D1B7A901F00A8B96C /* ADuplicateCellView.xib in Resources */, D55C6CC71B5D757300301B0D /* Images.xcassets in Resources */, D52725FC1C4A7C6A0005C8D4 /* Sky.tiff in Resources */, D5E513BE1B8E111A0035ECAA /* GdyBkltter1911.ttf in Resources */, D51E60C61BB1E600004BB376 /* User@white@2x.png in Resources */, E2156B6E1CC42B6700F341DC /* @@.strings in Resources */, D51E60C11BB13626004BB376 /* Colors.jpg in Resources */, E22070771C92E137007A090B /* WhitespaceReuseIdentifer.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; D55C6CCD1B5D757300301B0D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D5FAD9091B63B05700ECE230 /* Images.xcassets in Resources */, D58AF2811B708CB300FB2A4E /* rswift.log in Resources */, CCBC9CBA1EC480A2002F3D0E /* Images2.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 89BF8D4EC08D38DB6564C369 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ResourceApp/Pods-ResourceApp-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SWRevealViewController/SWRevealViewController.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SWRevealViewController.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ResourceApp/Pods-ResourceApp-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 978E4B8123C372F370555011 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-ResourceApp-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; D55C6CED1B5E172900301B0D /* R.swift */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = R.swift; outputPaths = ( $SRCROOT/R.generated.swift, $SRCROOT/R.UITest.generated.swift, ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "../../.build/release/rswift generate --import SWRevealViewController \"$SRCROOT/R.generated.swift\" > \"$SRCROOT/rswift.log\"\n../../.build/release/rswift generate \"$SRCROOT/R.UITest.generated.swift\" --generators id\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ D55C6CB41B5D757300301B0D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D5AD5C9F1B7A924000A8B96C /* AppDelegate.swift in Sources */, E2F768FC244D92A200761E14 /* SceneDelegate.swift in Sources */, D55C6CC21B5D757300301B0D /* SecondViewController.swift in Sources */, D55C6CC01B5D757300301B0D /* FirstViewController.swift in Sources */, D5CBCE491B7682B800C5D96B /* MyViewController.swift in Sources */, E25984A122AEE89B00467E1E /* CustomSegue.swift in Sources */, D5DE480E1B5E1CC7000F6A85 /* R.generated.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D55C6CCB1B5D757300301B0D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E20983241D585E78005ACBAA /* SegueTests.swift in Sources */, D5E513C01B8E11810035ECAA /* FontsTests.swift in Sources */, D56DC7701C42A5E700623437 /* StoryboardTests.swift in Sources */, 5D9E41341C96918E002172D3 /* StringsTests.swift in Sources */, E2DB0EB02334DCC100815AAF /* InfoPlistTests.swift in Sources */, D51F47231B8FAF9F0028BAFD /* NibTests.swift in Sources */, D55C6CD61B5D757300301B0D /* ResourceAppTests.swift in Sources */, D5D398EC20D43ADE00D67745 /* IgnoreTests.swift in Sources */, D5EB32701B63AD6B005C7B47 /* ValidationTests.swift in Sources */, D5F05D481BB520B1003AE55E /* FilesTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ D55C6CD11B5D757300301B0D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D55C6CB71B5D757300301B0D /* ResourceApp */; targetProxy = D55C6CD01B5D757300301B0D /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 5D1AFAAF1C858637003FE7AB /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( 5D1AFAB01C858637003FE7AB /* en */, 5D1AFAB21C858647003FE7AB /* es */, 5D1AFAB31C85864F003FE7AB /* ja */, ); name = Localizable.strings; sourceTree = ""; }; D50175BC1B5FEFD000DB8314 /* Secondary.storyboard */ = { isa = PBXVariantGroup; children = ( D50175BD1B5FEFD000DB8314 /* Base */, ); name = Secondary.storyboard; sourceTree = ""; }; D55C6CC31B5D757300301B0D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( D55C6CC41B5D757300301B0D /* Base */, ); name = Main.storyboard; sourceTree = ""; }; D55C6CC81B5D757300301B0D /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( D55C6CC91B5D757300301B0D /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; E2156B651CC4042900F341DC /* Settings.strings */ = { isa = PBXVariantGroup; children = ( E2156B641CC4042900F341DC /* Base */, E2156B661CC4043C00F341DC /* nl */, ); name = Settings.strings; sourceTree = ""; }; E2762AC21CCCDFDA0009BCAA /* Settings.stringsdict */ = { isa = PBXVariantGroup; children = ( E2762AC11CCCDFDA0009BCAA /* Base */, E2762AC31CCCDFE10009BCAA /* nl */, ); name = Settings.stringsdict; sourceTree = ""; }; E2CD68641D7CACC100BEBE59 /* hello.txt */ = { isa = PBXVariantGroup; children = ( E2CD68631D7CACC100BEBE59 /* Base */, E2CD68651D7CACCA00BEBE59 /* es */, E2CD68661D7CACCB00BEBE59 /* nl */, ); name = hello.txt; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ D55C6CD71B5D757300301B0D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; D55C6CD81B5D757300301B0D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; }; name = Release; }; D55C6CDA1B5D757300301B0D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = BCFE901EE74D3A3CF9909E5D /* Pods-ResourceApp.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ResourceApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; name = Debug; }; D55C6CDB1B5D757300301B0D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 41D4DA51D96C4F7DDF13157E /* Pods-ResourceApp.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ResourceApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; }; name = Release; }; D55C6CDD1B5D757300301B0D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = ResourceAppTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ResourceApp.app/ResourceApp"; }; name = Debug; }; D55C6CDE1B5D757300301B0D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = ResourceAppTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ResourceApp.app/ResourceApp"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ D55C6CB31B5D757300301B0D /* Build configuration list for PBXProject "ResourceApp" */ = { isa = XCConfigurationList; buildConfigurations = ( D55C6CD71B5D757300301B0D /* Debug */, D55C6CD81B5D757300301B0D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D55C6CD91B5D757300301B0D /* Build configuration list for PBXNativeTarget "ResourceApp" */ = { isa = XCConfigurationList; buildConfigurations = ( D55C6CDA1B5D757300301B0D /* Debug */, D55C6CDB1B5D757300301B0D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D55C6CDC1B5D757300301B0D /* Build configuration list for PBXNativeTarget "ResourceAppTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D55C6CDD1B5D757300301B0D /* Debug */, D55C6CDE1B5D757300301B0D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ E2C415CF28EED7890028D537 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D55C6CB01B5D757300301B0D /* Project object */; } ================================================ FILE: Examples/ResourceApp/ResourceApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/ResourceApp/ResourceApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "cd466d6e8c5ffd2f2b61165d37b0646f09068e1e", "version" : "2.9.0" } } ], "version" : 2 } ================================================ FILE: Examples/ResourceApp/ResourceApp.xcodeproj/xcshareddata/xcschemes/ResourceApp.xcscheme ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/ResourceApp/ResourceApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/ResourceApp/ResourceApp.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "1e761a55dd8d73b4e9cc227a297f438413953571", "version" : "2.11.1" } } ], "version" : 2 } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/FilesTests.swift ================================================ // // FilesTests.swift // ResourceApp // // Created by Mathijs Kadijk on 25-09-15. // Copyright © 2015 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest @testable import ResourceApp class FilesTests: XCTestCase { func testNoNilResourceFiles() { XCTAssertNotNil(R.file.someJson()) } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/FontsTests.swift ================================================ // // FontsTests.swift // ResourceApp // // Created by Mathijs Kadijk on 26-08-15. // Copyright © 2015 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest import RswiftResources @testable import ResourceApp class FontsTests: XCTestCase { func testNoNilFonts() { XCTAssertNotNil(R.font.averiaLibreBold(size: 10)) XCTAssertNotNil(R.font.averiaLibreBoldItalic(size: 20)) XCTAssertNotNil(R.font.averiaLibreLight(size: 30)) XCTAssertNotNil(R.font.averiaLibreRegular(size: 40)) XCTAssertNotNil(R.font.goudyBookletter1911(size: 50)) } func testNoValidationError() { XCTAssertNoThrow(try R.font.validate()) } func testAllFonts() { XCTAssertEqual(Array(R.font.map(\.name)), ["AveriaLibre-Bold", "AveriaLibre-BoldItalic", "AveriaLibre-Light", "AveriaLibre-Regular", "GoudyBookletter1911"]) } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/IgnoreTests.swift ================================================ // // IgnoreTests.swift // ResourceAppTests // // Created by Mathijs Kadijk on 15-06-18. // Copyright © 2018 Mathijs Kadijk. All rights reserved. // import Foundation import XCTest import RswiftResources @testable import ResourceApp class IgnoreTests: XCTestCase { func testExplicitInclude() { XCTAssertNotNil(R.image.keepDontIgnoreme()) } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Examples/ResourceApp/ResourceAppTests/InfoPlistTests.swift ================================================ // // InfoPlistTests.swift // ResourceAppTests // // Created by Tom Lokhorst on 2019-09-20. // Copyright © 2019 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest @testable import ResourceApp class InfoPlistTests: XCTestCase { func testUserActivityTypes() { XCTAssertNotNil(R.info.nsUserActivityTypes.planTripIntent) } func testVariable() { XCTAssertEqual(R.info.nsExtension.nsExtensionPrincipalClass, "ResourceApp.IntentHandler") } func testUIApplicationShortcutItems() { XCTAssertEqual(R.info.uiApplicationShortcutItems.nlMathijskadijkShortcutsQrScanning.uiApplicationShortcutItemIconFile, "ShortcutQrScanning") XCTAssertEqual(R.info.uiApplicationShortcutItems.nlMathijskadijkShortcutsQrScanning.uiApplicationShortcutItemTitle, "Scan QR-code") XCTAssertEqual(R.info.uiApplicationShortcutItems.nlMathijskadijkShortcutsQrScanning.uiApplicationShortcutItemType, "nl.mathijskadijk.shortcuts.qr-scanning") XCTAssertEqual(R.info.uiApplicationShortcutItems.nlMathijskadijkShortcutsSendParcel.uiApplicationShortcutItemIconFile, "ShortcutSendParcel") XCTAssertEqual(R.info.uiApplicationShortcutItems.nlMathijskadijkShortcutsSendParcel.uiApplicationShortcutItemTitle, "Send a Parcel") XCTAssertEqual(R.info.uiApplicationShortcutItems.nlMathijskadijkShortcutsSendParcel.uiApplicationShortcutItemType, "nl.mathijskadijk.shortcuts.send-parcel") } func testUIApplicationSceneManifest() { XCTAssertFalse(R.info.uiApplicationSceneManifest.uiApplicationSupportsMultipleScenes) XCTAssertEqual(R.info.uiApplicationSceneManifest.uiSceneConfigurations.uiWindowSceneSessionRoleApplication.defaultConfiguration.uiSceneConfigurationName, "Default Configuration") XCTAssertEqual(R.info.uiApplicationSceneManifest.uiSceneConfigurations.uiWindowSceneSessionRoleApplication.defaultConfiguration.uiSceneDelegateClassName, "ResourceApp.SceneDelegate") } func testNSUserActivityTypes() { XCTAssertEqual(R.info.nsUserActivityTypes.planTripIntent, "PlanTripIntent") XCTAssertEqual(R.info.nsUserActivityTypes.showDeparturesIntent, "ShowDeparturesIntent") } func testNSExtension() { XCTAssertEqual(R.info.nsExtension.nsExtensionAttributes.intentsSupported.planTripIntent, "PlanTripIntent") XCTAssertEqual(R.info.nsExtension.nsExtensionAttributes.intentsSupported.showDeparturesIntent, "ShowDeparturesIntent") XCTAssertEqual(R.info.nsExtension.nsExtensionPrincipalClass, "ResourceApp.IntentHandler") XCTAssertEqual(R.info.nsExtension.nsExtensionPointIdentifier, "com.apple.intents-service") } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/NibTests.swift ================================================ // // NibTests.swift // ResourceApp // // Created by Mathijs Kadijk on 27-08-15. // Copyright © 2015 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest @testable import ResourceApp class NibTests: XCTestCase { func testNibName() { XCTAssertEqual(R.nib.myView.name, "My View") } func testRelativeToProjectGroup() { XCTAssertTrue(R.nib.relativeToProject(owner: nil) != nil) XCTAssertTrue(R.nib.relativeToProject.firstView(owner: nil) != nil) } func testNibIsOfCorrectType() { XCTAssertTrue(type(of: R.nib.supplementaryElement).Reusable.classForCoder() == UICollectionReusableView.classForCoder()) } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/ResourceAppTests.swift ================================================ // // ResourceAppTests.swift // ResourceAppTests // // Created by Mathijs Kadijk on 20-07-15. // Copyright (c) 2015 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest @testable import ResourceApp class ResourceAppTests: XCTestCase { let expectedWarnings = """ warning: [R.swift] Missing reference 'missing' in 'fault delta' 'Generic.stringsdict' warning: [R.swift] Can't unify 'first' in 'fault beta' 'Generic.stringsdict' warning: [R.swift] Can't unify 'first' in 'fault gamma' 'Generic.stringsdict' warning: [R.swift] Missing reference 'missing' in 'fault alpha' 'Generic.stringsdict' warning: [R.swift] Missing reference 'first_one' in 'fault epsilon' 'Generic.stringsdict' warning: [R.swift] Missing reference 'first' in 'incorrect in dutch' 'Settings.stringsdict' (nl) warning: [R.swift] Skipping 2 images because symbol 'second' would be generated for all of these images: Second, second warning: [R.swift] Skipping 2 images because symbol 'theAppIcon' would be generated for all of these images: The App Icon, TheAppIcon warning: [R.swift] Skipping asset namespace 'conflicting' because symbol 'conflicting' would conflict with image: conflicting warning: [R.swift] Skipping 2 images namespace because symbol 'second' would be generated for all of these images: Second, Second warning: [R.swift] Skipping 2 colors because symbol 'myRed' would be generated for all of these colors: My Red, My Red warning: [R.swift] Destination view controller with id Zbd-89-K73 for segue toUnknown in FirstViewController not found in storyboard References. Is this storyboard corrupt? warning: [R.swift] Skipping 2 segues for 'SecondViewController' because symbol 'toFirst' would be generated for all of these segues: ToFirst, toFirst warning: [R.swift] Skipping 2 storyboards because symbol 'duplicate' would be generated for all of these files: Duplicate, duplicate warning: [R.swift] Skipping 2 view controllers because symbol 'validationClash' would be generated for all of these view controller identifiers: Validation clash, ValidationClash warning: [R.swift] Skipping 2 xibs because symbol 'duplicate' would be generated for all of these files: Duplicate, duplicate warning: [R.swift] Skipping 2 reuseIdentifiers because symbol 'duplicateCellView' would be generated for all of these reuse identifiers: DuplicateCellView, duplicateCellView warning: [R.swift] Skipping 1 reuseIdentifier because no swift identifier can be generated for reuse identifier: ' ' warning: [R.swift] Skipping 2 resource files because symbol 'duplicateJson' would be generated for all of these files: Duplicate.json, duplicateJson warning: [R.swift] Skipping 2 strings files because symbol 'duplicate' would be generated for all of these files: Duplicate, Duplicate# warning: [R.swift] Skipping 1 strings file because no swift identifier can be generated for file: '@@' warning: [R.swift] Strings file 'Localizable' (es) is missing translations for keys: 'japanese only' warning: [R.swift] Strings file 'Localizable' (en) is missing translations for keys: 'japanese only' warning: [R.swift] Strings file 'Settings' (nl) is missing translations for keys: 'Not translated', 'incorrect in dutch' warning: [R.swift] Skipping string FormatSpecifiers2 in 'Settings' (nl), not all format specifiers are consecutive warning: [R.swift] Skipping string FormatSpecifiers6 in 'Settings' (Base), not all format specifiers are consecutive warning: [R.swift] Skipping string FormatSpecifiers6 in 'Settings' (nl), not all format specifiers are consecutive warning: [R.swift] Skipping string for key FormatSpecifiers5 (Settings), format specifiers don't match for all locales: Base, nl warning: [R.swift] Skipping string for key mismatch (Settings), format specifiers don't match for all locales: Base, nl warning: [R.swift] Skipping 1 string in 'Generic' because no swift identifier can be generated for key: '#' warning: [R.swift] Strings file 'Settings' (nl) has extra translations (not in Base) for keys: 'Only Dutch' warning: [R.swift] Strings file 'Generic' has extra translations (not in English) for keys: '#' warning: [R.swift] Skipping 2 infos because symbol 'duplicatePlistKey' would be generated for all of these infos: DuplicatePlistKey#, DuplicatePlistKey* warning: [R.swift] Skipping 2 infos because symbol 'duplicatePlistValue' would be generated for all of these infos: DuplicatePlistValue, DuplicatePlistValue """ .trimmingCharacters(in: .whitespacesAndNewlines) .components(separatedBy: "\n") func testWarningsAreLogged() { guard let logURL = Bundle(for: ResourceAppTests.self).url(forResource: "rswift", withExtension: "log") else { XCTFail("File rswift.log not found") return } do { let logContent = try String(contentsOf: logURL) let logLines = logContent .trimmingCharacters(in: .whitespacesAndNewlines) .components(separatedBy: "\n") for warning in expectedWarnings { XCTAssertTrue(logLines.contains(warning), "Warning is not logged: '\(warning)'") } for logLine in logLines { XCTAssertTrue(expectedWarnings.contains(logLine), "Warning was not expected: '\(logLine)'") } XCTAssertEqual(logLines.count, expectedWarnings.count, "There are more/less warnings then expected") } catch { XCTFail("Failed to read rswift.log") } } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/SegueTests.swift ================================================ // // SegueTests.swift // ResourceApp // // Created by Tom Lokhorst on 2016-08-08. // Copyright © 2016 Mathijs Kadijk. All rights reserved. // import XCTest @testable import ResourceApp class SegueTests: XCTestCase { func testSegueNames() { XCTAssertEqual(R.segue.firstViewController.toSomeStoryboard.identifier, "toSomeStoryboard") XCTAssertEqual(R.segue.secondViewController.attachedSegue.identifier, "attachedSegue") XCTAssertEqual(R.segue.secondViewController.recognizerSegue.identifier, "recognizerSegue") XCTAssertEqual(R.segue.secondViewController.toThird.identifier, "toThird") } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/StoryboardTests.swift ================================================ // // StoryboardTests.swift // ResourceApp // // Created by Mathijs Kadijk on 10-01-16. // Copyright © 2016 Mathijs Kadijk. All rights reserved. // import XCTest @testable import ResourceApp class StoryboardTests: XCTestCase { func testStoryboardNames() { XCTAssertEqual(R.storyboard.main.name, "Main") XCTAssertEqual(R.storyboard.secondary.name, "Secondary") XCTAssertEqual(R.storyboard.specials.name, "Specials") } func testStoryboardInitialViewControllers() { XCTAssertNotNil(R.storyboard.main.instantiateInitialViewController(), "Initial view controller is missing") XCTAssertNotNil(R.storyboard.secondary.instantiateInitialViewController(), "Initial view controller is missing") } func testStoryboardSpecificViewControllers() { XCTAssertNotNil(R.storyboard.main.thirdViewController(), "Specific view controller is missing") XCTAssertNotNil(R.storyboard.specials.glkVC(), "Specific view controller is missing") } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/StringsTests.swift ================================================ // // StringsTests.swift // ResourceApp // // Created by Nolan Warner on 26-08-15. // Copyright © 2015 Nolan Warner. All rights reserved. // import UIKit import XCTest @testable import ResourceApp class StringsTests: XCTestCase { func testNoNilStrings() { XCTAssertNotNil(R.string.generic.loremipsum()) // XCTAssertNotNil(R.string.localizable.japaneseOnly()) XCTAssertNotNil(R.string.localizable.one()) XCTAssertNotNil(R.string.localizable.quote(4)) XCTAssertNotNil(R.string.localizable.two()) XCTAssertNotNil(R.string.settings.copyProgress(2, 4, 50.0)) XCTAssertNotNil(R.string.settings.formatSpecifiers1(11, 22, "str")) XCTAssertNotNil(R.string.settings.formatSpecifiers3(11, 22, "str")) XCTAssertNotNil(R.string.settings.formatSpecifiers4(11, 22, "str")) XCTAssertNotNil(R.string.settings.multilineKeyWeird()) XCTAssertNotNil(R.string.settings.notTranslated()) XCTAssertNotNil(R.string.settings.title()) XCTAssertNotNil(R.string.settings.scopeLuOutOfLuRuns(lu_completed_runs: 4, lu_total_runs: 2)) } func testCorrectValues() { // Force locales, for decimal point and decimal comma versions let stringsEN = R.string(locale: Locale(identifier: "en_US")) let stringsNL = R.string(locale: Locale(identifier: "nl_NL")) let stringsFR = R.string(locale: Locale(identifier: "fr_FR")) XCTAssertEqual(stringsEN.generic.precision1(12345.678), "one - 12,345.68") XCTAssertEqual(stringsEN.generic.precision2(12345.678), "two - 12,345.68") XCTAssertEqual(stringsEN.generic.precision3(12345.678), "three - 12,345.6780") XCTAssertEqual(stringsEN.generic.precision4(12345.678), "four - 12,345.68") XCTAssertEqual(stringsNL.generic.precision1(12345.678), "one - 12.345,68") XCTAssertEqual(stringsNL.generic.precision2(12345.678), "two - 12.345,68") XCTAssertEqual(stringsNL.generic.precision3(12345.678), "three - 12.345,6780") XCTAssertEqual(stringsNL.generic.precision4(12345.678), "four - 12.345,68") XCTAssertEqual(stringsFR.generic.precision1(12345.678), "one - 12\u{202F}345,68") XCTAssertEqual(stringsFR.generic.precision2(12345.678), "two - 12\u{202F}345,68") XCTAssertEqual(stringsFR.generic.precision3(12345.678), "three - 12\u{202F}345,6780") XCTAssertEqual(stringsFR.generic.precision4(12345.678), "four - 12\u{202F}345,68") XCTAssertEqual(R.string.generic.discount10(), "Today, 10% off!") XCTAssertEqual(R.string.generic.discountX(20), "Today, 20% off!") XCTAssertEqual(R.string.localizable.discount10(), "Today, 10% off!") XCTAssertEqual(R.string.localizable.discountX(20), "Today, 20% off!") XCTAssertEqual(R.string.generic.url(), "http%3A%2F%2Fwww.abc.xyz") XCTAssertEqual( R.string.settings.multilineKeyWeird(), NSLocalizedString("Multiline\t\\key/\n\"weird\"?!", tableName: "Settings", comment: "")) XCTAssertEqual( R.string.generic.correctAlpha(first: 1), "Pre Alpha (| One Alpha |)") XCTAssertEqual( R.string.generic.correctBeta(first: 1, second: 2), "Pre Beta (| One Beta.first x Other Beta.second: 2 |)") XCTAssertEqual( R.string.generic.correctGamma(first: 1, second: 2), "Pre Gamma (| Other Gamma.second: 2 x One Gamma.first |)") XCTAssertEqual( R.string.generic.correctDelta(first: 1, second: 2), "Pre Delta (| One Delta.first (1). Second: Other Delta.second: 2 |)") XCTAssertEqual( R.string.generic.correctEpsilon(first: 1, second: 2), "Pre Epsilon (| Other Epsilon.first: 1. Second: Other Epsilon.second: 2 |)") XCTAssertEqual( R.string.generic.correctEta("ONE", second: 2, 3), "Pre Eta (| ONE - Other Eta.second: 2. - 3|)") XCTAssertEqual( R.string.generic.correctTheta(first: 1, second: 2, third: 3), "Pre Theta (| One Theta.first |)") XCTAssertEqual( R.string.generic.correctZeta("ONE", second: 2), "Pre Zeta (| ONE Other Zeta.second: 2. |)") } } ================================================ FILE: Examples/ResourceApp/ResourceAppTests/ValidationTests.swift ================================================ // // ValidationTests.swift // ResourceAppTests // // Created by Mathijs Kadijk on 20-07-15. // Copyright (c) 2015 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest import RswiftResources @testable import ResourceApp class ValidationTests: XCTestCase { func testRunGlobalValidateMethod() { do { try R.validate() XCTFail("No error thrown") } catch let error as ValidationError { XCTAssertEqual(error.description, "[R.swift] Image named 'First' is used in storyboard 'Secondary', but couldn't be loaded.") } catch { XCTFail("Wrong error thrown") } } func testRunSpecificValidateMethods() { do { try R.storyboard.main.validate() } catch { XCTFail("Wrong error thrown") } do { try R.storyboard.secondary.validate() XCTFail("No error thrown") } catch let error as ValidationError { XCTAssertEqual(error.description, "[R.swift] Image named 'First' is used in storyboard 'Secondary', but couldn't be loaded.") } catch { XCTFail("Wrong error thrown") } } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UISceneStoryboardFile Main UIApplicationSupportsIndirectInputEvents UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Resources/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Resources/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Resources/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Sources/AppDelegate.swift ================================================ import UIKit import Foo import Bar @main final class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FooClass().foo() BarClass().bar() return true } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Sources/SceneDelegate.swift ================================================ // // SceneDelegate.swift // FooBar // // Created by Maciej Piotrowski on 04/01/2021. // import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/App/Sources/ViewController.swift ================================================ import UIKit import Foo import Bar final class ViewController: UIViewController { @IBOutlet weak var fooImageView: UIImageView! @IBOutlet weak var barImageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() fooImageView.image = FooClass().sampleImage() barImageView.image = BarClass().sampleImage() } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/AppTests/AppTests.swift ================================================ // // AppTests.swift // AppTests // // Created by Tom Lokhorst on 2022-11-10. // import XCTest @testable import Foo @testable import Bar final class AppTests: XCTestCase { func testNotNil() throws { let fooBundle = Bundle.main.path(forResource: "Foo", ofType: "bundle").flatMap(Bundle.init(path:))! let barBundle = Bundle.main.path(forResource: "Bar", ofType: "bundle").flatMap(Bundle.init(path:))! let fooR = Foo._R(bundle: fooBundle) let barR = Bar._R(bundle: barBundle) XCTAssertNotNil(UIImage(resource: fooR.image.user)) XCTAssertNotNil(UIImage(resource: barR.image.colorsJpg)) } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/Bar/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/Bar/Sources/Bar.swift ================================================ import UIKit let bundle = Bundle.main.path(forResource: "Bar", ofType: "bundle").flatMap(Bundle.init(path:))! public final class BarClass { public init() {} public func bar() { print("bar") } public func sampleImage() -> UIImage { R.image(bundle: bundle).colorsJpg()! } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/Foo/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/Foo/Sources/Foo.swift ================================================ import UIKit let bundle = Bundle.main.path(forResource: "Foo", ofType: "bundle").flatMap(Bundle.init(path:))! public final class FooClass { public init() {} public func foo() { print("foo") } public func sampleImage() -> UIImage { R.image(bundle: bundle).user()! } } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 23D0DE433EC1766BB2FE59C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3844C19EF2D85F958F010218 /* Assets.xcassets */; }; 37A6C8B54F86BE2228F892B5 /* Foo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71F7B7842FB9EF2B65125CA8 /* Foo.framework */; }; 4680E921FB7046245B234C95 /* FooBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 47FFEF3E3191F365876C33B1 /* FooBundle.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 50D25F3E8DE46F91123C0CC5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C0B0FCA09D48FF877E95970 /* ViewController.swift */; }; A025843A2D354BB0B413A717 /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003AB83A00F5D1B9A9F9B90 /* R.generated.swift */; }; A14D88A4A3403DACF2DC2ECF /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7750863E11F70C8B71F811A /* R.generated.swift */; }; A7940548A881305B7778FC55 /* Bar.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F77580EFDC1015090A2B822 /* Bar.framework */; }; A9A2E8F57CA32D93229A2462 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D52D56702E90AADBC46B4EB /* LaunchScreen.storyboard */; }; B237F040341B112E7909766C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6ED7964632BE36BB21735A9 /* AppDelegate.swift */; }; B2AF344DDA24E5AE91D9D3B1 /* User.png in Resources */ = {isa = PBXBuildFile; fileRef = A51DA98728043B2D10ECA1B3 /* User.png */; }; C035B4491A5A10E08C72F4D4 /* Foo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C541BB310FEB70B665E8E397 /* Foo.swift */; }; C6170449030C8F20798DFC3F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DBD12E6769ED8625AC7210E6 /* Main.storyboard */; }; D80E585DBD9FA2E07EB14DA2 /* BarBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = F1DD55F25DE874A0AA75B238 /* BarBundle.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DD2203C09F7FD1ECB305B8C2 /* Colors@3x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 655641603F257DD75189A0F6 /* Colors@3x.jpg */; }; DD544B6A13EA12A2EFF14EE3 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2241208CE1C221B1E493B1CA /* SceneDelegate.swift */; }; E2CAA5CD291C40F300EAE67C /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E2CAA5CC291C40F300EAE67C /* RswiftLibrary */; }; E2CAA5CF291C40F700EAE67C /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E2CAA5CE291C40F700EAE67C /* RswiftLibrary */; }; E2E58367291D341F006E17D9 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E58366291D341F006E17D9 /* AppTests.swift */; }; F8DB9C27FD3259718C746DBA /* Bar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA3FBEC5BB6C4FE0CF1A43A /* Bar.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 1DFDF5BED3E06260DD0983D2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C88653A8855B27A3CA0F5055 /* Project object */; proxyType = 1; remoteGlobalIDString = 8F2521905D0CF087FFD375B3; remoteInfo = BarBundle; }; 4148B3991FED2CFF64E2BFB4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C88653A8855B27A3CA0F5055 /* Project object */; proxyType = 1; remoteGlobalIDString = 0328DD4A87BE56889AA0F781; remoteInfo = Bar; }; 803498BC9B607C125AE5E616 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C88653A8855B27A3CA0F5055 /* Project object */; proxyType = 1; remoteGlobalIDString = 59A219B1BF6C52119E76405D; remoteInfo = Foo; }; C9A1FDF0190D9DA54DB7D4B0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C88653A8855B27A3CA0F5055 /* Project object */; proxyType = 1; remoteGlobalIDString = 8B28E1AAD3ADDC6347204D85; remoteInfo = FooBundle; }; E2E58368291D341F006E17D9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C88653A8855B27A3CA0F5055 /* Project object */; proxyType = 1; remoteGlobalIDString = E6815CC966750C0B4B8C0903; remoteInfo = App; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 09EBE6C782F6AFDFAAAB82E4 /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2241208CE1C221B1E493B1CA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 2DA3FBEC5BB6C4FE0CF1A43A /* Bar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bar.swift; sourceTree = ""; }; 3844C19EF2D85F958F010218 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47FFEF3E3191F365876C33B1 /* FooBundle.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.plug-in"; name = FooBundle.bundle; path = Foo.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 655641603F257DD75189A0F6 /* Colors@3x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "Colors@3x.jpg"; sourceTree = ""; }; 65B047577B44066BF0F03323 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 71F7B7842FB9EF2B65125CA8 /* Foo.framework */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.framework; path = Foo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7C0B0FCA09D48FF877E95970 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 7F77580EFDC1015090A2B822 /* Bar.framework */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.framework; path = Bar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A51DA98728043B2D10ECA1B3 /* User.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = User.png; sourceTree = ""; }; B5D7765B6F9ED6E52E0C0E9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; C541BB310FEB70B665E8E397 /* Foo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Foo.swift; sourceTree = ""; }; CCFC93145C8B40C96FC845E0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; D003AB83A00F5D1B9A9F9B90 /* R.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; }; E2CAA5CA291C403400EAE67C /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; E2E58364291D341F006E17D9 /* AppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E2E58366291D341F006E17D9 /* AppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTests.swift; sourceTree = ""; }; E6ED7964632BE36BB21735A9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; E7750863E11F70C8B71F811A /* R.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; }; F1DD55F25DE874A0AA75B238 /* BarBundle.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.plug-in"; name = BarBundle.bundle; path = Bar.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0A731942ACBB4ECBC9AAB971 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E2CAA5CD291C40F300EAE67C /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 2D2E9B6337E9A1F293CFEF1A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E2CAA5CF291C40F700EAE67C /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 4579F2BF429599A2B22EF7E9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 37A6C8B54F86BE2228F892B5 /* Foo.framework in Frameworks */, A7940548A881305B7778FC55 /* Bar.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; A9E1015776CFBF373AD544CC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; E2E58361291D341F006E17D9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; EDBDCA658D347C739094B5A8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 09954D985BD90D3535BA5E29 /* Bar */ = { isa = PBXGroup; children = ( A2BED99BA03167AE6623D710 /* Resources */, F0B54132DA7DE455F60E7A34 /* Sources */, ); path = Bar; sourceTree = ""; }; 370D29654D2F7D3ED5FF8790 /* App */ = { isa = PBXGroup; children = ( CCFC93145C8B40C96FC845E0 /* Info.plist */, 62CE76B9A9B4F9BD5021F441 /* Resources */, 848C8ADB35C45933DBD38D2E /* Sources */, ); path = App; sourceTree = ""; }; 582737745B10EC73FF0579D7 = { isa = PBXGroup; children = ( E2CAA5C9291C403400EAE67C /* Packages */, 370D29654D2F7D3ED5FF8790 /* App */, 09954D985BD90D3535BA5E29 /* Bar */, C59E71F563315A14B3980DA2 /* Foo */, E2E58365291D341F006E17D9 /* AppTests */, F9DDB8B557D329344CC4A0CC /* Products */, E2CAA5BB291C38D900EAE67C /* Frameworks */, ); sourceTree = ""; }; 62CE76B9A9B4F9BD5021F441 /* Resources */ = { isa = PBXGroup; children = ( 3844C19EF2D85F958F010218 /* Assets.xcassets */, 9D52D56702E90AADBC46B4EB /* LaunchScreen.storyboard */, DBD12E6769ED8625AC7210E6 /* Main.storyboard */, ); path = Resources; sourceTree = ""; }; 82705CC060AFE6E95F5ADB07 /* Sources */ = { isa = PBXGroup; children = ( C541BB310FEB70B665E8E397 /* Foo.swift */, D003AB83A00F5D1B9A9F9B90 /* R.generated.swift */, ); path = Sources; sourceTree = ""; }; 848C8ADB35C45933DBD38D2E /* Sources */ = { isa = PBXGroup; children = ( E6ED7964632BE36BB21735A9 /* AppDelegate.swift */, 2241208CE1C221B1E493B1CA /* SceneDelegate.swift */, 7C0B0FCA09D48FF877E95970 /* ViewController.swift */, ); path = Sources; sourceTree = ""; }; A2BED99BA03167AE6623D710 /* Resources */ = { isa = PBXGroup; children = ( 655641603F257DD75189A0F6 /* Colors@3x.jpg */, ); path = Resources; sourceTree = ""; }; AEBCA0D51F6A1C59A1517331 /* Resources */ = { isa = PBXGroup; children = ( A51DA98728043B2D10ECA1B3 /* User.png */, ); path = Resources; sourceTree = ""; }; C59E71F563315A14B3980DA2 /* Foo */ = { isa = PBXGroup; children = ( AEBCA0D51F6A1C59A1517331 /* Resources */, 82705CC060AFE6E95F5ADB07 /* Sources */, ); path = Foo; sourceTree = ""; }; E2CAA5BB291C38D900EAE67C /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; E2CAA5C9291C403400EAE67C /* Packages */ = { isa = PBXGroup; children = ( E2CAA5CA291C403400EAE67C /* R.swift */, ); name = Packages; sourceTree = ""; }; E2E58365291D341F006E17D9 /* AppTests */ = { isa = PBXGroup; children = ( E2E58366291D341F006E17D9 /* AppTests.swift */, ); path = AppTests; sourceTree = ""; }; F0B54132DA7DE455F60E7A34 /* Sources */ = { isa = PBXGroup; children = ( 2DA3FBEC5BB6C4FE0CF1A43A /* Bar.swift */, E7750863E11F70C8B71F811A /* R.generated.swift */, ); path = Sources; sourceTree = ""; }; F9DDB8B557D329344CC4A0CC /* Products */ = { isa = PBXGroup; children = ( 09EBE6C782F6AFDFAAAB82E4 /* App.app */, 7F77580EFDC1015090A2B822 /* Bar.framework */, F1DD55F25DE874A0AA75B238 /* BarBundle.bundle */, 71F7B7842FB9EF2B65125CA8 /* Foo.framework */, 47FFEF3E3191F365876C33B1 /* FooBundle.bundle */, E2E58364291D341F006E17D9 /* AppTests.xctest */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 0328DD4A87BE56889AA0F781 /* Bar */ = { isa = PBXNativeTarget; buildConfigurationList = A0FB50A44CF6F3E23F1D04B0 /* Build configuration list for PBXNativeTarget "Bar" */; buildPhases = ( E2CAA5CB291C404A00EAE67C /* R.swift */, 40C7251D6D0A826CD4FC20FF /* Sources */, 2690BC128C6239F7341A0E1B /* Resources */, 0A731942ACBB4ECBC9AAB971 /* Frameworks */, ); buildRules = ( ); dependencies = ( DF0A2FBC262B99BDB95C08AD /* PBXTargetDependency */, ); name = Bar; packageProductDependencies = ( E2CAA5CC291C40F300EAE67C /* RswiftLibrary */, ); productName = Bar; productReference = 7F77580EFDC1015090A2B822 /* Bar.framework */; productType = "com.apple.product-type.framework.static"; }; 59A219B1BF6C52119E76405D /* Foo */ = { isa = PBXNativeTarget; buildConfigurationList = CB8E0D95C8221EB66322BB76 /* Build configuration list for PBXNativeTarget "Foo" */; buildPhases = ( E2CAA5D1291C414A00EAE67C /* R.swift */, 5D824023BAD1D687E5B2AD5F /* Sources */, 641BD0BED6B86B8355FD746E /* Resources */, 2D2E9B6337E9A1F293CFEF1A /* Frameworks */, ); buildRules = ( ); dependencies = ( 47421C68E32922D308DC7D74 /* PBXTargetDependency */, ); name = Foo; packageProductDependencies = ( E2CAA5CE291C40F700EAE67C /* RswiftLibrary */, ); productName = Foo; productReference = 71F7B7842FB9EF2B65125CA8 /* Foo.framework */; productType = "com.apple.product-type.framework.static"; }; 8B28E1AAD3ADDC6347204D85 /* FooBundle */ = { isa = PBXNativeTarget; buildConfigurationList = C87CE7344FD89D4A4F49943C /* Build configuration list for PBXNativeTarget "FooBundle" */; buildPhases = ( 93F7254F4D2B16BE33DB2BDF /* Resources */, EDBDCA658D347C739094B5A8 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = FooBundle; productName = FooBundle; productReference = 47FFEF3E3191F365876C33B1 /* FooBundle.bundle */; productType = "com.apple.product-type.bundle"; }; 8F2521905D0CF087FFD375B3 /* BarBundle */ = { isa = PBXNativeTarget; buildConfigurationList = DE89F2BC7BD62BB58420F5EC /* Build configuration list for PBXNativeTarget "BarBundle" */; buildPhases = ( F752C24D8952745834991833 /* Resources */, A9E1015776CFBF373AD544CC /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = BarBundle; productName = BarBundle; productReference = F1DD55F25DE874A0AA75B238 /* BarBundle.bundle */; productType = "com.apple.product-type.bundle"; }; E2E58363291D341F006E17D9 /* AppTests */ = { isa = PBXNativeTarget; buildConfigurationList = E2E5836C291D341F006E17D9 /* Build configuration list for PBXNativeTarget "AppTests" */; buildPhases = ( E2E58360291D341F006E17D9 /* Sources */, E2E58361291D341F006E17D9 /* Frameworks */, E2E58362291D341F006E17D9 /* Resources */, ); buildRules = ( ); dependencies = ( E2E58369291D341F006E17D9 /* PBXTargetDependency */, ); name = AppTests; productName = AppTests; productReference = E2E58364291D341F006E17D9 /* AppTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; E6815CC966750C0B4B8C0903 /* App */ = { isa = PBXNativeTarget; buildConfigurationList = B6DEF19BFDFDD330B369BBE8 /* Build configuration list for PBXNativeTarget "App" */; buildPhases = ( ADE3A7C6DD9F273AC89B3ED5 /* Sources */, BC9CC850DB0B3548EBDC9E7D /* Resources */, 4579F2BF429599A2B22EF7E9 /* Frameworks */, 7F553EDAB894541615C8EB2C /* Copy Bundles */, ); buildRules = ( ); dependencies = ( 04CE573ED9492DE29603C7A4 /* PBXTargetDependency */, 63408DB2AC810020287B7FD0 /* PBXTargetDependency */, ); name = App; packageProductDependencies = ( ); productName = App; productReference = 09EBE6C782F6AFDFAAAB82E4 /* App.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ C88653A8855B27A3CA0F5055 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1410; LastUpgradeCheck = 1200; TargetAttributes = { E2E58363291D341F006E17D9 = { CreatedOnToolsVersion = 14.1; TestTargetID = E6815CC966750C0B4B8C0903; }; }; }; buildConfigurationList = B0168AC1C5483CCEB3271728 /* Build configuration list for PBXProject "RswiftAppWithStaticFrameworks" */; compatibilityVersion = "Xcode 10.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( Base, en, ); mainGroup = 582737745B10EC73FF0579D7; productRefGroup = F9DDB8B557D329344CC4A0CC /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E6815CC966750C0B4B8C0903 /* App */, 0328DD4A87BE56889AA0F781 /* Bar */, 8F2521905D0CF087FFD375B3 /* BarBundle */, 59A219B1BF6C52119E76405D /* Foo */, 8B28E1AAD3ADDC6347204D85 /* FooBundle */, E2E58363291D341F006E17D9 /* AppTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 2690BC128C6239F7341A0E1B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D80E585DBD9FA2E07EB14DA2 /* BarBundle.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 641BD0BED6B86B8355FD746E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 4680E921FB7046245B234C95 /* FooBundle.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 93F7254F4D2B16BE33DB2BDF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( B2AF344DDA24E5AE91D9D3B1 /* User.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; BC9CC850DB0B3548EBDC9E7D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 23D0DE433EC1766BB2FE59C6 /* Assets.xcassets in Resources */, A9A2E8F57CA32D93229A2462 /* LaunchScreen.storyboard in Resources */, C6170449030C8F20798DFC3F /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; E2E58362291D341F006E17D9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F752C24D8952745834991833 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( DD2203C09F7FD1ECB305B8C2 /* Colors@3x.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 7F553EDAB894541615C8EB2C /* Copy Bundles */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Copy Bundles"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "./copy_bundles.sh\n"; }; E2CAA5CB291C404A00EAE67C /* R.swift */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = R.swift; outputFileListPaths = ( ); outputPaths = ( $SRCROOT/Bar/Sources/R.generated.swift, ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "../../.build/release/rswift generate $SRCROOT/Bar/Sources/R.generated.swift --target ${PRODUCT_NAME}Bundle\n"; showEnvVarsInLog = 0; }; E2CAA5D1291C414A00EAE67C /* R.swift */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = R.swift; outputFileListPaths = ( ); outputPaths = ( $SRCROOT/Foo/Sources/R.generated.swift, ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "../../.build/release/rswift generate $SRCROOT/Foo/Sources/R.generated.swift --target ${PRODUCT_NAME}Bundle\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 40C7251D6D0A826CD4FC20FF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F8DB9C27FD3259718C746DBA /* Bar.swift in Sources */, A14D88A4A3403DACF2DC2ECF /* R.generated.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 5D824023BAD1D687E5B2AD5F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( C035B4491A5A10E08C72F4D4 /* Foo.swift in Sources */, A025843A2D354BB0B413A717 /* R.generated.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; ADE3A7C6DD9F273AC89B3ED5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B237F040341B112E7909766C /* AppDelegate.swift in Sources */, DD544B6A13EA12A2EFF14EE3 /* SceneDelegate.swift in Sources */, 50D25F3E8DE46F91123C0CC5 /* ViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E2E58360291D341F006E17D9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E2E58367291D341F006E17D9 /* AppTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 04CE573ED9492DE29603C7A4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 59A219B1BF6C52119E76405D /* Foo */; targetProxy = 803498BC9B607C125AE5E616 /* PBXContainerItemProxy */; }; 47421C68E32922D308DC7D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8B28E1AAD3ADDC6347204D85 /* FooBundle */; targetProxy = C9A1FDF0190D9DA54DB7D4B0 /* PBXContainerItemProxy */; }; 63408DB2AC810020287B7FD0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0328DD4A87BE56889AA0F781 /* Bar */; targetProxy = 4148B3991FED2CFF64E2BFB4 /* PBXContainerItemProxy */; }; DF0A2FBC262B99BDB95C08AD /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8F2521905D0CF087FFD375B3 /* BarBundle */; targetProxy = 1DFDF5BED3E06260DD0983D2 /* PBXContainerItemProxy */; }; E2E58369291D341F006E17D9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E6815CC966750C0B4B8C0903 /* App */; targetProxy = E2E58368291D341F006E17D9 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 9D52D56702E90AADBC46B4EB /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 65B047577B44066BF0F03323 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; DBD12E6769ED8625AC7210E6 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( B5D7765B6F9ED6E52E0C0E9A /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 34AE2C662C40B3A8D071F0F2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Foo/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 42F07A51D83C6D0157DE516F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Bar/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; PRODUCT_NAME = Bar; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 45F5BF9169D32C7AE87F0699 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = Foo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MACH_O_TYPE = mh_bundle; PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; PRODUCT_NAME = Foo; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; 66BAA81A15AA74DBDAA90FD6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Bar/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; PRODUCT_NAME = Bar; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 887AA668D7785BA542E846E0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = Bar/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MACH_O_TYPE = mh_bundle; PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; PRODUCT_NAME = Bar; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 8CD98AF60F03A3684AF41FF9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = App/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; 994E34063ABAC54789FA4C14 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; }; name = Release; }; 9F98089B10E355F2695FAD9A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = Bar/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MACH_O_TYPE = mh_bundle; PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; PRODUCT_NAME = Bar; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; B00C96695DF77912869D2A02 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = Foo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MACH_O_TYPE = mh_bundle; PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; PRODUCT_NAME = Foo; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; B78B2DA0006A2053E8E8D15E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Foo/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; E2E5836A291D341F006E17D9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.nonstrict.AppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/App"; }; name = Debug; }; E2E5836B291D341F006E17D9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.nonstrict.AppTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/App"; VALIDATE_PRODUCT = YES; }; name = Release; }; E8315FC5728EA2DB95EEA61F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DEBUG=1", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; FD856F4445F4086EFDE59CF8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = App/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.rswift.$(PRODUCT_NAME:c99extidentifier)"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ A0FB50A44CF6F3E23F1D04B0 /* Build configuration list for PBXNativeTarget "Bar" */ = { isa = XCConfigurationList; buildConfigurations = ( 66BAA81A15AA74DBDAA90FD6 /* Debug */, 42F07A51D83C6D0157DE516F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; B0168AC1C5483CCEB3271728 /* Build configuration list for PBXProject "RswiftAppWithStaticFrameworks" */ = { isa = XCConfigurationList; buildConfigurations = ( E8315FC5728EA2DB95EEA61F /* Debug */, 994E34063ABAC54789FA4C14 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; B6DEF19BFDFDD330B369BBE8 /* Build configuration list for PBXNativeTarget "App" */ = { isa = XCConfigurationList; buildConfigurations = ( FD856F4445F4086EFDE59CF8 /* Debug */, 8CD98AF60F03A3684AF41FF9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; C87CE7344FD89D4A4F49943C /* Build configuration list for PBXNativeTarget "FooBundle" */ = { isa = XCConfigurationList; buildConfigurations = ( B00C96695DF77912869D2A02 /* Debug */, 45F5BF9169D32C7AE87F0699 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; CB8E0D95C8221EB66322BB76 /* Build configuration list for PBXNativeTarget "Foo" */ = { isa = XCConfigurationList; buildConfigurations = ( 34AE2C662C40B3A8D071F0F2 /* Debug */, B78B2DA0006A2053E8E8D15E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; DE89F2BC7BD62BB58420F5EC /* Build configuration list for PBXNativeTarget "BarBundle" */ = { isa = XCConfigurationList; buildConfigurations = ( 887AA668D7785BA542E846E0 /* Debug */, 9F98089B10E355F2695FAD9A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; E2E5836C291D341F006E17D9 /* Build configuration list for PBXNativeTarget "AppTests" */ = { isa = XCConfigurationList; buildConfigurations = ( E2E5836A291D341F006E17D9 /* Debug */, E2E5836B291D341F006E17D9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ E2CAA5CC291C40F300EAE67C /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E2CAA5CE291C40F700EAE67C /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = C88653A8855B27A3CA0F5055 /* Project object */; } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "1e761a55dd8d73b4e9cc227a297f438413953571", "version" : "2.11.1" } } ], "version" : 2 } ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/xcshareddata/xcschemes/App.xcscheme ================================================ ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/xcshareddata/xcschemes/Bar.xcscheme ================================================ ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/RswiftAppWithStaticFrameworks.xcodeproj/xcshareddata/xcschemes/Foo.xcscheme ================================================ ================================================ FILE: Examples/RswiftAppWithStaticFrameworks/copy_bundles.sh ================================================ #!/bin/sh find "${BUILT_PRODUCTS_DIR}" -d 1 -name "*.framework" | while read framework do find -L "${framework}" -name "*.bundle" -d 1 | while read source do destination="${TARGET_BUILD_DIR}/${EXECUTABLE_FOLDER_PATH}" rsync -auv "${source}" "${destination}" || exit 1 done done exit 0 ================================================ FILE: Examples/RswiftUI/RswiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUI/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUI/Assets.xcassets/hand.ignoreme.imageset/Contents.json ================================================ { "images" : [ { "filename" : "hand.ignoreme.png", "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUI/ContentView.swift ================================================ // // ContentView.swift // RswiftUI // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI struct ContentView: View { var body: some View { Text("Hello, SwiftUI App!") .padding() Image(R.image.handIgnoreme) .resizable() .aspectRatio(1, contentMode: .fit) .frame(width: 140) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ================================================ FILE: Examples/RswiftUI/RswiftUI/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UIApplicationSupportsIndirectInputEvents UILaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/RswiftUI/RswiftUI/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUI/RswiftUIApp.swift ================================================ // // RswiftUIApp.swift // RswiftUI // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI @main struct RswiftUIApp: App { var body: some Scene { WindowGroup { ContentView() } } } ================================================ FILE: Examples/RswiftUI/RswiftUI.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ E212C64E291BE24B000E4F65 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E212C64D291BE24B000E4F65 /* RswiftLibrary */; }; E212C650291BE252000E4F65 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E212C64F291BE252000E4F65 /* RswiftLibrary */; }; E243EF952510DF9100DC653F /* RswiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243EF942510DF9100DC653F /* RswiftUIApp.swift */; }; E243EF972510DF9100DC653F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243EF962510DF9100DC653F /* ContentView.swift */; }; E243EF992510DF9200DC653F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EF982510DF9200DC653F /* Assets.xcassets */; }; E243EF9C2510DF9200DC653F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EF9B2510DF9200DC653F /* Preview Assets.xcassets */; }; E243EFB02510E08D00DC653F /* RswiftUIAppClipApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243EFAF2510E08D00DC653F /* RswiftUIAppClipApp.swift */; }; E243EFB22510E08D00DC653F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E243EFB12510E08D00DC653F /* ContentView.swift */; }; E243EFB42510E08E00DC653F /* ClipAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EFB32510E08E00DC653F /* ClipAssets.xcassets */; }; E243EFB72510E08E00DC653F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EFB62510E08E00DC653F /* Preview Assets.xcassets */; }; E243EFBC2510E08E00DC653F /* RswiftUIAppClip.app in Embed App Clips */ = {isa = PBXBuildFile; fileRef = E243EFAD2510E08D00DC653F /* RswiftUIAppClip.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; E2CD1B0C2510F900000ACEFB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E243EF982510DF9200DC653F /* Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ E243EFBA2510E08E00DC653F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E243EF892510DF9100DC653F /* Project object */; proxyType = 1; remoteGlobalIDString = E243EFAC2510E08D00DC653F; remoteInfo = RswiftUIAppClip; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ E243EFBD2510E08E00DC653F /* Embed App Clips */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "$(CONTENTS_FOLDER_PATH)/AppClips"; dstSubfolderSpec = 16; files = ( E243EFBC2510E08E00DC653F /* RswiftUIAppClip.app in Embed App Clips */, ); name = "Embed App Clips"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ E212C64C291BE1DB000E4F65 /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; E243EF912510DF9100DC653F /* RswiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RswiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; E243EF942510DF9100DC653F /* RswiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RswiftUIApp.swift; sourceTree = ""; }; E243EF962510DF9100DC653F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; E243EF982510DF9200DC653F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; E243EF9B2510DF9200DC653F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; E243EF9D2510DF9200DC653F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E243EFAD2510E08D00DC653F /* RswiftUIAppClip.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RswiftUIAppClip.app; sourceTree = BUILT_PRODUCTS_DIR; }; E243EFAF2510E08D00DC653F /* RswiftUIAppClipApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RswiftUIAppClipApp.swift; sourceTree = ""; }; E243EFB12510E08D00DC653F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; E243EFB32510E08E00DC653F /* ClipAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ClipAssets.xcassets; sourceTree = ""; }; E243EFB62510E08E00DC653F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; E243EFB82510E08E00DC653F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E243EFB92510E08E00DC653F /* RswiftUIAppClip.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RswiftUIAppClip.entitlements; sourceTree = ""; }; E243EFC22510E0D900DC653F /* Rswift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Rswift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ E243EF8E2510DF9100DC653F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E212C64E291BE24B000E4F65 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E243EFAA2510E08D00DC653F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E212C650291BE252000E4F65 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ E212C64B291BE1DB000E4F65 /* Packages */ = { isa = PBXGroup; children = ( E212C64C291BE1DB000E4F65 /* R.swift */, ); name = Packages; sourceTree = ""; }; E243EF882510DF9100DC653F = { isa = PBXGroup; children = ( E212C64B291BE1DB000E4F65 /* Packages */, E243EF932510DF9100DC653F /* RswiftUI */, E243EFAE2510E08D00DC653F /* RswiftUIAppClip */, E243EF922510DF9100DC653F /* Products */, E243EFC12510E0D900DC653F /* Frameworks */, ); sourceTree = ""; }; E243EF922510DF9100DC653F /* Products */ = { isa = PBXGroup; children = ( E243EF912510DF9100DC653F /* RswiftUI.app */, E243EFAD2510E08D00DC653F /* RswiftUIAppClip.app */, ); name = Products; sourceTree = ""; }; E243EF932510DF9100DC653F /* RswiftUI */ = { isa = PBXGroup; children = ( E243EF942510DF9100DC653F /* RswiftUIApp.swift */, E243EF962510DF9100DC653F /* ContentView.swift */, E243EF982510DF9200DC653F /* Assets.xcassets */, E243EF9D2510DF9200DC653F /* Info.plist */, E243EF9A2510DF9200DC653F /* Preview Content */, ); path = RswiftUI; sourceTree = ""; }; E243EF9A2510DF9200DC653F /* Preview Content */ = { isa = PBXGroup; children = ( E243EF9B2510DF9200DC653F /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; E243EFAE2510E08D00DC653F /* RswiftUIAppClip */ = { isa = PBXGroup; children = ( E243EFAF2510E08D00DC653F /* RswiftUIAppClipApp.swift */, E243EFB12510E08D00DC653F /* ContentView.swift */, E243EFB32510E08E00DC653F /* ClipAssets.xcassets */, E243EFB82510E08E00DC653F /* Info.plist */, E243EFB92510E08E00DC653F /* RswiftUIAppClip.entitlements */, E243EFB52510E08E00DC653F /* Preview Content */, ); path = RswiftUIAppClip; sourceTree = ""; }; E243EFB52510E08E00DC653F /* Preview Content */ = { isa = PBXGroup; children = ( E243EFB62510E08E00DC653F /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; E243EFC12510E0D900DC653F /* Frameworks */ = { isa = PBXGroup; children = ( E243EFC22510E0D900DC653F /* Rswift.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ E243EF902510DF9100DC653F /* RswiftUI */ = { isa = PBXNativeTarget; buildConfigurationList = E243EFA02510DF9200DC653F /* Build configuration list for PBXNativeTarget "RswiftUI" */; buildPhases = ( E243EF8D2510DF9100DC653F /* Sources */, E243EF8E2510DF9100DC653F /* Frameworks */, E243EF8F2510DF9100DC653F /* Resources */, E243EFBD2510E08E00DC653F /* Embed App Clips */, ); buildRules = ( ); dependencies = ( E212C655291BE2D9000E4F65 /* PBXTargetDependency */, E243EFBB2510E08E00DC653F /* PBXTargetDependency */, ); name = RswiftUI; packageProductDependencies = ( E212C64D291BE24B000E4F65 /* RswiftLibrary */, ); productName = RswiftUI; productReference = E243EF912510DF9100DC653F /* RswiftUI.app */; productType = "com.apple.product-type.application"; }; E243EFAC2510E08D00DC653F /* RswiftUIAppClip */ = { isa = PBXNativeTarget; buildConfigurationList = E243EFC02510E08E00DC653F /* Build configuration list for PBXNativeTarget "RswiftUIAppClip" */; buildPhases = ( E243EFA92510E08D00DC653F /* Sources */, E243EFAA2510E08D00DC653F /* Frameworks */, E243EFAB2510E08D00DC653F /* Resources */, ); buildRules = ( ); dependencies = ( E212C652291BE2C0000E4F65 /* PBXTargetDependency */, ); name = RswiftUIAppClip; packageProductDependencies = ( E212C64F291BE252000E4F65 /* RswiftLibrary */, ); productName = RswiftUIAppClip; productReference = E243EFAD2510E08D00DC653F /* RswiftUIAppClip.app */; productType = "com.apple.product-type.application.on-demand-install-capable"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E243EF892510DF9100DC653F /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1200; LastUpgradeCheck = 1500; TargetAttributes = { E243EF902510DF9100DC653F = { CreatedOnToolsVersion = 12.0; }; E243EFAC2510E08D00DC653F = { CreatedOnToolsVersion = 12.0; }; }; }; buildConfigurationList = E243EF8C2510DF9100DC653F /* Build configuration list for PBXProject "RswiftUI" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = E243EF882510DF9100DC653F; productRefGroup = E243EF922510DF9100DC653F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E243EF902510DF9100DC653F /* RswiftUI */, E243EFAC2510E08D00DC653F /* RswiftUIAppClip */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ E243EF8F2510DF9100DC653F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E243EF9C2510DF9200DC653F /* Preview Assets.xcassets in Resources */, E243EF992510DF9200DC653F /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; E243EFAB2510E08D00DC653F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E243EFB72510E08E00DC653F /* Preview Assets.xcassets in Resources */, E2CD1B0C2510F900000ACEFB /* Assets.xcassets in Resources */, E243EFB42510E08E00DC653F /* ClipAssets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ E243EF8D2510DF9100DC653F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E243EF972510DF9100DC653F /* ContentView.swift in Sources */, E243EF952510DF9100DC653F /* RswiftUIApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E243EFA92510E08D00DC653F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E243EFB22510E08D00DC653F /* ContentView.swift in Sources */, E243EFB02510E08D00DC653F /* RswiftUIAppClipApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ E212C652291BE2C0000E4F65 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E212C651291BE2C0000E4F65 /* RswiftGenerateInternalResources */; }; E212C655291BE2D9000E4F65 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E212C654291BE2D9000E4F65 /* RswiftGenerateInternalResources */; }; E243EFBB2510E08E00DC653F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E243EFAC2510E08D00DC653F /* RswiftUIAppClip */; targetProxy = E243EFBA2510E08E00DC653F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ E243EF9E2510DF9200DC653F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; E243EF9F2510DF9200DC653F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; }; E243EFA12510DF9200DC653F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"RswiftUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = RswiftUI/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.RswiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E243EFA22510DF9200DC653F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"RswiftUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = RswiftUI/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.RswiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; E243EFBE2510E08E00DC653F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = RswiftUIAppClip/RswiftUIAppClip.entitlements; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"RswiftUIAppClip/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = RswiftUIAppClip/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.RswiftUI.Clip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E243EFBF2510E08E00DC653F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = RswiftUIAppClip/RswiftUIAppClip.entitlements; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"RswiftUIAppClip/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = RswiftUIAppClip/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.RswiftUI.Clip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E243EF8C2510DF9100DC653F /* Build configuration list for PBXProject "RswiftUI" */ = { isa = XCConfigurationList; buildConfigurations = ( E243EF9E2510DF9200DC653F /* Debug */, E243EF9F2510DF9200DC653F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E243EFA02510DF9200DC653F /* Build configuration list for PBXNativeTarget "RswiftUI" */ = { isa = XCConfigurationList; buildConfigurations = ( E243EFA12510DF9200DC653F /* Debug */, E243EFA22510DF9200DC653F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E243EFC02510E08E00DC653F /* Build configuration list for PBXNativeTarget "RswiftUIAppClip" */ = { isa = XCConfigurationList; buildConfigurations = ( E243EFBE2510E08E00DC653F /* Debug */, E243EFBF2510E08E00DC653F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ E212C64D291BE24B000E4F65 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E212C64F291BE252000E4F65 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E212C651291BE2C0000E4F65 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; E212C654291BE2D9000E4F65 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = E243EF892510DF9100DC653F /* Project object */; } ================================================ FILE: Examples/RswiftUI/RswiftUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/RswiftUI/RswiftUI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/RswiftUI/RswiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "cd466d6e8c5ffd2f2b61165d37b0646f09068e1e", "version" : "2.9.0" } } ], "version" : 2 } ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/ClipAssets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/ClipAssets.xcassets/MyColor.colorset/Contents.json ================================================ { "colors" : [ { "color" : { "platform" : "ios", "reference" : "systemTealColor" }, "idiom" : "universal" }, { "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "color" : { "platform" : "ios", "reference" : "systemOrangeColor" }, "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/ContentView.swift ================================================ // // ContentView.swift // RswiftUIAppClip // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI struct ContentView: View { var body: some View { Text("Hello, App Clip!") .padding() Image(R.image.handIgnoreme) .resizable() .aspectRatio(1, contentMode: .fit) .frame(width: 140) .border(Color(R.color.myColor)) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName RswiftUI CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UIApplicationSupportsIndirectInputEvents UILaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/RswiftUIAppClip.entitlements ================================================ com.apple.developer.parent-application-identifiers $(AppIdentifierPrefix)nl.mathijskadijk.RswiftUI ================================================ FILE: Examples/RswiftUI/RswiftUIAppClip/RswiftUIAppClipApp.swift ================================================ // // RswiftUIAppClipApp.swift // RswiftUIAppClip // // Created by Tom Lokhorst on 2020-09-15. // import SwiftUI @main struct RswiftUIAppClipApp: App { var body: some Scene { WindowGroup { ContentView() } } } ================================================ FILE: Examples/RtvApp/.rswiftignore ================================================ # Filtering single file ResourceApp/Images/Sky.tiff # Corrupt line # Ignore all files containing '.ignoreme.' **/*.ignoreme.* # Explicitly include single file !ResourceApp/ExplicitInclude.ignoreme.png # Explicitly include all files containing '.dont.ignoreme.' !**/*.dont.ignoreme.* ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/AppDelegate.swift ================================================ // // AppDelegate.swift // ResourceApp-tvOS // // Created by Carl Hill-Popper on 3/24/16. // Copyright © 2016 Mathijs Kadijk. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Contents.json ================================================ { "layers" : [ { "filename" : "Front.imagestacklayer" }, { "filename" : "Middle.imagestacklayer" }, { "filename" : "Back.imagestacklayer" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Contents.json ================================================ { "layers" : [ { "filename" : "Front.imagestacklayer" }, { "filename" : "Middle.imagestacklayer" }, { "filename" : "Back.imagestacklayer" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/Contents.json ================================================ { "assets" : [ { "size" : "1280x768", "idiom" : "tv", "filename" : "App Icon - Large.imagestack", "role" : "primary-app-icon" }, { "size" : "400x240", "idiom" : "tv", "filename" : "App Icon - Small.imagestack", "role" : "primary-app-icon" }, { "size" : "2320x720", "idiom" : "tv", "filename" : "Top Shelf Image Wide.imageset", "role" : "top-shelf-image-wide" }, { "size" : "1920x720", "idiom" : "tv", "filename" : "Top Shelf Image.imageset", "role" : "top-shelf-image" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/Top Shelf Image Wide.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Brand Assets.brandassets/Top Shelf Image.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/BrightWhite.colorset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "colors" : [ { "idiom" : "universal", "color" : { "color-space" : "srgb", "components" : { "red" : "1.000", "alpha" : "1.000", "blue" : "1.000", "green" : "1.000" } } } ] } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Back.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "filename" : "allWhiteSmall.png", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Back.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Contents.json ================================================ { "layers" : [ { "filename" : "Front.imagestacklayer" }, { "filename" : "Middle.imagestacklayer" }, { "filename" : "Back.imagestacklayer" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Front.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "filename" : "first.pdf", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Front.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "tv", "filename" : "second.pdf", "scale" : "1x" }, { "idiom" : "tv", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/ImageStackAsset.imagestack/Middle.imagestacklayer/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "landscape", "idiom" : "tv", "extent" : "full-screen", "minimum-system-version" : "11.0", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "tv", "extent" : "full-screen", "minimum-system-version" : "9.0", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Examples/RtvApp/ResourceApp-tvOS/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIcons CFBundleIcons~ipad CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UIMainStoryboardFile Main UIRequiredDeviceCapabilities arm64 ================================================ FILE: Examples/RtvApp/ResourceAppTests-tvOS/ImageTests.swift ================================================ // // ImagesTests.swift // ResourceAppTests-tvOS // // Created by Mathijs Kadijk on 20-07-15. // Copyright (c) 2015 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest @testable import ResourceApp_tvOS class ImagesTests: XCTestCase { func testNonNilImages() throws { XCTAssertNotNil(R.image.imageStackAsset()) } } ================================================ FILE: Examples/RtvApp/ResourceAppTests-tvOS/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Examples/RtvApp/ResourceAppTests-tvOS/ValidationTests.swift ================================================ // // ValidationTests.swift // ResourceAppTests-tvOS // // Created by Mathijs Kadijk on 06/04/2019. // Copyright © 2019 Mathijs Kadijk. All rights reserved. // import UIKit import XCTest @testable import ResourceApp_tvOS class ValidationTests: XCTestCase { func testValidation() throws { try R.validate() } } ================================================ FILE: Examples/RtvApp/RtvApp.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 52; objects = { /* Begin PBXBuildFile section */ D56470312258CA8A005F5E7A /* ValidationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56470302258CA8A005F5E7A /* ValidationTests.swift */; }; DEF5599A1CA4873D009B8C51 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF559991CA4873D009B8C51 /* AppDelegate.swift */; }; DEF5599F1CA4873D009B8C51 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DEF5599D1CA4873D009B8C51 /* Main.storyboard */; }; DEF559A11CA4873D009B8C51 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DEF559A01CA4873D009B8C51 /* Assets.xcassets */; }; E26B761B2451E7D100E1170F /* ImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26B761A2451E7D100E1170F /* ImageTests.swift */; }; E2C415D428F6E5E00028D537 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E2C415D328F6E5E00028D537 /* RswiftLibrary */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ DEF559B01CA48892009B8C51 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D55C6CB01B5D757300301B0D /* Project object */; proxyType = 1; remoteGlobalIDString = DEF559961CA4873D009B8C51; remoteInfo = "ResourceApp-tvOS"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ D56470302258CA8A005F5E7A /* ValidationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidationTests.swift; sourceTree = ""; }; D5B799881C1B8F0C009EA901 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; DEF559971CA4873D009B8C51 /* ResourceApp-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ResourceApp-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; DEF559991CA4873D009B8C51 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DEF5599E1CA4873D009B8C51 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; DEF559A01CA4873D009B8C51 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DEF559A21CA4873D009B8C51 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DEF559AB1CA48892009B8C51 /* ResourceAppTests-tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ResourceAppTests-tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; DEF559AF1CA48892009B8C51 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E26B761A2451E7D100E1170F /* ImageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTests.swift; sourceTree = ""; }; E2C415D228F6E5C60028D537 /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ DEF559941CA4873D009B8C51 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E2C415D428F6E5E00028D537 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DEF559A81CA48892009B8C51 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 065D32753EEB6C7AE2FA201F /* Frameworks */ = { isa = PBXGroup; children = ( D5B799881C1B8F0C009EA901 /* AVKit.framework */, ); name = Frameworks; sourceTree = ""; }; D55C6CAF1B5D757300301B0D = { isa = PBXGroup; children = ( E2C415D128F6E5C60028D537 /* Packages */, DEF559981CA4873D009B8C51 /* ResourceApp-tvOS */, DEF559AC1CA48892009B8C51 /* ResourceAppTests-tvOS */, D55C6CB91B5D757300301B0D /* Products */, 065D32753EEB6C7AE2FA201F /* Frameworks */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; D55C6CB91B5D757300301B0D /* Products */ = { isa = PBXGroup; children = ( DEF559971CA4873D009B8C51 /* ResourceApp-tvOS.app */, DEF559AB1CA48892009B8C51 /* ResourceAppTests-tvOS.xctest */, ); name = Products; sourceTree = ""; }; D5CE930B1CA966C6009D0E62 /* Supporting Files */ = { isa = PBXGroup; children = ( DEF559AF1CA48892009B8C51 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; DEF559981CA4873D009B8C51 /* ResourceApp-tvOS */ = { isa = PBXGroup; children = ( DEF559991CA4873D009B8C51 /* AppDelegate.swift */, DEF5599D1CA4873D009B8C51 /* Main.storyboard */, DEF559A01CA4873D009B8C51 /* Assets.xcassets */, DEF559A21CA4873D009B8C51 /* Info.plist */, ); path = "ResourceApp-tvOS"; sourceTree = ""; }; DEF559AC1CA48892009B8C51 /* ResourceAppTests-tvOS */ = { isa = PBXGroup; children = ( D5CE930B1CA966C6009D0E62 /* Supporting Files */, D56470302258CA8A005F5E7A /* ValidationTests.swift */, E26B761A2451E7D100E1170F /* ImageTests.swift */, ); path = "ResourceAppTests-tvOS"; sourceTree = ""; }; E2C415D128F6E5C60028D537 /* Packages */ = { isa = PBXGroup; children = ( E2C415D228F6E5C60028D537 /* R.swift */, ); name = Packages; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ DEF559961CA4873D009B8C51 /* ResourceApp-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = DEF559A31CA4873D009B8C51 /* Build configuration list for PBXNativeTarget "ResourceApp-tvOS" */; buildPhases = ( DEF559931CA4873D009B8C51 /* Sources */, DEF559941CA4873D009B8C51 /* Frameworks */, DEF559951CA4873D009B8C51 /* Resources */, ); buildRules = ( ); dependencies = ( E2E58383291D6428006E17D9 /* PBXTargetDependency */, ); name = "ResourceApp-tvOS"; packageProductDependencies = ( E2C415D328F6E5E00028D537 /* RswiftLibrary */, ); productName = "ResourceApp-tvOS"; productReference = DEF559971CA4873D009B8C51 /* ResourceApp-tvOS.app */; productType = "com.apple.product-type.application"; }; DEF559AA1CA48892009B8C51 /* ResourceAppTests-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = DEF559B21CA48892009B8C51 /* Build configuration list for PBXNativeTarget "ResourceAppTests-tvOS" */; buildPhases = ( DEF559A71CA48892009B8C51 /* Sources */, DEF559A81CA48892009B8C51 /* Frameworks */, DEF559A91CA48892009B8C51 /* Resources */, ); buildRules = ( ); dependencies = ( DEF559B11CA48892009B8C51 /* PBXTargetDependency */, ); name = "ResourceAppTests-tvOS"; productName = "ResourceAppTests-tvOS"; productReference = DEF559AB1CA48892009B8C51 /* ResourceAppTests-tvOS.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D55C6CB01B5D757300301B0D /* Project object */ = { isa = PBXProject; attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 1000; LastUpgradeCheck = 1410; ORGANIZATIONNAME = "Mathijs Kadijk"; TargetAttributes = { DEF559961CA4873D009B8C51 = { CreatedOnToolsVersion = 7.3; LastSwiftMigration = 1140; }; DEF559AA1CA48892009B8C51 = { CreatedOnToolsVersion = 7.3; LastSwiftMigration = 1140; TestTargetID = DEF559961CA4873D009B8C51; }; }; }; buildConfigurationList = D55C6CB31B5D757300301B0D /* Build configuration list for PBXProject "RtvApp" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, es, ja, nl, ); mainGroup = D55C6CAF1B5D757300301B0D; productRefGroup = D55C6CB91B5D757300301B0D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( DEF559961CA4873D009B8C51 /* ResourceApp-tvOS */, DEF559AA1CA48892009B8C51 /* ResourceAppTests-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ DEF559951CA4873D009B8C51 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( DEF559A11CA4873D009B8C51 /* Assets.xcassets in Resources */, DEF5599F1CA4873D009B8C51 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; DEF559A91CA48892009B8C51 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ DEF559931CA4873D009B8C51 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DEF5599A1CA4873D009B8C51 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DEF559A71CA48892009B8C51 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D56470312258CA8A005F5E7A /* ValidationTests.swift in Sources */, E26B761B2451E7D100E1170F /* ImageTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ DEF559B11CA48892009B8C51 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DEF559961CA4873D009B8C51 /* ResourceApp-tvOS */; targetProxy = DEF559B01CA48892009B8C51 /* PBXContainerItemProxy */; }; E2E58383291D6428006E17D9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E2E58382291D6428006E17D9 /* RswiftGenerateInternalResources */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ DEF5599D1CA4873D009B8C51 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( DEF5599E1CA4873D009B8C51 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ D55C6CD71B5D757300301B0D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = appletvos; SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; D55C6CD81B5D757300301B0D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = appletvos; SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; }; name = Release; }; DEF559A41CA4873D009B8C51 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ANALYZER_NONNULL = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = BQF78J8BF9; INFOPLIST_FILE = "ResourceApp-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.ResourceApp-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; DEF559A51CA4873D009B8C51 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ANALYZER_NONNULL = YES; DEVELOPMENT_TEAM = BQF78J8BF9; INFOPLIST_FILE = "ResourceApp-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.ResourceApp-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Release; }; DEF559B31CA48892009B8C51 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; DEBUG_INFORMATION_FORMAT = dwarf; INFOPLIST_FILE = "ResourceAppTests-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.ResourceAppTests-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ResourceApp-tvOS.app/ResourceApp-tvOS"; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; DEF559B41CA48892009B8C51 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; INFOPLIST_FILE = "ResourceAppTests-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "nl.mathijskadijk.ResourceAppTests-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ResourceApp-tvOS.app/ResourceApp-tvOS"; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ D55C6CB31B5D757300301B0D /* Build configuration list for PBXProject "RtvApp" */ = { isa = XCConfigurationList; buildConfigurations = ( D55C6CD71B5D757300301B0D /* Debug */, D55C6CD81B5D757300301B0D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DEF559A31CA4873D009B8C51 /* Build configuration list for PBXNativeTarget "ResourceApp-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( DEF559A41CA4873D009B8C51 /* Debug */, DEF559A51CA4873D009B8C51 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DEF559B21CA48892009B8C51 /* Build configuration list for PBXNativeTarget "ResourceAppTests-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( DEF559B31CA48892009B8C51 /* Debug */, DEF559B41CA48892009B8C51 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ E2C415D328F6E5E00028D537 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; E2E58382291D6428006E17D9 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D55C6CB01B5D757300301B0D /* Project object */; } ================================================ FILE: Examples/RtvApp/RtvApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/RtvApp/RtvApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/RtvApp/RtvApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "cd466d6e8c5ffd2f2b61165d37b0646f09068e1e", "version" : "2.9.0" } } ], "version" : 2 } ================================================ FILE: Examples/RtvApp/RtvApp.xcodeproj/xcshareddata/xcschemes/ResourceApp-tvOS.xcscheme ================================================ ================================================ FILE: Examples/RtvApp/RtvApp.xcodeproj/xcshareddata/xcschemes/ResourceAppTests-tvOS.xcscheme ================================================ ================================================ FILE: Examples/RwatchApp/.rswiftignore ================================================ # Filtering single file ResourceApp/Images/Sky.tiff # Corrupt line # Ignore all files containing '.ignoreme.' **/*.ignoreme.* # Explicitly include single file !ResourceApp/ExplicitInclude.ignoreme.png # Explicitly include all files containing '.dont.ignoreme.' !**/*.dont.ignoreme.* ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "role" : "notificationCenter", "scale" : "2x", "size" : "24x24", "subtype" : "38mm" }, { "idiom" : "watch", "role" : "notificationCenter", "scale" : "2x", "size" : "27.5x27.5", "subtype" : "42mm" }, { "idiom" : "watch", "role" : "companionSettings", "scale" : "2x", "size" : "29x29" }, { "idiom" : "watch", "role" : "companionSettings", "scale" : "3x", "size" : "29x29" }, { "idiom" : "watch", "role" : "appLauncher", "scale" : "2x", "size" : "40x40", "subtype" : "38mm" }, { "idiom" : "watch", "role" : "appLauncher", "scale" : "2x", "size" : "44x44", "subtype" : "40mm" }, { "idiom" : "watch", "role" : "appLauncher", "scale" : "2x", "size" : "50x50", "subtype" : "44mm" }, { "idiom" : "watch", "role" : "quickLook", "scale" : "2x", "size" : "86x86", "subtype" : "38mm" }, { "idiom" : "watch", "role" : "quickLook", "scale" : "2x", "size" : "98x98", "subtype" : "42mm" }, { "idiom" : "watch", "role" : "quickLook", "scale" : "2x", "size" : "108x108", "subtype" : "44mm" }, { "idiom" : "watch-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS/Base.lproj/Interface.storyboard ================================================ ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName ResourceApp CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown WKCompanionAppBundleIdentifier nl.mathijskadijk.ResourceApp WKWatchKitApp ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : "<=145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Contents.json ================================================ { "assets" : [ { "filename" : "Circular.imageset", "idiom" : "watch", "role" : "circular" }, { "filename" : "Extra Large.imageset", "idiom" : "watch", "role" : "extra-large" }, { "filename" : "Graphic Bezel.imageset", "idiom" : "watch", "role" : "graphic-bezel" }, { "filename" : "Graphic Circular.imageset", "idiom" : "watch", "role" : "graphic-circular" }, { "filename" : "Graphic Corner.imageset", "idiom" : "watch", "role" : "graphic-corner" }, { "filename" : "Graphic Extra Large.imageset", "idiom" : "watch", "role" : "graphic-extra-large" }, { "filename" : "Graphic Large Rectangular.imageset", "idiom" : "watch", "role" : "graphic-large-rectangular" }, { "filename" : "Modular.imageset", "idiom" : "watch", "role" : "modular" }, { "filename" : "Utilitarian.imageset", "idiom" : "watch", "role" : "utilitarian" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : "<=145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : "<=145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : "<=145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "watch", "scale" : "2x", "screen-width" : "<=145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">161" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">145" }, { "idiom" : "watch", "scale" : "2x", "screen-width" : ">183" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/MyColor.colorset/Contents.json ================================================ { "colors" : [ { "color" : { "color-space" : "extended-srgb", "components" : { "alpha" : "1.000", "blue" : "0.188", "green" : "0.187", "red" : "1.000" } }, "idiom" : "universal" }, { "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "color" : { "color-space" : "extended-srgb", "components" : { "alpha" : "1.000", "blue" : "1.000", "green" : "0.838", "red" : "0.392" } }, "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Assets.xcassets/hand.ignoreme.imageset/Contents.json ================================================ { "images" : [ { "filename" : "hand.ignoreme.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/ExtensionDelegate.swift ================================================ // // ExtensionDelegate.swift // ResourceApp-watchOS Extension // // Created by Lammert Westerhoff on 28/08/2018. // Copyright © 2018 Mathijs Kadijk. All rights reserved. // import WatchKit class ExtensionDelegate: NSObject, WKExtensionDelegate { func applicationDidFinishLaunching() { // Perform any final initialization of your application. } func applicationDidBecomeActive() { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillResignActive() { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, etc. } func handle(_ backgroundTasks: Set) { // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one. for task in backgroundTasks { // Use a switch statement to check the task type switch task { case let backgroundTask as WKApplicationRefreshBackgroundTask: // Be sure to complete the background task once you’re done. backgroundTask.setTaskCompletedWithSnapshot(false) case let snapshotTask as WKSnapshotRefreshBackgroundTask: // Snapshot tasks have a unique completion call, make sure to set your expiration date snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil) case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask: // Be sure to complete the connectivity task once you’re done. connectivityTask.setTaskCompletedWithSnapshot(false) case let urlSessionTask as WKURLSessionRefreshBackgroundTask: // Be sure to complete the URL session task once you’re done. urlSessionTask.setTaskCompletedWithSnapshot(false) case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask: // Be sure to complete the relevant-shortcut task once you're done. relevantShortcutTask.setTaskCompletedWithSnapshot(false) case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask: // Be sure to complete the intent-did-run task once you're done. intentDidRunTask.setTaskCompletedWithSnapshot(false) default: // make sure to complete unhandled task types task.setTaskCompletedWithSnapshot(false) } } } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName ResourceApp-watchOS Extension CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType XPC! CFBundleShortVersionString 1.0 CFBundleVersion 1 NSExtension NSExtensionAttributes WKAppBundleIdentifier nl.mathijskadijk.ResourceApp.watchkitapp NSExtensionPointIdentifier com.apple.watchkit WKExtensionDelegateClassName $(PRODUCT_MODULE_NAME).ExtensionDelegate ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/InterfaceController.swift ================================================ // // InterfaceController.swift // ResourceApp-watchOS Extension // // Created by Lammert Westerhoff on 28/08/2018. // Copyright © 2018 Mathijs Kadijk. All rights reserved. // import WatchKit import Foundation import RswiftResources class InterfaceController: WKInterfaceController { @IBOutlet weak var label: WKInterfaceLabel! override func awake(withContext context: Any?) { super.awake(withContext: context) label.setText(R.string.localizable.quote(11)) label.setTextColor(UIColor(named: R.color.myColor.name)) } override func willActivate() { // This method is called when watch view controller is about to be visible to user super.willActivate() } override func didDeactivate() { // This method is called when watch view controller is no longer visible super.didDeactivate() } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/NotificationController.swift ================================================ // // NotificationController.swift // ResourceApp-watchOS Extension // // Created by Lammert Westerhoff on 28/08/2018. // Copyright © 2018 Mathijs Kadijk. All rights reserved. // import WatchKit import Foundation import UserNotifications class NotificationController: WKUserNotificationInterfaceController { override init() { // Initialize variables here. super.init() // Configure interface objects here. } override func willActivate() { // This method is called when watch view controller is about to be visible to user super.willActivate() } override func didDeactivate() { // This method is called when watch view controller is no longer visible super.didDeactivate() } override func didReceive(_ notification: UNNotification) { // This method is called when a notification needs to be presented. // Implement it if you use a dynamic notification interface. // Populate your dynamic notification interface as quickly as possible. } } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/PushNotificationPayload.apns ================================================ { "aps": { "alert": { "body": "Test message", "title": "Optional title", "subtitle": "Optional subtitle" }, "category": "myCategory", "thread-id":"5280" }, "WatchKit Simulator Actions": [ { "title": "First Button", "identifier": "firstButtonAction" } ], "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App." } ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Strings/en.lproj/Localizable.strings ================================================ /* Localizable.strings ResourceApp Created by Lammert Westerhoff on 28/08/2018. Copyright © 2018 Mathijs Kadijk. All rights reserved. */ one = Zero; // Duplicate keys are ignored, a warning from R.swift would be nice one = One; two = 2; "quote" = "There are %d lights!"; ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Strings/es.lproj/Localizable.strings ================================================ /* Localizable.strings ResourceApp Created by Lammert Westerhoff on 28/08/2018. Copyright © 2018 Mathijs Kadijk. All rights reserved. */ one = Uno; two = 2; "quote" = "Hay %d luces!"; ================================================ FILE: Examples/RwatchApp/ResourceApp-watchOS-Extension/Strings/ja.lproj/Localizable.strings ================================================ /* Localizable.strings ResourceApp Created by Lammert Westerhoff on 28/08/2018. Copyright © 2018 Mathijs Kadijk. All rights reserved. */ one = "一つ"; two = 2; "quote" = "%dつの光があります!"; "japanese only" = "Not translated in other languages, and there is no Base"; ================================================ FILE: Examples/RwatchApp/RwatchApp.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 52; objects = { /* Begin PBXBuildFile section */ 2F5FBC192135561200A83A69 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2F5FBC172135561200A83A69 /* Interface.storyboard */; }; 2F5FBC1B2135561300A83A69 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2F5FBC1A2135561300A83A69 /* Assets.xcassets */; }; 2F5FBC222135561300A83A69 /* ResourceApp-watchOS-Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 2F5FBC212135561300A83A69 /* ResourceApp-watchOS-Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 2F5FBC272135561300A83A69 /* InterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5FBC262135561300A83A69 /* InterfaceController.swift */; }; 2F5FBC292135561300A83A69 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5FBC282135561300A83A69 /* ExtensionDelegate.swift */; }; 2F5FBC2B2135561300A83A69 /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5FBC2A2135561300A83A69 /* NotificationController.swift */; }; 2F5FBC2D2135561400A83A69 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2F5FBC2C2135561400A83A69 /* Assets.xcassets */; }; 2F5FBC622135665000A83A69 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2F5FBC642135665000A83A69 /* Localizable.strings */; }; E2C415D828F6F9A90028D537 /* RswiftLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = E2C415D728F6F9A90028D537 /* RswiftLibrary */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 2F5FBC232135561300A83A69 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D55C6CB01B5D757300301B0D /* Project object */; proxyType = 1; remoteGlobalIDString = 2F5FBC202135561300A83A69; remoteInfo = "ResourceApp-watchOS Extension"; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 2F5FBC362135561400A83A69 /* Embed App Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 13; files = ( 2F5FBC222135561300A83A69 /* ResourceApp-watchOS-Extension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 2F5FBC152135561200A83A69 /* ResourceApp-watchOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ResourceApp-watchOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2F5FBC182135561200A83A69 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; 2F5FBC1A2135561300A83A69 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 2F5FBC1C2135561300A83A69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2F5FBC212135561300A83A69 /* ResourceApp-watchOS-Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "ResourceApp-watchOS-Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 2F5FBC262135561300A83A69 /* InterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceController.swift; sourceTree = ""; }; 2F5FBC282135561300A83A69 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = ""; }; 2F5FBC2A2135561300A83A69 /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = ""; }; 2F5FBC2C2135561400A83A69 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 2F5FBC2E2135561400A83A69 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2F5FBC2F2135561400A83A69 /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = ""; }; 2F5FBC632135665000A83A69 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 2F5FBC652135665400A83A69 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 2F5FBC662135665600A83A69 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; D5B799881C1B8F0C009EA901 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; E2C415D628F6F99A0028D537 /* R.swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = R.swift; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0082C73FC737DBCB914FD29C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 2F5FBC1E2135561300A83A69 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E2C415D828F6F9A90028D537 /* RswiftLibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 065D32753EEB6C7AE2FA201F /* Frameworks */ = { isa = PBXGroup; children = ( D5B799881C1B8F0C009EA901 /* AVKit.framework */, ); name = Frameworks; sourceTree = ""; }; 2F5FBC162135561200A83A69 /* ResourceApp-watchOS */ = { isa = PBXGroup; children = ( 2F5FBC172135561200A83A69 /* Interface.storyboard */, 2F5FBC1A2135561300A83A69 /* Assets.xcassets */, 2F5FBC1C2135561300A83A69 /* Info.plist */, ); path = "ResourceApp-watchOS"; sourceTree = ""; }; 2F5FBC252135561300A83A69 /* ResourceApp-watchOS-Extension */ = { isa = PBXGroup; children = ( 2F5FBC262135561300A83A69 /* InterfaceController.swift */, 2F5FBC282135561300A83A69 /* ExtensionDelegate.swift */, 2F5FBC2A2135561300A83A69 /* NotificationController.swift */, 2F5FBC2C2135561400A83A69 /* Assets.xcassets */, 2F5FBC2E2135561400A83A69 /* Info.plist */, 2F5FBC2F2135561400A83A69 /* PushNotificationPayload.apns */, 2F5FBC5F2135660300A83A69 /* Strings */, ); path = "ResourceApp-watchOS-Extension"; sourceTree = ""; }; 2F5FBC5F2135660300A83A69 /* Strings */ = { isa = PBXGroup; children = ( 2F5FBC642135665000A83A69 /* Localizable.strings */, ); path = Strings; sourceTree = ""; }; D55C6CAF1B5D757300301B0D = { isa = PBXGroup; children = ( E2C415D528F6F99A0028D537 /* Packages */, 2F5FBC162135561200A83A69 /* ResourceApp-watchOS */, 2F5FBC252135561300A83A69 /* ResourceApp-watchOS-Extension */, D55C6CB91B5D757300301B0D /* Products */, 065D32753EEB6C7AE2FA201F /* Frameworks */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; D55C6CB91B5D757300301B0D /* Products */ = { isa = PBXGroup; children = ( 2F5FBC152135561200A83A69 /* ResourceApp-watchOS.app */, 2F5FBC212135561300A83A69 /* ResourceApp-watchOS-Extension.appex */, ); name = Products; sourceTree = ""; }; E2C415D528F6F99A0028D537 /* Packages */ = { isa = PBXGroup; children = ( E2C415D628F6F99A0028D537 /* R.swift */, ); name = Packages; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 2F5FBC142135561200A83A69 /* ResourceApp-watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = 2F5FBC372135561400A83A69 /* Build configuration list for PBXNativeTarget "ResourceApp-watchOS" */; buildPhases = ( 2F5FBC132135561200A83A69 /* Resources */, 2F5FBC362135561400A83A69 /* Embed App Extensions */, 0082C73FC737DBCB914FD29C /* Frameworks */, ); buildRules = ( ); dependencies = ( 2F5FBC242135561300A83A69 /* PBXTargetDependency */, ); name = "ResourceApp-watchOS"; productName = "ResourceApp-watchOS"; productReference = 2F5FBC152135561200A83A69 /* ResourceApp-watchOS.app */; productType = "com.apple.product-type.application.watchapp2"; }; 2F5FBC202135561300A83A69 /* ResourceApp-watchOS-Extension */ = { isa = PBXNativeTarget; buildConfigurationList = 2F5FBC332135561400A83A69 /* Build configuration list for PBXNativeTarget "ResourceApp-watchOS-Extension" */; buildPhases = ( 2F5FBC1D2135561300A83A69 /* Sources */, 2F5FBC1E2135561300A83A69 /* Frameworks */, 2F5FBC1F2135561300A83A69 /* Resources */, ); buildRules = ( ); dependencies = ( E212C641291BD9DF000E4F65 /* PBXTargetDependency */, ); name = "ResourceApp-watchOS-Extension"; packageProductDependencies = ( E2C415D728F6F9A90028D537 /* RswiftLibrary */, ); productName = "ResourceApp-watchOS Extension"; productReference = 2F5FBC212135561300A83A69 /* ResourceApp-watchOS-Extension.appex */; productType = "com.apple.product-type.watchkit2-extension"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D55C6CB01B5D757300301B0D /* Project object */ = { isa = PBXProject; attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 1000; LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Mathijs Kadijk"; TargetAttributes = { 2F5FBC142135561200A83A69 = { CreatedOnToolsVersion = 10.0; ProvisioningStyle = Automatic; }; 2F5FBC202135561300A83A69 = { CreatedOnToolsVersion = 10.0; LastSwiftMigration = 1140; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = D55C6CB31B5D757300301B0D /* Build configuration list for PBXProject "RwatchApp" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, es, ja, nl, ); mainGroup = D55C6CAF1B5D757300301B0D; productRefGroup = D55C6CB91B5D757300301B0D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 2F5FBC142135561200A83A69 /* ResourceApp-watchOS */, 2F5FBC202135561300A83A69 /* ResourceApp-watchOS-Extension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 2F5FBC132135561200A83A69 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 2F5FBC1B2135561300A83A69 /* Assets.xcassets in Resources */, 2F5FBC192135561200A83A69 /* Interface.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 2F5FBC1F2135561300A83A69 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 2F5FBC2D2135561400A83A69 /* Assets.xcassets in Resources */, 2F5FBC622135665000A83A69 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 2F5FBC1D2135561300A83A69 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 2F5FBC2B2135561300A83A69 /* NotificationController.swift in Sources */, 2F5FBC292135561300A83A69 /* ExtensionDelegate.swift in Sources */, 2F5FBC272135561300A83A69 /* InterfaceController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 2F5FBC242135561300A83A69 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2F5FBC202135561300A83A69 /* ResourceApp-watchOS-Extension */; targetProxy = 2F5FBC232135561300A83A69 /* PBXContainerItemProxy */; }; E212C641291BD9DF000E4F65 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = E212C640291BD9DF000E4F65 /* RswiftGenerateInternalResources */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 2F5FBC172135561200A83A69 /* Interface.storyboard */ = { isa = PBXVariantGroup; children = ( 2F5FBC182135561200A83A69 /* Base */, ); name = Interface.storyboard; sourceTree = ""; }; 2F5FBC642135665000A83A69 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( 2F5FBC632135665000A83A69 /* en */, 2F5FBC652135665400A83A69 /* es */, 2F5FBC662135665600A83A69 /* ja */, ); name = Localizable.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 2F5FBC342135561400A83A69 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "ResourceApp-watchOS-Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.ResourceApp.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; }; name = Debug; }; 2F5FBC352135561400A83A69 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "ResourceApp-watchOS-Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.ResourceApp.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; }; name = Release; }; 2F5FBC382135561400A83A69 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; IBSC_MODULE = ResourceApp_watchOS_Extension; INFOPLIST_FILE = "ResourceApp-watchOS/Info.plist"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.ResourceApp.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; }; name = Debug; }; 2F5FBC392135561400A83A69 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; IBSC_MODULE = ResourceApp_watchOS_Extension; INFOPLIST_FILE = "ResourceApp-watchOS/Info.plist"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = nl.mathijskadijk.ResourceApp.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; }; name = Release; }; D55C6CD71B5D757300301B0D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "watchsimulator watchos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 5.0; }; name = Debug; }; D55C6CD81B5D757300301B0D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "watchsimulator watchos"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; WATCHOS_DEPLOYMENT_TARGET = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2F5FBC332135561400A83A69 /* Build configuration list for PBXNativeTarget "ResourceApp-watchOS-Extension" */ = { isa = XCConfigurationList; buildConfigurations = ( 2F5FBC342135561400A83A69 /* Debug */, 2F5FBC352135561400A83A69 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 2F5FBC372135561400A83A69 /* Build configuration list for PBXNativeTarget "ResourceApp-watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 2F5FBC382135561400A83A69 /* Debug */, 2F5FBC392135561400A83A69 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D55C6CB31B5D757300301B0D /* Build configuration list for PBXProject "RwatchApp" */ = { isa = XCConfigurationList; buildConfigurations = ( D55C6CD71B5D757300301B0D /* Debug */, D55C6CD81B5D757300301B0D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ E212C640291BD9DF000E4F65 /* RswiftGenerateInternalResources */ = { isa = XCSwiftPackageProductDependency; productName = "plugin:RswiftGenerateInternalResources"; }; E2C415D728F6F9A90028D537 /* RswiftLibrary */ = { isa = XCSwiftPackageProductDependency; productName = RswiftLibrary; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D55C6CB01B5D757300301B0D /* Project object */; } ================================================ FILE: Examples/RwatchApp/RwatchApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/RwatchApp/RwatchApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/RwatchApp/RwatchApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", "version" : "1.2.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "cd466d6e8c5ffd2f2b61165d37b0646f09068e1e", "version" : "2.9.0" } } ], "version" : 2 } ================================================ FILE: Examples/RwatchApp/RwatchApp.xcodeproj/xcshareddata/xcschemes/ResourceApp-watchOS (Notification).xcscheme ================================================ ================================================ FILE: Examples/RwatchApp/RwatchApp.xcodeproj/xcshareddata/xcschemes/ResourceApp-watchOS.xcscheme ================================================ ================================================ FILE: License ================================================ The MIT License (MIT) Copyright (c) 2014-2023 Mathijs Kadijk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Package.resolved ================================================ { "pins" : [ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "41982a3656a71c768319979febd796c6fd111d5c", "version" : "1.5.0" } }, { "identity" : "xcodeedit", "kind" : "remoteSourceControl", "location" : "https://github.com/tomlokhorst/XcodeEdit", "state" : { "revision" : "0e550cdee72844b35431afc3a1e176042be6d0f0", "version" : "2.13.0" } } ], "version" : 2 } ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.6 import PackageDescription let package = Package( name: "Rswift", platforms: [ .macOS(.v10_15), .iOS(.v11), .tvOS(.v11), .watchOS(.v4), ], products: [ .executable(name: "rswift", targets: ["rswift"]), .library(name: "RswiftLibrary", targets: ["RswiftResources"]), .plugin(name: "RswiftGenerateInternalResources", targets: ["RswiftGenerateInternalResources"]), .plugin(name: "RswiftGeneratePublicResources", targets: ["RswiftGeneratePublicResources"]), .plugin(name: "RswiftGenerateResourcesCommand", targets: ["RswiftGenerateResourcesCommand"]), .plugin(name: "RswiftModifyXcodePackages", targets: ["RswiftModifyXcodePackages"]), ], dependencies: [ .package(url: "https://github.com/tomlokhorst/XcodeEdit", from: "2.13.0"), .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), ], targets: [ .target(name: "RswiftResources"), .target(name: "RswiftGenerators", dependencies: ["RswiftResources"]), .target(name: "RswiftParsers", dependencies: ["RswiftResources", "XcodeEdit"]), .testTarget(name: "RswiftGeneratorsTests", dependencies: ["RswiftGenerators"]), .testTarget(name: "RswiftParsersTests", dependencies: ["RswiftParsers"]), // Executable that brings all previous parts together .executableTarget(name: "rswift", dependencies: [ .target(name: "RswiftParsers"), .target(name: "RswiftGenerators"), .product(name: "ArgumentParser", package: "swift-argument-parser"), ]), .plugin(name: "RswiftGenerateInternalResources", capability: .buildTool(), dependencies: ["rswift"]), .plugin(name: "RswiftGeneratePublicResources", capability: .buildTool(), dependencies: ["rswift"]), .plugin( name: "RswiftGenerateResourcesCommand", capability: .command( intent: .custom( verb: "rswift-generate-resources", description: "Rswift generate resources" ), permissions: [ .writeToPackageDirectory(reason: "Rswift generates a file with statically typed, autocompleted resources") ] ), dependencies: ["rswift"] ), .plugin( name: "RswiftModifyXcodePackages", capability: .command( intent: .custom( verb: "rswift-modify-xcode-packages", description: "Rswift modify Xcode packages" ), permissions: [ .writeToPackageDirectory(reason: "Modifies Xcode project to fix package reference for plugins") ] ), dependencies: ["rswift"] ), ] ) ================================================ FILE: Plugins/RswiftGenerateInternalResources/RswiftGenerateInternalResources.swift ================================================ // // RswiftGenerateInternalResources.swift // // // Created by Tom Lokhorst on 2022-10-19. // import Foundation import PackagePlugin @main struct RswiftGenerateInternalResources: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { guard let target = target as? SourceModuleTarget else { return [] } let outputDirectoryPath = context.pluginWorkDirectory .appending(subpath: target.name) try FileManager.default.createDirectory(atPath: outputDirectoryPath.string, withIntermediateDirectories: true) let rswiftPath = outputDirectoryPath.appending(subpath: "R.generated.swift") let sourceFiles = target.sourceFiles .filter { $0.type == .resource || $0.type == .unknown } .map(\.path.string) let inputFilesArguments = sourceFiles .flatMap { ["--input-files", $0 ] } let bundleSource = target.kind == .generic ? "module" : "finder" let description = "\(target.kind) module \(target.name)" return [ .buildCommand( displayName: "R.swift generate resources for \(description)", executable: try context.tool(named: "rswift").path, arguments: [ "generate", rswiftPath.string, "--input-type", "input-files", "--bundle-source", bundleSource, ] + inputFilesArguments, outputFiles: [rswiftPath] ), ] } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension RswiftGenerateInternalResources: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let resourcesDirectoryPath = context.pluginWorkDirectory .appending(subpath: target.displayName) .appending(subpath: "Resources") try FileManager.default.createDirectory(atPath: resourcesDirectoryPath.string, withIntermediateDirectories: true) let rswiftPath = resourcesDirectoryPath.appending(subpath: "R.generated.swift") let description: String if let product = target.product { description = "\(product.kind) \(target.displayName)" } else { description = target.displayName } return [ .buildCommand( displayName: "R.swift generate resources for \(description)", executable: try context.tool(named: "rswift").path, arguments: [ "generate", rswiftPath.string, "--target", target.displayName, "--input-type", "xcodeproj", "--bundle-source", "finder", ], outputFiles: [rswiftPath] ), ] } } #endif ================================================ FILE: Plugins/RswiftGeneratePublicResources/RswiftGeneratePublicResources.swift ================================================ // // RswiftGeneratePublicResources.swift // // // Created by Tom Lokhorst on 2022-10-19. // import Foundation import PackagePlugin @main struct RswiftGeneratePublicResources: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { guard let target = target as? SourceModuleTarget else { return [] } let outputDirectoryPath = context.pluginWorkDirectory .appending(subpath: target.name) try FileManager.default.createDirectory(atPath: outputDirectoryPath.string, withIntermediateDirectories: true) let rswiftPath = outputDirectoryPath.appending(subpath: "R.generated.swift") let sourceFiles = target.sourceFiles .filter { $0.type == .resource || $0.type == .unknown } .map(\.path.string) let inputFilesArguments = sourceFiles .flatMap { ["--input-files", $0 ] } let bundleSource = target.kind == .generic ? "module" : "finder" let description = "\(target.kind) module \(target.name)" return [ .buildCommand( displayName: "R.swift generate resources for \(description)", executable: try context.tool(named: "rswift").path, arguments: [ "generate", rswiftPath.string, "--input-type", "input-files", "--bundle-source", bundleSource, "--access-level", "public", ] + inputFilesArguments, outputFiles: [rswiftPath] ), ] } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension RswiftGeneratePublicResources: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let resourcesDirectoryPath = context.pluginWorkDirectory .appending(subpath: target.displayName) .appending(subpath: "Resources") try FileManager.default.createDirectory(atPath: resourcesDirectoryPath.string, withIntermediateDirectories: true) let rswiftPath = resourcesDirectoryPath.appending(subpath: "R.generated.swift") let description: String if let product = target.product { description = "\(product.kind) \(target.displayName)" } else { description = target.displayName } return [ .buildCommand( displayName: "R.swift generate resources for \(description)", executable: try context.tool(named: "rswift").path, arguments: [ "generate", rswiftPath.string, "--target", target.displayName, "--input-type", "xcodeproj", "--bundle-source", "finder", "--access-level", "public", ], outputFiles: [rswiftPath] ), ] } } #endif ================================================ FILE: Plugins/RswiftGenerateResourcesCommand/RswiftGenerateResourcesCommand.swift ================================================ // // RswiftGenerateResourcesCommand.swift // R.swift // // Created by Tom Lokhorst on 2022-10-19. // import Foundation import PackagePlugin @main struct RswiftGenerateResourcesCommand: CommandPlugin { func performCommand(context: PluginContext, arguments externalArgs: [String]) async throws { let rswift = try context.tool(named: "rswift") let parsedArguments = ParsedArguments.parse(arguments: externalArgs) let outputSubpath = parsedArguments.outputFile ?? "R.generated.swift" for target in context.package.targets { guard let target = target as? SourceModuleTarget else { continue } guard parsedArguments.targets.contains(target.name) || parsedArguments.targets.isEmpty else { continue } let outputPath = target.directory.appending(subpath: outputSubpath) let sourceFiles = target.sourceFiles .filter { $0.type == .resource || $0.type == .unknown } .map(\.path.string) let inputFilesArguments = sourceFiles .flatMap { ["--input-files", $0 ] } let bundleSource = target.kind == .generic ? "module" : "finder" let arguments: [String] = [ "generate", outputPath.string, "--input-type", "input-files", "--bundle-source", bundleSource, ] + inputFilesArguments + parsedArguments.remaining do { try rswift.run(arguments: arguments, environment: nil) } catch let error as RunError { Diagnostics.error(error.description) } } } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension RswiftGenerateResourcesCommand: XcodeCommandPlugin { func performCommand(context: XcodePluginContext, arguments externalArgs: [String]) throws { let rswift = try context.tool(named: "rswift") let parsedArguments = ParsedArguments.parse(arguments: externalArgs) let outputSubpath = parsedArguments.outputFile ?? "R.generated.swift" for target in context.xcodeProject.targets { guard parsedArguments.targets.contains(target.displayName) || parsedArguments.targets.isEmpty else { continue } let outputPath = context.xcodeProject.directory.appending(subpath: outputSubpath) let sourceFiles = target.inputFiles .filter { $0.type == .resource || $0.type == .unknown } .map(\.path.string) let inputFilesArguments = sourceFiles .flatMap { ["--input-files", $0 ] } let arguments: [String] = [ "generate", outputPath.string, "--input-type", "input-files", "--bundle-source", "finder", ] + inputFilesArguments + parsedArguments.remaining var environment: [String: String] = [ "SOURCE_ROOT": context.xcodeProject.directory.string, ] if let product = target.product { environment["PRODUCT_MODULE_NAME"] = product.name } do { try rswift.run(arguments: arguments, environment: environment) } catch let error as RunError { Diagnostics.error(error.description) } } } } #endif struct ParsedArguments { var targets: [String] = [] var remaining: [String] = [] var outputFile: String? static func parse(arguments: [String]) -> ParsedArguments { var result = ParsedArguments() for (key, value) in zip(arguments, arguments.dropFirst()) { if result.outputFile == nil && key.hasSuffix(".swift") { result.outputFile = key continue } if result.outputFile == nil && value.hasSuffix(".swift") { result.outputFile = value continue } if key == "--target" { result.targets.append(value) } else if value != "--target" { result.remaining.append(value) } } return result } } struct RunError: Error { let description: String } private extension PluginContext.Tool { func run(arguments: [String], environment: [String: String]?) throws { let pipe = Pipe() let process = Process() process.executableURL = URL(fileURLWithPath: path.string) process.arguments = arguments process.environment = environment process.standardError = pipe try process.run() process.waitUntilExit() if process.terminationReason == .exit && process.terminationStatus == 0 { return } let data = try pipe.fileHandleForReading.readToEnd() let stderr = data.flatMap { String(data: $0, encoding: .utf8) } if let stderr { throw RunError(description: stderr) } else { let problem = "\(process.terminationReason.rawValue):\(process.terminationStatus)" throw RunError(description: "\(name) invocation failed: \(problem)") } } } ================================================ FILE: Plugins/RswiftModifyXcodePackages/RswiftModifyXcodePackages.swift ================================================ // // RswiftModifyXcodePackages.swift // R.swift // // Created by Tom Lokhorst on 2022-11-07. // import Foundation import PackagePlugin @main struct RswiftModifyXcodePackages: CommandPlugin { func performCommand(context: PluginContext, arguments externalArgs: [String]) async throws { Diagnostics.warning("Command only supported as Xcode command plugin") } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension RswiftModifyXcodePackages: XcodeCommandPlugin { func performCommand(context: XcodePluginContext, arguments externalArgs: [String]) throws { let rswift = try context.tool(named: "rswift") let projectArgument = externalArgs.first { $0.hasSuffix(".xcodeproj") } if let projectArgument { let arguments = ["modify-xcode-packages", "--xcodeproj", projectArgument] + externalArgs.filter { $0 != projectArgument } try rswift.run(arguments: arguments, environment: nil) return } let xcodeProjects = try FileManager.default.contentsOfDirectory(atPath: context.xcodeProject.directory.string) .filter { $0.hasSuffix(".xcodeproj") } guard let xcodeproj = xcodeProjects.first else { Diagnostics.error("Can't find .xcodeproj in \(context.xcodeProject.directory.string). Manually specify .xcodeproj file to this command.") return } if xcodeProjects.count > 1 { Diagnostics.error("Found multiple .xcodeproj files in \(context.xcodeProject.directory.string). Manually specify .xcodeproj file to this command.") return } let arguments = ["modify-xcode-packages", "--xcodeproj", xcodeproj] + externalArgs try rswift.run(arguments: arguments, environment: nil) } } #endif private extension PluginContext.Tool { func run(arguments: [String], environment: [String: String]?) throws { let pipe = Pipe() let process = Process() process.executableURL = URL(fileURLWithPath: path.string) process.arguments = arguments process.environment = environment process.standardError = pipe try process.run() process.waitUntilExit() if process.terminationReason == .exit && process.terminationStatus == 0 { return } let data = try pipe.fileHandleForReading.readToEnd() let stderr = data.flatMap { String(data: $0, encoding: .utf8) } if let stderr { Diagnostics.error(stderr) } else { let problem = "\(process.terminationReason.rawValue):\(process.terminationStatus)" Diagnostics.error(problem) } } } ================================================ FILE: R.swift.podspec ================================================ Pod::Spec.new do |spec| spec.name = "R.swift" spec.version = ENV['POD_VERSION'] spec.license = "MIT" spec.summary = "Get strong typed, autocompleted resources like images, fonts and segues in Swift projects" spec.description = <<-DESC R.swift is a tool to get strong typed, autocompleted resources like images, fonts and segues in Swift projects. * Never type string identifiers again * Supports images, fonts, storyboards, nibs, segues, reuse identifiers and more * Compile time checks and errors instead of runtime crashes DESC spec.homepage = "https://github.com/mac-cain13/R.swift" spec.documentation_url = "https://github.com/mac-cain13/R.swift/tree/master/Documentation" spec.screenshots = [ "https://raw.githubusercontent.com/mac-cain13/R.swift/master/Documentation/Images/DemoUseImage.gif", "https://raw.githubusercontent.com/mac-cain13/R.swift/master/Documentation/Images/DemoRenameImage.gif" ] spec.author = { "Mathijs Kadijk" => "mkadijk@gmail.com" } spec.social_media_url = "https://twitter.com/mac_cain13" spec.requires_arc = true spec.source = { :http => "https://github.com/mac-cain13/R.swift/releases/download/#{spec.version}/rswift-#{spec.version}.zip" } spec.swift_version = "5.7" spec.osx.deployment_target = '10.15' spec.ios.deployment_target = '12' spec.tvos.deployment_target = '12' spec.watchos.deployment_target = '4' spec.preserve_paths = "rswift" spec.source_files = "Sources/RswiftResources/**/*.swift" spec.module_name = "RswiftResources" end ================================================ FILE: README.md ================================================ # R.swift [![Version](https://img.shields.io/cocoapods/v/R.swift.svg?style=flat)](https://cocoapods.org/pods/R.swift) [![License](https://img.shields.io/cocoapods/l/R.swift.svg?style=flat)](License) ![Platform](https://img.shields.io/cocoapods/p/R.swift.svg?style=flat) _Get strong typed, autocompleted resources like images, fonts and segues in Swift projects_ ## Why use this? It makes your code that uses resources: - **Fully typed**, less casting and guessing what a method will return - **Compile time checked**, no more incorrect strings that make your app crash at runtime - **Autocompleted**, never have to guess that image name again Currently you type: ```swift let icon = UIImage(named: "settings-icon") let font = UIFont(name: "San Francisco", size: 42) let color = UIColor(named: "indicator highlight") let viewController = CustomViewController(nibName: "CustomView", bundle: nil) let string = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Arthur Dent") ``` With R.swift it becomes: ```swift let icon = R.image.settingsIcon() let font = R.font.sanFrancisco(size: 42) let color = R.color.indicatorHighlight() let viewController = CustomViewController(nib: R.nib.customView) let string = R.string.localizable.welcomeWithName("Arthur Dent") ``` Check out [more examples](Documentation/Examples.md) or hear about [how Fabric.app uses R.swift](https://academy.realm.io/posts/slug-javi-soto-building-fabric-in-swift/#rswift-2956)! ## Demo **Autocompleted images:** ![Autocompleted images](Documentation/Images/DemoUseImage.gif) **Compiletime checked images:** ![Compiletime checked images](Documentation/Images/DemoRenameImage.gif) This is only the beginning, check out [more examples](Documentation/Examples.md)! ## CocoaHeadsNL presentation Mathijs Kadijk presented R.swift at the September 2016 CocoaHeadsNL meetup. Talking about the ideas behind R.swift and demonstrating how to move from plain stringly-typed iOS code to statically typed code. R.swift presentation at CocoaHeadsNL ## Features After installing R.swift into your project you can use the `R`-struct to access resources. If the struct is outdated just build and R.swift will correct any missing/changed/added resources. R.swift currently supports these types of resources: - [Images](Documentation/Examples.md#images) - [Fonts](Documentation/Examples.md#custom-fonts) - [Resource files](Documentation/Examples.md#resource-files) - [Colors](Documentation/Examples.md#colors) - [Localized strings](Documentation/Examples.md#localized-strings) - [Storyboards](Documentation/Examples.md#storyboards) - [Segues](Documentation/Examples.md#segues) - [Nibs](Documentation/Examples.md#nibs) - [Reusable cells](Documentation/Examples.md#reusable-table-view-cells) - [Project](Documentation/Examples.md#project) - [Entitlements](Documentation/Examples.md#entitlements) - [Info.plist](Documentation/Examples.md#info-plist) Runtime validation with [`R.validate()`](Documentation/Examples.md#runtime-validation): - If all images used in storyboards and nibs are available - If all named colors used in storyboards and nibs are available - If all view controllers with storyboard identifiers can be loaded - If all custom fonts can be loaded ## Q&A - [Why was R.swift created?](Documentation/QandA.md#why-was-rswift-created) - [Why should I choose R.swift over alternative X or Y?](Documentation/QandA.md#why-should-i-choose-rswift-over-alternative-x-or-y) - [What are the requirements to run R.swift?](Documentation/QandA.md#what-are-the-requirements-to-run-rswift) - [How to fix missing imports in the generated file?](Documentation/QandA.md#how-to-fix-missing-imports-in-the-generated-file) - [How to use classes with the same name as their module?](Documentation/QandA.md#how-to-use-classes-with-the-same-name-as-their-module) - [Can I ignore resources?](Documentation/Ignoring.md) - [Can I use R.swift in a library?](Documentation/QandA.md#can-i-use-rswift-in-a-library) - [How does R.swift work?](Documentation/QandA.md#how-does-rswift-work) - [How to upgrade to a new major version?](Documentation/Migration.md) - [How can I only run specific generators?](Documentation/Ignoring.md#only-run-specific-generators-exclude-rsomething) ## Installation As of Rswift 7, Swift Package Manager is the recommended method of installation. [Demo video: Updating from R.swift 6 to Rswift 7](https://youtu.be/icihJ_hin3I?t=66) (Starting at 1:06, this describes the installation of Rswift 7). ### Xcode project using SPM (Recommended) [Demo Video: Install R.swift in Xcode with SPM](Documentation/RswiftSPMInstallation.mp4) 1. In Project Settings, on the tab "Package Dependencies", click "+", search for `https://github.com/mac-cain13/R.swift` and click "Add Package". 2. Select the target that will use R.swift next to "RswiftLibrary" and click "Add Package". 4. Now click on your target, on the tab "Build Phases", in the section "Run Build Tool Plug-ins", click "+" and add `RswiftGenerateInternalResources`. ([Screenshot](Documentation/Images/RunBuildToolPluginsRswift.png)) 5. Now the `R` struct should be available in your code, use auto-complete to explore all static references. Note: The first build you might need to approve the new plugin by clicking the build error warning you about the new plugin. #### R.swift on Xcode Cloud or any other CI On your CI server you can't explicitly allow the build plugin to run, so you need to disable plugin validation to be able to build without user interaction: 5. Run a script on your CI that runs: `defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES` before Xcode starts building. On Xcode Cloud you can add a [custom build script](https://developer.apple.com/documentation/xcode/writing-custom-build-scripts) in `ci_scripts/ci_post_clone.sh` with this line that Xcode will run. ### Package.swift based SPM project 1. Add a dependency in Package.swift: ```swift dependencies: [ .package(url: "https://github.com/mac-cain13/R.swift.git", from: "7.0.0") ] ``` 2. For each relevant target, add a dependency and a plugin ```swift .target( name: "Example", dependencies: [.product(name: "RswiftLibrary", package: "R.swift")], plugins: [.plugin(name: "RswiftGeneratePublicResources", package: "R.swift")] ) ``` 3. Build your project, now the `R` struct should be available in your code, use auto-complete to explore all static references

CocoaPods

1. Add `pod 'R.swift'` to your [Podfile](http://cocoapods.org/#get_started) and run `pod install` 2. In Xcode: Click on your project in the file list, choose your target under `TARGETS`, click the `Build Phases` tab and add a `New Run Script Phase` by clicking the little plus icon in the top left 3. Drag the new `Run Script` phase **above** the `Compile Sources` phase and **below** `Check Pods Manifest.lock`, expand it and paste the following script: ```bash "$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/R.generated.swift" ``` 4. Add `$SRCROOT/R.generated.swift` to the "Output Files" of the Build Phase 5. Uncheck "Based on dependency analysis" so that R.swift is run on each build 6. Build your project, in Finder you will now see a `R.generated.swift` in the `$SRCROOT`-folder, drag the `R.generated.swift` files into your project and **uncheck** `Copy items if needed` _Screenshot of the Build Phase can be found [here](Documentation/Images/BuildPhaseExample.png)_ _Tip:_ Add the `*.generated.swift` pattern to your `.gitignore` file to prevent unnecessary conflicts.

Manually

0. Add the [R.swift](https://github.com/mac-cain13/R.swift) library to your project 1. [Download](https://github.com/mac-cain13/R.swift/releases) a R.swift release, unzip it and put it into your source root directory 2. In Xcode: Click on your project in the file list, choose your target under `TARGETS`, click the `Build Phases` tab and add a `New Run Script Phase` by clicking the little plus icon in the top left 3. Drag the new `Run Script` phase **above** the `Compile Sources` phase, expand it and paste the following script: ```bash "$SRCROOT/rswift" generate "$SRCROOT/R.generated.swift" ``` 4. Add `$SRCROOT/R.generated.swift` to the "Output Files" of the Build Phase 5. Uncheck "Based on dependency analysis" so that R.swift is run on each build 6. Build your project, in Finder you will now see a `R.generated.swift` in the `$SRCROOT`-folder, drag the `R.generated.swift` files into your project and **uncheck** `Copy items if needed` _Screenshot of the Build Phase can be found [here](Documentation/Images/ManualBuildPhaseExample.png)_ _Tip:_ Add the `*.generated.swift` pattern to your `.gitignore` file to prevent unnecessary conflicts.
## Contribute We'll love contributions, read the [contribute docs](Documentation/Contribute.md) for info on how to report issues, submit ideas and submit pull requests! ## License [R.swift](https://github.com/mac-cain13/R.swift) is created by [Mathijs Kadijk](https://github.com/mac-cain13) and [Tom Lokhorst](https://github.com/tomlokhorst) released under a [MIT License](License). ================================================ FILE: Sources/RswiftGenerators/AccessibilityIdentifier+Generator.swift ================================================ // // AccessibilityIdentifier+Generator.swift // // // Created by Tom Lokhorst on 2022-07-23. // import Foundation import RswiftResources private protocol AccessibilityIdentifierContainer { var name: String { get } var usedAccessibilityIdentifiers: [String] { get } } extension NibResource: AccessibilityIdentifierContainer {} extension StoryboardResource: AccessibilityIdentifierContainer {} public struct AccessibilityIdentifier { public static func generateStruct(nibs: [NibResource], storyboards: [StoryboardResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "id") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let containers: [AccessibilityIdentifierContainer] = nibs + storyboards let mergedContainers = Dictionary(grouping: containers, by: \.name) .mapValues { $0.flatMap(\.usedAccessibilityIdentifiers) } .filter { $0.value.count > 0 } let structs = mergedContainers .map { (name, ids) in generateStruct( viewControllerName: name, usedAccessibilityIdentifiers: ids, prefix: qualifiedName, warning: warning ) } .sorted { $0.name < $1.name } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(structs.count) accessibility identifiers."] return Struct(comments: comments, name: structName) { for s in structs { s.generateLetBinding() s } } } static func generateStruct(viewControllerName: String, usedAccessibilityIdentifiers: [String], prefix: SwiftIdentifier, warning: (String) -> Void) -> Struct { let structName = SwiftIdentifier(name: viewControllerName) let qualifiedName = prefix + structName // Deduplicate identifiers, report warnings for empties let groupedIdentifiers = Array(Set(usedAccessibilityIdentifiers)) .grouped(bySwiftIdentifier: { $0 }) groupedIdentifiers.reportWarningsForDuplicatesAndEmpties(source: "accessibility identifier", container: "in \(viewControllerName)", result: "accessibility identifier", warning: warning) let letbindings = groupedIdentifiers.uniques .map { id in LetBinding( comments: ["Accessibility identifier `\(id)`."], name: SwiftIdentifier(name: id), valueCodeString: "\"\(id)\"" ) } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(letbindings.count) accessibility identifiers."] return Struct(comments: comments, name: structName) { letbindings } } } ================================================ FILE: Sources/RswiftGenerators/AssetCatalog+Generator.swift ================================================ // // AssetCatalog+Generator.swift // // // Created by Tom Lokhorst on 2022-07-23. // import Foundation import RswiftResources public protocol AssetCatalogContent { var name: String { get } func generateVarGetter() -> VarGetter } extension ColorResource { public static func generateStruct(catalogs: [AssetCatalog], prefix: SwiftIdentifier) -> Struct { let merged: AssetCatalog.Namespace = catalogs.map(\.root).reduce(.init(), { $0.merging($1) }) return merged.generateStruct(name: "color", resourcesSelector: { $0.colors }, prefix: prefix) } } extension DataResource { public static func generateStruct(catalogs: [AssetCatalog], prefix: SwiftIdentifier) -> Struct { let merged: AssetCatalog.Namespace = catalogs.map(\.root).reduce(.init(), { $0.merging($1) }) return merged.generateStruct(name: "data", resourcesSelector: { $0.dataAssets }, prefix: prefix) } } extension ImageResource { public static func generateStruct(catalogs: [AssetCatalog], toplevel resources: [ImageResource], prefix: SwiftIdentifier) -> Struct { // Multiple resources can share same name, // for example: Colors.jpg and Colors@2x.jpg are both named "Colors.jpg" // Deduplicate these let namedResources = Dictionary(grouping: resources, by: \.name).values.map(\.first!) var merged: AssetCatalog.Namespace = catalogs.map(\.root).reduce(.init(), { $0.merging($1) }) merged.images += namedResources return merged.generateStruct(name: "image", resourcesSelector: { $0.images }, prefix: prefix) } } extension AssetCatalog.Namespace { public func generateStruct(name: String, resourcesSelector: (Self) -> [AssetCatalogContent], prefix: SwiftIdentifier) -> Struct { generateStruct(resourceName: name, source: name, path: [], resourcesSelector: resourcesSelector, prefix: prefix) } private func generateStruct(resourceName: String, source: String, path: [String], resourcesSelector: (Self) -> [AssetCatalogContent], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: resourceName) let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let container = path.isEmpty ? nil : path.joined(separator: "/") let allResources = resourcesSelector(self) let groupedResources = allResources.grouped(bySwiftIdentifier: { $0.name }) groupedResources.reportWarningsForDuplicatesAndEmpties(source: source, container: container, result: source, warning: warning) let vargetters = groupedResources.uniques.map { $0.generateVarGetter() } let otherIdentifiers = groupedResources.uniques.map { SwiftIdentifier(name: $0.name) } let mergedNamespaces = AssetCatalogMergedNamespaces(all: subnamespaces, otherIdentifiers: otherIdentifiers) mergedNamespaces.printWarningsForDuplicates(result: resourceName, warning: warning) let structs = mergedNamespaces.namespaces .sorted { $0.key < $1.key } .map { (name, namespace) in namespace.generateStruct( resourceName: name.value, source: source, path: path + [name.value], resourcesSelector: resourcesSelector, prefix: qualifiedName ) } .filter { !$0.isEmpty } let comment = [ "This `\(qualifiedName.value)` struct is generated, and contains static references to \(vargetters.count) \(resourceName)s", structs.isEmpty ? "" : ", and \(structs.count) namespaces", "." ].joined() let comments = [comment] return Struct(comments: comments, name: structName) { Init.bundle vargetters structs for s in structs { s.generateBundleVarGetter(name: s.name.value) s.generateBundleFunction(name: s.name.value) } } } } extension ColorResource: AssetCatalogContent { public func generateVarGetter() -> VarGetter { let fullname = (path + [name]).joined(separator: "/") let code = ".init(name: \"\(fullname.escapedStringLiteral)\", path: \(path), bundle: bundle)" return VarGetter( comments: ["Color `\(fullname)`."], name: SwiftIdentifier(name: name), typeReference: TypeReference(module: .rswiftResources, rawName: "ColorResource"), valueCodeString: code ) } } extension DataResource: AssetCatalogContent { public func generateVarGetter() -> VarGetter { let fullname = (path + [name]).joined(separator: "/") let odrt = onDemandResourceTags?.debugDescription ?? "nil" let code = ".init(name: \"\(fullname.escapedStringLiteral)\", path: \(path), bundle: bundle, onDemandResourceTags: \(odrt))" return VarGetter( comments: ["Data asset `\(fullname)`."], name: SwiftIdentifier(name: name), typeReference: TypeReference(module: .rswiftResources, rawName: "DataResource"), valueCodeString: code ) } } extension ImageResource: AssetCatalogContent { public func generateVarGetter() -> VarGetter { let locs = locale.map { $0.codeString() } ?? "nil" let odrt = onDemandResourceTags?.debugDescription ?? "nil" let fullname = (path + [name]).joined(separator: "/") let code = ".init(name: \"\(fullname.escapedStringLiteral)\", path: \(path), bundle: bundle, locale: \(locs), onDemandResourceTags: \(odrt))" return VarGetter( comments: ["Image `\(fullname)`."], name: SwiftIdentifier(name: name), typeReference: TypeReference(module: .rswiftResources, rawName: "ImageResource"), valueCodeString: code ) } } ================================================ FILE: Sources/RswiftGenerators/Extensions/Array+Extensions.swift ================================================ // // Array+Extensions.swift // RswiftGenerators // // Created by Tom Lokhorst on 2022-10-11. // import Foundation extension Array where Element: Comparable, Element: Hashable { func uniqueAndSorted() -> [Element] { Set(self).sorted() } } ================================================ FILE: Sources/RswiftGenerators/Extensions/String+Extensions.swift ================================================ // // String+Extensions.swift // RswiftGenerators // // Created by Tom Lokhorst on 2021-04-18. // import Foundation extension String { var lowercaseFirstCharacter: String { if self.count <= 1 { return self.lowercased() } let index = self.index(startIndex, offsetBy: 1) return self[.. String { return self .components(separatedBy: "\n") .map { line in line .isEmpty ? "" : "\(indentation)\(line)" } .joined(separator: "\n") } var fullRange: NSRange { return NSRange(location: 0, length: self.count) } var escapedStringLiteral: String { return self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") .replacingOccurrences(of: "\t", with: "\\t") .replacingOccurrences(of: "\r", with: "\\r") .replacingOccurrences(of: "\n", with: "\\n") } var commentString: String { return self .replacingOccurrences(of: "\r\n", with: " ") .replacingOccurrences(of: "\r", with: " ") .replacingOccurrences(of: "\n", with: " ") } } ================================================ FILE: Sources/RswiftGenerators/FileResource+Generator.swift ================================================ // // FileResource+Generator.swift // // // Created by Tom Lokhorst on 2022-06-24. // import Foundation import RswiftResources extension FileResource { public static func generateStruct(resources: [FileResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "file") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } // For resource files, the contents of the different locales don't matter, so we just use the first one let firstLocales = Dictionary(grouping: resources, by: \.filename) .values.map(\.first!) let groupedFiles = firstLocales.grouped(bySwiftIdentifier: \.filename) groupedFiles.reportWarningsForDuplicatesAndEmpties(source: "resource file", result: "file", warning: warning) let vargetters = groupedFiles.uniques.map { $0.generateVarGetter() } // .sorted { $0.name < $1.name } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(vargetters.count) resource files."] return Struct(comments: comments, name: structName) { Init.bundle vargetters } } } extension FileResource { func generateVarGetter() -> VarGetter { VarGetter( comments: ["Resource file `\(filename)`."], name: SwiftIdentifier(name: filename), typeReference: TypeReference(module: .rswiftResources, rawName: "FileResource"), valueCodeString: ".init(name: \"\(name.escapedStringLiteral)\", pathExtension: \"\(pathExtension.escapedStringLiteral)\", bundle: bundle, locale: \(locale?.codeString() ?? "nil"))" ) } } ================================================ FILE: Sources/RswiftGenerators/FontResource+Generator.swift ================================================ // // FontResource+Generator.swift // rswift // // Created by Tom Lokhorst on 2021-04-18. // import Foundation import RswiftResources extension FontResource { public static func generateStruct(resources: [FontResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "font") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let groupedResources = resources.grouped(bySwiftIdentifier: { $0.name }) groupedResources.reportWarningsForDuplicatesAndEmpties(source: "font resource", result: "font", warning: warning) let vargetters = groupedResources.uniques.map { $0.generateVarGetter() } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(vargetters.count) fonts."] return Struct(comments: comments, name: structName, protocols: [.sequence]) { Init.bundle if vargetters.count > 0 { generateMakeIterator(names: vargetters.map(\.name)) generateValidate() } vargetters } } private static func generateMakeIterator(names: [SwiftIdentifier]) -> Function { Function( comments: [], name: .init(name: "makeIterator"), params: [], returnType: .indexingIterator(.fontResource), valueCodeString: "[\(names.map(\.value).joined(separator: ", "))].makeIterator()" ) } private static func generateValidate() -> Function { Function( comments: [], name: .init(name: "validate"), params: [], returnThrows: true, returnType: .void, valueCodeString: #""" for font in self { if !font.canBeLoaded() { throw RswiftResources.ValidationError("[R.swift] Font '\(font.name)' could not be loaded, is '\(font.filename)' added to the UIAppFonts array in this targets Info.plist?") } } """# ) } } extension FontResource { func generateVarGetter() -> VarGetter { VarGetter( comments: ["Font `\(name)`."], name: SwiftIdentifier(name: name), typeReference: TypeReference(module: .rswiftResources, rawName: "FontResource"), valueCodeString: ".init(name: \"\(name)\", bundle: bundle, filename: \"\(filename)\")" ) } } ================================================ FILE: Sources/RswiftGenerators/Nib+Generator.swift ================================================ // // NibResource+Generator.swift // // // Created by Tom Lokhorst on 2022-06-24. // import Foundation import RswiftResources extension NibResource { public static func generateStruct(nibs: [NibResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "nib") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } // Unify different localizations of nibs let unifiedNibs = unifyLocalizations(nibs: nibs, warning: warning) let groupedNibs = unifiedNibs.grouped(bySwiftIdentifier: \.name) groupedNibs.reportWarningsForDuplicatesAndEmpties(source: "xib", result: "file", warning: warning) let vargetters = groupedNibs.uniques .map { $0.generateVarGetter() } .sorted { $0.name < $1.name } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(vargetters.count) nibs."] // additional module references, for use in validate function let additionalModuleReferences = Set(nibs.map { $0.isAppKit ? ModuleReference.appKit : ModuleReference.uiKit }) return Struct(comments: comments, name: structName, additionalModuleReferences: additionalModuleReferences) { Init.bundle vargetters if groupedNibs.uniques.count > 0 { generateValidate(nibs: groupedNibs.uniques) } } } private static func generateValidate(nibs: [NibResource]) -> Function { Function( comments: [], name: .init(name: "validate"), params: [], returnThrows: true, returnType: .void, valueCodeString: nibs.flatMap { $0.generateValidateLines() }.joined(separator: "\n") ) } private static func unifyLocalizations(nibs: [NibResource], warning: (String) -> Void) -> [NibResource] { var result: [NibResource] = [] for localizations in Dictionary(grouping: nibs, by: \.name).values { guard let nib = localizations.first else { continue } let ur = nib.unify(localizations: localizations) let diffs: [String] = [ ur.differentNames ? "names" : nil, ur.differentRootViews ? "root views" : nil, ur.differentInitialReusables ? "initial reusables" : nil, ur.differentDeploymentTargets ? "deployment targets" : nil, ].compactMap { $0 } if diffs.count > 0 { warning("Skipping generation of nib '\(nib.name)', because \(diffs.joined(separator: ", ")) don't match in all localizations") continue } result.append(ur.resource) } return result } } extension NibResource { var genericTypeReference: TypeReference { TypeReference( module: .rswiftResources, name: "NibReference", genericArgs: [rootViews.first ?? TypeReference.uiView] ) } func generateVarGetter() -> VarGetter { if let reusable = reusables.first { let typeReference = TypeReference( module: .rswiftResources, name: "NibReferenceReuseIdentifier", genericArgs: [rootViews.first ?? TypeReference.uiView, reusable.type] ) return VarGetter( comments: ["Nib `\(name)`."], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), typeReference: typeReference, valueCodeString: ".init(name: \"\(name.escapedStringLiteral)\", bundle: bundle, identifier: \"\(reusable.identifier.escapedStringLiteral)\")" ) } else { let typeReference = TypeReference( module: .rswiftResources, name: "NibReference", genericArgs: [rootViews.first ?? TypeReference.uiView] ) return VarGetter( comments: ["Nib `\(name)`."], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), typeReference: typeReference, valueCodeString: ".init(name: \"\(name.escapedStringLiteral)\", bundle: bundle)" ) } } func generateValidateLines() -> [String] { let validateImagesLines = self.usedImageIdentifiers.uniqueAndSorted() .map { nameCatalog -> String in if isAppKit { if nameCatalog.isSystemCatalog { return "if #available(macOS 11.0, *) { if AppKit.NSImage(systemSymbolName: \"\(nameCatalog.name)\", accessibilityDescription: nil) == nil { throw RswiftResources.ValidationError(\"[R.swift] System image named '\(nameCatalog.name)' is used in nib '\(self.name)', but couldn't be loaded.\") } }" } else { return "if bundle.image(forResource: \"\(nameCatalog.name)\") == nil { throw RswiftResources.ValidationError(\"[R.swift] Image named '\(nameCatalog.name)' is used in nib '\(self.name)', but couldn't be loaded.\") }" } } else { if nameCatalog.isSystemCatalog { return "if #available(iOS 13.0, *) { if UIKit.UIImage(systemName: \"\(nameCatalog.name)\") == nil { throw RswiftResources.ValidationError(\"[R.swift] System image named '\(nameCatalog.name)' is used in nib '\(self.name)', but couldn't be loaded.\") } }" } else { return "if UIKit.UIImage(named: \"\(nameCatalog.name)\", in: bundle, compatibleWith: nil) == nil { throw RswiftResources.ValidationError(\"[R.swift] Image named '\(nameCatalog.name)' is used in nib '\(self.name)', but couldn't be loaded.\") }" } } } let validateColorLines = self.usedColorResources.uniqueAndSorted() .filter { !$0.isSystemCatalog } .map { nameCatalog in isAppKit ? "if AppKit.NSColor(named: \"\(nameCatalog.name)\", bundle: bundle) == nil { throw RswiftResources.ValidationError(\"[R.swift] Color named '\(nameCatalog.name)' is used in nib '\(self.name)', but couldn't be loaded.\") }" : "if UIKit.UIColor(named: \"\(nameCatalog.name)\", in: bundle, compatibleWith: nil) == nil { throw RswiftResources.ValidationError(\"[R.swift] Color named '\(nameCatalog.name)' is used in nib '\(self.name)', but couldn't be loaded.\") }" } return (validateImagesLines + validateColorLines) } } ================================================ FILE: Sources/RswiftGenerators/PropertyListResource+Generator.swift ================================================ // // PropertyListResource+Generator.swift // // // Created by Tom Lokhorst on 2022-07-23. // import Foundation import RswiftResources extension PropertyListResource { public static func generateInfoStruct(resourceName: String, plists: [PropertyListResource], prefix: SwiftIdentifier) -> Struct { generateStruct( resourceName: resourceName, plists: plists, toplevelKeysWhitelist: ["UIApplicationShortcutItems", "UIApplicationSceneManifest", "NSUserActivityTypes", "NSExtension"], isInfoPlist: true, prefix: prefix ) } public static func generateStruct(resourceName: String, plists: [PropertyListResource], toplevelKeysWhitelist: [String]? = nil, isInfoPlist: Bool = false, prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: resourceName) let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } guard let plist = plists.first else { return .empty } guard plists.allSatisfy({ $0.url == plist.url }) else { let configs = plists.map { $0.buildConfigurationName } warning("Build configurations \(configs) use different \(resourceName) files, this is not yet supported") return .empty } let contents: PropertyListResource.Contents if let whitelist = toplevelKeysWhitelist { contents = plist.contents.filter { (key, _) in whitelist.contains(key) } } else { contents = plist.contents } let members = contents.generateMembers(resourceName: resourceName, path: [], isInfoPlist: isInfoPlist, warning: warning) .sorted() let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(members.structs.count) properties."] return Struct(comments: comments, name: structName) { if isInfoPlist { Init.bundle } members } } } protocol PlistPathComponent { typealias Key = String typealias Index = Int } extension PlistPathComponent.Key: PlistPathComponent {} extension PlistPathComponent.Index: PlistPathComponent {} extension PropertyListResource.Contents { @StructMembersBuilder func generateMembers(resourceName: String, path: [PlistPathComponent], includeKey: Bool = true, isInfoPlist: Bool, warning: (String) -> Void) -> StructMembers { let groupedContents = self.grouped(bySwiftIdentifier: { $0.key }) groupedContents.reportWarningsForDuplicatesAndEmpties(source: resourceName, result: resourceName, warning: warning) for (key, value) in groupedContents.uniques { let newPath = path + [key] switch value { case let value as Bool: LetBinding( name: SwiftIdentifier(name: key), typeReference: .bool, valueCodeString: "\(value)" ) case let value as String: if isInfoPlist { VarGetter( name: SwiftIdentifier(name: key), typeReference: .string, valueCodeString: valueCodedString(path: path, includeKey: includeKey, key: key, value: value) ) } else { LetBinding( name: SwiftIdentifier(name: key), typeReference: .string, valueCodeString: "\"\(value.escapedStringLiteral)\"" ) } case let duplicateArray as [String]: let groupedArray = duplicateArray.grouped(bySwiftIdentifier: { $0 }) groupedArray.reportWarningsForDuplicatesAndEmpties(source: resourceName, result: resourceName, warning: warning) bundleStruct(name: key, usesBundle: isInfoPlist) { for (index, value) in groupedArray.uniques.enumerated() { [value: value] .generateMembers(resourceName: resourceName, path: newPath + [index], includeKey: false, isInfoPlist: isInfoPlist, warning: warning) .sorted() } } case var dict as [String: Any]: dict["_key"] = key bundleStruct(name: key, usesBundle: isInfoPlist) { dict.generateMembers(resourceName: resourceName, path: newPath, isInfoPlist: isInfoPlist, warning: warning) .sorted() } case let dicts as [[String: Any]] where arrayOfDictionariesPrimaryKeys.keys.contains(key): bundleStruct(name: key, usesBundle: isInfoPlist) { for (index, dict) in dicts.enumerated() { if let primaryKey = arrayOfDictionariesPrimaryKeys[key], let primary = dict[primaryKey] as? String { bundleStruct(name: primary, usesBundle: isInfoPlist) { dict.generateMembers(resourceName: resourceName, path: newPath + [index], isInfoPlist: isInfoPlist, warning: warning) .sorted() } } } } default: do {} } } } private func valueCodedString(path: [PlistPathComponent], includeKey: Bool, key: String, value: String) -> String { var string = "bundle.infoDictionaryString(path: \(path)" if includeKey { string += ", key: \"\(key.escapedStringLiteral)\"" } return string + ") ?? \"\(value.escapedStringLiteral)\"" } } @StructMembersBuilder func bundleStruct(name: String, usesBundle: Bool, @StructMembersBuilder builder: () -> StructMembers) -> StructMembers { let str = Struct(name: SwiftIdentifier(name: name)) { if usesBundle { Init.bundle } builder() } if usesBundle { str.generateBundleVarGetter(name: name) str.generateBundleFunction(name: name) } else { str.generateLetBinding() } str } // For arrays of dictionaries we need a primary key. // This key will be used as a name for the struct in the generated code. private let arrayOfDictionariesPrimaryKeys: [String: String] = [ "UIWindowSceneSessionRoleExternalDisplay": "UISceneConfigurationName", "UIWindowSceneSessionRoleApplication": "UISceneConfigurationName", "UIApplicationShortcutItems": "UIApplicationShortcutItemType", "CFBundleDocumentTypes": "CFBundleTypeName", "CFBundleURLTypes": "CFBundleURLName" ] ================================================ FILE: Sources/RswiftGenerators/ReuseIdentifier+Generator.swift ================================================ // // ReuseIdentifier+Generator.swift // // // Created by Tom Lokhorst on 2022-07-24. // import Foundation import RswiftResources extension Reusable { public static func generateStruct(nibs: [NibResource], storyboards: [StoryboardResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "reuseIdentifier") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let unifiedNibs = unifyLocalizations(nibs: nibs, warning: warning) let unifiedStoryboards = unifyLocalizations(storyboards: storyboards, warning: warning) let reusables = unifiedNibs.flatMap(\.reusables) + unifiedStoryboards.flatMap(\.reusables) let deduplicatedReusables = Dictionary(grouping: reusables, by: \.hashValue) .values.compactMap(\.first) let groupedReusables = deduplicatedReusables.grouped(bySwiftIdentifier: \.identifier) groupedReusables.reportWarningsForDuplicatesAndEmpties(source: "reuseIdentifier", result: "reuse identifier", warning: warning) let letbindings = groupedReusables.uniques .map { $0.generateVarGetter() } .sorted { $0.name < $1.name } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(letbindings.count) reuse identifiers."] return Struct(comments: comments, name: structName) { letbindings } } private static func unifyLocalizations(nibs: [NibResource], warning: (String) -> Void) -> [NibResource] { var result: [NibResource] = [] for localizations in Dictionary(grouping: nibs, by: \.name).values { guard let nib = localizations.first else { continue } let ur = nib.unify(localizations: localizations) let rs = ur.differentReusables.map { "'\($0.identifier)'" }.uniqueAndSorted() if rs.count > 0 { warning("Skipping generation of \(rs.count) reuseIdentifiers in nib '\(nib.name)', because \(rs.joined(separator: ", ")) don't match in all localizations") continue } result.append(ur.resource) } return result } private static func unifyLocalizations(storyboards: [StoryboardResource], warning: (String) -> Void) -> [StoryboardResource] { var result: [StoryboardResource] = [] for localizations in Dictionary(grouping: storyboards, by: \.name).values { guard let storyboard = localizations.first else { continue } let ur = storyboard.unify(localizations: localizations) let rs = ur.differentReusables.map { "'\($0.identifier)'" }.uniqueAndSorted() if rs.count > 0 { warning("Skipping generation of \(rs.count) reuseIdentifiers in storyboard '\(storyboard.name)', because \(rs.joined(separator: ", ")) don't match in all localizations") continue } result.append(ur.storyboard) } return result } } extension Reusable { var genericTypeReference: TypeReference { TypeReference( module: .rswiftResources, name: "ReuseIdentifier", genericArgs: [type] ) } func generateVarGetter() -> VarGetter { VarGetter( comments: ["Reuse identifier `\(identifier)`."], name: SwiftIdentifier(name: identifier), typeReference: genericTypeReference, valueCodeString: ".init(identifier: \"\(identifier)\")" ) } } ================================================ FILE: Sources/RswiftGenerators/Segue+Generator.swift ================================================ // // Segue+Generator.swift // // // Created by Tom Lokhorst on 2022-07-22. // import Foundation import RswiftResources public struct Segue { public static func generateStruct(storyboards: [StoryboardResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "segue") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } // Unify different localizations of storyboards let unifiedStoryboards = unifyLocalizations(storyboards: storyboards, warning: warning) let allSegues = allSegueInfos(storyboards: unifiedStoryboards, warning: warning) let viewControllers = viewControllers(segues: allSegues, warning: warning) let structs = viewControllers .map { generateStruct(sourceType: $0.key, segues: $0.value) } .sorted { $0.name < $1.name } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(structs.count) view controllers."] return Struct(comments: comments, name: structName) { for s in structs { s.generateLetBinding() } structs } } private static func viewControllers(segues: [SegueWithInfo], warning: (String) -> Void) -> [TypeReference: [SegueWithInfo]] { var result: [TypeReference: [SegueWithInfo]] = [:] let grouped = Dictionary(grouping: segues, by: \.sourceType) for (sourceType, seguesBySourceType) in grouped { let segues = seguesBySourceType.grouped(bySwiftIdentifier: { $0.segue.identifier }) segues.reportWarningsForDuplicatesAndEmpties(source: "segue", container: "for '\(sourceType.name)'", result: "segue", warning: warning) result[sourceType] = segues.uniques } return result } private static func generateStruct(sourceType: TypeReference, segues: [SegueWithInfo]) -> Struct { let comments = ["This struct is generated for `\(sourceType.name)`, and contains static references to \(segues.count) segues."] return Struct(comments: comments, name: SwiftIdentifier(name: sourceType.name)) { segues.map { $0.generateVarGetter() } } } private static func allSegueInfos(storyboards: [StoryboardResource], warning: (String) -> Void) -> [SegueWithInfo] { let allSegues = storyboards.flatMap { storyboard in storyboard.viewControllers.flatMap { viewController in viewController.segues.compactMap { segue -> SegueWithInfo? in guard let destinationType = resolveDestinationType( for: segue, inViewController: viewController, inStoryboard: storyboard, allStoryboards: storyboards) else { warning("Destination view controller with id \(segue.destination) for segue \(segue.identifier) in \(viewController.type.codeString()) not found in storyboard \(storyboard.name). Is this storyboard corrupt?") return nil } guard !segue.identifier.isEmpty else { return nil } return SegueWithInfo( deploymentTarget: storyboard.deploymentTarget, segue: segue, sourceType: viewController.type, destinationType: destinationType ) } } } // Deduplicate segues that are identical let deduplicatedSeguesWithInfo = Dictionary(grouping: allSegues, by: \.groupKey) .values .compactMap { $0.first } return deduplicatedSeguesWithInfo } private static func resolveDestinationType(for segue: StoryboardResource.Segue, inViewController: StoryboardResource.ViewController, inStoryboard storyboard: StoryboardResource, allStoryboards storyboards: [StoryboardResource]) -> TypeReference? { let uiViewController: TypeReference = storyboard.isAppKit ? .nsViewController : .uiViewController if segue.kind == "unwind" { return uiViewController } let destinationViewControllerType = storyboard.viewControllers .filter { $0.id == segue.destination } .first? .type let destinationViewControllerPlaceholderType = storyboard.viewControllerPlaceholders .filter { $0.id == segue.destination } .first .flatMap { storyboard -> TypeReference? in switch storyboard.resolveWithStoryboards(storyboards) { case .customBundle: return uiViewController // Not supported, fallback to UIViewController case let .resolved(vc): return vc?.type } } return destinationViewControllerType ?? destinationViewControllerPlaceholderType } private static func unifyLocalizations(storyboards: [StoryboardResource], warning: (String) -> Void) -> [StoryboardResource] { var result: [StoryboardResource] = [] for localizations in Dictionary(grouping: storyboards, by: \.name).values { guard let storyboard = localizations.first else { continue } let ur = storyboard.unify(localizations: localizations) for vur in ur.viewControllerResults.values { if vur.differentSegueIDs.isEmpty { continue } let segues = vur.differentSegueIDs.sorted() let ns = segues.map { "'\($0)'" }.joined(separator: ", ") warning("Skipping generation of \(segues.count) segues in view controller '\(vur.viewcontroller.storyboardIdentifier ?? vur.viewcontroller.id)' in storyboard '\(storyboard.name)', because segues \(ns) aren't identical in all localizations") } result.append(ur.storyboard) } return result } } private extension StoryboardResource.ViewControllerPlaceholder { enum ResolvedResult { case customBundle case resolved(StoryboardResource.ViewController?) } func resolveWithStoryboards(_ storyboards: [StoryboardResource]) -> ResolvedResult { if nil != bundleIdentifier { // Can't resolve storyboard in other bundles return .customBundle } guard let storyboardName = storyboardName else { // Storyboard reference without a storyboard defined?! return .resolved(nil) } let storyboard = storyboards .filter { $0.name == storyboardName } guard let referencedIdentifier = referencedIdentifier else { return .resolved(storyboard.first?.initialViewController) } return .resolved(storyboard .flatMap { $0.viewControllers.filter { $0.storyboardIdentifier == referencedIdentifier } } .first ) } } struct SegueWithInfo { let deploymentTarget: DeploymentTarget? let segue: StoryboardResource.Segue let sourceType: TypeReference let destinationType: TypeReference var groupKey: String { "\(String(describing: deploymentTarget))|\(segue.identifier)|\(segue.type)|\(sourceType)|\(destinationType)" } var genericTypeReference: TypeReference { TypeReference( module: .rswiftResources, name: "SegueIdentifier", genericArgs: [segue.type, sourceType, destinationType] ) } func generateVarGetter() -> VarGetter { VarGetter( comments: ["Segue identifier `\(segue.identifier)`."], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: segue.identifier), typeReference: genericTypeReference, valueCodeString: ".init(identifier: \"\(segue.identifier)\")" ) } } ================================================ FILE: Sources/RswiftGenerators/Shared/AssetCatalogMergedNamespaces.swift ================================================ // // AssetCatalogMergedNamespaces.swift // R.swift // // Created by Tom Lokhorst on 2017-06-06. // import Foundation import RswiftResources struct AssetCatalogMergedNamespaces { var namespaces: [SwiftIdentifier: AssetCatalog.Namespace] = [:] var duplicates: [(SwiftIdentifier, String)] = [] init(all: [String: AssetCatalog.Namespace], otherIdentifiers: [SwiftIdentifier]) { for (name, namespace) in all { let id = SwiftIdentifier(name: name) if otherIdentifiers.contains(id) { duplicates.append((id, name)) } else { namespaces[id, default: .init()].merge(namespace) } } } func printWarningsForDuplicates(result: String, warning: (String) -> Void) { for (identifier, name) in duplicates { warning("Skipping asset namespace '\(name)' because symbol '\(identifier.value)' would conflict with \(result): \(identifier.value)") } } } ================================================ FILE: Sources/RswiftGenerators/Shared/LocaleReference+Generator.swift ================================================ // // File.swift // // // Created by Tom Lokhorst on 2022-07-22. // import RswiftResources extension LocaleReference { func codeString() -> String { switch self { case .none: return "LocaleReference.none" // Plain `.none` is ambiguous whith Optional case .base: return ".base" case .language(let string): return #".language("\#(string)")"# } } } ================================================ FILE: Sources/RswiftGenerators/Shared/SwiftIdentifier.swift ================================================ // // SwiftIdentifier.swift // R.swift // // Created by Mathijs Kadijk on 11-12-15. // import Foundation private let numberPrefixRegex = try! NSRegularExpression(pattern: "^[0-9]+") private let upperCasedPrefixRegex = try! NSRegularExpression(pattern: "^([A-Z]+)(?=[^a-z]{1})") /* Disallowed characters: whitespace, mathematical symbols, arrows, private-use and invalid Unicode points, line- and boxdrawing characters Special rules: Can't begin with a number */ public struct SwiftIdentifier: Hashable, Comparable, Sendable { public let value: String public init(name: String, lowercaseStartingCharacters: Bool = true) { // Remove all disallowed characters from the name and uppercase the character after a disallowed character var nameComponents = name.components(separatedBy: disallowedCharacters) let firstComponent = nameComponents.remove(at: 0) let cleanedSwiftName = nameComponents.reduce(firstComponent) { $0 + $1.uppercaseFirstCharacter } // Remove numbers at the start of the name let sanitizedSwiftName = numberPrefixRegex.stringByReplacingMatches(in: cleanedSwiftName, options: [], range: cleanedSwiftName.fullRange, withTemplate: "") // Lowercase the start of the name let capitalizedSwiftName = lowercaseStartingCharacters ? SwiftIdentifier.lowercasePrefix(sanitizedSwiftName) : sanitizedSwiftName // Escape the name if it is a keyword if SwiftKeywords.contains(capitalizedSwiftName) { value = "`\(capitalizedSwiftName)`" } else { value = capitalizedSwiftName } } public init(rawValue: String) { value = rawValue } private static func lowercasePrefix(_ name: String) -> String { let prefixRange = upperCasedPrefixRegex.rangeOfFirstMatch(in: name, options: [], range: name.fullRange) if prefixRange.location == NSNotFound { return name.lowercaseFirstCharacter } else { let lowercasedPrefix = (name as NSString).substring(with: prefixRange).lowercased() return (name as NSString).replacingCharacters(in: prefixRange, with: lowercasedPrefix) } } static func +(lhs: SwiftIdentifier, rhs: SwiftIdentifier) -> SwiftIdentifier { return SwiftIdentifier(rawValue: "\(lhs.value).\(rhs.value)") } public static func < (lhs: SwiftIdentifier, rhs: SwiftIdentifier) -> Bool { lhs.value < rhs.value } } struct SwiftNameGroups { let uniques: [T] let duplicates: [(SwiftIdentifier, [String])] // Identifiers that result in duplicate Swift names let empties: [String] // Identifiers (wrapped in quotes) that result in empty swift names // Example: // source: "xib", container: nil, result: "file" // "Skipping 1 xib, because ... for all these files" // // source: "segue", container: "for MyViewController", result: "segue" // "Skipping 2 segues for MyViewController, because ... for all these segues" func reportWarningsForDuplicatesAndEmpties(source: String, container: String? = nil, result: String, warning: (String) -> Void) { let sourceSingular = [source, container].compactMap { $0 }.joined(separator: " ") let sourcePlural = ["\(source)s", container].compactMap { $0 }.joined(separator: " ") let resultSingular = result let resultPlural = "\(result)s" for (sanitizedName, dups) in duplicates { let source = dups.count == 1 ? sourceSingular : sourcePlural warning("Skipping \(dups.count) \(source) because symbol '\(sanitizedName.value)' would be generated for all of these \(resultPlural): \(dups.joined(separator: ", "))") } if let empty = empties.first , empties.count == 1 { warning("Skipping 1 \(sourceSingular) because no swift identifier can be generated for \(resultSingular): \(empty)") } else if empties.count > 1 { warning("Skipping \(empties.count) \(sourcePlural) because no swift identifier can be generated for all of these \(resultPlural): \(empties.joined(separator: ", "))") } } func reportWarningsForReservedNames(source: String, container: String? = nil, result: String, warning: (String) -> Void) { let sourceSingular = [source, container].compactMap { $0 }.joined(separator: " ") let sourcePlural = ["\(source)s", container].compactMap { $0 }.joined(separator: " ") for (sanitizedName, dups) in duplicates { let count = dups.count - 1 let source = count == 1 ? sourceSingular : sourcePlural warning("Skipping \(count) \(source) because symbol '\(sanitizedName.value)' would conflict with reserved name") } } } extension Sequence { func grouped(bySwiftIdentifier identifierSelector: @escaping (Iterator.Element) -> String) -> SwiftNameGroups { var groupedBy = Dictionary(grouping: self, by: { SwiftIdentifier(name: identifierSelector($0)) }) let empty = SwiftIdentifier(name: "") let empties = groupedBy[empty]?.map { "'\(identifierSelector($0))'" }.sorted() groupedBy[empty] = nil let uniques = Array(groupedBy.values.filter { $0.count == 1 }.joined()) .sorted { identifierSelector($0) < identifierSelector($1) } let duplicates = groupedBy .filter { $0.1.count > 1 } .map { ($0.0, $0.1.map(identifierSelector).sorted()) } .sorted { $0.0.value < $1.0.value } return SwiftNameGroups(uniques: uniques, duplicates: duplicates, empties: empties ?? []) } } private let disallowedCharacters: CharacterSet = { var disallowed = CharacterSet(charactersIn: "") disallowed.formUnion(CharacterSet.whitespacesAndNewlines) disallowed.formUnion(CharacterSet.punctuationCharacters) disallowed.formUnion(CharacterSet.symbols) disallowed.formUnion(CharacterSet.illegalCharacters) disallowed.formUnion(CharacterSet.controlCharacters) disallowed.remove(charactersIn: "_") // Emoji ranges, roughly based on http://www.unicode.org/Public/emoji/1.0//emoji-data.txt [ 0x2600...0x27BF, 0x1F300...0x1F6FF, 0x1F900...0x1F9FF, 0x1F1E6...0x1F1FF, ].forEach { range in range.compactMap(UnicodeScalar.init).forEach { scalar in disallowed.remove(scalar) } } return disallowed }() // Based on https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID413 private let SwiftKeywords = [ // Keywords used in declarations "associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import", "init", "inout", "internal", "let", "open", "operator", "private", "protocol", "public", "static", "struct", "subscript", "typealias", "var", // Keywords used in statements "break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", "in", "repeat", "return", "switch", "where", "while", // Keywords used in expressions and types "as", "Any", "catch", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws", "true", "try", // Keywords that begin with a number sign (#) "#available", "#colorLiteral", "#column", "#else", "#elseif", "#endif", "#error", "#file", "#fileLiteral", "#function", "#if", "#imageLiteral", "#line", "#selector", "#sourceLocation", "#warning", // Keywords from Swift 2 that are still reserved "__COLUMN__", "__FILE__", "__FUNCTION__", "__LINE__", ] ================================================ FILE: Sources/RswiftGenerators/Shared/TypeReference+Generator.swift ================================================ // // File.swift // // // Created by Tom Lokhorst on 2022-07-24. // import Foundation import RswiftResources extension TypeReference { func codeString() -> String { let args = genericArgs.map { $0.codeString() }.joined(separator: ", ") let rawName = args.isEmpty ? name : "\(name)<\(args)>" if case .custom(let module) = module { return "\(module).\(rawName)" } else { return rawName } } // static func someIteratorProtocol(_ element: TypeReference) -> TypeReference { // var result = TypeReference(module: .stdLib, rawName: "some IteratorProtocol") // result.genericArgs = [element] // return result // } static func indexingIterator(_ element: TypeReference) -> TypeReference { var result = TypeReference(module: .stdLib, rawName: "IndexingIterator") result.genericArgs = [TypeReference(module: .stdLib, rawName: "[\(element.codeString())]")] return result } static let bundle: TypeReference = .init(module: .foundation, rawName: "Bundle") static let locale: TypeReference = .init(module: .foundation, rawName: "Locale") static let void: TypeReference = .init(module: .stdLib, rawName: "Void") static let bool: TypeReference = .init(module: .stdLib, rawName: "Bool") static let string: TypeReference = .init(module: .stdLib, rawName: "String") static let sequence: TypeReference = .init(module: .stdLib, rawName: "Sequence") static let someIteratorProtocol: TypeReference = .init(module: .stdLib, rawName: "some IteratorProtocol") static let uiView: TypeReference = .init(module: .uiKit, rawName: "UIView") static let uiViewController: TypeReference = .init(module: .uiKit, rawName: "UIViewController") static let nsViewController: TypeReference = .init(module: .appKit, rawName: "NSViewController") static let fontResource: TypeReference = .init(module: .rswiftResources, rawName: "FontResource") } ================================================ FILE: Sources/RswiftGenerators/Storyboard+Generator.swift ================================================ // // StoryboardResource+Generator.swift // // // Created by Tom Lokhorst on 2022-06-24. // import Foundation import RswiftResources extension StoryboardResource { public static func generateStruct(storyboards: [StoryboardResource], prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "storyboard") let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } // Unify different localizations of storyboards let unifiedStoryboards = unifyLocalizations(storyboards: storyboards, warning: warning) let groupedStoryboards = unifiedStoryboards.grouped(bySwiftIdentifier: { $0.name }) groupedStoryboards.reportWarningsForDuplicatesAndEmpties(source: "storyboard", result: "file", warning: warning) let structs = groupedStoryboards.uniques .map { $0.generateStruct(prefix: qualifiedName, warning: warning) } .sorted { $0.name < $1.name } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(structs.count) storyboards."] return Struct(comments: comments, name: structName) { Init.bundle for s in structs { s.generateBundleVarGetter(name: s.name.value) s.generateBundleFunction(name: s.name.value) } structs if structs.count > 0 { generateValidate(structs: structs) } } } private static func generateValidate(structs: [Struct]) -> Function { let lines = structs .map { s -> String in let code = "try self.\(s.name.value).validate()" return s.deploymentTarget?.codeIf(around: code) ?? code } return Function( comments: [], name: .init(name: "validate"), params: [], returnThrows: true, returnType: .void, valueCodeString: lines.joined(separator: "\n") ) } private static func unifyLocalizations(storyboards: [StoryboardResource], warning: (String) -> Void) -> [StoryboardResource] { var result: [StoryboardResource] = [] for localizations in Dictionary(grouping: storyboards, by: \.name).values { guard let storyboard = localizations.first else { continue } let ur = storyboard.unify(localizations: localizations) let diffs: [String] = [ ur.differentInitialViewController ? "initial view controllers" : nil, ur.differentDeploymentTargets ? "deployment targets" : nil, ].compactMap { $0 } if diffs.count > 0 { warning("Skipping generation of storyboard '\(storyboard.name)', because \(diffs.joined(separator: ", ")) don't match in all localizations") continue } let vcs = ur.differentViewControllerIDs.sorted() if vcs.count > 0 { let ns = vcs.map { "'\($0)'" }.joined(separator: ", ") warning("Skipping generation of \(vcs.count) view controllers in storyboard '\(storyboard.name)', because view controllers \(ns) don't exist (with same class) in all localizations") } result.append(ur.storyboard) } return result } } private extension StoryboardResource { func generateStruct(prefix: SwiftIdentifier, warning: (String) -> Void) -> Struct { let nameIdentifier = SwiftIdentifier(rawValue: "name") let bundleIdentifier = SwiftIdentifier(name: "bundle") let reservedIdentifiers: Set = [nameIdentifier, bundleIdentifier] // View controllers with identifiers let grouped = viewControllers .compactMap { (vc) -> (identifier: String, vc: StoryboardResource.ViewController)? in guard let storyboardIdentifier = vc.storyboardIdentifier else { return nil } return (storyboardIdentifier, vc) } .grouped(bySwiftIdentifier: { $0.identifier }) grouped.reportWarningsForDuplicatesAndEmpties(source: "view controller", result: "view controller identifier", warning: warning) // Warning about conflicts with reserved identifiers (grouped.uniques.map(\.identifier) + reservedIdentifiers.map(\.value)) .grouped(bySwiftIdentifier: { $0 }) .reportWarningsForReservedNames(source: "view controller", container: "in storyboard '\(name)'", result: "view controller", warning: warning) let vargetters = grouped.uniques .filter { !reservedIdentifiers.contains(SwiftIdentifier(rawValue: $0.identifier)) } .map { (id, vc) in vc.generateVarGetter(identifier: id) } .sorted { $0.name < $1.name } let letName = LetBinding( name: nameIdentifier, valueCodeString: "\"\(name)\"") let identifier = SwiftIdentifier(name: name) let storyboardReference = TypeReference(module: .rswiftResources, rawName: "StoryboardReference") let initialContainer = initialViewController == nil ? nil : TypeReference(module: .rswiftResources, rawName: "InitialControllerContainer") // additional module reference, for use in validate function let additionalModuleReference = isAppKit ? ModuleReference.appKit : ModuleReference.uiKit return Struct( comments: ["Storyboard `\(name)`."], deploymentTarget: deploymentTarget, name: identifier, protocols: [storyboardReference, initialContainer].compactMap { $0 }, additionalModuleReferences: [additionalModuleReference] ) { if let initialViewController = initialViewController { TypeAlias(name: "InitialController", value: initialViewController.type) } Init.bundle letName vargetters generateValidate(viewControllers: grouped.uniques.map(\.vc)) } } func generateValidate(viewControllers: [StoryboardResource.ViewController]) -> Function { let validateImagesLines = self.usedImageIdentifiers.uniqueAndSorted() .map { nameCatalog -> String in if isAppKit { if nameCatalog.isSystemCatalog { return "if #available(macOS 11.0, *) { if AppKit.NSImage(systemSymbolName: \"\(nameCatalog.name)\", accessibilityDescription: nil) == nil { throw RswiftResources.ValidationError(\"[R.swift] System image named '\(nameCatalog.name)' is used in storyboard '\(self.name)', but couldn't be loaded.\") } }" } else { // AppKit.NSImage(named:) return "if bundle.image(forResource: \"\(nameCatalog.name)\") == nil { throw RswiftResources.ValidationError(\"[R.swift] Image named '\(nameCatalog.name)' is used in storyboard '\(self.name)', but couldn't be loaded.\") }" } } else { if nameCatalog.isSystemCatalog { return "if #available(iOS 13.0, *) { if UIKit.UIImage(systemName: \"\(nameCatalog.name)\") == nil { throw RswiftResources.ValidationError(\"[R.swift] System image named '\(nameCatalog.name)' is used in storyboard '\(self.name)', but couldn't be loaded.\") } }" } else { return "if UIKit.UIImage(named: \"\(nameCatalog.name)\", in: bundle, compatibleWith: nil) == nil { throw RswiftResources.ValidationError(\"[R.swift] Image named '\(nameCatalog.name)' is used in storyboard '\(self.name)', but couldn't be loaded.\") }" } } } let validateColorLines = self.usedColorResources.uniqueAndSorted() .filter { !$0.isSystemCatalog } .map { nameCatalog in isAppKit ? "if AppKit.NSColor(named: \"\(nameCatalog.name)\", bundle: bundle) == nil { throw RswiftResources.ValidationError(\"[R.swift] Color named '\(nameCatalog.name)' is used in storyboard '\(self.name)', but couldn't be loaded.\") }" : "if UIKit.UIColor(named: \"\(nameCatalog.name)\", in: bundle, compatibleWith: nil) == nil { throw RswiftResources.ValidationError(\"[R.swift] Color named '\(nameCatalog.name)' is used in storyboard '\(self.name)', but couldn't be loaded.\") }" } let validateViewControllersLines = viewControllers .compactMap { vc -> String? in guard let storyboardName = vc.storyboardIdentifier else { return nil } let storyboardIdentifier = SwiftIdentifier(name: storyboardName) return "if \(storyboardIdentifier.value)() == nil { throw RswiftResources.ValidationError(\"[R.swift] ViewController with identifier '\(storyboardIdentifier.value)' could not be loaded from storyboard '\(self.name)' as '\(vc.type.codeString())'.\") }" } let validateLines = (validateImagesLines + validateColorLines + validateViewControllersLines) return Function( comments: [], name: .init(name: "validate"), params: [], returnThrows: true, returnType: .void, valueCodeString: validateLines.joined(separator: "\n") ) } } private extension StoryboardResource.ViewController { var genericTypeReference: TypeReference { TypeReference( module: .rswiftResources, name: "StoryboardViewControllerIdentifier", genericArgs: [self.type] ) } func generateVarGetter(identifier: String) -> VarGetter { VarGetter( name: SwiftIdentifier(name: identifier), typeReference: genericTypeReference, valueCodeString: #".init(identifier: "\#(identifier.escapedStringLiteral)", storyboard: name, bundle: bundle)"# ) } } ================================================ FILE: Sources/RswiftGenerators/StringsTable+Generator.swift ================================================ // // StringsTable+Generator.swift // // // Created by Tom Lokhorst on 2022-06-24. // import Foundation import RswiftResources extension Struct { public func generateBundleVarGetterForString() -> VarGetter { VarGetter( deploymentTarget: deploymentTarget, name: name, typeReference: TypeReference(module: .host, rawName: name.value), valueCodeString: ".init(bundle: bundle, preferredLanguages: nil, locale: nil)" ) } public func generateBundleFunctionForString(name: String) -> Function { Function( comments: [], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), params: [.init(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil)], returnType: TypeReference(module: .host, rawName: self.name.value), valueCodeString: ".init(bundle: bundle, preferredLanguages: nil, locale: nil)" ) } public func generateLocaleFunctionForString(name: String) -> Function { Function( comments: [], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), params: [.init(name: "locale", localName: nil, typeReference: .locale, defaultValue: nil)], returnType: TypeReference(module: .host, rawName: self.name.value), valueCodeString: ".init(bundle: bundle, preferredLanguages: nil, locale: locale)" ) } public func generatePreferredLanguagesFunctionForString(name: String) -> Function { Function( comments: [], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), params: [ .init(name: "preferredLanguages", localName: nil, typeReference: .init(module: .stdLib, rawName: "[String]"), defaultValue: nil), .init(name: "locale", localName: nil, typeReference: .init(module: .stdLib, rawName: "Locale?"), defaultValue: "nil") ], returnType: TypeReference(module: .host, rawName: self.name.value), valueCodeString: ".init(bundle: bundle, preferredLanguages: preferredLanguages, locale: locale)" ) } } extension StringsTable { public static func generateStruct(tables: [StringsTable], developmentLanguage: String?, prefix: SwiftIdentifier) -> Struct { let structName = SwiftIdentifier(name: "string", lowercaseStartingCharacters: false) let qualifiedName = prefix + structName let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let localized = Dictionary(grouping: tables, by: \.filename) let groupedLocalized = localized.grouped(bySwiftIdentifier: \.key) groupedLocalized.reportWarningsForDuplicatesAndEmpties(source: "strings file", result: "file", warning: warning) let structs = groupedLocalized.uniques .compactMap { (filename, tables) -> Struct? in generateStruct( filename: filename, tables: tables, developmentLanguage: developmentLanguage, prefix: qualifiedName, warning: warning ) } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(groupedLocalized.uniques.count) localization tables."] return Struct(comments: comments, name: structName, additionalModuleReferences: [.rswiftResources]) { initBundlePreferredLanguages for name in groupedLocalized.uniques.map(\.0) { generateBundleLocaleVarGetter(name: SwiftIdentifier(name: name), tableName: name) // generateBundleLocaleFunction(name: SwiftIdentifier(name: name)) generatePreferredLanguagesFunction(name: SwiftIdentifier(name: name), tableName: name) } structs } } private static var initBundlePreferredLanguages: Init { Init( comments: [], params: [ .init(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil), .init(name: "preferredLanguages", localName: nil, typeReference: .init(module: .stdLib, rawName: "[String]?"), defaultValue: "nil"), .init(name: "locale", localName: nil, typeReference: .init(module: .stdLib, rawName: "Locale?"), defaultValue: "nil"), ], valueCodeString: """ self.bundle = bundle self.preferredLanguages = preferredLanguages self.locale = locale """ ) } private static func generateStruct(filename: String, tables: [StringsTable], developmentLanguage: String?, prefix: SwiftIdentifier, warning: (String) -> Void) -> Struct? { let structName = SwiftIdentifier(name: filename) let qualifiedName = prefix + structName let strings = computeStringsWithParams(filename: filename, tables: tables, developmentLanguage: developmentLanguage, warning: warning) let vargetters = strings.map { $0.generateVarGetter() } // only functions with named parameters let functions = strings .filter { $0.params.contains { $0.name != nil } } .flatMap { [$0.generateFunctionBlank(), $0.generateFunctionPreferredLanguages()] } let comments = ["This `\(qualifiedName.value)` struct is generated, and contains static references to \(vargetters.count) localization keys."] return Struct(comments: comments, name: structName) { initStringSource vargetters functions } } private static var initStringSource: Init { Init( comments: [], params: [ .init(name: "source", localName: nil, typeReference: .init(module: .rswiftResources, rawName: "StringResource.Source"), defaultValue: nil), ], valueCodeString: """ self.source = source """ ) } public static func generateBundleLocaleVarGetter(name: SwiftIdentifier, tableName: String) -> VarGetter { VarGetter( name: name, typeReference: TypeReference(module: .host, rawName: name.value), valueCodeString: #".init(source: .init(bundle: bundle, tableName: "\#(tableName.escapedStringLiteral)", preferredLanguages: preferredLanguages, locale: locale))"# ) } public static func generateBundleLocaleFunction(name: SwiftIdentifier) -> Function { Function( comments: [], name: name, params: [ .init(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil), .init(name: "locale", localName: nil, typeReference: .locale, defaultValue: nil), ], returnType: TypeReference(module: .host, rawName: name.value), valueCodeString: ".init(source: .selected(bundle, locale))" ) } public static func generatePreferredLanguagesFunction(name: SwiftIdentifier, tableName: String) -> Function { Function( comments: [], name: name, params: [ .init(name: "preferredLanguages", localName: nil, typeReference: TypeReference(module: .stdLib, rawName: "[String]"), defaultValue: nil), ], returnType: TypeReference(module: .host, rawName: name.value), valueCodeString: #".init(source: .init(bundle: bundle, tableName: "\#(tableName.escapedStringLiteral)", preferredLanguages: preferredLanguages, locale: locale))"# ) } // Ahem, this code is a bit of a mess. It might need cleaning up... ;-) private static func computeStringsWithParams(filename: String, tables: [StringsTable], developmentLanguage: String?, warning: (String) -> Void) -> [StringWithParams] { var allParams: [String: [(LocaleReference, String, [StringParam])]] = [:] let primaryLanguage: String? let primaryKeys: Set? let bases = tables.filter { $0.locale.isBase } let developments = tables.filter { $0.locale.localeDescription == developmentLanguage } if !bases.isEmpty { primaryKeys = Set(bases.flatMap { $0.dictionary.keys }) primaryLanguage = "Base" } else if !developments.isEmpty { primaryKeys = Set(developments.flatMap { $0.dictionary.keys }) primaryLanguage = developmentLanguage } else { primaryKeys = nil primaryLanguage = developmentLanguage } // Warnings about duplicates and empties for ls in tables { let filenameLocale = ls.locale.debugDescription(filename: filename) let groupedKeys = ls.dictionary.keys.grouped(bySwiftIdentifier: { $0 }) groupedKeys.reportWarningsForDuplicatesAndEmpties(source: "string", container: "in \(filenameLocale)", result: "key", warning: warning) // Save uniques for key in groupedKeys.uniques { if let value = ls.dictionary[key] { if let _ = allParams[key] { allParams[key]?.append((ls.locale, value.originalValue, value.params)) } else { allParams[key] = [(ls.locale, value.originalValue, value.params)] } } } } // Warnings about missing translations for (locale, lss) in Dictionary(grouping: tables, by: \.locale) { let filenameLocale = locale.debugDescription(filename: filename) let sourceKeys = primaryKeys ?? Set(allParams.keys) let missing = sourceKeys.subtracting(lss.flatMap { $0.dictionary.keys }) if missing.isEmpty { continue } let paddedKeys = missing.sorted().map { "'\($0)'" } let paddedKeysString = paddedKeys.joined(separator: ", ") warning("Strings file \(filenameLocale) is missing translations for keys: \(paddedKeysString)") } // Warnings about extra translations for (locale, lss) in Dictionary(grouping: tables, by: \.locale) { let filenameLocale = locale.debugDescription(filename: filename) let sourceKeys = primaryKeys ?? Set(allParams.keys) let usedKeys = Set(lss.flatMap { $0.dictionary.keys }) let extra = usedKeys.subtracting(sourceKeys) if extra.isEmpty { continue } let paddedKeys = extra.sorted().map { "'\($0)'" } let paddedKeysString = paddedKeys.joined(separator: ", ") if let primaryLanguage { warning("Strings file \(filenameLocale) has extra translations (not in \(primaryLanguage)) for keys: \(paddedKeysString)") } else { warning("Strings file \(filenameLocale) has extra translations for keys: \(paddedKeysString)") } } // Only include translation if it exists in the primary language func includeTranslation(_ key: String) -> Bool { if let primaryKeys = primaryKeys { return primaryKeys.contains(key) } return true } var results: [StringWithParams] = [] var badFormatSpecifiersKeys = Set() let filteredSortedParams = allParams .map { $0 } .filter { includeTranslation($0.0) } .sorted(by: { $0.0 < $1.0 }) // Unify format specifiers for (key, keyParams) in filteredSortedParams { var params: [StringParam] = [] var areCorrectFormatSpecifiers = true for (locale, _, ps) in keyParams { if ps.contains(where: { $0.spec == FormatSpecifier.topType }) { let name = locale.debugDescription(filename: filename) warning("Skipping string \(key) in \(name), not all format specifiers are consecutive") areCorrectFormatSpecifiers = false } } if !areCorrectFormatSpecifiers { continue } for (_, _, ps) in keyParams { if let unified = params.unify(ps) { params = unified } else { badFormatSpecifiersKeys.insert(key) areCorrectFormatSpecifiers = false } } if !areCorrectFormatSpecifiers { continue } let vals = keyParams.map { ($0.0, $0.1) } let values = StringWithParams(key: key, params: params, tableName: filename, values: vals, developmentLanguage: developmentLanguage) results.append(values) } for badKey in badFormatSpecifiersKeys.sorted() { let fewParams = allParams.filter { $0.0 == badKey }.map { $0.1 } if let params = fewParams.first { let locales = params.compactMap { $0.0.localeDescription }.sorted().joined(separator: ", ") warning("Skipping string for key \(badKey) (\(filename)), format specifiers don't match for all locales: \(locales)") } } return results } } private struct StringWithParams { let key: String let params: [StringParam] let tableName: String let values: [(LocaleReference, String)] let developmentLanguage: String? func generateFunctionBlank() -> Function { let parameters: [Function.Parameter] = zip(params.indices, params).map { (ix, p) in .init(name: p.name ?? "_", localName: "value\(ix + 1)", typeReference: p.spec.typeReference, defaultValue: nil) } let arguments = parameters.map { $0.localName ?? $0.name }.joined(separator: ", ") return Function( comments: self.comments, name: SwiftIdentifier(name: key), params: parameters, returnType: .string, valueCodeString: "String(format: \(SwiftIdentifier(name: key).value), \(arguments))" ) } func generateFunctionPreferredLanguages() -> Function { let parameters: [Function.Parameter] = zip(params.indices, params).map { (ix, p) in .init(name: p.name ?? "_", localName: "value\(ix + 1)", typeReference: p.spec.typeReference, defaultValue: nil) } let languages: Function.Parameter = .init(name: "preferredLanguages", localName: nil, typeReference: TypeReference(module: .stdLib, rawName: "[String]"), defaultValue: nil) let arguments = parameters.map { $0.localName ?? $0.name }.joined(separator: ", ") return Function( comments: self.comments, deprecated: "Use R.string(preferredLanguages:).*.* instead", name: SwiftIdentifier(name: key), params: parameters + [languages], returnType: .string, valueCodeString: "String(format: \(SwiftIdentifier(name: key).value), preferredLanguages: preferredLanguages, \(arguments))" ) } func generateVarGetter() -> VarGetter { let developmentLanguageValue = values.filter { $0.0.localeDescription == developmentLanguage }.first?.1 let developmentValue = developmentLanguageValue.map { "\"\($0.escapedStringLiteral)\"" } ?? "nil" let typeReference = TypeReference(module: .rswiftResources, name: "StringResource\(params.isEmpty ? "" : "\(params.count)")", genericArgs: params.map(\.spec.typeReference)) let varValueCodeString = #".init(key: "\#(key.escapedStringLiteral)", tableName: "\#(tableName)", source: source, developmentValue: \#(developmentValue), comment: nil)"# return VarGetter( comments: self.comments, name: SwiftIdentifier(name: key), typeReference: typeReference, valueCodeString: varValueCodeString ) } private var primaryLanguageValues: [(LocaleReference, String)] { values.filter { $0.0.isBase } + values.filter { $0.0.localeDescription == developmentLanguage } } private var comments: [String] { var results: [String] = [] let anyNone = values.contains { $0.0.isNone } let vs = primaryLanguageValues + values // Value if let (locale, value) = vs.first { if let localeDescription = locale.localeDescription { let str = "\(localeDescription) translation: \(value)".commentString results.append(str) } else { let str = "Value: \(value)".commentString results.append(str) } } // Key if !results.isEmpty { results.append("") } results.append("Key: \(key)".commentString) // Locales if !anyNone { if !results.isEmpty { results.append("") } let locales = values.compactMap { $0.0.localeDescription } results.append("Locales: \(locales.sorted().joined(separator: ", "))") } return results } } ================================================ FILE: Sources/RswiftGenerators/SwiftSyntax/Struct.swift ================================================ // // Struct.swift // // // Created by Tom Lokhorst on 2022-07-16. // import Foundation import RswiftResources public enum AccessControl: Sendable { case none case `public` func code() -> String? { switch self { case .none: return nil case .public: return "public" } } } public struct LetBinding: Sendable { public let comments: [String] public var accessControl = AccessControl.none public let isStatic: Bool public let name: SwiftIdentifier public let typeReference: TypeReference? public let valueCodeString: String? public init( comments: [String] = [], accessControl: AccessControl = AccessControl.none, isStatic: Bool = false, name: SwiftIdentifier, typeReference: TypeReference, valueCodeString: String? ) { self.comments = comments self.accessControl = accessControl self.isStatic = isStatic self.name = name self.typeReference = typeReference self.valueCodeString = valueCodeString } public init( comments: [String] = [], accessControl: AccessControl = AccessControl.none, isStatic: Bool = false, name: SwiftIdentifier, valueCodeString: String ) { self.comments = comments self.accessControl = accessControl self.isStatic = isStatic self.name = name self.typeReference = nil self.valueCodeString = valueCodeString } public var allModuleReferences: Set { if let typeReference { return typeReference.allModuleReferences } else { return Set() } } func render(_ pp: inout PrettyPrinter) { for c in comments { pp.append(words: ["///", c == "" ? nil : c]) } var words: [String?] = [ accessControl.code(), isStatic ? "static" : nil, "let", typeReference == nil ? name.value : "\(name.value):", typeReference?.codeString() ] if let valueCodeString = valueCodeString { words.append("=") words.append(valueCodeString) } pp.append(words: words) } } public struct VarGetter: Sendable { public let comments: [String] public let deploymentTarget: DeploymentTarget? public var accessControl = AccessControl.none public let name: SwiftIdentifier public let typeReference: TypeReference public let valueCodeString: String public init( comments: [String] = [], deploymentTarget: DeploymentTarget? = nil, accessControl: AccessControl = AccessControl.none, name: SwiftIdentifier, typeReference: TypeReference, valueCodeString: String ) { self.comments = comments self.deploymentTarget = deploymentTarget self.accessControl = accessControl self.name = name self.typeReference = typeReference self.valueCodeString = valueCodeString } public var allModuleReferences: Set { typeReference.allModuleReferences } func render(_ pp: inout PrettyPrinter) { for c in comments { pp.append(words: ["///", c == "" ? nil : c]) } deploymentTarget?.render(&pp) let words: [String?] = [ accessControl.code(), "var", "\(name.value):", typeReference.codeString(), "{", valueCodeString, "}" ] pp.append(words: words) } } public struct Function: Sendable { public let comments: [String] public let deploymentTarget: DeploymentTarget? public var deprecated: String? public var accessControl = AccessControl.none public let isStatic: Bool public let name: SwiftIdentifier public let params: [Parameter] public var returnThrows: Bool public let returnType: TypeReference public let valueCodeString: String public init( comments: [String], deploymentTarget: DeploymentTarget? = nil, deprecated: String? = nil, accessControl: AccessControl = AccessControl.none, isStatic: Bool = false, name: SwiftIdentifier, params: [Parameter], returnThrows: Bool = false, returnType: TypeReference, valueCodeString: String ) { self.comments = comments self.deploymentTarget = deploymentTarget self.deprecated = deprecated self.accessControl = accessControl self.isStatic = isStatic self.name = name self.params = params self.returnThrows = returnThrows self.returnType = returnType self.valueCodeString = valueCodeString } public struct Parameter: Sendable { public let name: String public let localName: String? public let typeReference: TypeReference public let defaultValue: String? public init(name: String, localName: String?, typeReference: TypeReference, defaultValue: String?) { self.name = name self.localName = localName self.typeReference = typeReference self.defaultValue = defaultValue } func codeString() -> String { var result = name if let localName { result += " \(localName)" } result += ": \(typeReference.codeString())" if let defaultValue { result += " = \(defaultValue)" } return result } } public var allModuleReferences: Set { Set(params.flatMap(\.typeReference.allModuleReferences)) .union(returnType.allModuleReferences) } func render(_ pp: inout PrettyPrinter) { for c in comments { pp.append(words: ["///", c == "" ? nil : c]) } deploymentTarget?.render(&pp) if let deprecated = deprecated { pp.append(line: #"@available(*, deprecated, message: "\#(deprecated.escapedStringLiteral)")"#) } let prs = params.map { $0.codeString() }.joined(separator: ", ") let words: [String?] = [ accessControl.code(), isStatic ? "static" : nil, "func", "\(name.value)(\(prs))", returnThrows ? "throws" : nil, returnType != .void ? "-> \(returnType.codeString())" : nil, "{" ] pp.append(words: words) pp.indented { pp in pp.append(line: valueCodeString) } pp.append(line: "}") } } public struct Init: Sendable { public let comments: [String] public var accessControl = AccessControl.none public let params: [Parameter] public let valueCodeString: String public init(comments: [String], accessControl: AccessControl = AccessControl.none, params: [Parameter], valueCodeString: String) { self.comments = comments self.accessControl = accessControl self.params = params self.valueCodeString = valueCodeString } public struct Parameter: Sendable { public let name: String public let localName: String? public let typeReference: TypeReference public let defaultValue: String? func codeString() -> String { var result = name if let localName { result += " \(localName)" } result += ": \(typeReference.codeString())" if let defaultValue { result += " = \(defaultValue)" } return result } } public var allModuleReferences: Set { Set(params.flatMap(\.typeReference.allModuleReferences)) } func render(_ pp: inout PrettyPrinter) { for param in params { let words: [String?] = [ accessControl.code(), "let", "\(param.localName ?? param.name):", param.typeReference.codeString() ] pp.append(words: words) } if accessControl != .none { for c in comments { pp.append(words: ["///", c == "" ? nil : c]) } let prs = params.map { $0.codeString() }.joined(separator: ", ") let words: [String?] = [ accessControl.code(), "init(\(prs))", "{" ] pp.append(words: words) pp.indented { pp in pp.append(line: valueCodeString) } pp.append(line: "}") } } public static var bundle: Init { Init( comments: [], params: [Parameter(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil),], valueCodeString: "self.bundle = bundle" ) } public static var bundleLocale: Init { Init( comments: [], params: [ Parameter(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil), Parameter(name: "locale", localName: nil, typeReference: .locale, defaultValue: nil), ], valueCodeString: """ self.bundle = bundle self.locale = locale """ ) } } public struct TypeAlias: Sendable { public let comments: [String] public var accessControl = AccessControl.none public let name: String public let value: TypeReference public init(comments: [String] = [], accessControl: AccessControl = AccessControl.none, name: String, value: TypeReference) { self.comments = comments self.accessControl = accessControl self.name = name self.value = value } public var allModuleReferences: Set { value.allModuleReferences } func render(_ pp: inout PrettyPrinter) { for c in comments { pp.append(words: ["///", c == "" ? nil : c]) } let words: [String?] = [ accessControl.code(), "typealias", name, "=", value.codeString() ] pp.append(words: words) } } public struct Struct: Sendable { public let comments: [String] public let deploymentTarget: DeploymentTarget? public var accessControl = AccessControl.none public let name: SwiftIdentifier public var protocols: [TypeReference] = [] public var lets: [LetBinding] = [] public var vars: [VarGetter] = [] public var inits: [Init] = [] public var funcs: [Function] = [] public var structs: [Struct] = [] public var typealiasses: [TypeAlias] = [] public var additionalModuleReferences: Set = [] public static let empty: Struct = Struct(name: SwiftIdentifier(name: "empty"), membersBuilder: {}) public init( comments: [String] = [], deploymentTarget: DeploymentTarget? = nil, accessControl: AccessControl = AccessControl.none, name: SwiftIdentifier, protocols: [TypeReference] = [], additionalModuleReferences: Set = [], @StructMembersBuilder membersBuilder: () -> StructMembers ) { self.comments = comments self.deploymentTarget = deploymentTarget self.accessControl = accessControl self.name = name self.protocols = protocols self.additionalModuleReferences = additionalModuleReferences let members = membersBuilder() self.lets = members.lets self.vars = members.vars self.inits = members.inits self.funcs = members.funcs self.structs = members.structs self.typealiasses = members.typealiasses } public var isEmpty: Bool { lets.isEmpty && vars.isEmpty && funcs.isEmpty && structs.isEmpty } public var allModuleReferences: Set { var result: Set = [] result.formUnion(protocols.flatMap(\.allModuleReferences)) result.formUnion(lets.flatMap(\.allModuleReferences)) result.formUnion(vars.flatMap(\.allModuleReferences)) result.formUnion(inits.flatMap(\.allModuleReferences)) result.formUnion(funcs.flatMap(\.allModuleReferences)) result.formUnion(structs.flatMap(\.allModuleReferences)) result.formUnion(typealiasses.flatMap(\.allModuleReferences)) result.formUnion(additionalModuleReferences) return result } public mutating func setAccessControl(_ accessControl: AccessControl) { self.accessControl = accessControl for i in lets.indices { lets[i].accessControl = accessControl } for i in vars.indices { vars[i].accessControl = accessControl } for i in inits.indices { inits[i].accessControl = accessControl } for i in funcs.indices { funcs[i].accessControl = accessControl } for i in structs.indices { structs[i].setAccessControl(accessControl) } for i in typealiasses.indices { typealiasses[i].accessControl = accessControl } } public mutating func markSendable() { self.protocols.append(.init(module: .host, rawName: "Sendable")) for i in structs.indices { structs[i].markSendable() } } public func prettyPrint() -> String { var pp = PrettyPrinter() render(&pp) return pp.render() } func render(_ pp: inout PrettyPrinter) { for c in comments { pp.append(words: ["///", c == "" ? nil : c]) } deploymentTarget?.render(&pp) let ps = protocols.map { $0.codeString() }.joined(separator: ", ") let implements = ps.isEmpty ? "" : ": \(ps)" pp.append(words: [accessControl.code(), "struct", "\(name.value)\(implements)", "{"]) pp.indented { pp in for talias in typealiasses { if !talias.comments.isEmpty { pp.append(line: "") } talias.render(&pp) } } if !typealiasses.isEmpty && !inits.isEmpty { pp.append(line: "") } pp.indented { pp in for inib in inits { if !inib.comments.isEmpty { pp.append(line: "") } inib.render(&pp) } } if !inits.isEmpty && !lets.isEmpty { pp.append(line: "") } pp.indented { pp in for letb in lets { if !letb.comments.isEmpty { pp.append(line: "") } letb.render(&pp) } } if !lets.isEmpty && !vars.isEmpty { pp.append(line: "") } pp.indented { pp in for varb in vars { if !varb.comments.isEmpty { pp.append(line: "") } varb.render(&pp) } } if !vars.isEmpty && !funcs.isEmpty { pp.append(line: "") } pp.indented { pp in for fun in funcs { if !fun.comments.isEmpty { pp.append(line: "") } fun.render(&pp) } } if !funcs.isEmpty && !structs.isEmpty { pp.append(line: "") } pp.indented { pp in for st in structs { if !st.comments.isEmpty { pp.append(line: "") } st.render(&pp) } } pp.append(line: "}") } } extension Struct { public func generateLetBinding() -> LetBinding { LetBinding( name: name, valueCodeString: "\(name.value)()" ) } public func generateVarGetter() -> VarGetter { VarGetter( deploymentTarget: deploymentTarget, name: name, typeReference: TypeReference(module: .host, rawName: self.name.value), valueCodeString: ".init()" ) } public func generateBundleVarGetter(name: String) -> VarGetter { VarGetter( deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), typeReference: TypeReference(module: .host, rawName: self.name.value), valueCodeString: ".init(bundle: bundle)" ) } public func generateBundleFunction(name: String) -> Function { Function( comments: [], deploymentTarget: deploymentTarget, name: SwiftIdentifier(name: name), params: [.init(name: "bundle", localName: nil, typeReference: .bundle, defaultValue: nil)], returnType: TypeReference(module: .host, rawName: self.name.value), valueCodeString: ".init(bundle: bundle)" ) } } extension DeploymentTarget { func render(_ pp: inout PrettyPrinter) { if let version { pp.append(line: "@available(\(platform) \(version.major).\(version.minor), *)") } } func codeIf(around code: String) -> String { if let version { return "if #available(\(platform) \(version.major).\(version.minor), *) { \(code) }" } else { return code } } } struct PrettyPrinter { private var indent = 0 private var lines: [(Int, String)] = [] mutating func indented(perform: (inout PrettyPrinter) -> Void) { indent += 1 perform(&self) indent -= 1 } mutating func append(line str: String) { if str.isEmpty { lines.append((indent, "")) } for line in str.split(separator: "\n") { lines.append((indent, String(line))) } } mutating func append(words: [String?]) { let ws = words.compactMap { $0 } if ws.isEmpty { return } append(line: ws.joined(separator: " ")) } func render() -> String { let ls = lines.map { (indent, line) in line.isEmpty ? line : String(repeating: " ", count: indent) + line } return ls.joined(separator: "\n") } } ================================================ FILE: Sources/RswiftGenerators/SwiftSyntax/StructMembersBuilder.swift ================================================ // // StructMembersBuilder.swift // // // Created by Tom Lokhorst on 2022-07-29. // import Foundation public struct StructMembers { var lets: [LetBinding] = [] var vars: [VarGetter] = [] var inits: [Init] = [] var funcs: [Function] = [] var structs: [Struct] = [] var typealiasses: [TypeAlias] = [] func sorted() -> StructMembers { var new = self new.lets.sort { $0.name < $1.name } new.vars.sort { $0.name < $1.name } new.funcs.sort { $0.name < $1.name } new.structs.sort { $0.name < $1.name } new.typealiasses.sort { $0.name < $1.name } return new } } @resultBuilder public struct StructMembersBuilder { public static func buildExpression(_ members: Void) -> StructMembers { StructMembers() } public static func buildExpression(_ expression: LetBinding) -> StructMembers { StructMembers(lets: [expression]) } public static func buildExpression(_ expressions: [LetBinding]) -> StructMembers { StructMembers(lets: expressions) } public static func buildExpression(_ expression: VarGetter) -> StructMembers { StructMembers(vars: [expression]) } public static func buildExpression(_ expressions: [VarGetter]) -> StructMembers { StructMembers(vars: expressions) } public static func buildExpression(_ expression: Init) -> StructMembers { StructMembers(inits: [expression]) } public static func buildExpression(_ expressions: [Init]) -> StructMembers { StructMembers(inits: expressions) } public static func buildExpression(_ expression: Function) -> StructMembers { StructMembers(funcs: [expression]) } public static func buildExpression(_ expressions: [Function]) -> StructMembers { StructMembers(funcs: expressions) } public static func buildExpression(_ expression: Struct) -> StructMembers { StructMembers(structs: [expression]) } public static func buildExpression(_ expressions: [Struct]) -> StructMembers { StructMembers(structs: expressions) } public static func buildExpression(_ expression: TypeAlias) -> StructMembers { StructMembers(typealiasses: [expression]) } public static func buildExpression(_ expressions: [TypeAlias]) -> StructMembers { StructMembers(typealiasses: expressions) } public static func buildExpression(_ members: StructMembers) -> StructMembers { members } public static func buildArray(_ members: [StructMembers]) -> StructMembers { StructMembers( lets: members.flatMap(\.lets), vars: members.flatMap(\.vars), inits: members.flatMap(\.inits), funcs: members.flatMap(\.funcs), structs: members.flatMap(\.structs), typealiasses: members.flatMap(\.typealiasses) ) } public static func buildBlock(_ members: StructMembers...) -> StructMembers { StructMembers( lets: members.flatMap(\.lets), vars: members.flatMap(\.vars), inits: members.flatMap(\.inits), funcs: members.flatMap(\.funcs), structs: members.flatMap(\.structs), typealiasses: members.flatMap(\.typealiasses) ) } public static func buildEither(first component: StructMembers) -> StructMembers { component } public static func buildEither(second component: StructMembers) -> StructMembers { component } public static func buildOptional(_ component: StructMembers?) -> StructMembers { component ?? StructMembers() } } ================================================ FILE: Sources/RswiftGenerators/XcodeProject+Generator.swift ================================================ // // XcodeProjectGenerator.swift // // // Created by Tom Lokhorst on 2022-11-03. // import Foundation public struct XcodeProjectGenerator { public static func generateProject(developmentRegion: String?, knownAssetTags: [String]?) -> Struct { Struct(name: SwiftIdentifier(name: "project")) { let warning: (String) -> Void = { print("warning: [R.swift]", $0) } if let developmentRegion { LetBinding(name: SwiftIdentifier(name: "developmentRegion"), valueCodeString: #""\#(developmentRegion)""#) } if let knownAssetTags { let grouped = knownAssetTags.grouped(bySwiftIdentifier: { $0 }) grouped.reportWarningsForDuplicatesAndEmpties(source: "known asset tag", result: "known asset tag", warning: warning) if grouped.uniques.count > 0 { Struct(name: SwiftIdentifier(name: "knownAssetTags"), protocols: [.sequence]) { grouped.uniques.map { tag in LetBinding(name: SwiftIdentifier(name: tag), valueCodeString: #""\#(tag)""#) } generateMakeIterator(names: grouped.uniques.map { SwiftIdentifier(name: $0) }) } } } } } private static func generateMakeIterator(names: [SwiftIdentifier]) -> Function { Function( comments: [], name: .init(name: "makeIterator"), params: [], returnType: .indexingIterator(.string), valueCodeString: "[\(names.map(\.value).joined(separator: ", "))].makeIterator()" ) } } ================================================ FILE: Sources/RswiftParsers/ProjectResources.swift ================================================ // // ProjectResources.swift // // // Created by Tom Lokhorst on 2022-07-29. // import Foundation import XcodeEdit import RswiftResources public enum ResourceType: String, CaseIterable { case image case string case color case data case file case font case nib case segue case storyboard case reuseIdentifier case entitlements case info case id case project } public struct ProjectResources { public let assetCatalogs: [AssetCatalog] public let files: [FileResource] public let fonts: [FontResource] public let images: [ImageResource] public let strings: [StringsTable] public let nibs: [NibResource] public let storyboards: [StoryboardResource] public let infoPlists: [PropertyListResource] public let codeSignEntitlements: [PropertyListResource] public static func parseXcodeproj( xcodeproj: Xcodeproj, targetName: String, rswiftIgnoreURL: URL?, infoPlistFile: URL?, codeSignEntitlements: URL?, sourceTreeURLs: SourceTreeURLs, parseFontsAsFiles: Bool, parseImagesAsFiles: Bool, resourceTypes: [ResourceType], warning: (String) -> Void ) throws -> ProjectResources { let ignoreFile = rswiftIgnoreURL.flatMap { try? IgnoreFile(ignoreFileURL: $0) } ?? IgnoreFile() let buildConfigurations = try xcodeproj.buildConfigurations(forTarget: targetName) var excludeURLs: [URL] = [] let infoPlists: [PropertyListResource] let entitlements: [PropertyListResource] if resourceTypes.contains(.info) { infoPlists = try buildConfigurations.compactMap { config -> PropertyListResource? in guard let url = infoPlistFile else { return nil } excludeURLs.append(url) return try parse(with: warning) { try PropertyListResource.parse(url: url, buildConfigurationName: config.name) } } } else { infoPlists = [] } if resourceTypes.contains(.entitlements) { entitlements = try buildConfigurations.compactMap { config -> PropertyListResource? in guard let url = codeSignEntitlements else { return nil } excludeURLs.append(url) return try parse(with: warning) { try PropertyListResource.parse(url: url, buildConfigurationName: config.name) } } } else { entitlements = [] } let paths = try xcodeproj.resourcePaths(forTarget: targetName) let pathURLs = paths.map { $0.url(with: sourceTreeURLs.url(for:)) } let extraURLs = try xcodeproj.extraResourceURLs(forTarget: targetName, sourceTreeURLs: sourceTreeURLs) // Combine URLs from Xcode project file with extra URLs found by scanning file system var pathAndExtraURLs = Array(Set(pathURLs + extraURLs)) // Find all localized strings files for ignore extension so that those can be removed let localizedExtensions = ["xib", "storyboard", "intentdefinition"] let localizedStringURLs = findLocalizedStrings(inputURLs: pathAndExtraURLs, ignoreExtensions: localizedExtensions) // These file types are compiled, and shouldn't be included as resources // Note that this should be done after finding localized files let sourceCodeExtensions = [ "swift", "h", "m", "mm", "c", "cpp", "metal", "xcdatamodeld", "entitlements", "intentdefinition", ] pathAndExtraURLs.removeAll(where: { sourceCodeExtensions.contains($0.pathExtension) }) // Remove all ignored files, excluded files and localized strings files let urls = pathAndExtraURLs .filter { !ignoreFile.matches(url: $0) } .filter { !excludeURLs.contains($0) } .filter { !localizedStringURLs.contains($0) } return try parseURLs( urls: urls, infoPlists: infoPlists, codeSignEntitlements: entitlements, parseFontsAsFiles: parseFontsAsFiles, parseImagesAsFiles: parseImagesAsFiles, resourceTypes: resourceTypes, warning: warning ) } public static func parseURLs( urls: [URL], infoPlists: [PropertyListResource], codeSignEntitlements: [PropertyListResource], parseFontsAsFiles: Bool, parseImagesAsFiles: Bool, resourceTypes: [ResourceType], warning: (String) -> Void ) throws -> ProjectResources { let assetCatalogs: [AssetCatalog] let files: [FileResource] let fonts: [FontResource] let images: [ImageResource] let strings: [StringsTable] let nibs: [NibResource] let storyboards: [StoryboardResource] if resourceTypes.contains(.image) || resourceTypes.contains(.color) || resourceTypes.contains(.data) { assetCatalogs = try urls .filter { AssetCatalog.supportedExtensions.contains($0.pathExtension) } .compactMap { url in try parse(with: warning) { try AssetCatalog.parse(url: url) } } } else { assetCatalogs = [] } if resourceTypes.contains(.file) { let dontParseFileForFonts = !parseFontsAsFiles let dontParseFileForImages = !parseImagesAsFiles files = try urls .filter { !FileResource.unsupportedExtensions.contains($0.pathExtension) } .filter { !(dontParseFileForFonts && FontResource.supportedExtensions.contains($0.pathExtension)) } .filter { !(dontParseFileForImages && ImageResource.supportedExtensions.contains($0.pathExtension)) } .compactMap { url in try parse(with: warning) { try FileResource.parse(url: url) } } } else { files = [] } if resourceTypes.contains(.font) { fonts = try urls .filter { FontResource.supportedExtensions.contains($0.pathExtension) } .compactMap { url in try parse(with: warning) { try FontResource.parse(url: url) } } } else { fonts = [] } if resourceTypes.contains(.image) { images = try urls .filter { ImageResource.supportedExtensions.contains($0.pathExtension) } .compactMap { url in try parse(with: warning) { try ImageResource.parse(url: url, assetTags: nil) } } } else { images = [] } if resourceTypes.contains(.string) { strings = try urls .filter { StringsTable.supportedExtensions.contains($0.pathExtension) } .compactMap { url in try parse(with: warning) { try StringsTable.parse(url: url) } } } else { strings = [] } if resourceTypes.contains(.nib) { nibs = try urls .filter { NibResource.supportedExtensions.contains($0.pathExtension) } .compactMap { url in try parse(with: warning) { try NibResource.parse(url: url) } } } else { nibs = [] } if resourceTypes.contains(.storyboard) { storyboards = try urls .filter { StoryboardResource.supportedExtensions.contains($0.pathExtension) } .compactMap { url in try parse(with: warning) { try StoryboardResource.parse(url: url) } } } else { storyboards = [] } return ProjectResources( assetCatalogs: assetCatalogs, files: files, fonts: fonts, images: images, strings: strings, nibs: nibs, storyboards: storyboards, infoPlists: infoPlists, codeSignEntitlements: codeSignEntitlements ) } } // Finds strings files for Xcode generated files // // Example 1: // some-dir/Base.lproj/MyIntents.intentdefinition // some-dir/nl.lproj/MyIntents.string // // Example 2: // some-dir/Base.lproj/Main.storyboard // some-dir/nl.lproj/Main.string private func findLocalizedStrings(inputURLs: [URL], ignoreExtensions: [String]) -> [URL] { // Dictionary to map each parent directory to its `.lproj` subdirectories var parentToLprojDirectories = [URL: [URL]]() // Dictionary to keep track of files in each `.lproj` directory var directoryContents = [URL: [URL]]() // Populate the dictionaries for url in inputURLs { let directoryURL = url.deletingLastPathComponent() let parentDirectory = directoryURL.deletingLastPathComponent() if directoryURL.lastPathComponent.hasSuffix(".lproj") { parentToLprojDirectories[parentDirectory, default: []].append(directoryURL) directoryContents[directoryURL, default: []].append(url) } } // Set of URLs to remove var urlsToRemove = Set() // Analyze each group of sibling `.lproj` directories under the same parent for (_, lprojDirectories) in parentToLprojDirectories { var baseFilenameToFileUrls = [String: [URL]]() var baseFilenamesWithIgnoreExtension = Set() // Collect all files by base filename and check for files with an ignoreExtension for directory in lprojDirectories { guard let files = directoryContents[directory] else { continue } for file in files { let baseFilename = file.deletingPathExtension().lastPathComponent let fileExtension = file.pathExtension baseFilenameToFileUrls[baseFilename, default: []].append(file) if ignoreExtensions.contains(fileExtension) { baseFilenamesWithIgnoreExtension.insert(baseFilename) } } } // Determine which files to remove based on the presence of files with an ignoreExtension for baseFilename in baseFilenamesWithIgnoreExtension { if let files = baseFilenameToFileUrls[baseFilename] { for file in files { if file.pathExtension == "strings" { urlsToRemove.insert(file) } } } } } return Array(urlsToRemove) } private func parse(with warning: (String) -> Void, closure: () throws -> R) throws -> R? { do { return try closure() } catch let error as ResourceParsingError { warning(error.description) return nil } } ================================================ FILE: Sources/RswiftParsers/Resources/AssetCatalog+Parser.swift ================================================ // // AssetFolder.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation import RswiftResources // Note: "appiconset" is not loadable by default, so it's not included here private let imageExtensions: Set = ["launchimage", "imageset", "imagestack", "symbolset"] private let colorExtensions: Set = ["colorset"] private let datasetExtensions: Set = ["dataset"] // Ignore everything in folders with these extensions private let ignoredExtensions: Set = ["brandassets", "imagestacklayer", "appiconset"] extension AssetCatalog: SupportedExtensions { static public let supportedExtensions: Set = ["xcassets"] static public func parse(url: URL) throws -> AssetCatalog { guard let basename = url.filenameWithoutExtension else { throw ResourceParsingError("Couldn't extract filename from URL: \(url)") } let directory = try parseDirectory(catalogURL: url) let namespace = try createNamespace(directory: directory, path: []) return AssetCatalog(filename: basename, root: namespace) } static private func parseDirectory(catalogURL: URL) throws -> NamespaceDirectory { let fileManager = FileManager.default func errorHandler(_ url: URL, _ error: Error) -> Bool { assertionFailure((error as NSError).debugDescription) return true } let options: FileManager.DirectoryEnumerationOptions if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { #if !os(Linux) options = [.skipsHiddenFiles, .producesRelativePathURLs] #else options = [.skipsHiddenFiles] #endif } else { options = [.skipsHiddenFiles] } guard let directoryEnumerator = fileManager.enumerator(at: catalogURL, includingPropertiesForKeys: [.isDirectoryKey], options: options, errorHandler: errorHandler) else { throw ResourceParsingError("Supposed AssetCatalog \(catalogURL) can't be enumerated") } let root = NamespaceDirectory() var namespaces: [URL: NamespaceDirectory] = [URL(fileURLWithPath: ".", relativeTo: catalogURL): root] for case let fileURL as URL in directoryEnumerator { guard fileURL.baseURL?.resolvingSymlinksInPath() == catalogURL.resolvingSymlinksInPath() else { throw ResourceParsingError("File \(fileURL) is not in AssetCatalog \(catalogURL)") } let resourceValues = try fileURL.resourceValues(forKeys: [.isDirectoryKey]) let isDirectory = resourceValues.isDirectory! guard let filename = fileURL.filenameWithoutExtension else { throw ResourceParsingError("Missing filename in \(fileURL)") } let pathExtension = fileURL.pathExtension let relativeURL = URL(fileURLWithPath: fileURL.relativePath, relativeTo: catalogURL) var parentURL = relativeURL var parent: NamespaceDirectory? for _ in 0.. Namespace { var subnamespaces: [String: AssetCatalog.Namespace] = [:] for (name, directory) in directory.subnamespaces { let namespace = try createNamespace(directory: directory, path: path + [name]) subnamespaces[name] = namespace } var colors: [ColorResource] = [] for fileURL in directory.colors { let name = fileURL.filenameWithoutExtension! colors.append(.init(name: name, path: path, bundle: .temp)) } var images: [ImageResource] = [] for fileURL in directory.images { let name = fileURL.filenameWithoutExtension! let tags = parseOnDemandResourceTags(directory: fileURL) images.append(.init(name: name, path: path, bundle: .temp, locale: nil, onDemandResourceTags: tags)) } var dataAssets: [DataResource] = [] for fileURL in directory.dataAssets { let name = fileURL.filenameWithoutExtension! let tags = parseOnDemandResourceTags(directory: fileURL) dataAssets.append(.init(name: name, path: path, bundle: .temp, onDemandResourceTags: tags)) } return AssetCatalog.Namespace( subnamespaces: subnamespaces, colors: colors, images: images, dataAssets: dataAssets ) } } private class NamespaceDirectory: CustomDebugStringConvertible { var subnamespaces: [String: NamespaceDirectory] = [:] var colors: [URL] = [] var images: [URL] = [] var dataAssets: [URL] = [] var debugDescription: String { "Directory(subnamespaces: \(subnamespaces), images: \(images)" } } private func parseProvidesNamespace(directory: URL) -> Bool { guard let contents = try? ContentsJson.parse(directory: directory), let providesNamespace = contents.properties.providesNamespace else { return false } return providesNamespace } private func parseOnDemandResourceTags(directory: URL) -> [String]? { guard let contents = try? ContentsJson.parse(directory: directory) else { return nil } return contents.properties.onDemandResourceTags } private struct ContentsJson: Decodable { let properties: Properties struct Properties: Decodable { let providesNamespace: Bool? let onDemandResourceTags: [String]? enum CodingKeys: String, CodingKey { case providesNamespace = "provides-namespace" case onDemandResourceTags = "on-demand-resource-tags" } } static func parse(directory: URL) throws -> ContentsJson { let decoder = JSONDecoder() let contentsFile = URL(string: "Contents.json", relativeTo: directory)! let contentsData = try Data(contentsOf: contentsFile) let contents = try decoder.decode(ContentsJson.self, from: contentsData) return contents } } ================================================ FILE: Sources/RswiftParsers/Resources/FileResource+Parser.swift ================================================ // // FileResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation import RswiftResources extension FileResource { // These are all extensions of resources that are passed to some special compiler step and not directly available at runtime static public let unsupportedExtensions: Set = [ AssetCatalog.supportedExtensions, StringsTable.supportedExtensions, NibResource.supportedExtensions, StoryboardResource.supportedExtensions, ] .reduce([]) { $0.union($1) } static public func parse(url: URL) throws -> FileResource { guard let basename = url.filenameWithoutExtension else { throw ResourceParsingError("Couldn't extract filename from URL: \(url)") } let locale = LocaleReference(url: url) return FileResource( name: basename, pathExtension: url.pathExtension, bundle: .temp, locale: locale ) } } ================================================ FILE: Sources/RswiftParsers/Resources/FontResource+Parser.swift ================================================ // // FontResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation import RswiftResources #if canImport(CoreGraphics) import CoreGraphics #endif extension FontResource: SupportedExtensions { static public let supportedExtensions: Set = ["otf", "ttf"] #if canImport(CoreGraphics) static public func parse(url: URL) throws -> FontResource { guard let dataProvider = CGDataProvider(url: url as CFURL) else { throw ResourceParsingError("Unable to create data provider for font at \(url)") } let font = CGFont(dataProvider) guard let postScriptName = font?.postScriptName else { throw ResourceParsingError("No postscriptName associated to font at \(url)") } return FontResource( name: postScriptName as String, bundle: .temp, filename: url.lastPathComponent ) } #else static public func parse(url: URL) throws -> FontResource { throw ResourceParsingError("Unsupported FontResource.parse") } #endif } ================================================ FILE: Sources/RswiftParsers/Resources/ImageResource+Parser.swift ================================================ // // ImageResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation import RswiftResources extension ImageResource: SupportedExtensions { // See "Supported Image Formats" on https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/ static public let supportedExtensions: Set = ["tiff", "tif", "jpg", "jpeg", "gif", "png", "bmp", "bmpf", "ico", "cur", "xbm"] static public func parse(url: URL, assetTags: [String]?) throws -> ImageResource { let filename = url.lastPathComponent let pathExtension = url.pathExtension guard filename.count > 0 && pathExtension.count > 0 else { throw ResourceParsingError("Filename and/or extension could not be parsed from URL: \(url.absoluteString)") } let locale = LocaleReference(url: url) let extensions = ImageResource.supportedExtensions.joined(separator: "|") let regex = try! NSRegularExpression(pattern: "(~(ipad|iphone))?(@[2,3]x)?\\.(\(extensions))$", options: .caseInsensitive) let fullFileNameRange = NSRange(location: 0, length: filename.count) let pathExtensionToUse = (pathExtension == "png") ? "" : ".\(pathExtension)" let name = regex.stringByReplacingMatches(in: filename, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: fullFileNameRange, withTemplate: pathExtensionToUse) return ImageResource(name: name, path: [], bundle: .temp, locale: locale, onDemandResourceTags: assetTags) } } ================================================ FILE: Sources/RswiftParsers/Resources/Nib+Parser.swift ================================================ // // Nib.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation #if canImport(FoundationXML) import FoundationXML #endif import RswiftResources extension NibResource: SupportedExtensions { static public let supportedExtensions: Set = ["xib"] static public func parse(url: URL) throws -> NibResource { guard let basename = url.filenameWithoutExtension else { throw ResourceParsingError("Couldn't extract filename from URL: \(url)") } let locale = LocaleReference(url: url) guard let parser = XMLParser(contentsOf: url) else { throw ResourceParsingError("Couldn't load file at: '\(url)'") } let parserDelegate = NibParserDelegate() parser.delegate = parserDelegate guard parser.parse() else { throw ResourceParsingError("Invalid XML in file at: '\(url)'") } return NibResource( name: basename, locale: locale, deploymentTarget: parserDelegate.deploymentTarget, rootViews: parserDelegate.rootViews, reusables: parserDelegate.reusables, generatedIds: parserDelegate.generatedIds, usedImageIdentifiers: parserDelegate.usedImageIdentifiers, usedColorResources: parserDelegate.usedColorReferences, usedAccessibilityIdentifiers: parserDelegate.usedAccessibilityIdentifiers, isAppKit: parserDelegate.isAppKit ) } } internal class NibParserDelegate: NSObject, XMLParserDelegate { var isAppKit = false let ignoredRootViewElements = ["placeholder"] var deploymentTarget: DeploymentTarget? var rootViews: [TypeReference] = [] var reusables: [Reusable] = [] var generatedIds: [String] = [] var usedImageIdentifiers: [NameCatalog] = [] var usedColorReferences: [NameCatalog] = [] var usedAccessibilityIdentifiers: [String] = [] // State var isObjectsTagOpened = false; var levelSinceObjectsTagOpened = 0; func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { if isObjectsTagOpened { levelSinceObjectsTagOpened += 1 } if elementName == "objects" { isObjectsTagOpened = true } if let id = attributeDict["id"], isGenerated(id: id) { generatedIds.append(id) } switch elementName { case "deployment": let version = attributeDict["version"] if let platform = attributeDict["identifier"] { deploymentTarget = DeploymentTarget(version: version.flatMap(parseDeploymentTargetVersion(_:)), platform: platform) } case "document": isAppKit = attributeDict["targetRuntime"] == "MacOSX.Cocoa" case "image": if let imageIdentifier = attributeDict["name"] { usedImageIdentifiers.append(NameCatalog(name: imageIdentifier, catalog: attributeDict["catalog"])) } case "color": if let colorName = attributeDict["name"] { usedColorReferences.append(NameCatalog(name: colorName, catalog: attributeDict["catalog"])) } case "accessibility": if let accessibilityIdentifier = attributeDict["identifier"] { usedAccessibilityIdentifiers.append(accessibilityIdentifier) } case "userDefinedRuntimeAttribute": if let accessibilityIdentifier = attributeDict["value"], "accessibilityIdentifier" == attributeDict["keyPath"] && "string" == attributeDict["type"] { usedAccessibilityIdentifiers.append(accessibilityIdentifier) } default: if let rootView = viewWithAttributes(attributeDict, elementName: elementName), levelSinceObjectsTagOpened == 1 && ignoredRootViewElements.allSatisfy({ $0 != elementName }) { rootViews.append(rootView) } if let reusable = reusableFromAttributes(attributeDict, elementName: elementName) { reusables.append(reusable) } } } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { switch elementName { case "objects": isObjectsTagOpened = false; default: if isObjectsTagOpened { levelSinceObjectsTagOpened -= 1 } } } func viewWithAttributes(_ attributeDict: [String : String], elementName: String) -> TypeReference? { let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] let customType = customClass .map { TypeReference(module: ModuleReference(name: customModule), rawName: $0) } return customType ?? (isAppKit ? (macosElementTypes[elementName] ?? .nsView) : (uikitElementToTypes[elementName] ?? .uiView)) } func reusableFromAttributes(_ attributeDict: [String : String], elementName: String) -> Reusable? { guard let reuseIdentifier = attributeDict["reuseIdentifier"] , reuseIdentifier != "" else { return nil } let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] let customType = customClass .map { TypeReference(module: ModuleReference(name: customModule), rawName: $0) } let type = customType ?? (isAppKit ? (macosElementTypes[elementName] ?? .nsView) : (uikitElementToTypes[elementName] ?? .uiView)) return Reusable(identifier: reuseIdentifier, type: type) } } ================================================ FILE: Sources/RswiftParsers/Resources/PropertyList+Parser.swift ================================================ // // PropertyList.swift // R.swift // // Created by Tom Lokhorst on 2018-07-08. // import Foundation import RswiftResources extension PropertyListResource { static public func parse(url: URL, buildConfigurationName: String) throws -> PropertyListResource { guard let nsDictionary = NSDictionary(contentsOf: url), let dictionary = nsDictionary as? [String: Any] else { throw ResourceParsingError("File could not be parsed as InfoPlist from URL: \(url.absoluteString)") } return PropertyListResource(buildConfigurationName: buildConfigurationName, contents: dictionary, url: url) } } ================================================ FILE: Sources/RswiftParsers/Resources/Storyboard+Parser.swift ================================================ // // Storyboard.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation #if canImport(FoundationXML) import FoundationXML #endif import RswiftResources let uikitElementToTypes: [String: TypeReference] = [ "viewController": TypeReference(module: .uiKit, rawName: "UIViewController"), "tabBarController": TypeReference(module: .uiKit, rawName: "UITabBarController"), "glkViewController": TypeReference(module: .custom(name: "GLKit"), rawName: "GLKViewController"), "hostingController": .uiViewController, // TypeReference(module: .custom(name: "SwiftUI"), rawName: "UIHostingController"), "pageViewController": TypeReference(module: .uiKit, rawName: "UIPageViewController"), "tableViewController": TypeReference(module: .uiKit, rawName: "UITableViewController"), "splitViewController": TypeReference(module: .uiKit, rawName: "UISplitViewController"), "navigationController": TypeReference(module: .uiKit, rawName: "UINavigationController"), "avPlayerViewController": TypeReference(module: .custom(name: "AVKit"), rawName: "AVPlayerViewController"), "collectionViewController": TypeReference(module: .uiKit, rawName: "UICollectionViewController"), "lookAroundViewController": TypeReference(module: .custom(name: "MapKit"), rawName: "MKLookAroundViewController"), "view": TypeReference.uiView, "tableViewCell": TypeReference(module: .uiKit, rawName: "UITableViewCell"), "collectionViewCell": TypeReference(module: .uiKit, rawName: "UICollectionViewCell"), "collectionReusableView": TypeReference(module: .uiKit, rawName: "UICollectionReusableView"), ] let macosElementTypes: [String: TypeReference] = [ "viewController": TypeReference(module: .appKit, rawName: "NSViewController"), "tabViewController": TypeReference(module: .appKit, rawName: "NSTabViewController"), "splitViewController": TypeReference(module: .appKit, rawName: "NSSplitViewController"), "hostingController": .nsViewController, // TypeReference(module: .custom(name: "SwiftUI"), rawName: "NSHostingController"), "pagecontroller": TypeReference(module: .appKit, rawName: "NSPageController"), "windowController": TypeReference(module: .appKit, rawName: "NSWindowController"), "lookAroundViewController": TypeReference(module: .custom(name: "MapKit"), rawName: "MKLookAroundViewController"), "view": TypeReference.nsView, "scrollView": TypeReference(module: .appKit, rawName: "NSScrollView"), "tableCellView": TypeReference(module: .appKit, rawName: "NSTableCellView"), "collectionViewItem": TypeReference(module: .appKit, rawName: "NSCollectionViewItem"), ] extension StoryboardResource: SupportedExtensions { static public let supportedExtensions: Set = ["storyboard"] static public func parse(url: URL) throws -> StoryboardResource { guard let basename = url.filenameWithoutExtension else { throw ResourceParsingError("Couldn't extract filename from URL: \(url)") } let locale = LocaleReference(url: url) guard let parser = XMLParser(contentsOf: url) else { throw ResourceParsingError("Couldn't load file at: '\(url)'") } let parserDelegate = StoryboardParserDelegate() parser.delegate = parserDelegate guard parser.parse() else { throw ResourceParsingError("Invalid XML in file at: '\(url)'") } return StoryboardResource( name: basename, locale: locale, deploymentTarget: parserDelegate.deploymentTarget, initialViewControllerIdentifier: parserDelegate.initialViewControllerIdentifier, viewControllers: parserDelegate.viewControllers, viewControllerPlaceholders: parserDelegate.viewControllerPlaceholders, generatedIds: parserDelegate.generatedIds, usedAccessibilityIdentifiers: parserDelegate.usedAccessibilityIdentifiers, usedImageIdentifiers: parserDelegate.usedImageIdentifiers, usedColorResources: parserDelegate.usedColorReferences, reusables: parserDelegate.reusables, isAppKit: parserDelegate.isAppKit ) } } private class StoryboardParserDelegate: NSObject, XMLParserDelegate { var isAppKit = false var initialViewControllerIdentifier: String? var deploymentTarget: DeploymentTarget? var viewControllers: [StoryboardResource.ViewController] = [] var viewControllerPlaceholders: [StoryboardResource.ViewControllerPlaceholder] = [] var generatedIds: [String] = [] var usedImageIdentifiers: [NameCatalog] = [] var usedColorReferences: [NameCatalog] = [] var usedAccessibilityIdentifiers: [String] = [] var reusables: [Reusable] = [] // State var currentViewController: StoryboardResource.ViewController? func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { if let id = attributeDict["id"], isGenerated(id: id) { generatedIds.append(id) } switch elementName { case "deployment": let version = attributeDict["version"] if let platform = attributeDict["identifier"] { deploymentTarget = DeploymentTarget(version: version.flatMap(parseDeploymentTargetVersion(_:)), platform: platform) } case "document": if let initialViewController = attributeDict["initialViewController"] { initialViewControllerIdentifier = initialViewController } isAppKit = attributeDict["targetRuntime"] == "MacOSX.Cocoa" case "segue": let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] let customType = customClass .map { TypeReference(module: ModuleReference(name: customModule), rawName: $0) } if let segueIdentifier = attributeDict["identifier"], let destination = attributeDict["destination"], let kind = attributeDict["kind"] { let type = customType ?? (isAppKit ? .nsStoryboardSegue : .uiStoryboardSegue) let segue = StoryboardResource.Segue(identifier: segueIdentifier, type: type, destination: destination, kind: kind) currentViewController?.segues.append(segue) } case "image": if let imageIdentifier = attributeDict["name"] { usedImageIdentifiers.append(NameCatalog(name: imageIdentifier, catalog: attributeDict["catalog"])) } case "color": if let colorName = attributeDict["name"] { usedColorReferences.append(NameCatalog(name: colorName, catalog: attributeDict["catalog"])) } case "accessibility": if let accessibilityIdentifier = attributeDict["identifier"] { usedAccessibilityIdentifiers.append(accessibilityIdentifier) } case "userDefinedRuntimeAttribute": if let accessibilityIdentifier = attributeDict["value"], "accessibilityIdentifier" == attributeDict["keyPath"] && "string" == attributeDict["type"] { usedAccessibilityIdentifiers.append(accessibilityIdentifier) } case "viewControllerPlaceholder": if let id = attributeDict["id"] , attributeDict["sceneMemberID"] == "viewController" { let placeholder = StoryboardResource.ViewControllerPlaceholder( id: id, storyboardName: attributeDict["storyboardName"], referencedIdentifier: attributeDict["referencedIdentifier"], bundleIdentifier: attributeDict["bundleIdentifier"] ) viewControllerPlaceholders.append(placeholder) } default: if let viewController = viewControllerFromAttributes(attributeDict, elementName: elementName) { currentViewController = viewController } if let reusable = reusableFromAttributes(attributeDict, elementName: elementName) { reusables.append(reusable) } } } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { // We keep the current view controller open to collect segues until the closing scene: // // // ... // // // // if elementName == "scene" { if let currentViewController = currentViewController { viewControllers.append(currentViewController) self.currentViewController = nil } } } func viewControllerFromAttributes(_ attributeDict: [String : String], elementName: String) -> StoryboardResource.ViewController? { guard let id = attributeDict["id"] , attributeDict["sceneMemberID"] == "viewController" else { return nil } let storyboardIdentifier = attributeDict["storyboardIdentifier"] let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] let customType = customClass .map { TypeReference(module: ModuleReference(name: customModule), rawName: $0) } let type = customType ?? (isAppKit ? (macosElementTypes[elementName] ?? .nsViewController) : (uikitElementToTypes[elementName] ?? .uiViewController)) return StoryboardResource.ViewController(id: id, storyboardIdentifier: storyboardIdentifier, type: type, segues: []) } func reusableFromAttributes(_ attributeDict: [String : String], elementName: String) -> Reusable? { guard let reuseIdentifier = attributeDict["reuseIdentifier"] , reuseIdentifier != "" else { return nil } let customModuleProvider = attributeDict["customModuleProvider"] let customModule = (customModuleProvider == "target") ? nil : attributeDict["customModule"] let customClass = attributeDict["customClass"] let customType = customClass .map { TypeReference(module: ModuleReference(name: customModule), rawName: $0) } let type = customType ?? (isAppKit ? (macosElementTypes[elementName] ?? .nsView) : (uikitElementToTypes[elementName] ?? .uiView)) return Reusable(identifier: reuseIdentifier, type: type) } } ================================================ FILE: Sources/RswiftParsers/Resources/StringsTable+Parser.swift ================================================ // // LocalizableStrings.swift // R.swift // // Created by Tom Lokhorst on 2016-04-24. // import Foundation import RswiftResources extension StringsTable: SupportedExtensions { static public let supportedExtensions: Set = ["strings", "stringsdict"] static public func parse(url: URL) throws -> StringsTable { let warning: (String) -> Void = { print("warning: [R.swift]", $0) } guard let basename = url.filenameWithoutExtension else { throw ResourceParsingError("Couldn't extract filename from URL: \(url)") } // Get locale from url (second to last component) let locale = LocaleReference(url: url) // Check to make sure url can be parsed as a dictionary guard let nsDictionary = NSDictionary(contentsOf: url) else { throw ResourceParsingError("File could not be parsed as a strings file: \(url.absoluteString)") } // Parse dicts from NSDictionary let dictionary: [StringsTable.Key: StringsTable.Value] switch url.pathExtension { case "strings": dictionary = try parseStrings(nsDictionary, source: locale.debugDescription(filename: "\(basename).strings")) case "stringsdict": dictionary = try parseStringsdict(nsDictionary, source: locale.debugDescription(filename: "\(basename).stringsdict"), warning: warning) default: throw ResourceParsingError("File could not be parsed as a strings file: \(url.absoluteString)") } return StringsTable(filename: basename, locale: locale, dictionary: dictionary) } } private func parseStrings(_ nsDictionary: NSDictionary, source: String) throws -> [StringsTable.Key: StringsTable.Value] { var dictionary: [StringsTable.Key: StringsTable.Value] = [:] for (key, obj) in nsDictionary { if let key = key as? String, let val = obj as? String { var params: [StringParam] = [] for part in FormatPart.formatParts(formatString: val) { switch part { case .reference: throw ResourceParsingError("Non-specifier reference in \(source): \(key) = \(val)") case .spec(let formatSpecifier): params.append(StringParam(name: nil, spec: formatSpecifier)) } } dictionary[key] = .init(params: params, originalValue: val) } else { throw ResourceParsingError("Non-string value in \(source): \(key) = \(obj)") } } return dictionary } private func parseStringsdict(_ nsDictionary: NSDictionary, source: String, warning: (String) -> Void) throws -> [StringsTable.Key: StringsTable.Value] { var dictionary: [StringsTable.Key: StringsTable.Value] = [:] for (key, obj) in nsDictionary { if let key = key as? String, let dict = obj as? [String: AnyObject] { guard let localizedFormat = dict["NSStringLocalizedFormatKey"] as? String else { continue } do { let params = try parseStringsdictParams(localizedFormat, dict: dict) dictionary[key] = .init(params: params, originalValue: localizedFormat) } catch let error as ResourceParsingError { warning("\(error.description) in '\(key)' \(source)") } } else { throw ResourceParsingError("Non-dict value in \(source): \(key) = \(obj)") } } return dictionary } private func parseStringsdictParams(_ format: String, dict: [String: AnyObject]) throws -> [StringParam] { var params: [StringParam] = [] let parts = FormatPart.formatParts(formatString: format) for part in parts { switch part { case .reference(let reference): params += try lookup(key: reference, in: dict) case .spec(let formatSpecifier): params.append(StringParam(name: nil, spec: formatSpecifier)) } } return params } private func lookup(key: String, in dict: [String: AnyObject], processedReferences: [String] = []) throws -> [StringParam] { var processedReferences = processedReferences if processedReferences.contains(key) { throw ResourceParsingError("Cyclic reference '\(key)'") } processedReferences.append(key) guard let obj = dict[key], let nested = obj as? [String: AnyObject] else { throw ResourceParsingError("Missing reference '\(key)'") } guard let formatSpecType = nested["NSStringFormatSpecTypeKey"] as? String, let formatValueType = nested["NSStringFormatValueTypeKey"] as? String , formatSpecType == "NSStringPluralRuleType" else { throw ResourceParsingError("Incorrect reference '\(key)'") } guard let formatSpecifier = FormatSpecifier(formatString: formatValueType) else { throw ResourceParsingError("Incorrect reference format specifier \"\(formatValueType)\" for '\(key)'") } var results = [StringParam(name: nil, spec: formatSpecifier)] let stringValues = nested.values.compactMap { $0 as? String }.sorted() for stringValue in stringValues { var alternative: [StringParam] = [] let parts = FormatPart.formatParts(formatString: stringValue) for part in parts { switch part { case .reference(let reference): alternative += try lookup(key: reference, in: dict, processedReferences: processedReferences) case .spec(let formatSpecifier): alternative.append(StringParam(name: key, spec: formatSpecifier)) } } if let unified = results.unify(alternative) { results = unified } else { throw ResourceParsingError("Can't unify '\(key)'") } } return results } ================================================ FILE: Sources/RswiftParsers/Shared/Bundle+Extensions.swift ================================================ // // Bundle+Extensions.swift // // // Created by Tom Lokhorst on 2022-09-30. // import Foundation extension Bundle { public static let temp: Bundle = .main } ================================================ FILE: Sources/RswiftParsers/Shared/DeploymentTarget+Parser.swift ================================================ // // DeploymentTarget+Parser.swift // // // Created by Tom Lokhorst on 2022-07-10. // import RswiftResources func parseDeploymentTargetVersion(_ str: String) -> DeploymentTarget.Version? { guard str.count > 2 else { return nil } guard let i = Int(str) else { return nil } let s = String(i, radix: 16) guard let major = Int(s[.. [FormatPart] { createFormatParts(formatString) } } // https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1 extension FormatSpecifier { // Convenience initializer, uses last character of string, // ignoring lengt modifiers, e.g. "lld" public init?(formatString string: String) { guard let last = string.last else { return nil } self.init(formatChar: last) } public init?(formatChar char: Swift.Character) { let lcChar = Swift.String(char).lowercased().first! switch lcChar { case "@": self = .object case "a", "e", "f", "g": self = .double case "d", "i": self = .int case "o", "u", "x": self = .uInt case "c": self = .character case "s": self = .cStringPointer case "p": self = .voidPointer default: return nil } } } private let referenceRegEx: NSRegularExpression = { do { return try NSRegularExpression(pattern: "#@([^@]+)@", options: [.caseInsensitive]) } catch { fatalError("Error building the regular expression used to match reference") } }() private let formatTypesRegEx: NSRegularExpression = { let pattern_int = "(?:h|hh|l|ll|q|z|t|j)?([dioux])" // %d/%i/%o/%u/%x with their optional length modifiers like in "%lld" let pattern_float = "[aefg]" let position = "([1-9]\\d*\\$)?" // like in "%3$" to make positional specifiers let precision = "[-+]?\\d*(?:\\.\\d*)?" // precision like in "%1.2f" or "%012.10" let reference = "#@([^@]+)@" // reference to NSStringFormatSpecType in .stringsdict do { return try NSRegularExpression(pattern: "(? [.Spec(.Int), .Spec(.String), .Reference("named")] private func createFormatParts(_ formatString: String) -> [FormatPart] { let nsString = formatString as NSString let range = NSRange(location: 0, length: nsString.length) // Extract the list of chars (conversion specifiers) and their optional positional specifier let chars = formatTypesRegEx.matches(in: formatString, options: [], range: range).map { match -> (String, Int?) in let range: NSRange if match.range(at: 3).location != NSNotFound { // [dioux] are in range #3 because in #2 there may be length modifiers (like in "lld") range = match.range(at: 3) } else { // otherwise, no length modifier, the conversion specifier is in #2 range = match.range(at: 2) } let char = nsString.substring(with: range) let posRange = match.range(at: 1) if posRange.location == NSNotFound { // No positional specifier return (char, nil) } else { // Remove the "$" at the end of the positional specifier, and convert to Int let posRange1 = NSRange(location: posRange.location, length: posRange.length-1) let pos = nsString.substring(with: posRange1) return (char, Int(pos)) } } // Build up params array var params = [FormatPart]() var nextNonPositional = 1 for (str, pos) in chars { let insertionPos: Int if let pos = pos { insertionPos = pos } else { insertionPos = nextNonPositional nextNonPositional += 1 } let param: FormatPart? if let reference = referenceRegEx.firstSubstring(input: str) { param = FormatPart.reference(reference) } else if let char = str.first, let fs = FormatSpecifier(formatChar: char) { param = FormatPart.spec(fs) } else { param = nil } if let param = param { if insertionPos > 0 { while params.count <= insertionPos - 1 { params.append(FormatPart.spec(FormatSpecifier.topType)) } params[insertionPos - 1] = param } } } return params } extension NSRegularExpression { fileprivate func firstSubstring(input: String) -> String? { let nsInput = input as NSString let inputRange = NSMakeRange(0, nsInput.length) guard let match = self.firstMatch(in: input, options: [], range: inputRange) else { return nil } guard match.numberOfRanges > 0 else { return nil } let range = match.range(at: 1) return nsInput.substring(with: range) } } ================================================ FILE: Sources/RswiftParsers/Shared/GeneratedId.swift ================================================ // // GeneratedId.swift // R.swift // // Created by Tom Lokhorst on 2022-07-15. // import Foundation private let generatedIdRegex = try! NSRegularExpression(pattern: #"^\w\w\w-\w\w-\w\w\w$"#) func isGenerated(id input: String) -> Bool { generatedIdRegex.firstMatch(in: input, range: NSRange(location: 0, length: input.utf16.count)) != nil } ================================================ FILE: Sources/RswiftParsers/Shared/Glob.swift ================================================ // // Created by Eric Firestone on 3/22/16. // Copyright © 2016 Square, Inc. All rights reserved. // Released under the Apache v2 License. // // Adapted from https://gist.github.com/blakemerryman/76312e1cbf8aec248167 // Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3 import Foundation #if os(Linux) import Glibc #else import Darwin #endif public let GlobBehaviorBashV3 = Glob.Behavior( supportsGlobstar: false, includesFilesFromRootOfGlobstar: false, includesDirectoriesInResults: true, includesFilesInResultsIfTrailingSlash: false ) public let GlobBehaviorBashV4 = Glob.Behavior( supportsGlobstar: true, // Matches Bash v4 with "shopt -s globstar" option includesFilesFromRootOfGlobstar: true, includesDirectoriesInResults: true, includesFilesInResultsIfTrailingSlash: false ) public let GlobBehaviorGradle = Glob.Behavior( supportsGlobstar: true, includesFilesFromRootOfGlobstar: true, includesDirectoriesInResults: false, includesFilesInResultsIfTrailingSlash: true ) /** Finds files on the file system using pattern matching. */ public class Glob: Collection { /** * Different glob implementations have different behaviors, so the behavior of this * implementation is customizable. */ public struct Behavior: Sendable { // If true then a globstar ("**") causes matching to be done recursively in subdirectories. // If false then "**" is treated the same as "*" let supportsGlobstar: Bool // If true the results from the directory where the globstar is declared will be included as well. // For example, with the pattern "dir/**/*.ext" the fie "dir/file.ext" would be included if this // property is true, and would be omitted if it's false. let includesFilesFromRootOfGlobstar: Bool // If false then the results will not include directory entries. This does not affect recursion depth. let includesDirectoriesInResults: Bool // If false and the last characters of the pattern are "**/" then only directories are returned in the results. let includesFilesInResultsIfTrailingSlash: Bool } public static let defaultBehavior = GlobBehaviorBashV4 public static let defaultBlacklistedDirectories = ["node_modules", "Pods"] private var isDirectoryCache = [String: Bool]() public let behavior: Behavior public let blacklistedDirectories: [String] var paths = [String]() public var startIndex: Int { return paths.startIndex } public var endIndex: Int { return paths.endIndex } /// Initialize a glob /// /// - Parameters: /// - pattern: The pattern to use when building the list of matching directories. /// - behavior: See individual descriptions on `Glob.Behavior` values. /// - blacklistedDirectories: An array of directories to ignore at the root level of the project. public init(pattern: String, behavior: Behavior = Glob.defaultBehavior, blacklistedDirectories: [String] = defaultBlacklistedDirectories) { self.behavior = behavior self.blacklistedDirectories = blacklistedDirectories var adjustedPattern = pattern let hasTrailingGlobstarSlash = pattern.hasSuffix("**/") var includeFiles = !hasTrailingGlobstarSlash if behavior.includesFilesInResultsIfTrailingSlash { includeFiles = true if hasTrailingGlobstarSlash { // Grab the files too. adjustedPattern += "*" } } let patterns = behavior.supportsGlobstar ? expandGlobstar(pattern: adjustedPattern) : [adjustedPattern] for pattern in patterns { var gt = glob_t() if executeGlob(pattern: pattern, gt: >) { populateFiles(gt: gt, includeFiles: includeFiles) } globfree(>) } paths = Array(Set(paths)).sorted { lhs, rhs in lhs.compare(rhs) != ComparisonResult.orderedDescending } clearCaches() } // MARK: Subscript Support public subscript(i: Int) -> String { return paths[i] } // MARK: Protocol of IndexableBase public func index(after i: Glob.Index) -> Glob.Index { return i + 1 } // MARK: Private private var globalFlags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK private func executeGlob(pattern: UnsafePointer, gt: UnsafeMutablePointer) -> Bool { return 0 == glob(pattern, globalFlags, nil, gt) } private func expandGlobstar(pattern: String) -> [String] { guard pattern.contains("**") else { return [pattern] } var results = [String]() var parts = pattern.components(separatedBy: "**") let firstPart = parts.removeFirst() var lastPart = parts.joined(separator: "**") let fileManager = FileManager.default var directories: [String] do { directories = try fileManager.contentsOfDirectory(atPath: firstPart).compactMap { subpath -> [String]? in if blacklistedDirectories.contains(subpath) { return nil } let firstLevelPath = NSString(string: firstPart).appendingPathComponent(subpath) if isDirectory(path: firstLevelPath) { var subDirs: [String] = try fileManager.subpathsOfDirectory(atPath: firstLevelPath).compactMap { subpath -> String? in let fullPath = NSString(string: firstLevelPath).appendingPathComponent(subpath) return isDirectory(path: fullPath) ? fullPath : nil } subDirs.append(firstLevelPath) return subDirs } else { return nil } }.joined().map { $0 } } catch { directories = [] print("Error parsing file system item: \(error)") } if behavior.includesFilesFromRootOfGlobstar { // Check the base directory for the glob star as well. directories.insert(firstPart, at: 0) // Include the globstar root directory ("dir/") in a pattern like "dir/**" or "dir/**/" if lastPart.isEmpty { results.append(firstPart) } } if lastPart.isEmpty { lastPart = "*" } for directory in directories { let partiallyResolvedPattern = NSString(string: directory).appendingPathComponent(lastPart) results.append(contentsOf: expandGlobstar(pattern: partiallyResolvedPattern)) } return results } private func isDirectory(path: String) -> Bool { if let isDirectory = isDirectoryCache[path] { return isDirectory } var isDirectoryBool = ObjCBool(false) let isDirectory = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectoryBool) && isDirectoryBool.boolValue isDirectoryCache[path] = isDirectory return isDirectory } private func clearCaches() { isDirectoryCache.removeAll() } private func populateFiles(gt: glob_t, includeFiles: Bool) { let includeDirectories = behavior.includesDirectoriesInResults for i in 0.. Bool { return ignoredURLs.contains(url) && !explicitlyIncludedURLs.contains(url) } static private func isPattern(potentialPattern: String) -> Bool { // Check for empty line if potentialPattern.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { return false } // Check for commented line if potentialPattern.trimmingCharacters(in: .whitespacesAndNewlines).first == "#" { return false } return true } static private func isExplicitlyIncludedPattern(potentialPattern: String) -> Bool { // Check for explicitly included line guard potentialPattern.trimmingCharacters(in: .whitespacesAndNewlines).first == "!" else { return false } return true } static private func expandPattern(_ pattern: String, workingDirectory: URL) -> [URL] { let globPattern = workingDirectory.path + "/" + pattern // This is a glob pattern, so we don't use URL here let filePaths = IgnoreFile.listFilePaths(pattern: globPattern) let urls = filePaths.map { URL(fileURLWithPath: $0).standardizedFileURL } return urls } static private func listFilePaths(pattern: String) -> [String] { guard !pattern.isEmpty else { return [] } return Glob(pattern: pattern).paths } } ================================================ FILE: Sources/RswiftParsers/Shared/ResourceParsingError.swift ================================================ // // ResourceParsingError.swift // R.swift // // Created by Tom Lokhorst on 2021-04-16. // import Foundation public struct ResourceParsingError: Error { public var description: String public init(_ description: String) { self.description = description } } ================================================ FILE: Sources/RswiftParsers/Shared/SourceTreeURLs.swift ================================================ // // SourceTreeURLs.swift // // // Created by Tom Lokhorst on 2022-07-29. // import Foundation import XcodeEdit public struct SourceTreeURLs { public let builtProductsDirURL: URL public let developerDirURL: URL public let sourceRootURL: URL public let sdkRootURL: URL public let platformURL: URL public init(builtProductsDirURL: URL, developerDirURL: URL, sourceRootURL: URL, sdkRootURL: URL, platformURL: URL) { self.builtProductsDirURL = builtProductsDirURL self.developerDirURL = developerDirURL self.sourceRootURL = sourceRootURL self.sdkRootURL = sdkRootURL self.platformURL = platformURL } public func url(for sourceTreeFolder: SourceTreeFolder) -> URL { switch sourceTreeFolder { case .buildProductsDir: return builtProductsDirURL case .developerDir: return developerDirURL case .sdkRoot: return sdkRootURL case .sourceRoot: return sourceRootURL case .platformDir: return platformURL } } } ================================================ FILE: Sources/RswiftParsers/Shared/SupportedExtensions.swift ================================================ // // SupportedExtensions.swift // R.swift // // Created by Mathijs Kadijk on 10-12-15. // import Foundation public protocol SupportedExtensions { static var supportedExtensions: Set { get } } extension SupportedExtensions { static func throwIfUnsupportedExtension(_ url: URL) throws { let pathExtension = url.pathExtension if !supportedExtensions.contains(pathExtension.lowercased()) { throw ResourceUnsupportedExtensionError(url: url, typeName: "\(Self.self)", supportedExtensions: supportedExtensions) } } } public struct ResourceUnsupportedExtensionError: LocalizedError { public let url: URL public let typeName: String public let supportedExtensions: Set public init(url: URL, typeName: String, supportedExtensions: Set) { self.url = url self.typeName = typeName self.supportedExtensions = supportedExtensions } public var errorDescription: String { "URL '\(url)' has not supported extension, for type '\(typeName)', supported extensions \(supportedExtensions.joined(separator: ", "))" } } ================================================ FILE: Sources/RswiftParsers/Shared/TypeReference+Extensions.swift ================================================ // // TypeReference+Extensions.swift // // // Created by Tom Lokhorst on 2022-06-24. // import Foundation import RswiftResources extension TypeReference { static let nsView = TypeReference(module: .appKit, rawName: "NSView") static let nsViewController = TypeReference(module: .appKit, rawName: "NSViewController") static let nsStoryboardSegue = TypeReference(module: .appKit, rawName: "NSStoryboardSegue") static let uiView = TypeReference(module: .uiKit, rawName: "UIView") static let uiViewController = TypeReference(module: .uiKit, rawName: "UIViewController") static let uiStoryboardSegue = TypeReference(module: .uiKit, rawName: "UIStoryboardSegue") } ================================================ FILE: Sources/RswiftParsers/Shared/URL+Extensions.swift ================================================ // // URL+Extensions.swift // RswiftResources // // Created by Tom Lokhorst on 2021-04-25. // import Foundation internal extension URL { var filenameWithoutExtension: String? { let name = self.deletingPathExtension().lastPathComponent return name == "" ? nil : name } } ================================================ FILE: Sources/RswiftParsers/Shared/Xcodeproj.swift ================================================ // // Xcodeproj.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // From: https://github.com/mac-cain13/R.swift // import Foundation import XcodeEdit import RswiftResources public struct Xcodeproj: SupportedExtensions { static public let supportedExtensions: Set = ["xcodeproj"] private let projectFile: XCProjectFile public let developmentRegion: String public let knownAssetTags: [String]? public init(url: URL, warning: (String) -> Void) throws { try Xcodeproj.throwIfUnsupportedExtension(url) let projectFile: XCProjectFile // Parse project file do { do { projectFile = try XCProjectFile(xcodeprojURL: url, ignoreReferenceErrors: false) } catch let error as ProjectFileError { warning(error.localizedDescription) projectFile = try XCProjectFile(xcodeprojURL: url, ignoreReferenceErrors: true) } } catch { throw ResourceParsingError("Project file at '\(url)' could not be parsed, is this a valid Xcode project file ending in *.xcodeproj?\n\(error.localizedDescription)") } self.projectFile = projectFile self.developmentRegion = projectFile.project.developmentRegion self.knownAssetTags = projectFile.project.knownAssetTags } public var allTargets: [PBXTarget] { projectFile.project.targets.compactMap { $0.value } } private func findTarget(name: String) throws -> PBXTarget { // Look for target in project file let allTargets = projectFile.project.targets.compactMap { $0.value } guard let target = allTargets.filter({ $0.name == name }).first else { let availableTargets = allTargets.compactMap { $0.name }.joined(separator: ", ") throw ResourceParsingError("Target '\(name)' not found in project file, available targets are: \(availableTargets)") } return target } public func resourcePaths(forTarget targetName: String) throws -> [Path] { let target = try findTarget(name: targetName) let resourcesFileRefs = target.buildPhases .compactMap { $0.value as? PBXResourcesBuildPhase } .flatMap { $0.files } .compactMap { $0.value?.fileRef } let fileRefPaths = resourcesFileRefs .compactMap { $0.value as? PBXFileReference } .compactMap { $0.fullPath } let variantGroupPaths = resourcesFileRefs .compactMap { $0.value as? PBXVariantGroup } .flatMap { $0.fileRefs } .compactMap { $0.value?.fullPath } return fileRefPaths + variantGroupPaths } // Returns extra resource URLs by extracting fileSystemSynchronizedGroups and scanning file system recursively. // Handles exceptions configured in fileSystemSynchronizedGroups func extraResourceURLs(forTarget targetName: String, sourceTreeURLs: SourceTreeURLs) throws -> [URL] { var resultURLs: [URL] = [] let (dirs, extraFiles, extraLocalizedFiles, exceptionPaths) = try fileSystemSynchronizedGroups(forTarget: targetName) for dir in dirs { let url = dir.url(with: sourceTreeURLs.url(for:)) resultURLs.append(contentsOf: recursiveContentsOf(url: url)) } let extraURLs = extraFiles.map { $0.url(with: sourceTreeURLs.url(for:)) } resultURLs.append(contentsOf: extraURLs) let extraLocalizedURLs = try extraLocalizedFiles .map { $0.url(with: sourceTreeURLs.url(for:)) } .flatMap { try expandLocalizedFileURL($0) } resultURLs.append(contentsOf: extraLocalizedURLs) let exceptionURLs = exceptionPaths.map { $0.url(with: sourceTreeURLs.url(for:)) } resultURLs.removeAll(where: { exceptionURLs.contains($0) }) let xcodeFilenames = ["Info.plist"] resultURLs.removeAll(where: { xcodeFilenames.contains($0.lastPathComponent) }) return resultURLs } // For target, extract file system groups. // Returns: // - directories to scan // - known files (based on exceptions of other targets) // - known files that are localized (inside .lproj directory) (based on exceptions of other targets) // - known exception files (based on exceptions of this target) func fileSystemSynchronizedGroups(forTarget targetName: String) throws -> (dirs: [Path], extraFiles: [Path], extraLocalizedFiles: [Path], exceptionPaths: [Path]) { var dirs: [Path] = [] var extraFiles: [Path] = [] var extraLocalizedFiles: [Path] = [] var exceptionPaths: [Path] = [] let target = try findTarget(name: targetName) guard let mainGroup = projectFile.project.mainGroup.value else { throw ResourceParsingError("Project file is missing mainGroup") } let targetFileSystemSynchronizedGroups = target.fileSystemSynchronizedGroups?.compactMap(\.value?.id) ?? [] let allFileSystemSynchronizedGroups = mainGroup.fileSystemSynchronizedGroups() for synchronizedGroup in allFileSystemSynchronizedGroups { guard let path = synchronizedGroup.fullPath else { continue } let exceptions = (synchronizedGroup.exceptions ?? []).compactMap(\.value) if targetFileSystemSynchronizedGroups.contains(synchronizedGroup.id) { dirs.append(path) for exception in exceptions { guard exception.target.id == target.id else { continue } let files = exception.membershipExceptions ?? [] let exPaths = files.map { file in path.map { dir in "\(dir)/\(file)" } } exceptionPaths.append(contentsOf: exPaths) } } else { for exception in exceptions { guard exception.target.id == target.id else { continue } let files = exception.membershipExceptions ?? [] // Xcode 16 project format uses "/Localized: ", earlier Xcode versions use "/Localized/" let localizeds = ["/Localized: ", "/Localized"] for file in files { if let localized = localizeds.first(where: { file.hasPrefix($0) }) { let cleanFile = String(file.dropFirst(localized.count)) let exPath = path.map { dir in "\(dir)/\(cleanFile)" } extraLocalizedFiles.append(exPath) } else { let exPath = path.map { dir in "\(dir)/\(file)" } extraFiles.append(exPath) } } } } } return (dirs: dirs, extraFiles: extraFiles, extraLocalizedFiles: extraLocalizedFiles, exceptionPaths: exceptionPaths) } public func buildConfigurations(forTarget targetName: String) throws -> [XCBuildConfiguration] { let target = try findTarget(name: targetName) guard let buildConfigurationList = target.buildConfigurationList.value else { return [] } let buildConfigurations = buildConfigurationList.buildConfigurations .compactMap { $0.value } return buildConfigurations } } extension PBXReference { func fileSystemSynchronizedGroups() -> [PBXFileSystemSynchronizedRootGroup] { if let root = self as? PBXFileSystemSynchronizedRootGroup { return [root] } else if let group = self as? PBXGroup { let children = group.children.compactMap(\.value) return children.flatMap { $0.fileSystemSynchronizedGroups() } } else { return [] } } } extension Path { func map(_ transform: (String) -> String) -> Path { switch self { case let .absolute(str): return .absolute(transform(str)) case let .relativeTo(folder, str): return .relativeTo(folder, transform(str)) } } } // Returns all(*) recursive files/directories that that are found on file system in specified directory. // (*): xcassets are returned once, no deeper contents. private func recursiveContentsOf(url: URL) -> [URL] { var resultURLs: [URL] = [] var excludedExtensions = AssetCatalog.supportedExtensions excludedExtensions.insert("bundle") if excludedExtensions.contains(url.pathExtension) { return [] } let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles]) // Enumerator gives directories in hierarchical order (I assume/hope). // If we hit a directory that is an .xcassets, we don't want to scan deeper, so we add it to the skipDirectories. // Subsequent files/directories that have a skipDirectory as prefix are ignored. var skipDirectories: [URL] = [] guard let enumerator else { return [] } for case let contentURL as URL in enumerator { let shouldSkip = skipDirectories.contains { skip in contentURL.path.hasPrefix(skip.path) } if shouldSkip { continue } if excludedExtensions.contains(contentURL.pathExtension) { resultURLs.append(contentURL) skipDirectories.append(contentURL) continue } if contentURL.hasDirectoryPath { if excludedExtensions.contains(contentURL.pathExtension) { resultURLs.append(contentURL) skipDirectories.append(contentURL) } } else { resultURLs.append(contentURL) } } return resultURLs } // Returns the localized versions of an input URL // Example: some-dir/Home.strings // Becomes: some-dir/Base.lproj/Home.strings, some-dir/nl.lproj/Home.strings private func expandLocalizedFileURL(_ url: URL) throws -> [URL] { let fileManager = FileManager.default var localizedURLs: [URL] = [] // Get the directory path and filename from the input URL let directory = url.deletingLastPathComponent() let filename = url.lastPathComponent // Scan the directory for contents let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) // Filter the contents to find directories with the ".lproj" suffix for item in contents { if item.pathExtension == "lproj" { // Construct the localized file path by appending the filename to the `.lproj` folder path let localizedFileURL = item.appendingPathComponent(filename) // Check if the localized file exists if fileManager.fileExists(atPath: localizedFileURL.path) { localizedURLs.append(localizedFileURL) } } } return localizedURLs } ================================================ FILE: Sources/RswiftResources/AssetCatalog.swift ================================================ // // AssetCatalog.swift // RswiftResources // // Created by Tom Lokhorst on 2021-06-13. // import Foundation public struct AssetCatalog: Sendable { public let filename: String public let root: Namespace public init(filename: String, root: Namespace) { self.filename = filename self.root = root } } extension AssetCatalog { public struct Namespace: Sendable { public var subnamespaces: [String: Namespace] = [:] public var colors: [ColorResource] = [] public var images: [ImageResource] = [] public var dataAssets: [DataResource] = [] public init() { } public init( subnamespaces: [String: Namespace], colors: [ColorResource], images: [ImageResource], dataAssets: [DataResource] ) { self.subnamespaces = subnamespaces self.colors = colors self.images = images self.dataAssets = dataAssets } public mutating func merge(_ other: Namespace) { self.subnamespaces = self.subnamespaces.merging(other.subnamespaces) { $0.merging($1) } self.colors += other.colors self.images += other.images self.dataAssets += other.dataAssets } public func merging(_ other: Namespace) -> Namespace { var new = self new.merge(other) return new } } } ================================================ FILE: Sources/RswiftResources/ColorResource.swift ================================================ // // ColorResource.swift // // // Created by Tom Lokhorst on 2022-07-23. // import Foundation public struct ColorResource: Sendable { public let name: String public let path: [String] public let bundle: Bundle public init(name: String, path: [String], bundle: Bundle) { self.name = name self.path = path self.bundle = bundle } } ================================================ FILE: Sources/RswiftResources/DataResource.swift ================================================ // // DataResource.swift // // // Created by Tom Lokhorst on 2022-07-23. // import Foundation public struct DataResource: Sendable { public let name: String public let path: [String] public let bundle: Bundle public let onDemandResourceTags: [String]? public init(name: String, path: [String], bundle: Bundle, onDemandResourceTags: [String]?) { self.name = name self.path = path self.bundle = bundle self.onDemandResourceTags = onDemandResourceTags } } ================================================ FILE: Sources/RswiftResources/FileResource.swift ================================================ // // FileResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation public struct FileResource: Sendable { public let name: String public let pathExtension: String public let bundle: Bundle public let locale: LocaleReference? public init(name: String, pathExtension: String, bundle: Bundle, locale: LocaleReference?) { self.name = name self.pathExtension = pathExtension self.bundle = bundle self.locale = locale } public var filename: String { name.isEmpty || pathExtension.isEmpty ? "\(name)\(pathExtension)" : "\(name).\(pathExtension)" } } ================================================ FILE: Sources/RswiftResources/FontResource.swift ================================================ // // FontResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation public struct FontResource: Sendable { public let name: String public let bundle: Bundle public let filename: String public init(name: String, bundle: Bundle, filename: String) { self.name = name self.bundle = bundle self.filename = filename } } ================================================ FILE: Sources/RswiftResources/ImageResource.swift ================================================ // // ImageResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation public struct ImageResource: Sendable { public let name: String public let path: [String] public let bundle: Bundle public let locale: LocaleReference? public let onDemandResourceTags: [String]? public init(name: String, path: [String], bundle: Bundle, locale: LocaleReference?, onDemandResourceTags: [String]?) { self.name = name self.path = path self.bundle = bundle self.locale = locale self.onDemandResourceTags = onDemandResourceTags } } ================================================ FILE: Sources/RswiftResources/Integrations/Bundle+Extensions.swift ================================================ // // Bundle+Extensions.swift // R.swift // // Created by Tom Lokhorst on 2022-07-30. // import Foundation public protocol PlistPathComponent { typealias Key = String typealias Index = Int } extension PlistPathComponent.Key: PlistPathComponent {} extension PlistPathComponent.Index: PlistPathComponent {} extension Bundle { /// Returns the string associated with the specified path + key in the receiver's information property list. public func infoDictionaryString(path: [PlistPathComponent], key: PlistPathComponent.Key? = nil) -> String? { var currentObject: Any? = infoDictionary for step in path { if let currentDict = currentObject as? [String: Any], let key = step as? String { // If the current object is a dictionary, move to the next step using the dictionary key currentObject = currentDict[key] } else if let currentArray = currentObject as? [Any], let index = step as? Int, currentArray.indices.contains(index) { // If the current object is an array, and the step is a valid index, move to the array element currentObject = currentArray[index] } else { // If the path leads to an invalid object type or out of bounds index, return nil return nil } } // Attempt to extract a string from the final object using the provided key, else if key == nil, assume // we have arrived at a string value. if let dict = currentObject as? [String: Any], let key = key { return dict[key] as? String } else if key == nil, let value = currentObject as? String { return value } return nil } /// Find first bundle and locale for which the table exists internal func firstBundleAndLocale(tableName: String, preferredLanguages: [String]) -> (bundle: Foundation.Bundle, locale: Foundation.Locale)? { let hostingBundle = self // Filter preferredLanguages to localizations, use first locale var languages = preferredLanguages .map { Foundation.Locale(identifier: $0) } .prefix(1) .flatMap { locale -> [String] in let language: String? if #available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) { // Xcode 14 doesn't recognize `Locale.language`, Xcode 14.1 does know `Locale.language` // Xcode 14.1 is first to ship with swift 5.7.1 #if swift(>=5.7.1) && !os(Linux) language = locale.language.languageCode?.identifier #else language = locale.languageCode #endif } else { language = locale.languageCode } if hostingBundle.localizations.contains(locale.identifier) { if let language = language, hostingBundle.localizations.contains(language) { return [locale.identifier, language] } else { return [locale.identifier] } } else if let language = language, hostingBundle.localizations.contains(language) { return [language] } else { return [] } } if languages.isEmpty { // If there's no languages, use development language as backstop if let developmentLocalization = hostingBundle.developmentLocalization { languages = [developmentLocalization] } } else { // Insert Base as second item (between locale identifier and languageCode) languages.insert("Base", at: 1) // Add development language as backstop if let developmentLocalization = hostingBundle.developmentLocalization { languages.append(developmentLocalization) } } // Find first language for which table exists // Note: key might not exist in chosen language (in that case, key will be shown) for language in languages { if let lproj = hostingBundle.url(forResource: language, withExtension: "lproj"), let lbundle = Bundle(url: lproj) { let strings = lbundle.url(forResource: tableName, withExtension: "strings") let stringsdict = lbundle.url(forResource: tableName, withExtension: "stringsdict") if strings != nil || stringsdict != nil { return (lbundle, Foundation.Locale(identifier: language)) } } } // If table is available in main bundle, don't look for localized resources let strings = hostingBundle.url(forResource: tableName, withExtension: "strings", subdirectory: nil, localization: nil) let stringsdict = hostingBundle.url(forResource: tableName, withExtension: "stringsdict", subdirectory: nil, localization: nil) let hostingLocale = hostingBundle.preferredLocalizations.first.flatMap { Foundation.Locale(identifier: $0) } if let hostingLocale = hostingLocale, strings != nil || stringsdict != nil { return (hostingBundle, hostingLocale) } // If table is not found for requested languages, key will be shown return nil } } ================================================ FILE: Sources/RswiftResources/Integrations/ColorResource+Integrations.swift ================================================ // // UIColor+ColorResource.swift // R.swift // // Created by Tom Lokhorst on 2017-06-06. // import Foundation #if canImport(SwiftUI) import SwiftUI @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, visionOS 1, *) extension Color { /** Creates a color from this resource (`R.color.*`). - parameter resource: The resource you want the color of (`R.color.*`) */ public init(_ resource: ColorResource) { self.init(resource.name, bundle: resource.bundle) } } #endif #if os(iOS) || os(tvOS) || os(visionOS) import UIKit extension ColorResource { /** Returns the color from this resource (`R.color.*`) that is compatible with the trait collection. - parameter resource: The resource you want the color of (`R.color.*`) - parameter traitCollection: Traits that describe the desired color to retrieve, pass nil to use traits that describe the main screen. - returns: A color that exactly or best matches the desired traits with the given resource (`R.color.*`), or nil if no suitable color was found. */ // @available(*, deprecated, message: "Use UIColor(resource:) initializer instead") public func callAsFunction(compatibleWith traitCollection: UITraitCollection? = nil) -> UIColor? { UIColor(named: name, in: bundle, compatibleWith: traitCollection) } } extension UIColor { /** Returns the color from this resource (`R.color.*`) that is compatible with the trait collection. - parameter resource: The resource you want the color of (`R.color.*`) - parameter traitCollection: Traits that describe the desired color to retrieve, pass nil to use traits that describe the main screen. - returns: A color that exactly or best matches the desired traits with the given resource (`R.color.*`), or nil if no suitable color was found. */ public convenience init?(resource: ColorResource, compatibleWith traitCollection: UITraitCollection? = nil) { self.init(named: resource.name, in: resource.bundle, compatibleWith: traitCollection) } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/DataResource+Integrations.swift ================================================ // // DataResource+Integrations.swift // // // Created by Tom Lokhorst on 2022-07-31. // import Foundation #if canImport(UIKit) import UIKit #elseif canImport(AppKit) import AppKit #endif #if canImport(UIKit) || canImport(AppKit) extension NSDataAsset { /** Returns the data asset from this resource (`R.data.*`) - parameter resource: The resource you want the data asset of (`R.data.*`) */ public convenience init?(resource: DataResource) { self.init(name: resource.name, bundle: resource.bundle) } } extension DataResource { /** Returns the raw data values from this resource (`R.data.*`) - parameter resource: The resource you want the data asset of (`R.data.*`) */ public func callAsFunction() -> Data? { NSDataAsset(resource: self)?.data } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/FileResource+Integrations.swift ================================================ // // Bundle+FileResource.swift // R.swift // // Created by Mathijs Kadijk on 10-01-16. // import Foundation extension FileResource { /** Returns the file URL for the given resource (`R.file.*`). - returns: The file URL for the resource file (`R.file.*`) or nil if the file could not be located. */ public func url() -> URL? { bundle.url(forResource: name, withExtension: pathExtension) } /** Returns the file URL for the given resource (`R.file.*`). - returns: The file URL for the resource file (`R.file.*`) or nil if the file could not be located. */ @available(*, renamed: "url()") public func callAsFunction() -> URL? { url() } } extension Bundle { /** Returns the file URL for the given resource (`R.file.*`). - parameter resource: The resource to get the file URL for (`R.file.*`). - returns: The file URL for the resource file (`R.file.*`) or nil if the file could not be located. */ public func url(forResource resource: FileResource) -> URL? { url(forResource: resource.name, withExtension: resource.pathExtension) } /** Returns the full pathname for the resource (`R.file.*`). - parameter resource: The resource file to get the path for (`R.file.*`). - returns: The full pathname for the resource file (`R.file.*`) or nil if the file could not be located. */ public func path(forResource resource: FileResource) -> String? { path(forResource: resource.name, ofType: resource.pathExtension) } } ================================================ FILE: Sources/RswiftResources/Integrations/FontResource+Integrations.swift ================================================ // // UIFont+FontResource.swift // R.swift // // Created by Mathijs Kadijk on 06-01-16. // import Foundation #if canImport(SwiftUI) import SwiftUI @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, visionOS 1, *) extension Font { /** Create a custom font from this resource (`R.font.*`) and and size that scales with the body text style. */ public static func custom(_ resource: FontResource, size: CGFloat) -> Font { .custom(resource.name, size: size) } /** Create a custom font from this resource (`R.font.*`) and a fixed size that does not scale with Dynamic Type. */ @available(macOS 11, iOS 14, tvOS 14, watchOS 7, visionOS 1, *) public static func custom(_ resource: FontResource, fixedSize: CGFloat) -> Font { .custom(resource.name, fixedSize: fixedSize) } /** Create a custom font from this resource (`R.font.*`) and and size that is relative to the given `textStyle`. */ @available(macOS 11, iOS 14, tvOS 14, watchOS 7, visionOS 1, *) public static func custom(_ resource: FontResource, size: CGFloat, relativeTo textStyle: Font.TextStyle) -> Font { .custom(resource.name, size: size, relativeTo: textStyle) } } #endif #if canImport(UIKit) import UIKit extension FontResource { /** Returns the font from this resource (`R.font.*`) at the specified zie. - parameter resource: The font resource (`R.font.*`) for the specific font to load - parameter size: The size (in points) to which the font is scaled. This value must be greater than 0.0. - returns: A color that exactly or best matches the desired traits with the given resource (R.color.\*), or nil if no suitable color was found. */ // @available(*, deprecated, message: "Use UIFont(resource:size:) initializer instead") public func callAsFunction(size: CGFloat) -> UIFont? { UIFont(name: name, size: size) } } public extension UIFont { /** Creates and returns a font object for the specified font resource (`R.font.*`) and size. - parameter resource: The font resource (`R.font.*`) for the specific font to load - parameter size: The size (in points) to which the font is scaled. This value must be greater than 0.0. - returns: A font object of the specified font resource and size. */ convenience init?(resource: FontResource, size: CGFloat) { self.init(name: resource.name, size: size) } } #endif #if canImport(UIKit) import UIKit extension FontResource { /** Returns true if the font can be loaded. Custom fonts may not be loaded if not properly configured in Info.plist */ public func canBeLoaded() -> Bool { UIFont(name: name, size: 42) != nil } } #elseif canImport(AppKit) import AppKit extension FontResource { /** Returns true if the font can be loaded. Custom fonts may not be loaded if not properly configured in Info.plist */ public func canBeLoaded() -> Bool { NSFont(name: name, size: 42) != nil } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/ImageResource+Integrations.swift ================================================ // // UIImage+ImageResource.swift // R.swift // // Created by Mathijs Kadijk on 11-01-16. // import Foundation #if canImport(SwiftUI) import SwiftUI @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, visionOS 1, *) extension Image { /** Creates a labelled image from this resource (`R.image.*`). - parameter resource: The resource you want the image of (`R.image.*`) */ public init(_ resource: ImageResource) { self.init(resource.name, bundle: resource.bundle) } /** Creates a labelled image from this resource (`R.image.*`), with the specified label - parameter resource: The resource you want the image of (`R.image.*`) - parameter label: The label associated with the image, for accessibility */ public init(_ resource: ImageResource, label: Text) { self.init(resource.name, bundle: resource.bundle, label: label) } /** Creates an unlabelled, decorative image from this resource (`R.image.*`). - parameter resource: The resource you want the image of (`R.image.*`) */ public init(decorative resource: ImageResource) { self.init(decorative: resource.name, bundle: resource.bundle) } } // Xcode 14 doesn't recognize `variableValue` init, Xcode 14.1 does know `variableValue` // Xcode 14.1 is first to ship with swift 5.7.1 #if swift(>=5.7.1) @available(macOS 13, iOS 16, tvOS 16, watchOS 9, visionOS 1, *) extension Image { /** Creates a labelled image from this resource (`R.image.*`), with the variable value. - parameter resource: The resource you want the image of (`R.image.*`) - parameter variableValue: Optional value between 1 and 0 */ public init(_ resource: ImageResource, variableValue: Double?) { self.init(resource.name, variableValue: variableValue, bundle: resource.bundle) } /** Creates a labelled image from this resource (`R.image.*`), with the specified label and variable value. - parameter resource: The resource you want the image of (`R.image.*`) - parameter variableValue: Optional value between 1 and 0 - parameter label: The label associated with the image, for accessibility */ public init(_ resource: ImageResource, variableValue: Double?, label: Text) { self.init(resource.name, variableValue: variableValue, bundle: resource.bundle, label: label) } /** Creates an unlabelled, decorative image from this resource (`R.image.*`), with variable value. - parameter resource: The resource you want the image of (`R.image.*`) - parameter variableValue: Optional value between 1 and 0 */ public init(decorative resource: ImageResource, variableValue: Double?) { self.init(decorative: resource.name, variableValue: variableValue, bundle: resource.bundle) } } #endif #endif #if os(iOS) || os(tvOS) || os(visionOS) import UIKit extension ImageResource { /** Returns the image from this resource (`R.image.*`) that is compatible with the trait collection. - parameter resource: The resource you want the image of (`R.image.*`) - parameter traitCollection: Traits that describe the desired image to retrieve, pass nil to use traits that describe the main screen. - returns: An image that exactly or best matches the desired traits with the given resource (`R.image.*`), or nil if no suitable image was found. */ // @available(*, deprecated, message: "Use UIImage(resource:) initializer instead") public func callAsFunction(compatibleWith traitCollection: UITraitCollection? = nil) -> UIImage? { UIImage(named: name, in: bundle, compatibleWith: traitCollection) } } extension UIImage { /** Returns the image from this resource (`R.image.*`) that is compatible with the trait collection. - parameter resource: The resource you want the image of (`R.image.*`) - parameter traitCollection: Traits that describe the desired image to retrieve, pass nil to use traits that describe the main screen. - returns: An image that exactly or best matches the desired traits with the given resource (`R.image.*`), or nil if no suitable image was found. */ public convenience init?(resource: ImageResource, compatibleWith traitCollection: UITraitCollection? = nil) { self.init(named: resource.name, in: resource.bundle, compatibleWith: traitCollection) } /** Returns the image from this resource (`R.image.*`) using the configuration specified. - parameter resource: The resource you want the image of (`R.image.*`) - parameter configuration: The image configuration the system appllies to the image - returns: An image that exactly or best matches the configuration of the given resource (`R.image.*`), or nil if no suitable image was found. */ @available(iOS 13, tvOS 13, visionOS 1, *) public convenience init?(resource: ImageResource, with configuration: UIImage.Configuration?) { self.init(named: resource.name, in: resource.bundle, with: configuration) } } #endif // Xcode 14 doesn't recognize `variableValue` init, Xcode 14.1 does know `variableValue` // Xcode 14.1 is first to ship with swift 5.7.1 #if swift(>=5.7.1) && (os(iOS) || os(tvOS)) || os(visionOS) extension UIImage { /** Returns the image from this resource (`R.image.*`) using the configuration, and variable value specified. - parameter resource: The resource you want the image of (`R.image.*`) - parameter variableValue: The value the system uses to customize the image content, between 0 and 1 - parameter configuration: The image configuration the system appllies to the image - returns: An image that exactly or best matches the configuration of the given resource (`R.image.*`), or nil if no suitable image was found. */ @available(iOS 16, tvOS 16, visionOS 1, *) public convenience init?(resource: ImageResource, variableValue: Double, with configuration: UIImage.Configuration? = nil) { self.init(named: resource.name, in: resource.bundle, variableValue: variableValue, configuration: configuration) } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/NibReference+Integrations.swift ================================================ // // UINib+NibResource.swift // R.swift // // Created by Mathijs Kadijk on 08-01-16. // #if os(iOS) || os(tvOS) import UIKit extension NibReferenceContainer { /** Instantiate the nib to get first object from this nib - parameter ownerOrNil: The owner, if the owner parameter is nil, connections to File's Owner are not permitted. - parameter options: Options are identical to the options specified with` -[NSBundle loadNibNamed:owner:options:]` */ public func callAsFunction(withOwner ownerOrNil: Any?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> FirstView? { UINib(nibName: name, bundle: bundle).instantiate(withOwner: ownerOrNil, options: optionsOrNil).first as? FirstView } @available(*, deprecated, message: "renamed to (withOwner:options:)") public func callAsFunction(owner ownerOrNil: Any?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> FirstView? { UINib(nibName: name, bundle: bundle).instantiate(withOwner: ownerOrNil, options: optionsOrNil).first as? FirstView } /** Instantiate the nib to get first object from this nib - parameter ownerOrNil: The owner, if the owner parameter is nil, connections to File's Owner are not permitted. - parameter options: Options are identical to the options specified with` -[NSBundle loadNibNamed:owner:options:]` */ public func firstView(withOwner ownerOrNil: Any?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> FirstView? { UINib(nibName: name, bundle: bundle).instantiate(withOwner: ownerOrNil, options: optionsOrNil).first as? FirstView } @available(*, deprecated, renamed: "firstView(withOwner:options:)") public func firstView(owner ownerOrNil: Any?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> FirstView? { UINib(nibName: name, bundle: bundle).instantiate(withOwner: ownerOrNil, options: optionsOrNil).first as? FirstView } /** Instantiate the nib to get the top-level objects from this nib - parameter ownerOrNil: The owner, if the owner parameter is nil, connections to File's Owner are not permitted. - parameter options: Options are identical to the options specified with` -[NSBundle loadNibNamed:owner:options:]` - returns: An array containing the top-level objects from the NIB */ public func instantiate(withOwner ownerOrNil: Any?, options optionsOrNil: [UINib.OptionsKey : Any]? = [:]) -> [Any] { UINib(nibName: name, bundle: bundle).instantiate(withOwner: ownerOrNil, options: optionsOrNil) } } extension UINib { /** Returns a UINib object initialized to the nib file of the specified resource (`R.nib.*`). - parameter resource: The resource (`R.nib.*`) to load - returns: The initialized UINib object. An exception is thrown if there were errors during initialization or the nib file could not be located. */ public convenience init(resource: Nib) { self.init(nibName: resource.name, bundle: resource.bundle) } } extension UIViewController { /** Returns a newly initialized view controller with the nib resource (`R.nib.*`). - parameter nib: The nib resource (`R.nib.*`) to associate with the view controller. - returns: A newly initialized UIViewController object. */ public convenience init(nib: Nib) { self.init(nibName: nib.name, bundle: nib.bundle) } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/ReuseIdentifier+Integrations.swift ================================================ // // UITableView+ReuseIdentifierProtocol.swift // R.swift // // Created by Mathijs Kadijk on 06-12-15. // From: https://github.com/mac-cain13/R.swift // #if os(iOS) || os(tvOS) import UIKit extension UITableView { /** Register a `R.nib.*` containing a cell with the table view under it's contained identifier. - parameter resource: A nib resource (`R.nib.*`) containing a table view cell that has a reuse identifier */ public func register(_ resource: Resource) where Resource.Reusable: UITableViewCell { register(UINib(resource: resource), forCellReuseIdentifier: resource.identifier) } /** Register a `R.reuseIdentifier.*` containing a cell with the table view under it's contained identifier. - parameter resource: A reuse identifier */ public func register(_ resource: Resource) where Resource.Reusable: UITableViewCell { register(Resource.Reusable.self, forCellReuseIdentifier: resource.identifier) } /** Register a `R.nib.*` containing a header or footer with the table view under it's contained identifier. - parameter resource: A nib resource (`R.nib.*`) containing a view that has a reuse identifier */ public func registerHeaderFooterView(_ resource: Resource) where Resource.Reusable: UIView { register(UINib(resource: resource), forHeaderFooterViewReuseIdentifier: resource.identifier) } /** Register a `R.reuseIdentifier.*` containing a header or footer with the table view under it's contained identifier. - parameter resource: A reuse identifier */ public func registerHeaderFooterView(_ resource: Resource) where Resource.Reusable: UITableViewHeaderFooterView { register(Resource.Reusable.self, forHeaderFooterViewReuseIdentifier: resource.identifier) } /** Returns a typed reusable table-view cell object for the specified reuse identifier and adds it to the table. - parameter identifier: A `R.reuseIdentifier.*` value identifying the cell object to be reused. - parameter indexPath: The index path specifying the location of the cell. The data source receives this information when it is asked for the cell and should just pass it along. This method uses the index path to perform additional configuration based on the cell’s position in the table view. - returns: The UITableViewCell subclass with the associated reuse identifier or nil if it couldn't be casted correctly. - precondition: You must register a class or nib file using the registerNib: or registerClass:forCellReuseIdentifier: method before calling this method. */ public func dequeueReusableCell(withIdentifier identifier: Identifier, for indexPath: IndexPath) -> Identifier.Reusable? where Identifier.Reusable: UITableViewCell { dequeueReusableCell(withIdentifier: identifier.identifier, for: indexPath) as? Identifier.Reusable } /** Returns a typed reusable header or footer view located by its identifier. - parameter identifier: A `R.reuseIdentifier.*` value identifying the header or footer view to be reused. - returns: A UITableViewHeaderFooterView object with the associated identifier or nil if no such object exists in the reusable view queue or if it couldn't be cast correctly. */ public func dequeueReusableHeaderFooterView(withIdentifier identifier: Identifier) -> Identifier.Reusable? where Identifier.Reusable: UITableViewHeaderFooterView { dequeueReusableHeaderFooterView(withIdentifier: identifier.identifier) as? Identifier.Reusable } } extension UICollectionView { /** Register a `R.nib.*` for use in creating new collection view cells. - parameter resource: A nib resource (`R.nib.*`) containing a object of type UICollectionViewCell that has a reuse identifier */ public func register(_ resource: Resource) where Resource.Reusable: UICollectionViewCell { register(UINib(resource: resource), forCellWithReuseIdentifier: resource.identifier) } /** Register a `R.reuseIdentifier.*` for use in creating new collection view cells. - parameter resource: A reuse identifier */ public func register(_ resource: Resource) where Resource.Reusable: UICollectionViewCell { register(Resource.Reusable.self, forCellWithReuseIdentifier: resource.identifier) } /** Register a `R.nib.*` for use in creating supplementary views for the collection view. - parameter resource: A nib resource (`R.nib.*`) containing a object of type UICollectionReusableView. that has a reuse identifier */ public func register(_ resource: Resource, forSupplementaryViewOfKind kind: String) where Resource.Reusable: UICollectionReusableView { register(UINib(resource: resource), forSupplementaryViewOfKind: kind, withReuseIdentifier: resource.identifier) } /** Register a `R.reuseIdentfier.*` for use in creating supplementary views for the collection view. - parameter resource: A reuseIdentifier */ public func register(_ resource: Resource, forSupplementaryViewOfKind kind: String) where Resource.Reusable: UICollectionReusableView { register(Resource.Reusable.self, forSupplementaryViewOfKind: kind, withReuseIdentifier: resource.identifier) } /** Returns a typed reusable cell object located by its identifier - parameter identifier: The `R.reuseIdentifier.*` value for the specified cell. - parameter indexPath: The index path specifying the location of the cell. The data source receives this information when it is asked for the cell and should just pass it along. This method uses the index path to perform additional configuration based on the cell’s position in the collection view. - returns: A subclass of UICollectionReusableView or nil if the cast fails. */ public func dequeueReusableCell(withReuseIdentifier identifier: Identifier, for indexPath: IndexPath) -> Identifier.Reusable? where Identifier.Reusable: UICollectionReusableView { dequeueReusableCell(withReuseIdentifier: identifier.identifier, for: indexPath) as? Identifier.Reusable } /** Returns a typed reusable supplementary view located by its identifier and kind. - parameter elementKind: The kind of supplementary view to retrieve. This value is defined by the layout object. - parameter identifier: The `R.reuseIdentifier.*` value for the specified view. - parameter indexPath: The index path specifying the location of the cell. The data source receives this information when it is asked for the cell and should just pass it along. This method uses the index path to perform additional configuration based on the cell’s position in the collection view. - returns: A subclass of UICollectionReusableView or nil if the cast fails. */ public func dequeueReusableSupplementaryView(ofKind elementKind: String, withReuseIdentifier identifier: Identifier, for indexPath: IndexPath) -> Identifier.Reusable? where Identifier.Reusable: UICollectionReusableView { dequeueReusableSupplementaryView(ofKind: elementKind, withReuseIdentifier: identifier.identifier, for: indexPath) as? Identifier.Reusable } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/SegueIdentifier+Integrations.swift ================================================ // // UIViewController+StoryboardSegueIdentifierProtocol.swift // R.swift // // Created by Mathijs Kadijk on 06-12-15. // From: https://github.com/mac-cain13/R.swift // import Foundation #if os(iOS) || os(tvOS) import UIKit public protocol SeguePerformer { func performSegue(withIdentifier identifier: String, sender: Any?) } extension UIViewController: SeguePerformer {} extension SeguePerformer { /** Initiates the segue with the specified identifier (`R.segue.*`) from the current view controller's storyboard file. - parameter identifier: The R.segue.\* that identifies the triggered segue. - parameter sender: The object that you want to use to initiate the segue. This object is made available for informational purposes during the actual segue. - SeeAlso: Library for typed block based segues: [tomlokhorst/SegueManager](https://github.com/tomlokhorst/SegueManager) */ public func performSegue(withIdentifier identifier: SegueIdentifier, sender: Any?) { performSegue(withIdentifier: identifier.identifier, sender: sender) } } extension SegueIdentifier where Segue: UIStoryboardSegue { /// Optionally returns a typed version of the segue. /// Returns nil if either the segue identifier, the source, destination, or segue types don't match. /// For use inside `prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)`. public func callAsFunction(segue: Segue) -> TypedSegue? { TypedSegue(segueIdentifier: self, uiStoryboardSegue: segue) } } extension SegueIdentifier where Segue: UIStoryboardSegue, Source: UIViewController, Destination: UIViewController { /// Trigger a segue by providing a source, destination and handler public func perform(source: Source, destination: Destination, handler: @escaping () -> Void) { let segue = Segue(identifier: identifier, source: source, destination: destination, performHandler: handler) segue.perform() } } extension TypedSegue { /** Returns typed information about the given segue, fails if the segue types don't exactly match types. - returns: A newly initialized TypedSegue object or nil. */ public init?(segueIdentifier: SegueIdentifier, uiStoryboardSegue: StoryboardSegue) { guard let identifier = uiStoryboardSegue.identifier, let source = uiStoryboardSegue.source as? Source, let destination = uiStoryboardSegue.destination as? Destination, let segue = uiStoryboardSegue as? Segue, identifier == segueIdentifier.identifier else { return nil } self.segue = segue self.identifier = identifier self.source = source self.destination = destination } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/StoryboardReference+Integrations.swift ================================================ // // StoryboardReference+Integrations.swift // R.swift // // Created by Tom Lokhorst on 2022-07-30. // #if os(iOS) || os(tvOS) import UIKit extension StoryboardReference where Self: InitialControllerContainer { /** Instantiates and returns the initial view controller in the view controller graph. - returns: The initial view controller in the storyboard. */ public func instantiateInitialViewController() -> InitialController? { UIStoryboard(name: name, bundle: bundle).instantiateInitialViewController() as? InitialController } /** Instantiates and returns the initial view controller in the view controller graph with native dependency injection. - parameter creator: The function to inject dependency. - returns: The initial view controller in the storyboard. */ @available(iOS 13.0, tvOS 13.0, visionOS 1, *) public func instantiateInitialViewController(creator: @escaping (NSCoder) -> InitialController?) -> InitialController? where InitialController: UIViewController { UIStoryboard(name: name, bundle: bundle).instantiateInitialViewController(creator: creator) } } extension StoryboardViewControllerIdentifier { /** Instantiates and returns the view controller with the specified resource (`R.storyboard.*.*`). - returns: The view controller corresponding to the specified resource (`R.storyboard.*.*`). If no view controller is associated, this method throws an exception. */ public func callAsFunction() -> ViewController? { UIStoryboard(name: storyboard, bundle: bundle).instantiateViewController(withIdentifier: identifier) as? ViewController } /** Instantiates and returns the view controller with the specified resource (`R.storyboard.*.*`) and native dependency injection. - parameter creator: The function to inject dependency. - returns: The view controller corresponding to the specified resource (`R.storyboard.*.*`). */ @available(iOS 13.0, tvOS 13.0, visionOS 1, *) public func callAsFunction(creator: @escaping (NSCoder) -> ViewController?) -> ViewController where ViewController: UIViewController { UIStoryboard(name: storyboard, bundle: bundle).instantiateViewController(identifier: identifier, creator: creator) } } extension UIStoryboard { /** Creates and returns a storyboard object for the specified storyboard resource (`R.storyboard.*`) file. - parameter resource: The storyboard resource (`R.storyboard.*`) for the specific storyboard to load - returns: A storyboard object for the specified file. If no storyboard resource file matching name exists, an exception is thrown with description: `Could not find a storyboard named 'XXXXXX' in bundle....` */ public convenience init(resource: Reference) { self.init(name: resource.name, bundle: resource.bundle) } /** Instantiates and returns the view controller with the specified resource (`R.storyboard.*.*`). - parameter resource: An resource (`R.storyboard.*.*`) that uniquely identifies the view controller in the storyboard file. If the specified resource does not exist in the storyboard file, this method raises an exception. - returns: The view controller corresponding to the specified resource (`R.storyboard.*.*`). If no view controller is associated, this method throws an exception. */ public func instantiateViewController(withIdentifier identifier: StoryboardViewControllerIdentifier) -> ViewController? { self.instantiateViewController(withIdentifier: identifier.identifier) as? ViewController } } #endif #if canImport(AppKit) && !targetEnvironment(macCatalyst) import AppKit extension StoryboardReference where Self: InitialControllerContainer { /** Instantiates and returns the initial view controller in the view controller graph. - returns: The initial view controller in the storyboard. */ public func instantiateInitialViewController() -> InitialController? { NSStoryboard(name: name, bundle: bundle).instantiateInitialController() as? InitialController } /** Instantiates and returns the initial view controller in the view controller graph with native dependency injection. - parameter creator: The function to inject dependency. - returns: The initial view controller in the storyboard. */ public func instantiateInitialViewController(creator: @escaping (NSCoder) -> InitialController?) -> InitialController? where InitialController: NSViewController { NSStoryboard(name: name, bundle: bundle).instantiateInitialController(creator: creator) } } extension StoryboardViewControllerIdentifier { /** Instantiates and returns the view controller with the specified resource (`R.storyboard.*.*`). - returns: The view controller corresponding to the specified resource (`R.storyboard.*.*`). If no view controller is associated, this method throws an exception. */ public func callAsFunction() -> ViewController? { NSStoryboard(name: storyboard, bundle: bundle).instantiateController(withIdentifier: identifier) as? ViewController } /** Instantiates and returns the view controller with the specified resource (`R.storyboard.*.*`) and native dependency injection. - parameter creator: The function to inject dependency. - returns: The view controller corresponding to the specified resource (`R.storyboard.*.*`). */ public func callAsFunction(creator: @escaping (NSCoder) -> ViewController?) -> ViewController? where ViewController: NSViewController { NSStoryboard(name: storyboard, bundle: bundle).instantiateController(identifier: identifier, creator: creator) } } extension NSStoryboard { /** Creates and returns a storyboard object for the specified storyboard resource (`R.storyboard.*`) file. - parameter resource: The storyboard resource (`R.storyboard.*`) for the specific storyboard to load - returns: A storyboard object for the specified file. If no storyboard resource file matching name exists, an exception is thrown with description: `Could not find a storyboard named 'XXXXXX' in bundle....` */ public convenience init(resource: Reference) { self.init(name: resource.name, bundle: resource.bundle) } /** Instantiates and returns the view controller with the specified resource (`R.storyboard.*.*`). - parameter resource: An resource (`R.storyboard.*.*`) that uniquely identifies the view controller in the storyboard file. If the specified resource does not exist in the storyboard file, this method raises an exception. - returns: The view controller corresponding to the specified resource (`R.storyboard.*.*`). If no view controller is associated, this method throws an exception. */ public func instantiateController(withIdentifier identifier: StoryboardViewControllerIdentifier) -> ViewController? { self.instantiateController(withIdentifier: identifier.identifier) as? ViewController } } #endif ================================================ FILE: Sources/RswiftResources/Integrations/StringResource+Integrations.swift ================================================ // // StringResource+Integrations.swift // // // Created by Tom Lokhorst on 2022-07-30. // import Foundation extension String { init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, locale overrideLocale: Locale?, arguments: [CVarArg]) { switch source { case let .hosting(bundle): // With fallback to developmentValue let format = NSLocalizedString(key.description, tableName: tableName, bundle: bundle, value: developmentValue ?? "", comment: "") self = String(format: format, locale: overrideLocale ?? Locale.current, arguments: arguments) case let .selected(bundle, locale): // Don't use developmentValue with selected bundle/locale let format = NSLocalizedString(key.description, tableName: tableName, bundle: bundle, value: "", comment: "") self = String(format: format, locale: overrideLocale ?? locale, arguments: arguments) case .none: self = key.description } } init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, preferredLanguages: [String], locale overrideLocale: Locale?, arguments: [CVarArg]) { guard let (bundle, locale) = source.bundle?.firstBundleAndLocale(tableName: tableName, preferredLanguages: preferredLanguages) else { self = key.description return } self.init(key: key, tableName: tableName, source: .selected(bundle, locale), developmentValue: developmentValue, locale: overrideLocale, arguments: arguments) } } extension String { public init(resource: StringResource) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: []) } public init(resource: StringResource, preferredLanguages: [String], locale overrideLocale: Locale? = nil) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: nil, arguments: []) } public init(format resource: StringResource1, locale overrideLocale: Locale? = nil, _ arg1: Arg1) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1]) } public init(format resource: StringResource1, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1]) } public init(format resource: StringResource2, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2]) } public init(format resource: StringResource2, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2]) } public init(format resource: StringResource3, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3]) } public init(format resource: StringResource3, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3]) } public init(format resource: StringResource4, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4]) } public init(format resource: StringResource4, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4]) } public init(format resource: StringResource5, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5]) } public init(format resource: StringResource5, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5]) } public init(format resource: StringResource6, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6]) } public init(format resource: StringResource6, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6]) } public init(format resource: StringResource7, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7]) } public init(format resource: StringResource7, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7]) } public init(format resource: StringResource8, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]) } public init(format resource: StringResource8, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8]) } public init(format resource: StringResource9, locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) } public init(format resource: StringResource9, preferredLanguages: [String], locale overrideLocale: Locale? = nil, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) { self.init(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, preferredLanguages: preferredLanguages, locale: overrideLocale, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) } } #if canImport(SwiftUI) import SwiftUI @available(macOS 10, iOS 13, tvOS 13, watchOS 6, visionOS 1, *) extension Text { public init(_ resource: StringResource) { self.init(String(resource: resource)) } public init(_ resource: StringResource1, _ arg1: Arg1) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1])) } public init(_ resource: StringResource2, _ arg1: Arg1, _ arg2: Arg2) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2])) } public init(_ resource: StringResource3, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3])) } public init(_ resource: StringResource4, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4])) } public init(_ resource: StringResource5, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5])) } public init(_ resource: StringResource6, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6])) } public init(_ resource: StringResource7, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7])) } public init(_ resource: StringResource8, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8])) } public init(_ resource: StringResource9, _ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) { self.init(String(key: resource.key, tableName: resource.tableName, source: resource.source, developmentValue: resource.developmentValue, locale: nil, arguments: [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9])) } } #endif extension StringResource.Source { public init(bundle: Bundle, tableName: String, preferredLanguages: [String]?, locale overrideLocale: Locale?) { guard let preferredLanguages = preferredLanguages else { if let locale = overrideLocale { self = .selected(bundle, locale) } else { self = .hosting(bundle) } return } if let (bundle, locale) = bundle.firstBundleAndLocale(tableName: tableName, preferredLanguages: preferredLanguages) { self = .selected(bundle, overrideLocale ?? locale) } else { self = .none } } } extension StringResource { public func callAsFunction() -> String { String(resource: self) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(preferredLanguages: [String]) -> String { String(resource: self, preferredLanguages: preferredLanguages) } // @available(macOS 13, iOS 16, tvOS 16, watchOS 9, visionOS 1, *) // public var localizedStringResource: LocalizedStringResource { // LocalizedStringResource(key, defaultValue: String.LocalizationValue(stringLiteral: defaultValue), bundle: bundle == .main ? .main : .atURL(bundle.bundleURL), comment: comment) // } } extension StringResource1 { public func callAsFunction(_ arg1: Arg1) -> String { String(format: self, arg1) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1) } } extension StringResource2 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2) -> String { String(format: self, arg1, arg2) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2) } } extension StringResource3 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3) -> String { String(format: self, arg1, arg2, arg3) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3) } } extension StringResource4 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4) -> String { String(format: self, arg1, arg2, arg3, arg4) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3, arg4) } } extension StringResource5 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5) -> String { String(format: self, arg1, arg2, arg3, arg4, arg5) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3, arg4, arg5) } } extension StringResource6 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6) -> String { String(format: self, arg1, arg2, arg3, arg4, arg5, arg6) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3, arg4, arg5, arg6) } } extension StringResource7 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7) -> String { String(format: self, arg1, arg2, arg3, arg4, arg5, arg6, arg7) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3, arg4, arg5, arg6, arg7) } } extension StringResource8 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8) -> String { String(format: self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) } } extension StringResource9 { public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9) -> String { String(format: self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) } @available(*, deprecated, message: "Use R.string(preferredLanguages:).*.* instead") public func callAsFunction(_ arg1: Arg1, _ arg2: Arg2, _ arg3: Arg3, _ arg4: Arg4, _ arg5: Arg5, _ arg6: Arg6, _ arg7: Arg7, _ arg8: Arg8, _ arg9: Arg9, preferredLanguages: [String]) -> String { String(format: self, preferredLanguages: preferredLanguages, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) } } ================================================ FILE: Sources/RswiftResources/NibResource.swift ================================================ // // NibResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation public struct NibResource: Sendable { public let name: String public var locale: LocaleReference public let deploymentTarget: DeploymentTarget? public let rootViews: [TypeReference] public var reusables: [Reusable] public let generatedIds: [String] public var usedImageIdentifiers: [NameCatalog] public var usedColorResources: [NameCatalog] public var usedAccessibilityIdentifiers: [String] public let isAppKit: Bool public init( name: String, locale: LocaleReference, deploymentTarget: DeploymentTarget?, rootViews: [TypeReference], reusables: [Reusable], generatedIds: [String], usedImageIdentifiers: [NameCatalog], usedColorResources: [NameCatalog], usedAccessibilityIdentifiers: [String], isAppKit: Bool ) { self.name = name self.locale = locale self.deploymentTarget = deploymentTarget self.rootViews = rootViews self.reusables = reusables self.generatedIds = generatedIds self.usedImageIdentifiers = usedImageIdentifiers self.usedColorResources = usedColorResources self.usedAccessibilityIdentifiers = usedAccessibilityIdentifiers self.isAppKit = isAppKit } } extension NibResource { public struct UnifyResult { public let resource: NibResource public let differentNames: Bool public let differentRootViews: Bool public let differentReusables: Set public let differentInitialReusables: Bool public let differentDeploymentTargets: Bool public func flatMap(_ transform: (NibResource) -> UnifyResult) -> UnifyResult { let r = transform(resource) return UnifyResult( resource: r.resource, differentNames: r.differentNames || self.differentNames, differentRootViews: r.differentRootViews || self.differentRootViews, differentReusables: r.differentReusables.union(self.differentReusables), differentInitialReusables: r.differentInitialReusables || self.differentInitialReusables, differentDeploymentTargets: r.differentDeploymentTargets || self.differentDeploymentTargets ) } } public func unify(localizations: [NibResource]) -> UnifyResult { var result = UnifyResult( resource: self, differentNames: false, differentRootViews: false, differentReusables: [], differentInitialReusables: false, differentDeploymentTargets: false ) for nib in localizations { result = result.flatMap { $0.unify(nib) } } return result } public func unify(_ other: NibResource) -> UnifyResult { // Merged used images/colors from both localizations, they all need to be validated var result = self result.usedImageIdentifiers = Array(Set(self.usedImageIdentifiers).union(other.usedImageIdentifiers)) result.usedColorResources = Array(Set(self.usedColorResources).union(other.usedColorResources)) // Only keep reusables that exist in both localizations result.reusables = self.reusables.filter { other.reusables.contains($0) } // Keep other fields from self only, if they are different, that is recorded in UnifyResult // Remove locale, this is a merger of both result.locale = .none return UnifyResult( resource: result, differentNames: name != other.name, differentRootViews: rootViews.first != other.rootViews.first, differentReusables: Set(reusables).symmetricDifference(other.reusables), differentInitialReusables: reusables.first != other.reusables.first, differentDeploymentTargets: deploymentTarget != other.deploymentTarget ) } } ================================================ FILE: Sources/RswiftResources/PropertyListResource.swift ================================================ // // PropertyListResource.swift // R.swift // // Created by Tom Lokhorst on 2018-07-08. // import Foundation public struct PropertyListResource { public typealias Contents = [String: Any] public let buildConfigurationName: String public let contents: Contents public let url: URL public init(buildConfigurationName: String, contents: Contents, url: URL) { self.buildConfigurationName = buildConfigurationName self.contents = contents self.url = url } } ================================================ FILE: Sources/RswiftResources/Shared/DeploymentTarget.swift ================================================ // // DeploymentTarget.swift // // // Created by Tom Lokhorst on 2022-07-10. // import Foundation public struct DeploymentTarget: Equatable, Sendable { public typealias Version = (major: Int, minor: Int) public let version: Version? public let platform: String public init(version: Version?, platform: String) { self.version = version self.platform = platform } public static func ==(lhs: DeploymentTarget, rhs: DeploymentTarget) -> Bool { lhs.platform == rhs.platform && lhs.version?.major == rhs.version?.major && lhs.version?.minor == rhs.version?.minor } } ================================================ FILE: Sources/RswiftResources/Shared/LocaleReference.swift ================================================ // // Locale.swift // R.swift // // Created by Tom Lokhorst on 2016-04-24. // import Foundation public enum LocaleReference: Hashable, Sendable { case none case base // Older projects use a "Base" locale case language(String) public var isNone: Bool { if case .none = self { return true } return false } public var isBase: Bool { if case .base = self { return true } return false } } extension LocaleReference { public init(url: URL) { if let localeComponent = url.pathComponents.dropLast().last , localeComponent.hasSuffix(".lproj") { let lang = localeComponent.replacingOccurrences(of: ".lproj", with: "") if lang == "Base" { self = .base } else { self = .language(lang) } } else { self = .none } } public var localeDescription: String? { switch self { case .none: return nil case .base: return "Base" case .language(let language): return language } } public func debugDescription(filename: String) -> String { switch self { case .none: return "'\(filename)'" case .base: return "'\(filename)' (Base)" case .language(let language): return "'\(filename)' (\(language))" } } } ================================================ FILE: Sources/RswiftResources/Shared/ModuleReference.swift ================================================ // // ModuleReference.swift // R.swift // // Created by Mathijs Kadijk on 11-12-15. // import Foundation public enum ModuleReference: Hashable, Sendable { case host case stdLib case custom(name: String) public init(name: String?, fallback: ModuleReference = .host) { let cleaned = name?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" self = cleaned.isEmpty ? fallback : .custom(name: cleaned) } public var isCustom: Bool { switch self { case .custom: return true default: return false } } public var name: String? { if case .custom(let name) = self { return name } else { return nil } } } extension ModuleReference { public static var uiKit: ModuleReference { .custom(name: "UIKit") } public static var appKit: ModuleReference { .custom(name: "AppKit") } public static var coreText: ModuleReference { .custom(name: "CoreText") } public static var foundation: ModuleReference { .custom(name: "Foundation") } public static var rswiftResources: ModuleReference { .custom(name: "RswiftResources") } } ================================================ FILE: Sources/RswiftResources/Shared/NameCatalog.swift ================================================ // // NameCatalog.swift // R.swift // // Created by Tom Lokhorst on 2020-05-08. // import Foundation public struct NameCatalog: Hashable, Comparable, Sendable { public let name: String public let catalog: String? public var isSystemCatalog: Bool { catalog == "System" // for colors || catalog == "system" // for images } public init(name: String, catalog: String?) { self.name = name self.catalog = catalog } static public func < (lhs: NameCatalog, rhs: NameCatalog) -> Bool { lhs.name < rhs.name } } ================================================ FILE: Sources/RswiftResources/Shared/Reusable.swift ================================================ // // ReusableContainer.swift // R.swift // // Created by Mathijs Kadijk on 10-12-15. // import Foundation public struct Reusable: Hashable, Sendable { public let identifier: String public let type: TypeReference public init(identifier: String, type: TypeReference) { self.identifier = identifier self.type = type } } ================================================ FILE: Sources/RswiftResources/Shared/StoryboardReference.swift ================================================ // // StoryboardSegueIdentifierProtocol.swift // R.swift // // Created by Mathijs Kadijk on 06-12-15. // From: https://github.com/mac-cain13/R.swift // import Foundation /// Storyboard reference public protocol StoryboardReference { /// Name of the storyboard file on disk var name: String { get } /// Bundle this storyboard is in var bundle: Bundle { get } } public protocol InitialControllerContainer { /// Type of the inital controller associatedtype InitialController } /// Storyboard view controller identifier public struct StoryboardViewControllerIdentifier: Sendable { /// Storyboard identifier of this view controller public let identifier: String /// Name of the storyboard file on disk public let storyboard: String /// Bundle this storyboard is in public let bundle: Bundle /** Create a new StoryboardViewControllerIdentifier based on the identifier string - parameter identifier: The string identifier for this view controller - parameter storyboard: The name of the storyboard file - parameter bundle: The bundle the storyboard is in */ public init(identifier: String, storyboard: String, bundle: Bundle) { self.identifier = identifier self.storyboard = storyboard self.bundle = bundle } } public protocol NibReferenceContainer { associatedtype FirstView var name: String { get } var bundle: Bundle { get } } public protocol ReuseIdentifierContainer { associatedtype Reusable var identifier: String { get } } /// Nib reference public struct NibReference: NibReferenceContainer, Sendable { /// String name of this nib public let name: String /// Bundle this nib is in public let bundle: Bundle /** Create a new NibRefence based on the name string - parameter name: The string name for this nib - parameter bundle: The bundle the nib is in */ public init(name: String, bundle: Bundle) { self.name = name self.bundle = bundle } } /// Reuse identifier public struct ReuseIdentifier: ReuseIdentifierContainer, Sendable { /// String identifier of this reusable public let identifier: String /** Create a new ReuseIdentifier based on the string identifier - parameter identifier: The string identifier for this reusable - returns: A new ReuseIdentifier */ public init(identifier: String) { self.identifier = identifier } } /// Nib reference, reuse identifier public struct NibReferenceReuseIdentifier: NibReferenceContainer, ReuseIdentifierContainer, Sendable { /// String name of this nib public let name: String /// Bundle this nib is in public let bundle: Bundle /// String identifier of this reusable public let identifier: String /** Create a new NibRefence based on the name string - parameter name: The string name for this nib - parameter bundle: The bundle the nib is in - parameter identifier: The string identifier for this reusable */ public init(name: String, bundle: Bundle, identifier: String) { self.name = name self.bundle = bundle self.identifier = identifier } } /// Segue identifier public struct SegueIdentifier: Sendable { /// Identifier string of this segue public let identifier: String /** Create a new SegueIdentifier based on the identifier string - parameter identifier: The string identifier for this segue - returns: A new SegueIdentifier */ public init(identifier: String) { self.identifier = identifier } } /// Typed segue information public struct TypedSegue { /// The original segue public let segue: Segue /// Segue source view controller public let source: Source /// Segue destination view controller public let destination: Destination /// Segue identifier public let identifier: String /** Create a new TypedSegue based on the original segue - parameter segue: The original segue - parameter source: Segue source view controller - parameter destination: Segue destination view controller - parameter identifier: The string identifier for this segue - returns: A new TypedSegue */ public init(segue: Segue, source: Source, destination: Destination, identifier: String) { self.segue = segue self.source = source self.destination = destination self.identifier = identifier } } extension TypedSegue: Sendable where Segue: Sendable, Source: Sendable, Destination: Sendable {} @available(*, renamed: "ReuseIdentifierContainer") public protocol ReuseIdentifierType {} @available(*, renamed: "SegueIdentifier") public struct StoryboardSegueIdentifier {} @available(*, renamed: "TypedSegue") public struct TypedStoryboardSegueInfo {} ================================================ FILE: Sources/RswiftResources/Shared/StringParam+Extensions.swift ================================================ // // StringParam.swift // R.swift // // Created by Tom Lokhorst on 2016-04-18. // // Parts of the content of this file are loosly based on StringsFileParser.swift from SwiftGen/GenumKit. // We don't feel this is a "substantial portion of the Software" so are not including their MIT license, // eventhough we would like to give credit where credit is due by referring to SwiftGen thanking Olivier // Halligon for creating SwiftGen and GenumKit. // // See: https://github.com/AliSoftware/SwiftGen/blob/master/GenumKit/Parsers/StringsFileParser.swift // import Foundation extension StringParam: Unifiable { public func unify(_ other: StringParam) -> StringParam? { if let name = name, let otherName = other.name , name != otherName { return nil } if let spec = spec.unify(other.spec) { return StringParam(name: name ?? other.name, spec: spec) } return nil } } extension FormatPart: Unifiable { public func unify(_ other: FormatPart) -> FormatPart? { switch (self, other) { case let (.spec(l), .spec(r)): if let spec = l.unify(r) { return .spec(spec) } else { return nil } case let (.reference(l), .reference(r)) where l == r: return .reference(l) default: return nil } } } extension FormatSpecifier: Unifiable { public func unify(_ other: FormatSpecifier) -> FormatSpecifier? { if self == .topType { return other } if other == .topType { return self } if self == other { return self } return nil } } extension FormatSpecifier { public var typeReference: TypeReference { switch self { case .object: return TypeReference(module: .stdLib, rawName: "String") case .double: return TypeReference(module: .stdLib, rawName: "Double") case .int: return TypeReference(module: .stdLib, rawName: "Int") case .uInt: return TypeReference(module: .stdLib, rawName: "UInt") case .character: return TypeReference(module: .stdLib, rawName: "Character") case .cStringPointer: return TypeReference(module: .stdLib, rawName: "UnsafePointer") case .voidPointer: return TypeReference(module: .stdLib, rawName: "UnsafePointer") case .topType: return TypeReference(module: .stdLib, rawName: "Any") } } } ================================================ FILE: Sources/RswiftResources/Shared/StringParam.swift ================================================ // // StringParam.swift // R.swift // // Created by Tom Lokhorst on 2016-04-18. // import Foundation public struct StringParam: Equatable, Sendable { public let name: String? public let spec: FormatSpecifier public init(name: String?, spec: FormatSpecifier) { self.name = name self.spec = spec } } public enum FormatPart: Sendable { case spec(FormatSpecifier) case reference(String) public var formatSpecifier: FormatSpecifier? { switch self { case .spec(let formatSpecifier): return formatSpecifier case .reference: return nil } } } // https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1 public enum FormatSpecifier: Sendable { case object case double case int case uInt case character case cStringPointer case voidPointer case topType } ================================================ FILE: Sources/RswiftResources/Shared/StringsTable.swift ================================================ // // LocalizableStrings.swift // R.swift // // Created by Tom Lokhorst on 2016-04-24. // import Foundation public struct StringsTable: Sendable { public let filename: String public let locale: LocaleReference public let dictionary: [Key: Value] public init(filename: String, locale: LocaleReference, dictionary: [Key: Value]) { self.filename = filename self.locale = locale self.dictionary = dictionary } public typealias Key = String public struct Value: Sendable { public let params: [StringParam] public let originalValue: String public init(params: [StringParam], originalValue: String) { self.params = params self.originalValue = originalValue } } } ================================================ FILE: Sources/RswiftResources/Shared/TypeReference.swift ================================================ // // TypeReference.swift // R.swift // // Created by Mathijs Kadijk on 10-12-15. // import Foundation public struct TypeReference: Hashable, Sendable { public let module: ModuleReference public let name: String public var genericArgs: [TypeReference] public init(module: ModuleReference, rawName: String) { self.module = module self.name = rawName self.genericArgs = [] } public init(module: ModuleReference, name: String, genericArgs: [TypeReference]) { self.module = module self.name = name self.genericArgs = genericArgs } public var allModuleReferences: Set { Set(genericArgs.flatMap(\.allModuleReferences)).union([module]) } } ================================================ FILE: Sources/RswiftResources/Shared/Unifiable.swift ================================================ // // Unifiable.swift // R.swift // // Created by Tom Lokhorst on 2016-04-30. // import Foundation public protocol Unifiable { func unify(_ other: Self) -> Self? } extension Array where Element : Unifiable { public func unify(_ other: [Element]) -> [Element]? { var result = self for (ix, right) in other.enumerated() { if let left = result[safe: ix] { if let unified = left.unify(right) { result[ix] = unified } else { return nil } } else { result.append(right) } } return result } } private extension Array { subscript (safe index: Int) -> Element? { indices ~= index ? self[index] : nil } } ================================================ FILE: Sources/RswiftResources/Shared/ValidationError.swift ================================================ // // Validatable.swift // R.swift // // Created by Mathijs Kadijk on 17-12-15. // From: https://github.com/mac-cain13/R.swift // import Foundation /// Error thrown during validation public struct ValidationError: Error, CustomStringConvertible, Sendable { /// Human readable description public let description: String public init(_ description: String) { self.description = description } } ================================================ FILE: Sources/RswiftResources/StoryboardResource.swift ================================================ // // StoryboardResource.swift // R.swift // // Created by Mathijs Kadijk on 09-12-15. // import Foundation public struct StoryboardResource: Equatable, Sendable { public let name: String public var locale: LocaleReference public let deploymentTarget: DeploymentTarget? public let initialViewControllerIdentifier: String? public var viewControllers: [ViewController] public let viewControllerPlaceholders: [ViewControllerPlaceholder] public let generatedIds: [String] public var usedAccessibilityIdentifiers: [String] public var usedImageIdentifiers: [NameCatalog] public var usedColorResources: [NameCatalog] public var reusables: [Reusable] public var isAppKit: Bool public init( name: String, locale: LocaleReference, deploymentTarget: DeploymentTarget?, initialViewControllerIdentifier: String?, viewControllers: [ViewController], viewControllerPlaceholders: [ViewControllerPlaceholder], generatedIds: [String], usedAccessibilityIdentifiers: [String], usedImageIdentifiers: [NameCatalog], usedColorResources: [NameCatalog], reusables: [Reusable], isAppKit: Bool ) { self.name = name self.locale = locale self.deploymentTarget = deploymentTarget self.initialViewControllerIdentifier = initialViewControllerIdentifier self.viewControllers = viewControllers self.viewControllerPlaceholders = viewControllerPlaceholders self.generatedIds = generatedIds self.usedAccessibilityIdentifiers = usedAccessibilityIdentifiers self.usedImageIdentifiers = usedImageIdentifiers self.usedColorResources = usedColorResources self.reusables = reusables self.isAppKit = isAppKit } public struct ViewController: Equatable, Sendable { public let id: String public let storyboardIdentifier: String? public let type: TypeReference public var segues: [Segue] public init(id: String, storyboardIdentifier: String?, type: TypeReference, segues: [Segue]) { self.id = id self.storyboardIdentifier = storyboardIdentifier self.type = type self.segues = segues } } public struct ViewControllerPlaceholder: Equatable, Sendable { public let id: String public let storyboardName: String? public let referencedIdentifier: String? public let bundleIdentifier: String? public init(id: String, storyboardName: String?, referencedIdentifier: String?, bundleIdentifier: String?) { self.id = id self.storyboardName = storyboardName self.referencedIdentifier = referencedIdentifier self.bundleIdentifier = bundleIdentifier } } public struct Segue: Equatable, Sendable { public let identifier: String public let type: TypeReference public let destination: String public let kind: String public init(identifier: String, type: TypeReference, destination: String, kind: String) { self.identifier = identifier self.type = type self.destination = destination self.kind = kind } } public var initialViewController: ViewController? { viewControllers .filter { $0.id == self.initialViewControllerIdentifier } .first } public var viewControllersById: [String: ViewController] { Dictionary(uniqueKeysWithValues: viewControllers.map { ($0.id, $0) }) } } extension StoryboardResource { public struct UnifyResult { public let storyboard: StoryboardResource public let viewControllerResults: [String: StoryboardResource.ViewController.UnifyResult] public let differentInitialViewController: Bool public let differentDeploymentTargets: Bool public let differentViewControllerIDs: Set public let differentReusables: Set public func flatMap(_ transform: (StoryboardResource) -> UnifyResult) -> UnifyResult { let r = transform(storyboard) return UnifyResult( storyboard: r.storyboard, viewControllerResults: viewControllerResults.merging(r.viewControllerResults) { $0.unify($1) }, differentInitialViewController: differentInitialViewController || r.differentInitialViewController, differentDeploymentTargets: differentDeploymentTargets || r.differentDeploymentTargets, differentViewControllerIDs: differentViewControllerIDs.union(r.differentViewControllerIDs), differentReusables: differentReusables.union(r.differentReusables) ) } } public func unify(localizations: [StoryboardResource]) -> UnifyResult { var result = UnifyResult( storyboard: self, viewControllerResults: [:], differentInitialViewController: false, differentDeploymentTargets: false, differentViewControllerIDs: [], differentReusables: [] ) for storyboard in localizations { result = result.flatMap { $0.unify(storyboard) } } return result } public func unify(_ other: StoryboardResource) -> UnifyResult { let lhsVcs = self.viewControllersById let rhsVcs = other.viewControllersById let unifiedViewControllers = lhsVcs.compactMap { (id, lhs) -> StoryboardResource.ViewController.UnifyResult? in guard let rhs = rhsVcs[id] else { return nil } return lhs.unify(rhs) } let vcs = unifiedViewControllers.compactMap { ur -> StoryboardResource.ViewController? in if ur.differentTypes || ur.differentStoryboardIdentifiers { return nil } return ur.viewcontroller } var result = self result.viewControllers = vcs // Merged used images/colors from both localizations, they all need to be validated result.usedImageIdentifiers = Array(Set(self.usedImageIdentifiers).union(other.usedImageIdentifiers)) result.usedColorResources = Array(Set(self.usedColorResources).union(other.usedColorResources)) // Only keep reusables that exist in both localizations result.reusables = self.reusables.filter { other.reusables.contains($0) } // Keep other fields from self only, if they are different, that is recorded in UnifyResult // Remove locale, this is a merger of both result.locale = .none let allVcs = self.viewControllers + other.viewControllers let usedIds = Set(vcs.map(\.id)) let skipped = allVcs.compactMap { vc -> String? in usedIds.contains(vc.id) ? nil : vc.storyboardIdentifier } return UnifyResult( storyboard: result, viewControllerResults: Dictionary(uniqueKeysWithValues: unifiedViewControllers.map { ($0.viewcontroller.id, $0) }), differentInitialViewController: initialViewControllerIdentifier != other.initialViewControllerIdentifier, differentDeploymentTargets: deploymentTarget != other.deploymentTarget, differentViewControllerIDs: Set(skipped), differentReusables: Set(reusables).symmetricDifference(other.reusables) ) } } extension StoryboardResource.ViewController { public struct UnifyResult { public let viewcontroller: StoryboardResource.ViewController public let differentStoryboardIdentifiers: Bool public let differentTypes: Bool public let differentSegueIDs: Set func unify(_ other: Self) -> Self { .init( viewcontroller: viewcontroller, differentStoryboardIdentifiers: differentStoryboardIdentifiers || other.differentStoryboardIdentifiers, differentTypes: differentTypes || other.differentTypes, differentSegueIDs: differentSegueIDs.union(other.differentSegueIDs) ) } } public func unify(_ other: Self) -> UnifyResult { let rhsSegues = Dictionary(grouping: other.segues, by: \.identifier) var result = self result.segues = result.segues.filter { l in guard let ss = rhsSegues[l.identifier], let r = ss.first else { return false } return l.canUnify(r) } let usedIDs = Set(result.segues.map(\.identifier)) let different = (self.segues + other.segues).filter { s in !usedIDs.contains(s.identifier) } return UnifyResult( viewcontroller: result, differentStoryboardIdentifiers: storyboardIdentifier != other.storyboardIdentifier, differentTypes: type != other.type, differentSegueIDs: Set(different.map(\.identifier)) ) } } private extension StoryboardResource.Segue { func canUnify(_ other: Self) -> Bool { self == other } } ================================================ FILE: Sources/RswiftResources/StringResource.swift ================================================ // // StringResource.swift // // // Created by Tom Lokhorst on 2022-07-24. // import Foundation public struct StringResource: Sendable { public enum Source: Sendable { case hosting(Bundle) case selected(Bundle, Locale) case none public var bundle: Bundle? { switch self { case .hosting(let bundle): return bundle case .selected(let bundle, _): return bundle case .none: return nil } } } public let key: StaticString public let tableName: String public let source: Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource1: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource2: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource3: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource4: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource5: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource6: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource7: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource8: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } public struct StringResource9: Sendable { public let key: StaticString public let tableName: String public let source: StringResource.Source public let developmentValue: String? public let comment: StaticString? public init(key: StaticString, tableName: String, source: StringResource.Source, developmentValue: String?, comment: StaticString?) { self.key = key self.tableName = tableName self.source = source self.developmentValue = developmentValue self.comment = comment } } ================================================ FILE: Sources/rswift/App.swift ================================================ // // App.swift // rswift // // Created by Tom Lokhorst on 2021-04-18. // import ArgumentParser import Foundation import RswiftParsers import XcodeEdit @main struct App: ParsableCommand { static let configuration = CommandConfiguration( commandName: "rswift", abstract: "Generate static references for autocompleted resources like images, fonts and localized strings in Swift projects", version: Config.version, subcommands: [Generate.self, ModifyXcodePackages.self] ) } enum InputType: String, ExpressibleByArgument { case xcodeproj = "xcodeproj" case inputFiles = "input-files" } struct GlobalOptions: ParsableArguments { @Option(help: "The type of input for generation") var inputType: InputType = .xcodeproj @Option(help: "Only run specified generators, options: \(generatorsString)", transform: parseGenerators) var generators: [ResourceType] = [] @Flag(help: "Don't generate main `R` let") var omitMainLet = false @Option(name: .customLong("import", withSingleDash: false), help: "Add extra modules as import in the generated file") var imports: [String] = [] @Option(help: "The access level [public|internal] to use for the generated R-file") var accessLevel: AccessLevel = .internalLevel @Option(help: "Path to pattern file that describes files that should be ignored") var rswiftignore = ".rswiftignore" @Option(help: "Paths of files for which resources should be generated") var inputFiles: [String] = [] @Option(help: "Source of default bundle to use") var bundleSource: BundleSource = .finder // MARK: Project specific - Environment variable overrides @Option(help: "Override environment variable \(EnvironmentKeys.targetName)") var target: String? } private let generatorsString = ResourceType.allCases.map(\.rawValue).joined(separator: ", ") private func parseGenerators(_ str: String) -> [ResourceType] { str.components(separatedBy: ",").map { ResourceType(rawValue: $0)! } } extension App { struct Generate: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Generates R.generated.swift file") @OptionGroup var globals: GlobalOptions @Option(help: "Override environment variable \(EnvironmentKeys.productFilePath)") var xcodeproj: String? @Argument(help: "Output path for the generated file") var outputPath: String mutating func run() throws { let processInfo = ProcessInfo.processInfo let productModuleName = processInfo.environment[EnvironmentKeys.productModuleName] let infoPlistFile = processInfo.environment[EnvironmentKeys.infoPlistFile] let codeSignEntitlements = processInfo.environment[EnvironmentKeys.codeSignEntitlements] // If no environment is provided, we're not running inside Xcode, fallback to names let sourceTreeURLs = SourceTreeURLs( builtProductsDirURL: URL(fileURLWithPath: processInfo.environment[EnvironmentKeys.builtProductsDir] ?? EnvironmentKeys.builtProductsDir), developerDirURL: URL(fileURLWithPath: processInfo.environment[EnvironmentKeys.developerDir] ?? EnvironmentKeys.developerDir), sourceRootURL: URL(fileURLWithPath: processInfo.environment[EnvironmentKeys.sourceRoot] ?? "."), sdkRootURL: URL(fileURLWithPath: processInfo.environment[EnvironmentKeys.sdkRoot] ?? EnvironmentKeys.sdkRoot), platformURL: URL(fileURLWithPath: processInfo.environment[EnvironmentKeys.platformDir] ?? EnvironmentKeys.platformDir) ) let outputURL = URL(fileURLWithPath: outputPath) let rswiftIgnoreURL = sourceTreeURLs.sourceRootURL .appendingPathComponent(globals.rswiftignore, isDirectory: false) let core = RswiftCore( outputURL: outputURL, generators: globals.generators.isEmpty ? ResourceType.allCases : globals.generators, accessLevel: globals.accessLevel, bundleSource: globals.bundleSource, importModules: globals.imports, productModuleName: productModuleName, infoPlistFile: infoPlistFile.map(URL.init(fileURLWithPath:)), codeSignEntitlements: codeSignEntitlements.map(URL.init(fileURLWithPath:)), omitMainLet: globals.omitMainLet, rswiftIgnoreURL: rswiftIgnoreURL, sourceTreeURLs: sourceTreeURLs ) do { switch globals.inputType { case .xcodeproj: let xcodeprojPath = try xcodeproj ?? ProcessInfo.processInfo .environmentVariable(name: EnvironmentKeys.productFilePath) let xcodeprojURL = URL(fileURLWithPath: xcodeprojPath) let targetName = try getTargetName(xcodeprojURL: xcodeprojURL) try core.generateFromXcodeproj(url: xcodeprojURL, targetName: targetName) case .inputFiles: try core.generateFromFiles(inputFileURLs: globals.inputFiles.map(URL.init(fileURLWithPath:))) } } catch let error as ResourceParsingError { throw ValidationError(error.description) } } func getTargetName(xcodeprojURL: URL) throws -> String { if let targetName = globals.target ?? ProcessInfo.processInfo .environment[EnvironmentKeys.targetName] { return targetName } do { let xcodeproj = try Xcodeproj(url: xcodeprojURL, warning: { _ in }) let targets = xcodeproj.allTargets if let target = targets.first, targets.count == 1 { return target.name } if targets.count > 0 { let lines = [ "Missing argument --target", "Available targets:" ] + targets.map { "- \($0.name)" } throw ValidationError(lines.joined(separator: "\n")) } throw ValidationError("Missing argument --target") } catch { throw ValidationError("Missing argument --target") } } } } extension App { struct ModifyXcodePackages: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Modifies Xcode project to fix package reference for plugins") @Option(help: "Path to xcodeproj file") var xcodeproj: String @Option(help: "Targets for which to remove package reference") var target: [String] = [] mutating func run() throws { let url = URL(fileURLWithPath: xcodeproj) let file = try XCProjectFile(xcodeprojURL: url, ignoreReferenceErrors: true) for target in file.project.targets.compactMap(\.value) { guard self.target.contains(target.name) else { continue } for product in target.dependencies.compactMap(\.value?.productRef?.value) { let plugins = ["plugin:RswiftGenerateInternalResources", "plugin:RswiftGeneratePublicResources"] if let name = product.productName, plugins.contains(name) { product.removePackage() } } } try file.write(to: url) } } } struct EnvironmentKeys { static let action = "ACTION" static let targetName = "TARGET_NAME" static let infoPlistFile = "INFOPLIST_FILE" static let productFilePath = "PROJECT_FILE_PATH" static let productModuleName = "PRODUCT_MODULE_NAME" static let codeSignEntitlements = "CODE_SIGN_ENTITLEMENTS" static let builtProductsDir = SourceTreeFolder.buildProductsDir.rawValue static let developerDir = SourceTreeFolder.developerDir.rawValue static let platformDir = SourceTreeFolder.platformDir.rawValue static let sdkRoot = SourceTreeFolder.sdkRoot.rawValue static let sourceRoot = SourceTreeFolder.sourceRoot.rawValue } extension ProcessInfo { func environmentVariable(name: String) throws -> String { guard let value = self.environment[name] else { throw ValidationError("Missing argument \(name)") } return value } } ================================================ FILE: Sources/rswift/Config.swift ================================================ // // Config.swift // R.swift // // Created by Tom Lokhorst on 2017-04-22. // import Foundation struct Config { static let version = "Unknown" } ================================================ FILE: Sources/rswift/RswiftCore.swift ================================================ // // RswiftCore.swift // rswift // // Created by Tom Lokhorst on 2021-04-16. // import Foundation import ArgumentParser import XcodeEdit import RswiftParsers import RswiftResources import RswiftGenerators extension ResourceType: ExpressibleByArgument {} public enum AccessLevel: String, ExpressibleByArgument { case publicLevel = "public" case internalLevel = "internal" case filePrivate = "fileprivate" case privateLevel = "private" } public enum BundleSource: String, ExpressibleByArgument { case module case finder } public struct RswiftCore { let outputURL: URL let generators: [ResourceType] let accessLevel: AccessLevel let bundleSource: BundleSource let importModules: [String] let productModuleName: String? let infoPlistFile: URL? let codeSignEntitlements: URL? let omitMainLet: Bool let sourceTreeURLs: SourceTreeURLs let rswiftIgnoreURL: URL public init( outputURL: URL, generators: [ResourceType], accessLevel: AccessLevel, bundleSource: BundleSource, importModules: [String], productModuleName: String?, infoPlistFile: URL?, codeSignEntitlements: URL?, omitMainLet: Bool, rswiftIgnoreURL: URL, sourceTreeURLs: SourceTreeURLs ) { self.outputURL = outputURL self.generators = generators self.accessLevel = accessLevel self.bundleSource = bundleSource self.importModules = importModules self.productModuleName = productModuleName self.infoPlistFile = infoPlistFile self.codeSignEntitlements = codeSignEntitlements self.omitMainLet = omitMainLet self.rswiftIgnoreURL = rswiftIgnoreURL self.sourceTreeURLs = sourceTreeURLs } public func generateFromXcodeproj(url xcodeprojURL: URL, targetName: String) throws { let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let xcodeproj = try Xcodeproj(url: xcodeprojURL, warning: warning) let resources = try ProjectResources.parseXcodeproj( xcodeproj: xcodeproj, targetName: targetName, rswiftIgnoreURL: rswiftIgnoreURL, infoPlistFile: infoPlistFile, codeSignEntitlements: codeSignEntitlements, sourceTreeURLs: sourceTreeURLs, parseFontsAsFiles: true, parseImagesAsFiles: true, resourceTypes: generators, warning: warning ) try generateFromProjectResources(resources: resources, developmentRegion: xcodeproj.developmentRegion, knownAssetTags: xcodeproj.knownAssetTags) } public func generateFromFiles(inputFileURLs urls: [URL]) throws { let warning: (String) -> Void = { print("warning: [R.swift]", $0) } let resources = try ProjectResources.parseURLs( urls: urls, infoPlists: [], codeSignEntitlements: [], parseFontsAsFiles: true, parseImagesAsFiles: true, resourceTypes: generators, warning: warning ) try generateFromProjectResources(resources: resources, developmentRegion: nil, knownAssetTags: nil) } private func generateFromProjectResources(resources: ProjectResources, developmentRegion: String?, knownAssetTags: [String]?) throws { let structName = SwiftIdentifier(rawValue: "_R") let qualifiedName = structName let segueStruct = Segue.generateStruct( storyboards: resources.storyboards, prefix: qualifiedName ) let imageStruct = ImageResource.generateStruct( catalogs: resources.assetCatalogs, toplevel: resources.images, prefix: qualifiedName ) let colorStruct = ColorResource.generateStruct( catalogs: resources.assetCatalogs, prefix: qualifiedName ) let dataStruct = DataResource.generateStruct( catalogs: resources.assetCatalogs, prefix: qualifiedName ) let fileStruct = FileResource.generateStruct( resources: resources.files, prefix: qualifiedName ) let idStruct = AccessibilityIdentifier.generateStruct( nibs: resources.nibs, storyboards: resources.storyboards, prefix: qualifiedName ) let fontStruct = FontResource.generateStruct( resources: resources.fonts, prefix: qualifiedName ) let storyboardStruct = StoryboardResource.generateStruct( storyboards: resources.storyboards, prefix: qualifiedName ) let infoStruct = PropertyListResource.generateInfoStruct( resourceName: "info", plists: resources.infoPlists, prefix: qualifiedName ) let entitlementsStruct = PropertyListResource.generateStruct( resourceName: "entitlements", plists: resources.codeSignEntitlements, prefix: qualifiedName ) let nibStruct = NibResource.generateStruct( nibs: resources.nibs, prefix: qualifiedName ) let reuseIdentifierStruct = Reusable.generateStruct( nibs: resources.nibs, storyboards: resources.storyboards, prefix: qualifiedName ) let stringStruct = StringsTable.generateStruct( tables: resources.strings, developmentLanguage: developmentRegion, prefix: qualifiedName ) let projectStruct = XcodeProjectGenerator.generateProject(developmentRegion: developmentRegion, knownAssetTags: knownAssetTags) let generateFont = generators.contains(.font) && !fontStruct.isEmpty let generateNib = generators.contains(.nib) && !nibStruct.isEmpty let generateStoryboard = generators.contains(.storyboard) && !storyboardStruct.isEmpty let validateLines = [ generateFont ? "try self.font.validate()" : "", generateNib ? "try self.nib.validate()" : "", generateStoryboard ? "try self.storyboard.validate()" : "", ] .filter { $0 != "" } .joined(separator: "\n") let validate = Function( comments: [], name: SwiftIdentifier(name: "validate"), params: [], returnThrows: true, returnType: .init(module: .stdLib, rawName: "Void"), valueCodeString: validateLines ) var s = Struct(name: structName, additionalModuleReferences: [.rswiftResources]) { Init.bundle if generators.contains(.project), !projectStruct.isEmpty { projectStruct } if generators.contains(.string), !stringStruct.isEmpty { stringStruct.generateBundleVarGetterForString() stringStruct.generateBundleFunctionForString(name: "string") stringStruct.generateLocaleFunctionForString(name: "string") stringStruct.generatePreferredLanguagesFunctionForString(name: "string") stringStruct } if generators.contains(.data), !dataStruct.isEmpty { dataStruct.generateBundleVarGetter(name: "data") dataStruct.generateBundleFunction(name: "data") dataStruct } if generators.contains(.color), !colorStruct.isEmpty { colorStruct.generateBundleVarGetter(name: "color") colorStruct.generateBundleFunction(name: "color") colorStruct } if generators.contains(.image), !imageStruct.isEmpty { imageStruct.generateBundleVarGetter(name: "image") imageStruct.generateBundleFunction(name: "image") imageStruct } if generators.contains(.info), !infoStruct.isEmpty { infoStruct.generateBundleVarGetter(name: "info") infoStruct.generateBundleFunction(name: "info") infoStruct } if generators.contains(.entitlements), !entitlementsStruct.isEmpty { entitlementsStruct.generateVarGetter() entitlementsStruct } if generateFont { fontStruct.generateBundleVarGetter(name: "font") fontStruct.generateBundleFunction(name: "font") fontStruct } if generators.contains(.file), !fileStruct.isEmpty { fileStruct.generateBundleVarGetter(name: "file") fileStruct.generateBundleFunction(name: "file") fileStruct } if generators.contains(.segue), !segueStruct.isEmpty { segueStruct.generateVarGetter() segueStruct } if generators.contains(.id), !idStruct.isEmpty { idStruct.generateVarGetter() idStruct } if generateNib { nibStruct.generateBundleVarGetter(name: "nib") nibStruct.generateBundleFunction(name: "nib") nibStruct } if generators.contains(.reuseIdentifier), !reuseIdentifierStruct.isEmpty { reuseIdentifierStruct.generateVarGetter() reuseIdentifierStruct } if generateStoryboard { storyboardStruct.generateBundleVarGetter(name: "storyboard") storyboardStruct.generateBundleFunction(name: "storyboard") storyboardStruct } validate } if accessLevel == .publicLevel { s.setAccessControl(.public) s.markSendable() } let imports = Set(s.allModuleReferences.compactMap(\.name)) .union(importModules) .subtracting([productModuleName].compactMap { $0 }) .sorted() .map { "import \($0)" } .joined(separator: "\n") let mainLet: String switch bundleSource { case .module: mainLet = "\(accessLevel == .publicLevel ? "public " : "")let R = _R(bundle: Bundle.module)" case .finder: mainLet = """ private class BundleFinder {} \(accessLevel == .publicLevel ? "public " : "")let R = _R(bundle: Bundle(for: BundleFinder.self)) """ } let body = s.prettyPrint() let header = """ // // This is a generated file, do not edit! // Generated by R.swift, see https://github.com/mac-cain13/R.swift // """ let parts = [header, imports, omitMainLet ? nil : mainLet, body].compactMap { $0 } let code = parts.joined(separator: "\n\n") try writeIfChanged(contents: code, toURL: outputURL) } } private func writeIfChanged(contents: String, toURL outputURL: URL) throws { let currentFileContents = try? String(contentsOf: outputURL, encoding: .utf8) guard currentFileContents != contents else { return } try contents.write(to: outputURL, atomically: false, encoding: .utf8) } ================================================ FILE: Tests/RswiftGeneratorsTests/MainTests.swift ================================================ // // MainTests.swift // R.swift // // Created by Mathijs Kadijk on 28-09-15. // import XCTest @testable import RswiftGenerators class MainTests: XCTestCase { override func setUp() { super.setUp() } override func tearDown() { super.tearDown() } let swiftNameData = [ "easy": "easy", "easyAndSimple": "easyAndSimple", "easy with some spaces": "easyWithSomeSpaces", "(looks) easy": "looksEasy", "looks-easy": "looksEasy", "looks+like^some-kind*of%easy": "looksLikeSomeKindOfEasy", "(looks) easy, but it's not really NeXT that easy!": "looksEasyButItSNotReallyNeXTThatEasy", "easy 123 and done...": "easy123AndDone", "123 easy!": "easy", "123 456easy": "easy", "123 😄": "😄", "🇳🇱": "🇳🇱", "🌂MakeItRain!": "🌂MakeItRain", "PRFXMyClass": "prfxMyClass", "NSSomeThing": "nsSomeThing", "MyClass": "myClass", "PRFX_MyClass": "prfx_MyClass", "PRFX-myClass": "prfxMyClass", "123NSSomeThing": "nsSomeThing", "PR123FXMyClass": "pr123FXMyClass" ] func testSwiftNameSanitization() { swiftNameData.forEach { let sanitizedResult = SwiftIdentifier(name: $0.0, lowercaseStartingCharacters: true).value XCTAssertEqual(sanitizedResult, $0.1) } } func testPerformanceSwiftNameSanitization() { // This is an example of a performance test case. self.measure { (0...1000).forEach { _ in let _ = SwiftIdentifier(name: "(looks) easy, but it's not reallY that easy!", lowercaseStartingCharacters: true) } } } } ================================================ FILE: Tests/RswiftParsersTests/GlobTests.swift ================================================ // // Created by Eric Firestone on 3/22/16. // Copyright © 2016 Square, Inc. All rights reserved. // Released under the Apache v2 License. // // Adapted from https://gist.github.com/blakemerryman/76312e1cbf8aec248167 // Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3 import XCTest @testable import RswiftParsers class GlobTests : XCTestCase { let tmpFiles = ["foo", "bar", "baz", "dir1/file1.ext", "dir1/dir2/dir3/file2.ext", "dir1/file1.extfoo"] var tmpDir = "" override func setUp() { super.setUp() self.tmpDir = newTmpDir() let flags = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH mkdir("\(tmpDir)/dir1/", flags) mkdir("\(tmpDir)/dir1/dir2", flags) mkdir("\(tmpDir)/dir1/dir2/dir3", flags) for file in tmpFiles { close(open("\(tmpDir)/\(file)", O_CREAT)) } } override func tearDown() { for file in tmpFiles { unlink("\(tmpDir)/\(file)") } rmdir("\(tmpDir)/dir1/dir2/dir3") rmdir("\(tmpDir)/dir1/dir2") rmdir("\(tmpDir)/dir1") rmdir(self.tmpDir) super.tearDown() } private func newTmpDir() -> String { var tmpDirTmpl = "/tmp/glob-test.XXXXX".cString(using: .utf8)! return String(validatingCString: mkdtemp(&tmpDirTmpl))! } func testBraces() { let pattern = "\(tmpDir)/ba{r,y,z}" let glob = Glob(pattern: pattern) var contents = [String]() for file in glob { contents.append(file) } XCTAssertEqual(contents, ["\(tmpDir)/bar", "\(tmpDir)/baz"], "matching with braces failed") } func testNothingMatches() { let pattern = "\(tmpDir)/nothing" let glob = Glob(pattern: pattern) var contents = [String]() for file in glob { contents.append(file) } XCTAssertEqual(contents, [], "expected empty list of files") } func testDirectAccess() { let pattern = "\(tmpDir)/ba{r,y,z}" let glob = Glob(pattern: pattern) XCTAssertEqual(glob.paths, ["\(tmpDir)/bar", "\(tmpDir)/baz"], "matching with braces failed") } func testIterateTwice() { let pattern = "\(tmpDir)/ba{r,y,z}" let glob = Glob(pattern: pattern) var contents1 = [String]() var contents2 = [String]() for file in glob { contents1.append(file) } let filesAfterOnce = glob.paths for file in glob { contents2.append(file) } XCTAssertEqual(contents1, contents2, "results for calling for-in twice are the same") XCTAssertEqual(glob.paths, filesAfterOnce, "calling for-in twice doesn't only memoizes once") } func testIndexing() { let pattern = "\(tmpDir)/ba{r,y,z}" let glob = Glob(pattern: pattern) XCTAssertEqual(glob[0], "\(tmpDir)/bar", "indexing") } // MARK: - Globstar - Bash v3 func testGlobstarBashV3NoSlash() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**" let pattern = "\(tmpDir)/**" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV3) XCTAssertEqual(glob.paths, ["\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/dir1/", "\(tmpDir)/foo"]) } func testGlobstarBashV3WithSlash() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**/" let pattern = "\(tmpDir)/**/" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV3) XCTAssertEqual(glob.paths, ["\(tmpDir)/dir1/"]) } func testGlobstarBashV3WithSlashAndWildcard() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**/*" let pattern = "\(tmpDir)/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV3) XCTAssertEqual(glob.paths, ["\(tmpDir)/dir1/dir2/", "\(tmpDir)/dir1/file1.ext", "\(tmpDir)/dir1/file1.extfoo"]) } func testDoubleGlobstarBashV3() { let pattern = "\(tmpDir)/**/dir2/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV3) XCTAssertEqual(glob.paths, ["\(tmpDir)/dir1/dir2/dir3/file2.ext"]) } // MARK: - Globstar - Bash v4 func testGlobstarBashV4NoSlash() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**" let pattern = "\(tmpDir)/**" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV4) XCTAssertEqual(glob.paths, [ "\(tmpDir)/", "\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/dir1/", "\(tmpDir)/dir1/dir2/", "\(tmpDir)/dir1/dir2/dir3/", "\(tmpDir)/dir1/dir2/dir3/file2.ext", "\(tmpDir)/dir1/file1.ext", "\(tmpDir)/dir1/file1.extfoo", "\(tmpDir)/foo" ]) } func testGlobstarBashV4WithSlash() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**/" let pattern = "\(tmpDir)/**/" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV4) XCTAssertEqual(glob.paths, [ "\(tmpDir)/", "\(tmpDir)/dir1/", "\(tmpDir)/dir1/dir2/", "\(tmpDir)/dir1/dir2/dir3/", ]) } func testGlobstarBashV4WithSlashAndWildcard() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**/*" let pattern = "\(tmpDir)/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV4) XCTAssertEqual(glob.paths, [ "\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/dir1/", "\(tmpDir)/dir1/dir2/", "\(tmpDir)/dir1/dir2/dir3/", "\(tmpDir)/dir1/dir2/dir3/file2.ext", "\(tmpDir)/dir1/file1.ext", "\(tmpDir)/dir1/file1.extfoo", "\(tmpDir)/foo", ]) } func testDoubleGlobstarBashV4() { let pattern = "\(tmpDir)/**/dir2/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV4) XCTAssertEqual(glob.paths, [ "\(tmpDir)/dir1/dir2/dir3/", "\(tmpDir)/dir1/dir2/dir3/file2.ext", ]) } func testDoubleGlobstarBashV4WithFileExtension() { // Should be the equivalent of "ls -d -1 /(tmpdir)/**/*.ext" // Should not find "\(tmpDir)/dir1/file1.extfoo" which the file extension prefix is .ext let pattern = "\(tmpDir)/**/*.ext" let glob = Glob(pattern: pattern, behavior: GlobBehaviorBashV4) XCTAssertEqual(glob.paths, [ "\(tmpDir)/dir1/dir2/dir3/file2.ext", "\(tmpDir)/dir1/file1.ext" ]) } // MARK: - Globstar - Gradle func testGlobstarGradleNoSlash() { // Should be the equivalent of // FileTree tree = project.fileTree((Object)'/tmp') { // include 'glob-test.7m0Lp/**' // } // // Note that the sort order currently matches Bash and not Gradle let pattern = "\(tmpDir)/**" let glob = Glob(pattern: pattern, behavior: GlobBehaviorGradle) XCTAssertEqual(glob.paths, [ "\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/dir1/dir2/dir3/file2.ext", "\(tmpDir)/dir1/file1.ext", "\(tmpDir)/dir1/file1.extfoo", "\(tmpDir)/foo", ]) } func testGlobstarGradleWithSlash() { // Should be the equivalent of // FileTree tree = project.fileTree((Object)'/tmp') { // include 'glob-test.7m0Lp/**/' // } // // Note that the sort order currently matches Bash and not Gradle let pattern = "\(tmpDir)/**/" let glob = Glob(pattern: pattern, behavior: GlobBehaviorGradle) XCTAssertEqual(glob.paths, [ "\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/dir1/dir2/dir3/file2.ext", "\(tmpDir)/dir1/file1.ext", "\(tmpDir)/dir1/file1.extfoo", "\(tmpDir)/foo", ]) } func testGlobstarGradleWithSlashAndWildcard() { // Should be the equivalent of // FileTree tree = project.fileTree((Object)'/tmp') { // include 'glob-test.7m0Lp/**/*' // } // // Note that the sort order currently matches Bash and not Gradle let pattern = "\(tmpDir)/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorGradle) XCTAssertEqual(glob.paths, [ "\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/dir1/dir2/dir3/file2.ext", "\(tmpDir)/dir1/file1.ext", "\(tmpDir)/dir1/file1.extfoo", "\(tmpDir)/foo", ]) } func testDoubleGlobstarGradle() { // Should be the equivalent of // FileTree tree = project.fileTree((Object)'/tmp') { // include 'glob-test.7m0Lp/**/dir2/**/*' // } // // Note that the sort order currently matches Bash and not Gradle let pattern = "\(tmpDir)/**/dir2/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorGradle) XCTAssertEqual(glob.paths, [ "\(tmpDir)/dir1/dir2/dir3/file2.ext", ]) } func testBlacklistedDirectories() { let pattern = "\(tmpDir)/**/*" let glob = Glob(pattern: pattern, behavior: GlobBehaviorGradle, blacklistedDirectories: ["dir1"]) XCTAssertEqual(glob.paths, [ "\(tmpDir)/bar", "\(tmpDir)/baz", "\(tmpDir)/foo", ]) } } ================================================ FILE: Tests/RswiftParsersTests/NibParserDelegateTests.swift ================================================ // // NibParserTests.swift // RswiftCoreTests // // Created by Rafael Nobre on 04/07/18. // import XCTest @testable import RswiftResources @testable import RswiftParsers class NibParserTests: XCTestCase { let nibContents = """ """ func testTopLevelObjectsAreNotAffectedByColorTags() { guard let data = nibContents.data(using: String.Encoding.utf8) else { return XCTFail("Unable to create nibContents") } let parser = XMLParser(data: data) let parserDelegate = NibParserDelegate() parser.delegate = parserDelegate guard parser.parse() else { return XCTFail("Invalid XML") } XCTAssert(parserDelegate.rootViews.count == 1) XCTAssert(parserDelegate.reusables.count == 1) } func testRootViewTypeIsCorrectlyExposed() { guard let data = nibContents.data(using: String.Encoding.utf8) else { return XCTFail("Unable to create nibContents") } let parser = XMLParser(data: data) let parserDelegate = NibParserDelegate() parser.delegate = parserDelegate guard parser.parse() else { return XCTFail("Invalid XML") } XCTAssert(parserDelegate.rootViews.first != TypeReference(module: .uiKit, rawName: "UIView")) } }