├── Sources └── Cleanse ├── Tests └── CleanseTests ├── Documentation ├── README.rst ├── .gitignore ├── Components.png ├── cleanse_logo.png ├── ChangeToolchain.png ├── cleanse_logo_small.png ├── under-construction.gif ├── index.rst └── Binding Grammar.rst ├── .coveralls.yml ├── cleansec ├── .gitignore ├── Sandbox │ ├── Sandbox │ │ ├── Assets.xcassets │ │ │ └── Contents.json │ │ ├── ViewController.swift │ │ ├── AppComponent.swift │ │ ├── AppDelegate.swift │ │ └── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ └── Sandbox.xcodeproj │ │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── script │ ├── Fixtures.template │ ├── create-fixtures.rb │ └── swiftc-ast.rb ├── cleansec.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── cleansec.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── CleansecFramework │ ├── main.swift │ ├── Linking │ │ ├── LinkedInterface.swift │ │ ├── LinkedModule.swift │ │ └── LinkedComponent.swift │ ├── Visitors │ │ ├── Representations │ │ │ ├── DebugData.swift │ │ │ └── ProviderModels.swift │ │ └── Provider Visitor │ │ │ ├── ComponentRootVisitor.swift │ │ │ └── APITypes.swift │ ├── CleansecFramework.h │ ├── Info.plist │ └── Resolver │ │ ├── LinkedMerging.swift │ │ └── ResolvedComponent.swift ├── Cleansec-Generate-Fixtures │ ├── Code Fixtures │ │ ├── DoesNotImportCleanse.swift │ │ ├── ImportsCleanse.swift │ │ ├── NestedModule.swift │ │ ├── ModuleWithImplicitType.swift │ │ ├── ModuleIncludesModule.swift │ │ ├── ModuleWithImplicitInitFactory.swift │ │ ├── PropertyInjection.swift │ │ ├── SimpleRootComponent.swift │ │ ├── GenericType.swift │ │ ├── BasicBindings.swift │ │ ├── ModuleWithTaggedProvider.swift │ │ ├── TaggedProviderDependency.swift │ │ ├── ComponentWithSeed.swift │ │ ├── AssistedInjection.swift │ │ ├── InnerTag.swift │ │ ├── ManyDependencies.swift │ │ ├── CustomScopeBinding.swift │ │ ├── ModuleIncludesSubcomponent.swift │ │ ├── ModuleWithDependencies.swift │ │ ├── PropertyInjectorRoot.swift │ │ ├── SimpleComponent.swift │ │ └── CollectionBindings.swift │ ├── Cleansec_Generate_Fixtures.h │ └── Info.plist ├── SwiftAstParser │ ├── Syntax.swift │ ├── Parsing │ │ ├── DataStringMapper.swift │ │ ├── SyntaxParser.swift │ │ └── ASTStringHelpers.swift │ ├── Nodes │ │ ├── TypedSyntax.swift │ │ └── InheritableSyntax.swift │ ├── SwiftAstParser.h │ ├── script │ │ ├── Nodes.template │ │ └── SyntaxVisitor.template │ ├── Info.plist │ └── README.md ├── cleansec │ └── PluginRunner.swift ├── Makefile ├── SwiftAstParserTests │ ├── Info.plist │ └── SwiftAstParserTests.swift └── CleansecFrameworkTests │ ├── Info.plist │ ├── LinkerTests.swift │ └── PluginTests.swift ├── arities-autogen.sh ├── Gemfile ├── Examples ├── CleanseGithubBrowser │ ├── CleanseGithubBrowser │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── TabBarIcons │ │ │ │ ├── Contents.json │ │ │ │ ├── Members.imageset │ │ │ │ │ ├── icon_member.pdf │ │ │ │ │ └── Contents.json │ │ │ │ ├── Settings.imageset │ │ │ │ │ ├── icon_settings.pdf │ │ │ │ │ └── Contents.json │ │ │ │ └── Repositories.imageset │ │ │ │ │ ├── icon_repository.pdf │ │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app-icon-ipad.png │ │ │ │ ├── cleanse_logo.png │ │ │ │ ├── app-icon-ipad@2x.png │ │ │ │ ├── app-icon-iphone@2x.png │ │ │ │ ├── app-icon-iphone@3x.png │ │ │ │ ├── app-icon-spotlight.png │ │ │ │ ├── app-icon-setting@2x-1.png │ │ │ │ ├── app-icon-setting@2x-2.png │ │ │ │ ├── app-icon-setting@3x-1.png │ │ │ │ ├── app-icon-spotlight@2x-1.png │ │ │ │ ├── app-icon-spotlight@2x.png │ │ │ │ └── app-icon-spotlight@3x.png │ │ ├── SingletonScope.swift │ │ ├── HTTPError.swift │ │ ├── FoundationCommonModule.swift │ │ ├── TableViewController.swift │ │ ├── SplitViewController.swift │ │ ├── NetworkModule.swift │ │ ├── GithubMemberService.swift │ │ ├── GithubRepositoriesService.swift │ │ ├── Info.plist │ │ ├── GithubServicesModule.swift │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ ├── NSURLSessionAdditions.swift │ │ └── UIKitCommonModule.swift │ ├── CleanseGithubBrowser.xcodeproj │ │ └── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── CleanseGithubBrowserTests │ │ ├── Info.plist │ │ └── CleanseGithubBrowserTests.swift │ └── CleanseGithubBrowserUITests │ │ └── Info.plist ├── CleanseSwiftUIExample │ ├── CleanseSwiftUIExample │ │ ├── SupportingFiles │ │ │ ├── Assets.xcassets │ │ │ │ ├── Contents.json │ │ │ │ ├── me.imageset │ │ │ │ │ ├── me.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── cat-solid.imageset │ │ │ │ │ ├── cat-solid.png │ │ │ │ │ ├── cat-solid@2x.png │ │ │ │ │ ├── cat-solid@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── dog-solid.imageset │ │ │ │ │ ├── dog-solid.png │ │ │ │ │ ├── dog-solid@2x.png │ │ │ │ │ ├── dog-solid@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── paw-solid.imageset │ │ │ │ │ ├── paw-solid.png │ │ │ │ │ ├── paw-solid@2x.png │ │ │ │ │ ├── paw-solid@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── otter-solid.imageset │ │ │ │ │ ├── otter-solid.png │ │ │ │ │ ├── otter-solid@2x.png │ │ │ │ │ ├── otter-solid@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── illustration-cat.imageset │ │ │ │ │ ├── illustration-cat.png │ │ │ │ │ ├── illustration-cat@2x.png │ │ │ │ │ ├── illustration-cat@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── illustration-dog.imageset │ │ │ │ │ ├── illustration-dog.png │ │ │ │ │ ├── illustration-dog@2x.png │ │ │ │ │ ├── illustration-dog@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── on-primary.colorset │ │ │ │ │ └── Contents.json │ │ │ │ └── primary.colorset │ │ │ │ │ └── Contents.json │ │ │ └── Info.plist │ │ ├── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ │ ├── Contents.json │ │ │ │ ├── me.imageset │ │ │ │ ├── me.png │ │ │ │ └── Contents.json │ │ │ │ ├── cat-solid.imageset │ │ │ │ ├── cat-solid.png │ │ │ │ ├── cat-solid@2x.png │ │ │ │ ├── cat-solid@3x.png │ │ │ │ └── Contents.json │ │ │ │ ├── dog-solid.imageset │ │ │ │ ├── dog-solid.png │ │ │ │ ├── dog-solid@2x.png │ │ │ │ ├── dog-solid@3x.png │ │ │ │ └── Contents.json │ │ │ │ ├── paw-solid.imageset │ │ │ │ ├── paw-solid.png │ │ │ │ ├── paw-solid@2x.png │ │ │ │ ├── paw-solid@3x.png │ │ │ │ └── Contents.json │ │ │ │ ├── otter-solid.imageset │ │ │ │ ├── otter-solid.png │ │ │ │ ├── otter-solid@2x.png │ │ │ │ ├── otter-solid@3x.png │ │ │ │ └── Contents.json │ │ │ │ ├── illustration-cat.imageset │ │ │ │ ├── illustration-cat.png │ │ │ │ ├── illustration-cat@2x.png │ │ │ │ ├── illustration-cat@3x.png │ │ │ │ └── Contents.json │ │ │ │ ├── illustration-dog.imageset │ │ │ │ ├── illustration-dog.png │ │ │ │ ├── illustration-dog@2x.png │ │ │ │ ├── illustration-dog@3x.png │ │ │ │ └── Contents.json │ │ │ │ ├── primary.colorset │ │ │ │ └── Contents.json │ │ │ │ └── on-primary.colorset │ │ │ │ └── Contents.json │ │ ├── Resources │ │ │ ├── cat-peep.jpg │ │ │ ├── cat-pine.jpg │ │ │ ├── cat-unit.jpg │ │ │ ├── dog-link.jpg │ │ │ ├── cat-crawler.jpg │ │ │ ├── cat-payton.jpg │ │ │ ├── cat-rumble.jpg │ │ │ ├── cat-wiley.jpg │ │ │ ├── dog-squeek.jpg │ │ │ └── chameleon-isaac.jpg │ │ ├── Models │ │ │ ├── UserData.swift │ │ │ ├── User.swift │ │ │ ├── Data.swift │ │ │ ├── Pet.swift │ │ │ └── ImageStore.swift │ │ ├── Views │ │ │ ├── Components │ │ │ │ ├── LikeButton.swift │ │ │ │ ├── PetBadge.swift │ │ │ │ ├── PetHeader.swift │ │ │ │ ├── ProgressBar.swift │ │ │ │ ├── PetSize.swift │ │ │ │ └── PetRow.swift │ │ │ └── Screens │ │ │ │ └── HomeView.swift │ │ ├── DI │ │ │ └── AppComponent.swift │ │ └── App │ │ │ └── AdoptmeApp.swift │ └── CleanseSwiftUIExample.xcodeproj │ │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── Examples.xcworkspace │ ├── xcshareddata │ └── IDEWorkspaceChecks.plist │ └── contents.xcworkspacedata ├── .slather.yml ├── Cleanse.xcodeproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── CleansePlayground.playground ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── CleansePlayground.xcscmblueprint ├── Pages │ └── Index.xcplaygroundpage │ │ └── Contents.swift └── contents.xcplayground ├── Cleanse ├── Component.swift ├── ScopedModule.swift ├── BindingReceipt.swift ├── Lock.swift ├── AssistedFactory.swift ├── Finalizable.swift ├── Assisted.swift ├── ScopedBindingBuilder.swift ├── AssistedInjectionSeedDecorator.swift ├── Factory.swift ├── Cleanse.h ├── BindToable.swift ├── ComponentBinding.swift ├── AnyBinder.swift ├── CombinedHashable.swift ├── ScopedBindingDecorator.swift ├── LegacyKey.swift ├── DelegatedHashable.swift ├── TaggedBindingBuilderDecorator.swift ├── BaseBindingBuilder.swift ├── Installer.swift ├── TypeKeyProtocol.swift ├── CleanseServiceLoader.swift ├── RawProviderBinding.swift ├── SourceLocation.swift ├── ComponentBase.swift ├── Module.swift ├── Info.plist ├── Binder.swift ├── Scope.swift ├── CleanseErrorReporter.swift ├── CleanseBindingPlugin.swift ├── RootComponent.swift ├── AssistedInjectionBuilder.swift ├── AssistedInjection.swift ├── WeakProvider.swift ├── WrappedBinder.swift ├── TaggedProvider.swift ├── ScopedProvider.swift ├── PropertyInjectionReceiptBinder.swift ├── ProviderProvider.swift ├── CollectionBindingBuilderDecorator.swift ├── ReceiptBinder.swift ├── SingularCollectionBindingBuilderDecorator.swift ├── ScopedBinder.swift ├── PropertyInjector.swift ├── ComponentFactory.swift └── BindingBuilderDecorator.swift ├── Cleanse.xcworkspace ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── contents.xcworkspacedata ├── CleanseTests ├── ObjectGraphTests.swift ├── ScopeTests.swift ├── NoopVisitor.swift ├── Info.plist ├── TaggedProviderTests.swift ├── SPITests.swift ├── DebuggingTests.swift └── SubcomponentTests.swift ├── Package.swift ├── Cleanse.podspec ├── CleanseGen ├── CleanseGen.h └── Info.plist ├── LICENSE ├── Makefile ├── .gitignore ├── .github └── workflows │ └── main.yml └── CHANGELOG.md /Sources/Cleanse: -------------------------------------------------------------------------------- 1 | ../Cleanse -------------------------------------------------------------------------------- /Tests/CleanseTests: -------------------------------------------------------------------------------- 1 | ../CleanseTests -------------------------------------------------------------------------------- /Documentation/README.rst: -------------------------------------------------------------------------------- 1 | ../README.rst -------------------------------------------------------------------------------- /Documentation/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | .* 3 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | 3 | -------------------------------------------------------------------------------- /cleansec/.gitignore: -------------------------------------------------------------------------------- 1 | *.ast 2 | *.xcarchive 3 | *.zip 4 | build/ 5 | bin/ 6 | -------------------------------------------------------------------------------- /arities-autogen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | swift CleanseGen/main.swift 4 | -------------------------------------------------------------------------------- /Documentation/Components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Documentation/Components.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'cocoapods', '~> 1.8' 4 | gem 'cocoapods-generate' 5 | -------------------------------------------------------------------------------- /Documentation/cleanse_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Documentation/cleanse_logo.png -------------------------------------------------------------------------------- /Documentation/ChangeToolchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Documentation/ChangeToolchain.png -------------------------------------------------------------------------------- /Documentation/cleanse_logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Documentation/cleanse_logo_small.png -------------------------------------------------------------------------------- /Documentation/under-construction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Documentation/under-construction.gif -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.slather.yml: -------------------------------------------------------------------------------- 1 | coverage_service: coveralls 2 | xcodeproj: Cleanse.xcodeproj 3 | scheme: Cleanse 4 | ignore: 5 | - Cleanse/PropertyInjectionArities.swift 6 | - Cleanse/BinderArities.swift 7 | 8 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-peep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-peep.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-pine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-pine.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-unit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-unit.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/dog-link.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/dog-link.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-crawler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-crawler.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-payton.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-payton.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-rumble.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-rumble.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-wiley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/cat-wiley.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/dog-squeek.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/dog-squeek.jpg -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/chameleon-isaac.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Resources/chameleon-isaac.jpg -------------------------------------------------------------------------------- /cleansec/script/Fixtures.template: -------------------------------------------------------------------------------- 1 | // This file is generated! DO NOT EDIT! 2 | 3 | struct Fixtures { 4 | <% for @f in @fixtures %> 5 | static let <%= @f.var_name %> = """ 6 | <%= @f.contents %> 7 | """ 8 | <% end %> 9 | } -------------------------------------------------------------------------------- /Cleanse.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CleansePlayground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /cleansec/cleansec.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /cleansec/cleansec.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-ipad.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/cleanse_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/cleanse_logo.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/me.imageset/me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/me.imageset/me.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-ipad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-ipad@2x.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-iphone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-iphone@2x.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-iphone@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-iphone@3x.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-setting@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-setting@2x-1.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-setting@2x-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-setting@2x-2.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-setting@3x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-setting@3x-1.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight@2x-1.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight@2x.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/AppIcon.appiconset/app-icon-spotlight@3x.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Members.imageset/icon_member.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Members.imageset/icon_member.pdf -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/me.imageset/me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/me.imageset/me.png -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Settings.imageset/icon_settings.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Settings.imageset/icon_settings.pdf -------------------------------------------------------------------------------- /cleansec/CleansecFramework/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // cleansec 4 | // 5 | // Created by Sebastian Edward Shanus on 5/6/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | print("Hello, World!") 12 | 13 | -------------------------------------------------------------------------------- /CleansePlayground.playground/Pages/Index.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: # Cleanse - Swift Dependency Injection 2 | 3 | /*: 4 | ## Index: 5 | 6 | 1. [CoffeeMaker Example](CoffeeMakerExample) 7 | 1. [GitHub Client Example](GithubClientExample) 8 | 9 | */ 10 | 11 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/cat-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/cat-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/dog-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/dog-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/paw-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/paw-solid.png -------------------------------------------------------------------------------- /Cleanse/Component.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Component.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 7/6/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public protocol Component : ComponentBase { 13 | } 14 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Repositories.imageset/icon_repository.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Repositories.imageset/icon_repository.pdf -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/cat-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/cat-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/cat-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/cat-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/dog-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/dog-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/dog-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/dog-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/paw-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/paw-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/paw-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/paw-solid@3x.png -------------------------------------------------------------------------------- /Cleanse/ScopedModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScopedModule.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 3/14/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public protocol ScopedModule : Module { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/otter-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/otter-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/cat-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/cat-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/dog-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/dog-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/paw-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/paw-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/otter-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/otter-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/otter-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/otter-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/cat-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/cat-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/cat-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/cat-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/dog-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/dog-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/dog-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/dog-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/paw-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/paw-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/paw-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/paw-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/otter-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/otter-solid.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/otter-solid@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/otter-solid@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/otter-solid@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/otter-solid@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/illustration-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/illustration-cat.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/illustration-dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/illustration-dog.png -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/DoesNotImportCleanse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DoesNotImportCleanse.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/illustration-cat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/illustration-cat@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/illustration-cat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/illustration-cat@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/illustration-dog@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/illustration-dog@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/illustration-dog@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/illustration-dog@3x.png -------------------------------------------------------------------------------- /Cleanse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Members.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_member.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Settings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_settings.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ImportsCleanse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImportsCleanse.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | -------------------------------------------------------------------------------- /Cleanse.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/illustration-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/illustration-cat.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/illustration-dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/illustration-dog.png -------------------------------------------------------------------------------- /CleanseTests/ObjectGraphTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectGraphTests.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/26/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | import Cleanse 12 | 13 | class ObjectGraphTests : XCTestCase { 14 | 15 | } 16 | 17 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Assets.xcassets/TabBarIcons/Repositories.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_repository.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/illustration-cat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/illustration-cat@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/illustration-cat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/illustration-cat@3x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/illustration-dog@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/illustration-dog@2x.png -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/illustration-dog@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square/Cleanse/master/Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/illustration-dog@3x.png -------------------------------------------------------------------------------- /Examples/Examples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cleansec/cleansec.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Cleanse.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Examples.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /cleansec/cleansec.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CleanseTests/ScopeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScopeTests.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/28/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | import XCTest 9 | 10 | @testable import Cleanse 11 | 12 | class ScopeTests: XCTestCase { 13 | 14 | func testScopes() { 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Cleanse/BindingReceipt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BindingReceipt.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 1/6/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// This is used to fulfill contracts that a binding has occured 13 | public struct BindingReceipt { 14 | } 15 | -------------------------------------------------------------------------------- /CleansePlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/SingletonScope.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SingletonScope.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by holmes on 6/28/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | public typealias SingletonBinder = Binder 13 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Cleanse", 7 | products: [ 8 | .library(name: "Cleanse", targets: ["Cleanse"]), 9 | ], 10 | dependencies: [], 11 | targets: [ 12 | .target(name: "Cleanse", dependencies: [], path: "Cleanse"), 13 | ] 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Syntax.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Represents a raw syntax element in a source file. 4 | public protocol Syntax { 5 | var raw: String { get } 6 | var children: [Syntax] { get } 7 | } 8 | 9 | public extension SyntaxVisitor { 10 | mutating func walkChildren(_ node: Syntax) { 11 | node.children.forEach { walk($0) } 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /CleanseTests/NoopVisitor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoopVisitor.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/3/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import XCTest 12 | 13 | @testable import Cleanse 14 | 15 | final class NoopVisitor : SimpleComponentVisitor { 16 | var visitorState = VisitorState() 17 | } 18 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Parsing/DataStringMapper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Data { 4 | func mapToLines(seperator: UInt8) -> [String] { 5 | return withUnsafeBytes { bytes in 6 | return bytes 7 | .split(separator: seperator) 8 | .map { String(decoding: UnsafeRawBufferPointer(rebasing: $0), as: UTF8.self) } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Cleanse/Lock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Lock.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/25/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension NSLock { 13 | func with(_ closure: () throws -> Element) rethrows -> Element { 14 | lock() 15 | defer { unlock() } 16 | 17 | return try closure() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Cleanse/AssistedFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssistedFactory.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 9/5/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AssistedFactory: Tag { 12 | associatedtype Seed 13 | } 14 | 15 | public struct EmptySeed : AssistedFactory { 16 | public typealias Seed = Void 17 | public typealias Element = E 18 | } 19 | -------------------------------------------------------------------------------- /Cleanse/Finalizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Finalizable.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 7/6/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | protocol Finalizable { 10 | func finalize() throws 11 | } 12 | 13 | struct AnonymousFinalizable : Finalizable { 14 | let finalizeFunc: () throws -> Void 15 | 16 | func finalize() throws { 17 | try self.finalizeFunc() 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Sandbox 4 | // 5 | // Created by Sebastian Edward Shanus on 5/13/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view. 16 | } 17 | 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/NestedModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NestedModule.swift 3 | // cleasecTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct Blah { 13 | struct Module: Cleanse.Module { 14 | static func configure(binder: Binder) { 15 | 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cleansec/cleansec.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "swift-argument-parser", 6 | "repositoryURL": "https://github.com/apple/swift-argument-parser", 7 | "state": { 8 | "branch": null, 9 | "revision": "9f04d1ff1afbccd02279338a2c91e5f27c45e93a", 10 | "version": "0.0.5" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /cleansec/cleansec/PluginRunner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PluginRunner.swift 3 | // cleansec 4 | // 5 | // Created by Sebastian Edward Shanus on 5/21/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CleansecFramework 11 | 12 | struct PluginRunner { 13 | static func run(plugin path: String, astFiles: [String]) -> [ModuleRepresentation] { 14 | astFiles.compactMap { Cleansec.run(plugin: path, astFilePath: $0) } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Linking/LinkedInterface.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedInterface.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Representation of all components and modules with their providers linked. 12 | public struct LinkedInterface { 13 | public let components: [LinkedComponent] 14 | public let modules: [LinkedModule] 15 | } 16 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/me.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "me.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "swift-argument-parser", 6 | "repositoryURL": "https://github.com/apple/swift-argument-parser", 7 | "state": { 8 | "branch": null, 9 | "revision": "9f04d1ff1afbccd02279338a2c91e5f27c45e93a", 10 | "version": "0.0.5" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Cleanse", 6 | "repositoryURL": "https://github.com/square/Cleanse.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "c854787f83d99527587b5387f04ccd0030e6133a", 10 | "version": "4.2.6" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Cleanse.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Cleanse' 3 | s.version = '4.2.6' 4 | s.license = 'Apache License, Version 2.0' 5 | s.summary = 'Lightweight Swift Dependency Injection Framework' 6 | s.homepage = 'https://github.com/square/Cleanse' 7 | s.authors = 'Square' 8 | s.source = { :git => 'https://github.com/square/Cleanse.git', :tag => s.version } 9 | s.source_files = 'Cleanse/*.swift' 10 | s.ios.deployment_target = '8.3' 11 | s.swift_versions = ['4.2', '5.0'] 12 | end 13 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/me.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "me.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/on-primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.380", 9 | "green" : "0.580", 10 | "red" : "0.965" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.882", 9 | "green" : "0.886", 10 | "red" : "0.988" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.882", 9 | "green" : "0.886", 10 | "red" : "0.988" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /cleansec/Makefile: -------------------------------------------------------------------------------- 1 | 2 | WORKSPACE=cleansec.xcworkspace 3 | XCODEBUILD_WORKSPACE=xcodebuild -workspace $(WORKSPACE) 4 | 5 | clean: 6 | rm -fr bin 7 | $(XCODEBUILD_WORKSPACE) -scheme cleansec clean 8 | 9 | build: 10 | $(XCODEBUILD_WORKSPACE) -scheme cleansec build 11 | 12 | release: clean 13 | mkdir bin 14 | $(XCODEBUILD_WORKSPACE) -scheme cleansec archive -archivePath bin/cleansec 15 | zip -j bin/cleansec bin/cleansec.xcarchive/Products/usr/local/bin/cleansec script/swiftc-ast.rb 16 | rm -fr bin/cleansec.xcarchive 17 | 18 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/on-primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.380", 9 | "green" : "0.580", 10 | "red" : "0.965" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Cleanse/Assisted.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Assisted.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 9/5/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Assisted : ProviderProtocol { 12 | public typealias Element = E 13 | 14 | let getter: () -> Element 15 | public init(getter: @escaping () -> E) { 16 | self.getter = getter 17 | } 18 | 19 | public func get() -> E { 20 | return getter() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ModuleWithImplicitType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModuleWithImplicitType.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct CoreAppModule7 : Cleanse.Module { 13 | static func configure(binder: Binder) { 14 | binder 15 | .bind() 16 | .to(factory: A.init) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Cleanse/ScopedBindingBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScopedBindingBuilder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 3/14/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension BindingBuilder where Binder: BinderType, MaybeScope == Unscoped, Binder.Scope: Scope { 12 | // Declares binding as scoped. Also known as singletons in some contexts 13 | public func sharedInScope() -> ScopedBindingDecorator { 14 | return self.with() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Cleanse/AssistedInjectionSeedDecorator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssistedInjectionSeedDecorator.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 9/5/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct AssistedInjectionSeedDecorator : AssistedInjectionBuilder { 12 | public typealias Binder = Binder 13 | public typealias Element = S.Element 14 | public typealias Tag = S 15 | 16 | public let binder: Binder 17 | } 18 | -------------------------------------------------------------------------------- /Cleanse/Factory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Factory.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 9/5/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Factory { 12 | let factory: (Tag.Seed) -> Tag.Element 13 | public init(factory: @escaping (Tag.Seed) -> Tag.Element) { 14 | self.factory = factory 15 | } 16 | 17 | public func build(_ seed: Tag.Seed) -> Tag.Element { 18 | return factory(seed) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Visitors/Representations/DebugData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DebugData.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 5/26/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct DebugData: Equatable, Codable { 12 | public let location: String? 13 | 14 | public static var empty = DebugData(location: nil) 15 | 16 | public static func location(_ loc: String) -> DebugData { 17 | DebugData(location: loc) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Linking/LinkedModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedModule.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// `Cleanse.Module` representation with all standard providers and linked reference providers. 12 | public struct LinkedModule { 13 | public let type: String 14 | public let providers: [StandardProvider] 15 | public let includedModules: [String] 16 | public let subcomponents: [String] 17 | } 18 | -------------------------------------------------------------------------------- /Cleanse/Cleanse.h: -------------------------------------------------------------------------------- 1 | // 2 | // Cleanse.h 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/22/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Cleanse. 12 | FOUNDATION_EXPORT double CleanseVersionNumber; 13 | 14 | //! Project version string for Cleanse. 15 | FOUNDATION_EXPORT const unsigned char CleanseVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/HTTPError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPError.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | struct HTTPError : Error { 13 | let statusCode: Int 14 | 15 | /// - returns: nil if status code isn't an error code 16 | init?(statusCode: Int) { 17 | guard 400..<600 ~= statusCode else { 18 | return nil 19 | } 20 | 21 | self.statusCode = statusCode 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Documentation/index.rst: -------------------------------------------------------------------------------- 1 | .. Cleanse documentation master file, created by 2 | sphinx-quickstart on Fri Jun 10 12:46:56 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Cleanse's documentation! 7 | =================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | The README 15 | Binding Grammar 16 | 17 | 18 | Indices and tables 19 | ================== 20 | 21 | * :ref:`genindex` 22 | * :ref:`modindex` 23 | * :ref:`search` 24 | 25 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/paw-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "paw-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "paw-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "paw-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /CleanseGen/CleanseGen.h: -------------------------------------------------------------------------------- 1 | // 2 | // CleanseGen.h 3 | // CleanseGen 4 | // 5 | // Created by holmes on 6/28/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CleanseGen. 12 | FOUNDATION_EXPORT double CleanseGenVersionNumber; 13 | 14 | //! Project version string for CleanseGen. 15 | FOUNDATION_EXPORT const unsigned char CleanseGenVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/paw-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "paw-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "paw-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "paw-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ModuleIncludesModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModuleIncludesModule.swift 3 | // cleasecTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct AnotherModule: Cleanse.Module { 13 | static func configure(binder: Binder) {} 14 | } 15 | 16 | struct CoreAppModule5 : Cleanse.Module { 17 | static func configure(binder: Binder) { 18 | binder.include(module: AnotherModule.self) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Cleanse/BindToable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BindToable.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 1/6/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol BindToable { 12 | associatedtype Input 13 | associatedtype Binder : BinderBase 14 | 15 | func _innerTo( 16 | file: StaticString, 17 | line: Int, 18 | function: StaticString, 19 | provider: Provider) -> BindingReceipt 20 | 21 | var _finalProviderType: Any.Type { get } 22 | 23 | var binder: Binder { get } 24 | } 25 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/FoundationCommonModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FoundationCommonModule.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | /// Module that configures common bindings from the `Foundation` framework 13 | struct FoundationCommonModule : Module { 14 | static func configure(binder: SingletonBinder) { 15 | binder 16 | .bind(ProcessInfo.self) 17 | .to { ProcessInfo.processInfo } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ModuleWithImplicitInitFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModuleWithImplicitInitFactory.swift 3 | // cleasecTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct A { 13 | let string: String 14 | let number: Int 15 | } 16 | 17 | struct CoreAppModule3 : Cleanse.Module { 18 | static func configure(binder: Binder) { 19 | binder 20 | .bind(A.self) 21 | .to(factory: A.init) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-cat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "illustration-cat.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "illustration-cat@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "illustration-cat@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/illustration-dog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "illustration-dog.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "illustration-dog@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "illustration-dog@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/CleansecFramework.h: -------------------------------------------------------------------------------- 1 | // 2 | // Cleansec.h 3 | // Cleansec 4 | // 5 | // Created by Sebastian Edward Shanus on 5/11/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Cleansec. 12 | FOUNDATION_EXPORT double CleansecVersionNumber; 13 | 14 | //! Project version string for Cleansec. 15 | FOUNDATION_EXPORT const unsigned char CleansecVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Cleanse/ComponentBinding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComponentBinding.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 10/11/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Describes the object graph for a component node. 12 | public protocol ComponentBinding { 13 | var scope: Scope.Type? { get } 14 | var seed: Any.Type { get } 15 | var parent: ComponentBinding? { get } 16 | var subcomponents: [ComponentBinding] { get } 17 | var componentType: Any.Type? { get } 18 | 19 | var providers: [ProviderKey: [ProviderInfo]] { get } 20 | } 21 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-cat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "illustration-cat.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "illustration-cat@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "illustration-cat@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/illustration-dog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "illustration-dog.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "illustration-dog@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "illustration-dog@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/PropertyInjection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyInjection.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | class PropertyClass { 13 | } 14 | 15 | struct PropertyInjectionModule: Module { 16 | static func configure(binder: Binder) { 17 | binder 18 | .bindPropertyInjectionOf(PropertyClass.self) 19 | .to { (a: PropertyClass, number: Int) in 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/SimpleRootComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleRootComponent.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct MyRootComponent2: Cleanse.RootComponent { 13 | static func configure(binder: Binder) { 14 | 15 | } 16 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 17 | return bind.to(value: 3) 18 | } 19 | typealias Root = Int 20 | } 21 | -------------------------------------------------------------------------------- /Cleanse/AnyBinder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyBinder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 1/6/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Type erased binder 12 | public struct AnyBinder : BinderBase, WrappedBinder { 13 | public let binder: BinderBase 14 | 15 | public init(binder: BinderBase) { 16 | // Optimization to reduce nesting of wrapped binders 17 | if let binder = binder as? WrappedBinder { 18 | self.binder = binder.binder 19 | } else { 20 | self.binder = binder 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Nodes/TypedSyntax.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TypedSyntax.swift 3 | // SwiftAstParser 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol TypedSyntax: Syntax { 12 | var type: String { get } 13 | } 14 | 15 | extension TypedSyntax { 16 | public var type: String { 17 | raw.trimmedLeadingWhitespace.firstCapture(#"(? { 13 | let dependencyA: A 14 | } 15 | 16 | fileprivate struct GenericTypeModule: Module { 17 | static func configure(binder: Binder) { 18 | binder 19 | .bind(GenericType.self) 20 | .to(factory: GenericType.init) 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Linking/LinkedComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedComponent.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// `Cleanse.Component` representation with all linked providers. 12 | public struct LinkedComponent { 13 | public let type: String 14 | public let rootType: String 15 | public let providers: [StandardProvider] 16 | public let seed: String 17 | public let includedModules: [String] 18 | public let subcomponents: [String] 19 | public let isRoot: Bool 20 | } 21 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/BasicBindings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BasicBindings.swift 3 | // Cleansec-Generate-Fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 7/8/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | fileprivate struct BasicBindingsModule: Cleanse.Module { 13 | static func configure(binder: Binder) { 14 | binder 15 | .bind(Int.self) 16 | .to { (floatFactory: () -> Float, boolFactory: @escaping () -> Bool, float2Factory:()->Float) in 17 | return 3 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/SwiftAstParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftAstParser.h 3 | // SwiftAstParser 4 | // 5 | // Created by Sebastian Edward Shanus on 5/7/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftAstParser. 12 | FOUNDATION_EXPORT double SwiftAstParserVersionNumber; 13 | 14 | //! Project version string for SwiftAstParser. 15 | FOUNDATION_EXPORT const unsigned char SwiftAstParserVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Cleanse/CombinedHashable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CombinedHashable.swift 3 | // Appointments 4 | // 5 | // Created by Mike Lewis on 2/2/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// Combines two hashable values. Useful for paths of hashable values 13 | struct CombinedHashable : Hashable { 14 | let l: L 15 | let r: R 16 | 17 | init(_ l: L, _ r: R) { 18 | self.l = l 19 | self.r = r 20 | } 21 | } 22 | 23 | func == (lhs: CombinedHashable, rhs: CombinedHashable) -> Bool { 24 | return lhs.l == rhs.l && lhs.r == rhs.r 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/cat-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "cat-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "cat-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "cat-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/dog-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "dog-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "dog-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "dog-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ModuleWithTaggedProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModuleWithTaggedProvider.swift 3 | // cleasecTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | 13 | struct MyTag: Tag { 14 | typealias Element = A 15 | } 16 | 17 | struct CoreAppModule4 : Cleanse.Module { 18 | static func configure(binder: Binder) { 19 | binder 20 | .bind(A.self) 21 | .tagged(with: MyTag.self) 22 | .sharedInScope() 23 | .to(factory: A.init) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Models/UserData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserData.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/7/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import Combine 10 | import SwiftUI 11 | import Cleanse 12 | 13 | final class UserData: ObservableObject { 14 | @Published var showMineOnly = false 15 | @Published var pets = petData 16 | } 17 | 18 | extension UserData { 19 | struct Module: Cleanse.Module { 20 | static func configure(binder: Binder) { 21 | binder.bind(UserData.self).to(factory: UserData.init) 22 | } 23 | } 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/TaggedProviderDependency.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaggedProviderDependency.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct MyTag2: Tag { 13 | typealias Element = Int 14 | } 15 | 16 | struct TaggedDependency { 17 | let provider: TaggedProvider 18 | } 19 | struct TaggedDepModule: Module { 20 | static func configure(binder: Binder) { 21 | binder.bind(TaggedDependency.self).to(factory: TaggedDependency.init) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/cat-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "cat-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "cat-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "cat-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/dog-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "dog-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "dog-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "dog-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Assets.xcassets/otter-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "otter-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "otter-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "otter-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Preview Content/Preview Assets.xcassets/otter-solid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "otter-solid.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "otter-solid@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "otter-solid@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Components/LikeButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LikeButton.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct LikeButton: View { 12 | let isLiked: Bool 13 | var body: some View { 14 | Image(systemName: isLiked ? "heart.fill" : "heart").resizable().scaledToFill().frame(width: 24, height: 24, alignment: .center).foregroundColor(.red) 15 | } 16 | } 17 | 18 | struct LikeButton_Previews: PreviewProvider { 19 | static var previews: some View { 20 | LikeButton(isLiked: true) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Nodes/InheritableSyntax.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InheritableSyntax.swift 3 | // SwiftAstParser 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Syntax node types that can have an inherited type. 12 | public protocol InheritableSyntax: Syntax { 13 | var inherits: String? { get } 14 | } 15 | 16 | extension InheritableSyntax { 17 | public var inherits: String? { 18 | raw.trimmedLeadingWhitespace.firstCapture(#"inherits:\s*(\w+)"#) 19 | } 20 | } 21 | 22 | extension ClassDecl: InheritableSyntax {} 23 | extension StructDecl: InheritableSyntax {} 24 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /// Common base class for UITableViewController that has better default constructors 13 | class TableViewController : UITableViewController { 14 | init() { 15 | super.init(nibName: nil, bundle: nil) 16 | } 17 | 18 | @available(*, unavailable) 19 | required init?(coder aDecoder: NSCoder) { 20 | fatalError("init(coder:) has not been implemented") 21 | } 22 | } -------------------------------------------------------------------------------- /Cleanse/ScopedBindingDecorator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScopedBindingDecorator.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/6/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Internal type used for binding. We decorate a provider with this to indicate if we're scoped or not 12 | public struct ScopedBindingDecorator : BindingBuilderDecorator { 13 | public typealias MaybeScope = S 14 | 15 | public typealias FinalProvider = Wrapped.FinalProvider 16 | 17 | public let wrapped: Wrapped 18 | 19 | public init(wrapped: Wrapped) { 20 | self.wrapped = wrapped 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Cleanse/LegacyKey.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LegacyKey.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/27/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if SUPPORT_LEGACY_OBJECT_GRAPH 12 | 13 | /// Similar to how we keyed stuff inside LegacyObjectGraph 14 | struct LegacyKey : Hashable, DelegatedHashable { 15 | var cls: Any.Type 16 | var name: String? 17 | 18 | var hashable: CombinedHashable { 19 | return CombinedHashable(.init(cls), name ?? "NIL") 20 | } 21 | } 22 | 23 | func ==(lhs: LegacyKey, rhs: LegacyKey) -> Bool { 24 | return lhs.cls == rhs.cls && lhs.name == rhs.name 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /Cleanse/DelegatedHashable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DelegatedHashable.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/22/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Easy way to make a hashable object. Delegates it to a hashable property. 12 | public protocol DelegatedHashable : Hashable { 13 | associatedtype H: Hashable 14 | var hashable: H { get } 15 | } 16 | 17 | extension DelegatedHashable { 18 | public func hash(into hasher: inout Hasher) { 19 | hasher.combine(hashable) 20 | } 21 | } 22 | 23 | public func ==(lhs: DH, rhs: DH) -> Bool { 24 | return lhs.hashable == rhs.hashable 25 | } 26 | 27 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ComponentWithSeed.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComponentWithSeed.swift 3 | // Cleansec-Generate-Fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 7/9/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | fileprivate struct MySeed {} 13 | 14 | fileprivate struct SeededComponent: Cleanse.Component { 15 | typealias Root = Int 16 | typealias Seed = MySeed 17 | 18 | static func configure(binder: Binder) { 19 | 20 | } 21 | 22 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 23 | return bind.to(value: 3) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Cleanse/TaggedBindingBuilderDecorator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaggedBindingBuilderDecorator.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/7/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Internal type used for binding. We decorate a provider with this to indicate if we're scoped or not 12 | public struct TaggedBindingBuilderDecorator : BindingBuilderDecorator where Tag.Element == Wrapped.FinalProvider.Element { 13 | public typealias FinalProvider = TaggedProvider 14 | 15 | public let wrapped: Wrapped 16 | 17 | public init(wrapped: Wrapped) { 18 | self.wrapped = wrapped 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Cleanse 2 | Copyright 2016 Square, Inc. 3 | A full list of contributors is available at https://github.com/square/Cleanse/contributors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /Cleanse/BaseBindingBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseBindingBuilder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/9/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct BaseBindingBuilder : BindingBuilder { 12 | public typealias FinalProvider = Provider 13 | public typealias Input = Element 14 | public typealias Binder = B 15 | public let binder: B 16 | public static func mapElement(input: Input) -> FinalProvider.Element { 17 | return input 18 | } 19 | 20 | public static var collectionMergeFunc: Optional<([FinalProvider.Element]) -> FinalProvider.Element> { 21 | return nil 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Cleanse/Installer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Installer.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/2/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// The portion of the `Binder` Protocol that is responsible for installing module dependencies 13 | public protocol Installer { 14 | /** 15 | Installs a module as a dependnecy of the caller 16 | 17 | - parameter module: Module to install as a dependency of the caller (usually a `Module` or `RootComponent`). 18 | */ 19 | func include(module: M.Type) where M.Scope == Unscoped 20 | 21 | func install(dependency: C.Type) 22 | func install(dependency: C.Type) 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Cleanse/TypeKeyProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TypeKeyProtocol.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/29/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// An implementation of this is used to have a hashable of a type. 12 | /// This is preferable to using ObjectIdentifier since it can be typed and has a better description 13 | public protocol TypeKeyProtocol : DelegatedHashable, CustomStringConvertible { 14 | var type: Any.Type { get } 15 | } 16 | 17 | extension TypeKeyProtocol { 18 | public var hashable: ObjectIdentifier { 19 | return ObjectIdentifier(type) 20 | } 21 | 22 | public var description: String { 23 | return "\(type)" 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Cleansec_Generate_Fixtures.h: -------------------------------------------------------------------------------- 1 | // 2 | // Cleansec_Generate_Fixtures.h 3 | // Cleansec-Generate-Fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/11/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Cleansec_Generate_Fixtures. 12 | FOUNDATION_EXPORT double Cleansec_Generate_FixturesVersionNumber; 13 | 14 | //! Project version string for Cleansec_Generate_Fixtures. 15 | FOUNDATION_EXPORT const unsigned char Cleansec_Generate_FixturesVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/AssistedInjection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssistedInjection.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct AssistedObject { 13 | let assisted: Assisted 14 | let string: String 15 | } 16 | 17 | class AssistedSeed: AssistedFactory { 18 | typealias Seed = Int 19 | typealias Element = AssistedObject 20 | } 21 | 22 | struct AssistedModule: Module { 23 | static func configure(binder: Binder) { 24 | binder.bindFactory(AssistedObject.self).with(AssistedSeed.self).to(factory: AssistedObject.init) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/InnerTag.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InnerTag.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | fileprivate extension NSObject { 13 | /// This will represent the rootViewController that is assigned to our main window 14 | struct Root : Tag { 15 | typealias Element = NSObject 16 | } 17 | } 18 | 19 | struct InnerTagModule: Module { 20 | static func configure(binder: Binder) { 21 | binder 22 | .bind(NSObject.self) 23 | .tagged(with: NSObject.Root.self) 24 | .to(value: NSObject()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ManyDependencies.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ManyDependencies.swift 3 | // Cleansec-Generate-Fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/23/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct BigLot { 13 | let one: Int 14 | let two: Int 15 | let three: Int 16 | let four: Int 17 | let five: Int 18 | let six: Int 19 | let seven: Int 20 | let eight: Int 21 | let nine: Int 22 | let ten: Int 23 | } 24 | 25 | fileprivate struct ManyDependenciesModule: Module { 26 | static func configure(binder: Binder) { 27 | binder.bind(BigLot.self).to(factory: BigLot.init) 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Cleanse/CleanseServiceLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CleanseServiceLoader.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 10/10/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Service loader for binding plugins. Passed into `RootComponent` factory function. 12 | public final class CleanseServiceLoader { 13 | var services: [CleanseBindingPlugin] 14 | public init(_ services: [CleanseBindingPlugin] = []) { 15 | self.services = services 16 | } 17 | 18 | public func register(_ plugin: CleanseBindingPlugin) { 19 | services.append(plugin) 20 | } 21 | 22 | public static var instance: CleanseServiceLoader { 23 | return CleanseServiceLoader() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/CustomScopeBinding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomScopeBinding.swift 3 | // Cleansec-Generate-Fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 8/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | fileprivate struct CustomScope: Cleanse.Scope {} 13 | fileprivate typealias ShortScope = Binder 14 | fileprivate struct CustomScopeModule: Cleanse.Module { 15 | static func configure(binder: Binder) { 16 | binder.bind(Int.self).to(value: 3) 17 | } 18 | } 19 | 20 | fileprivate struct CustomScopeTypealiasModule: Cleanse.Module { 21 | static func configure(binder: ShortScope) { 22 | binder.bind(Int.self).to(value: 3) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ModuleIncludesSubcomponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModuleIncludesSubcomponent.swift 3 | // cleasecTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | 13 | struct Subcomponent: Component { 14 | static func configure(binder: Binder) { 15 | 16 | } 17 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 18 | return bind.to(value: 3) 19 | } 20 | typealias Root = Int 21 | } 22 | 23 | struct CoreAppModule6 : Cleanse.Module { 24 | static func configure(binder: Binder) { 25 | binder.install(dependency: Subcomponent.self) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/ModuleWithDependencies.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModuleWithDependencies.swift 3 | // cleasecTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct CoreAppModule : Cleanse.Module { 13 | static func configure(binder: Binder) { 14 | binder 15 | .bind(String.self) 16 | .to { (a: Int, b: Character, c: Float) -> String in 17 | return "\(a)\(b)\(c)" 18 | } 19 | } 20 | } 21 | 22 | struct CoreAppModule2 : Cleanse.Module { 23 | static func configure(binder: Binder) { 24 | binder 25 | .bind(String.self) 26 | .to(value: "square") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Cleanse/RawProviderBinding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProviderRegistry.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/7/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// Constains information about what needs to be registered 13 | public struct RawProviderBinding { 14 | let scope: Scope.Type? 15 | 16 | /// This is the provider. The key of this is what will be provided. 17 | let provider: AnyProvider 18 | 19 | /// Input is actually `[Element]` where `Element: Collection` 20 | let collectionMergeFunc: Optional<([Any]) -> Any> 21 | 22 | let sourceLocation: SourceLocation? 23 | } 24 | 25 | 26 | extension RawProviderBinding { 27 | var isCollectionProvider: Bool { 28 | return collectionMergeFunc != nil 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Models/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import Cleanse 10 | 11 | struct User { 12 | let firstName: String 13 | let lastName: String 14 | let photo: String 15 | var fullName : String { 16 | get { 17 | firstName + " " + lastName 18 | } 19 | } 20 | let email: String 21 | } 22 | 23 | extension User { 24 | struct Module: Cleanse.Module { 25 | static func configure(binder: Binder) { 26 | binder.bind(User.self).to { 27 | User(firstName: "John", lastName: "Doe", photo: "me", email: "abcd@ef.com") 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox/AppComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppComponent.swift 3 | // Sandbox 4 | // 5 | // Created by Sebastian Edward Shanus on 5/13/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct AppComponent: RootComponent { 13 | static func configure(binder: Binder) { 14 | binder 15 | .bind(String.self) 16 | .to { (amount: Double) -> String in 17 | return "hello" 18 | } 19 | 20 | binder 21 | .bind(Double.self) 22 | .to(value: 3.0) 23 | } 24 | 25 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 26 | return bind.to(value: 3) 27 | } 28 | 29 | typealias Root = Int 30 | } 31 | -------------------------------------------------------------------------------- /CleanseTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParserTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /cleansec/CleansecFrameworkTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Parsing/SyntaxParser.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | Parses the output from `swiftc -dump-ast` and emits its parsed `Syntax` nodes. 5 | */ 6 | public struct SyntaxParser { 7 | /** 8 | Parses data input and returns syntax nodes. 9 | - returns: List of `Syntax` nodes. 10 | - parameter data: Raw data. 11 | */ 12 | public static func parse(data: Data) -> [Syntax] { 13 | return InputParser.parse(lines: data.mapToLines(seperator: UInt8(ascii: "\n"))) 14 | } 15 | 16 | /** 17 | Parses text input and returns syntax nodes. 18 | - returns: List of `Syntax` nodes. 19 | - parameter text: Raw text. 20 | */ 21 | public static func parse(text: String) -> [Syntax] { 22 | return InputParser.parse(lines: text.split(separator: "\n").map { String($0) }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Cleanse/SourceLocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DebugInfo.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/28/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// This is used to pass around source info similar to what one would get from stack traces 13 | 14 | public struct SourceLocation : CustomStringConvertible { 15 | public let file: StaticString 16 | public let line: Int 17 | public let function: StaticString 18 | 19 | public init( 20 | file: StaticString, 21 | line: Int, 22 | function: StaticString 23 | ) { 24 | 25 | self.file = file 26 | self.line = line 27 | self.function = function 28 | } 29 | 30 | public var description: String { 31 | return "\(file):\(line)" 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /CleanseGen/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Documentation/Binding Grammar.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | DSL Grammars 4 | ============ 5 | 6 | Binding Grammar 7 | ``````````````` 8 | 9 | .. productionlist:: 10 | bind_stmt : "binder" 11 | : `bind_step` 12 | bind_step : ".bind(" [ element_metatype_expr ] ")" 13 | : `collection_step` 14 | collection_step : [ ".intoCollection()" ] 15 | : `tag_step` 16 | tag_step : [ ".tagged(with: " tag_metatype_expr ")" ] 17 | : `scope_step` 18 | scope_step : [ ".asSingleton()" ] 19 | : `terminating_step` 20 | terminating_step: `provider_terminator` 21 | : | `factory_terminator` 22 | : | `value_terminator` 23 | provider_terminator: ".to(provider:)" 24 | factory_terminator: ".to(factory:)" 25 | value_terminator: ".to(value:)" 26 | 27 | 28 | -------------------------------------------------------------------------------- /Cleanse/ComponentBase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComponentBase.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/5/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// Base protocol for both Components and RootComponents. Generally want to implement Components or RootComponent instead 13 | public protocol ComponentBase { 14 | /// This is the binding required to construct a new Component. Think of it as somewhat of an initialization value. 15 | associatedtype Seed = Void 16 | 17 | /// This should be set to the root type of object that is created. 18 | associatedtype Root 19 | 20 | associatedtype Scope: Cleanse._ScopeBase = Unscoped 21 | 22 | static func configure(binder: Binder) 23 | 24 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt 25 | } 26 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowserTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowserUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/DI/AppComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppComponent.swift 3 | // adoptme 4 | // 5 | // Created by Abdul Chathil on 12/25/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import Cleanse 10 | 11 | struct AppComponent: Cleanse.RootComponent { 12 | typealias Root = PropertyInjector 13 | 14 | static func configure(binder: Binder) { 15 | binder.include(module: UserData.Module.self) 16 | binder.include(module: User.Module.self) 17 | } 18 | 19 | static func configureRoot(binder bind: ReceiptBinder>) -> BindingReceipt> { 20 | bind.propertyInjector { (bind) -> BindingReceipt> in 21 | return bind.to(injector: AdoptmeApp.injectProperties) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/PropertyInjectorRoot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyInjectorRoot.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | class MainPropertyClass {} 13 | 14 | struct RootComponent: Cleanse.RootComponent { 15 | static func configureRoot(binder bind: ReceiptBinder>) -> BindingReceipt> { 16 | return bind.to { (injector: PropertyInjector) -> PropertyInjector in 17 | return injector 18 | } 19 | } 20 | 21 | typealias Root = PropertyInjector 22 | 23 | static func configure(binder: Binder) { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/script/Nodes.template: -------------------------------------------------------------------------------- 1 | // This file is generated! DO NOT EDIT! 2 | 3 | public enum NodeIdentifier: String { 4 | <% for @item in @decl_items %> 5 | case <%= @item.case_var_name %> = "<%= @item.case_name %>" 6 | <% end %> 7 | } 8 | 9 | <% for @item in @decl_items %> 10 | public struct <%= @item.class_name %>: Syntax { 11 | public let raw: String 12 | public let children: [Syntax] 13 | } 14 | <% end %> 15 | 16 | public struct UnknownSyntax: Syntax { 17 | public let raw: String 18 | public let children: [Syntax] 19 | } 20 | 21 | extension String { 22 | func createNode(id: NodeIdentifier, children: [Syntax]) -> Syntax { 23 | switch id { 24 | <% for @item in @decl_items %> 25 | case .<%= @item.case_var_name %>: 26 | return <%= @item.class_name %>(raw: self, children: children) 27 | <% end %> 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Cleanse/Module.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/28/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /** 13 | Basic building block for an object graph or component. A module defines how instances are created that are exposed to the rest of the object graph as well as requirements to construct these provided instances. 14 | 15 | In the words of Guice documentation, _["Modules should be fast and side-effect free"](https://github.com/google/guice/wiki/ModulesShouldBeFastAndSideEffectFree)_. 16 | 17 | This is the same for modules in Cleanse, if not even moreso since "configure" may be called more than once to validate the object graph. 18 | */ 19 | public protocol Module { 20 | associatedtype Scope: Cleanse._ScopeBase = Unscoped 21 | 22 | static func configure(binder: Binder) 23 | } 24 | -------------------------------------------------------------------------------- /Cleanse/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Cleanse/Binder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Binder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/25/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /** 13 | Internal representation of a completed `BindingBuilder`. It is consolidated into a protocol to make message signatures simpler. 14 | */ 15 | public protocol _InternalBindInfoProtocol { 16 | associatedtype BP : BindingBuilder 17 | 18 | var bindingProvider: BP { get } 19 | var provider: BP.FinalProvider { get } 20 | } 21 | 22 | struct InternalBindInfo : _InternalBindInfoProtocol { 23 | typealias BP = BP_ 24 | 25 | let bindingProvider: BP 26 | let provider: BP_.FinalProvider 27 | } 28 | 29 | public protocol BinderBase : Installer, ProviderProvider { 30 | /// Authoritative bind function. 31 | func _internalBind(binding: RawProviderBinding) 32 | } 33 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/SplitViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SplitViewController.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Common base class for UISplitViewController that has better default constructors 12 | class SplitViewController : UISplitViewController { 13 | init(masterViewController: RootVC) where RootVC: UISplitViewControllerDelegate { 14 | super.init(nibName: nil, bundle: nil) 15 | 16 | self.delegate = masterViewController 17 | self.viewControllers = [UINavigationController(rootViewController: masterViewController)] 18 | } 19 | 20 | @available(*, unavailable) 21 | required init?(coder aDecoder: NSCoder) { 22 | fatalError("init(coder:) has not been implemented") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/NetworkModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkModule.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | /// Wires up NSURLSession and friends 13 | struct NetworkModule : Module { 14 | static func configure(binder: SingletonBinder) { 15 | 16 | binder 17 | .bind() 18 | .sharedInScope() 19 | .to(value: URLSessionConfiguration.ephemeral) 20 | 21 | binder 22 | .bind(URLSession.self) 23 | .sharedInScope() 24 | .to { URLSession(configuration: $0, delegate: nil, delegateQueue: OperationQueue.main) } 25 | 26 | binder 27 | .bind(URL.self) 28 | .tagged(with: GithubBaseURL.self) 29 | .to(value: URL(string: "https://api.github.com")!) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2020 Square. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /Cleanse/Scope.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scope.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/22/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // Type erased version of Scope 12 | 13 | public protocol _ScopeBase { 14 | } 15 | 16 | 17 | /// Currently there are only two scopes, `Unscoped` and `Singleton`. 18 | public protocol Scope : _ScopeBase { 19 | } 20 | 21 | 22 | /// This a special scope that means its not scoped 23 | public struct Unscoped : _ScopeBase { 24 | } 25 | 26 | /// Default provided scope for the consumer to use in the Root Component. One does not have to use this scope 27 | /// and may use their own in the root component, but this is provided for convenience. 28 | public struct Singleton : Scope {} 29 | 30 | extension _ScopeBase { 31 | 32 | // Returns our metatype if we're not `Unscoped` 33 | static var scopeOrNil: Scope.Type? { 34 | return self as? Scope.Type 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2020 Square. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Components/PetBadge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PetBadge.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | 12 | struct PetBadge: View { 13 | var type: Pet.PetType 14 | var body: some View { 15 | HStack { 16 | Image(petTypeIcon[type]!).renderingMode(.template).resizable().frame(width: 16, height: 16).foregroundColor(Color("on-primary")) 17 | Text(type.rawValue) 18 | .font(.caption) 19 | .fontWeight(.bold).foregroundColor(Color("on-primary")) 20 | }.padding(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16)).background(Color("primary")).clipShape(Capsule()) 21 | } 22 | } 23 | 24 | struct PetBadge_Previews: PreviewProvider { 25 | static var previews: some View { 26 | PetBadge(type: Pet.PetType.dog) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2020 Square. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /Cleanse/CleanseErrorReporter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CleanseErrorReporter.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 10/11/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public final class CleanseErrorReporter { 12 | var errors: [CleanseError] = [] 13 | 14 | public func append(error: CleanseError) { 15 | errors.append(error) 16 | } 17 | 18 | public func append(contentsOf errorSet: [CleanseError]) { 19 | errors.append(contentsOf: errorSet) 20 | } 21 | 22 | func report() throws { 23 | errors.sort { 24 | return $0.description < $1.description 25 | } 26 | 27 | switch errors.count { 28 | case 0: 29 | // Everything is cool 30 | break 31 | case 1: 32 | throw errors[0] 33 | default: 34 | throw MultiError(errors: errors) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Cleanse/CleanseBindingPlugin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPI.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 10/9/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Plugin hook that gives conforming objects read-only access to the Cleanse object graph. 13 | 14 | In order for your plugin to be run, it must registered with an instance of a `CleanseServiceLoader` and passed into 15 | the `ComponentFactory.of(_:validate:serviceLoader:)` function. Plugins will only be run if the `validate` param is `true`. 16 | **/ 17 | 18 | public protocol CleanseBindingPlugin { 19 | /// Plugin entry point function that is called by the service loader. 20 | /// 21 | /// - Parameter root: Root component of the object graph. 22 | /// - Parameter errorReporter: Reporter used to append errors that are used to fail validation. 23 | /// 24 | func visit(root: ComponentBinding, errorReporter: CleanseErrorReporter) 25 | } 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DUMMY: build documentation 2 | 3 | SWIFT_ROOT=/Library/Developer/Toolchains/swift-latest.xctoolchain 4 | SWIFT=$(SWIFT_ROOT)/usr/bin/swift 5 | 6 | # This can go away once 7 | SWIFT_ARGS=-Xswiftc=-suppress-warnings 8 | 9 | .build: 10 | 11 | build: .build generated_sources 12 | $(SWIFT) build $(SWIFT_ARGS) 13 | 14 | test: build 15 | $(SWIFT) test 16 | 17 | clean: 18 | $(SWIFT) build --clean 19 | 20 | generated_sources: Cleanse/BinderArities.swift Cleanse/PropertyInjectionArities.swift 21 | 22 | Cleanse/BinderArities.swift: CleanseGen/GenerateBinderArities.swift 23 | xcrun swift CleanseGen/GenerateBinderArities.swift > Cleanse/BinderArities.swift 24 | 25 | Cleanse/PropertyInjectionArities.swift: CleanseGen/GeneratePropertyInjectionArities.swift 26 | xcrun swift CleanseGen/GeneratePropertyInjectionArities.swift > Cleanse/PropertyInjectionArities.swift 27 | 28 | docs/index.html: build 29 | jazzy 30 | 31 | docs: docs/index.html 32 | 33 | sphinx: 34 | make -C Documentation html 35 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/App/AdoptmeApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdoptmeApp.swift 3 | // adoptme 4 | // 5 | // Created by Abdul Chathil on 12/25/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import Cleanse 11 | 12 | @main 13 | class AdoptmeApp: App { 14 | var userData: UserData! 15 | var user: User! 16 | 17 | required init() { 18 | let propertyInjector = try? ComponentFactory.of(AppComponent.self).build(()) 19 | propertyInjector?.injectProperties(into: self) 20 | precondition(userData != nil) 21 | precondition(user != nil) 22 | } 23 | var body: some Scene { 24 | WindowGroup { 25 | HomeScreen(currentUser: user).environmentObject(userData) 26 | } 27 | } 28 | } 29 | 30 | extension AdoptmeApp { 31 | func injectProperties(_ userData: UserData, _ user: User) { 32 | self.userData = userData 33 | self.user = user 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Models/Data.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/7/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | let petData: [Pet] = load("pets.json") 13 | 14 | func load(_ filename: String) -> T { 15 | let data: Data 16 | 17 | guard let file = Bundle.main.url(forResource: filename, withExtension: nil) 18 | else { 19 | fatalError("Couldn't find \(filename) in main bundle.") 20 | } 21 | 22 | do { 23 | data = try Data(contentsOf: file) 24 | } catch { 25 | fatalError("Couldn't load \(filename) from main bundle:\n\(error)") 26 | } 27 | 28 | do { 29 | let decoder = JSONDecoder() 30 | return try decoder.decode(T.self, from: data) 31 | } catch { 32 | fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/SimpleComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleComponent.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct Subcomponent2: Component { 13 | static func configure(binder: Binder) { 14 | 15 | } 16 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 17 | return bind.to(value: 3) 18 | } 19 | typealias Root = Int 20 | } 21 | 22 | fileprivate struct Container { 23 | fileprivate struct NestedSubcomponent: Component { 24 | static func configure(binder: Binder) { 25 | 26 | } 27 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 28 | return bind.to(value: 3) 29 | } 30 | typealias Root = Int 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Cleanse/RootComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RootComponent.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/2/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public protocol RootComponent : ComponentBase { 13 | } 14 | 15 | public extension ComponentFactoryProtocol where ComponentElement : RootComponent { 16 | static func of(_ componentType: ComponentElement.Type, validate: Bool = true, serviceLoader: CleanseServiceLoader = CleanseServiceLoader.instance) throws -> ComponentFactory { 17 | 18 | if validate { 19 | let validator = ValidationVisitor() 20 | validator.install(dependency: ComponentElement.self) 21 | try validator.finalize(serviceLoader) 22 | } 23 | 24 | let graph = Graph(scope: nil) 25 | 26 | let p = graph.provider(ComponentFactory.self) 27 | 28 | graph.install(dependency: ComponentElement.self) 29 | 30 | try graph.finalize() 31 | 32 | return p.get() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Ignore the Mac OS X .DS_Store files 2 | .DS_Store 3 | .LSOverride 4 | 5 | #Ignore user-specific settings 6 | *.mode1v3 7 | *.mode2v3 8 | *.pbxuser 9 | *.perspectivev3 10 | xcuserdata 11 | 12 | #Ignore textmate build errors 13 | *.tm_build_errors 14 | 15 | #Ignore temp nibs and swap files 16 | *.swp 17 | *~.nib 18 | 19 | #Ignore the build, since we don't want archived builds 20 | build 21 | 22 | .gitattributes 23 | 24 | #Probably don't want to check in xcuserdata 25 | xcuserdata/ 26 | 27 | *.orig 28 | .idea 29 | 30 | #Ignore the token from the asset update script 31 | *.LastAssetUpdate_* 32 | 33 | env/ 34 | 35 | .build_env/ 36 | 37 | *.pyc 38 | 39 | # Instruments' output during UI Automation test 40 | traces 41 | instrumentscli*.trace 42 | 43 | git-cmp 44 | 45 | TestResults/* 46 | */TestResults/* 47 | 48 | .*.sw? 49 | .sw? 50 | 51 | DerivedCache_DerivedData/ 52 | DerivedCache/ 53 | .build/ 54 | 55 | 56 | # Not sure if we want to commit Jazzy docs yet 57 | /docs/ 58 | 59 | Carthage/ 60 | 61 | *.xcscmblueprint 62 | 63 | # Cocoapods 64 | gen/ 65 | 66 | # Swift PM 67 | .swiftpm 68 | -------------------------------------------------------------------------------- /Cleanse/AssistedInjectionBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssistedInjectionBuilder.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 9/5/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol BaseAssistedInjectionBuilder { 12 | associatedtype Binder: BinderBase 13 | associatedtype Tag: AssistedFactory = EmptySeed 14 | associatedtype Element 15 | var binder: Binder { get } 16 | } 17 | 18 | public protocol AssistedInjectionBuilder : BaseAssistedInjectionBuilder where Tag.Element == Element {} 19 | 20 | public struct AssistedInjectionBindingBuilder : AssistedInjectionBuilder { 21 | public typealias Binder = B 22 | public typealias Element = E 23 | 24 | public let binder: Binder 25 | } 26 | 27 | extension AssistedInjectionBindingBuilder { 28 | public func with(_ seed: S.Type) -> AssistedInjectionSeedDecorator where S.Element == Element { 29 | return AssistedInjectionSeedDecorator(binder: binder) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Resolver/LinkedMerging.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedMerging.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 5/21/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension LinkedModule { 12 | func merge(from other: LinkedModule) -> LinkedModule { 13 | LinkedModule( 14 | type: type, 15 | providers: providers + other.providers, 16 | includedModules: includedModules + other.includedModules, 17 | subcomponents: subcomponents + other.subcomponents 18 | ) 19 | } 20 | } 21 | 22 | extension LinkedComponent { 23 | func merge(from other: LinkedComponent) -> LinkedComponent { 24 | LinkedComponent( 25 | type: type, 26 | rootType: rootType, 27 | providers: providers + other.providers, 28 | seed: seed, 29 | includedModules: includedModules + other.includedModules, 30 | subcomponents: subcomponents + other.subcomponents, 31 | isRoot: isRoot 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Components/PetHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PetHeader.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct PetHeader: View { 12 | var body: some View { 13 | HStack { 14 | 15 | Image("illustration-cat").resizable().scaledToFill().frame(width: 186, height: 186).padding(.bottom, 16) 16 | Spacer() 17 | VStack(alignment: .leading) { 18 | Text("Find").font(.largeTitle).fontWeight(.bold) 19 | Text("Some descriptions about pets.\nThis description would look good\nin 2 lines or more").font(.caption).fontWeight(.medium).foregroundColor(.gray).multilineTextAlignment(.leading) 20 | .fixedSize(horizontal: false, vertical: true) 21 | .foregroundColor(.gray) 22 | } 23 | } 24 | } 25 | } 26 | 27 | struct PetHeader_Previews: PreviewProvider { 28 | static var previews: some View { 29 | PetHeader() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Components/ProgressBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressBar.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ProgressBar: View { 12 | let progress = 0.7 13 | var body: some View { 14 | GeometryReader { geometry in 15 | ZStack(alignment: .leading) { 16 | Rectangle().frame(width: geometry.size.width , height: geometry.size.height) 17 | .opacity(0.3) 18 | .foregroundColor(Color("primary")) 19 | 20 | Rectangle().frame(width: min(CGFloat(self.progress)*geometry.size.width, geometry.size.width), height: geometry.size.height) 21 | .foregroundColor(Color("primary")) 22 | .animation(.linear) 23 | }.frame(height: 8).cornerRadius(45.0) 24 | } 25 | }} 26 | 27 | struct ProgressBar_Previews: PreviewProvider { 28 | static var previews: some View { 29 | ProgressBar() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Components/PetSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PetSize.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct PetSize: View { 12 | let pet: Pet 13 | var body: some View { 14 | HStack(alignment: .bottom) { 15 | Image(petTypeIcon[pet.type]!).resizable().renderingMode(.template).frame(width: 24, height: 24).foregroundColor(pet.size == Pet.PetSize.s ? Color("on-primary") : Color("primary")) 16 | Image(petTypeIcon[pet.type]!).resizable().renderingMode(.template).frame(width: 48, height: 48).foregroundColor(pet.size == Pet.PetSize.m ? Color("on-primary") : Color("primary")) 17 | Image(petTypeIcon[pet.type]!).resizable().renderingMode(.template).frame(width: 72, height: 72).foregroundColor(pet.size == Pet.PetSize.l ? Color("on-primary") : Color("primary")) 18 | } 19 | } 20 | } 21 | 22 | struct PetSize_Previews: PreviewProvider { 23 | static var previews: some View { 24 | PetSize(pet: petData[0]) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowserTests/CleanseGithubBrowserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CleanseGithubBrowserTests.swift 3 | // CleanseGithubBrowserTests 4 | // 5 | // Created by Mike Lewis on 6/10/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import CleanseGithubBrowser 11 | import Cleanse 12 | 13 | /// Using the DI framework doens't mean its required to unit test its components. 14 | class CleanseGithubBrowserTests: XCTestCase { 15 | func testMembersViewController_Title() { 16 | // Tests that the member's view controller sets the title appropriately. 17 | let factory = Factory { _ in 18 | return MembersPageSettings() 19 | } 20 | let vc = MembersViewController( 21 | memberService: FakeGithubMembersService(), 22 | githubOrganizationName: .init(value: "Organiztion Name"), 23 | settings: factory 24 | ) 25 | 26 | XCTAssertEqual(vc.navigationItem.title, "Members of Organiztion Name") 27 | XCTAssertEqual(vc.title, "Members") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Models/Pet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pet.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/7/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | let petTypeIcon = [Pet.PetType.cat: "cat-solid", Pet.PetType.dog: "dog-solid", Pet.PetType.chameleon: "otter-solid"] 12 | 13 | struct Pet: Hashable, Codable, Identifiable { 14 | var id: Int 15 | var name: String 16 | fileprivate var imageName: String 17 | var type: PetType 18 | var desc: String 19 | var isLiked: Bool 20 | var isMale: Bool 21 | var size: PetSize 22 | var location: String 23 | 24 | enum PetType: String, CaseIterable, Codable, Hashable { 25 | case cat = "Cat" 26 | case dog = "Dog" 27 | case chameleon = "Chameleon" 28 | } 29 | 30 | enum PetSize: String, CaseIterable, Codable, Hashable { 31 | case s = "S" 32 | case m = "M" 33 | case l = "L" 34 | } 35 | 36 | } 37 | 38 | extension Pet { 39 | var image: Image { 40 | ImageStore.shared.image(name: imageName) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cleansec/Cleansec-Generate-Fixtures/Code Fixtures/CollectionBindings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionBindings.swift 3 | // cleansec-generate-fixtures 4 | // 5 | // Created by Sebastian Edward Shanus on 5/1/20. 6 | // Copyright © 2020 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct Singular { 13 | let a: Array 14 | } 15 | 16 | struct CollectionModule: Module { 17 | static func configure(binder: Binder) { 18 | binder.bind(Singular.self).to { (a:Array) -> Singular in 19 | return Singular(a: a) 20 | } 21 | 22 | binder.bind(Singular.self).to { (a: [ [Int] ]) in 23 | return Singular(a: a.first!) 24 | } 25 | 26 | binder 27 | .bind(Int.self) 28 | .intoCollection() 29 | .to(value: 5) 30 | 31 | binder 32 | .bind(Int.self) 33 | .intoCollection() 34 | .to(value: [1,2,3]) 35 | 36 | binder 37 | .bind([Int].self) 38 | .intoCollection() 39 | .to(value: [2]) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Cleanse/AssistedInjection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssistedInjection.swift 3 | // Cleanse 4 | // 5 | // Created by Sebastian Edward Shanus on 9/5/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension BinderBase { 12 | public func bindFactory(_ class: Element.Type) -> AssistedInjectionBindingBuilder { 13 | return AssistedInjectionBindingBuilder(binder: self) 14 | } 15 | } 16 | 17 | extension AssistedInjectionBuilder { 18 | @discardableResult public func to(file: StaticString=#file, line: Int=#line, function: StaticString=#function, factory: @escaping (Assisted) -> Element) -> BindingReceipt> { 19 | let binder = self.binder 20 | 21 | binder 22 | .bind(Factory.self) 23 | .to(value: Factory { seed in 24 | return factory( 25 | Assisted { seed } 26 | ) 27 | }, 28 | file: file, 29 | line: line, 30 | function: function) 31 | return BindingReceipt() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/Parsing/ASTStringHelpers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | These are string helpers unique to the -dump-ast format output. 5 | */ 6 | extension String { 7 | var isValidNewlineStart: Bool { 8 | if matches(#"^\(source_file"#) { 9 | return true 10 | } 11 | if let _ = firstCapture(#"^\s{2,}\((\w+)"#) { 12 | return true 13 | } else if matches(#"\s+\($"#) { 14 | return true 15 | } else { 16 | return false 17 | } 18 | } 19 | 20 | var isOnlyWhitespace: Bool { 21 | allSatisfy { $0.isWhitespace } 22 | } 23 | } 24 | 25 | extension String { 26 | var whitespaceIndentCount: Int { 27 | prefix { $0.isWhitespace }.count 28 | } 29 | 30 | var trimmedLeadingWhitespace: String { 31 | String(suffix(count - whitespaceIndentCount)) 32 | } 33 | 34 | var identifier: NodeIdentifier? { 35 | let pattern = #"\((\w+)"# 36 | guard let found = firstCapture(pattern) else { 37 | return nil 38 | } 39 | return NodeIdentifier(rawValue: found) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Resolver/ResolvedComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResolvedComponent.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 5/13/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public final class ResolvedComponent { 12 | public let type: String 13 | public weak var parent: ResolvedComponent? 14 | public var children: [ResolvedComponent] 15 | public let providersByType: [TypeKey:[CanonicalProvider]] 16 | public let diagnostics: [ResolutionError] 17 | 18 | public init(type: String, providersByType: [TypeKey:[CanonicalProvider]], children: [ResolvedComponent], parent: ResolvedComponent? = nil, diagnostics: [ResolutionError] = []) { 19 | self.type = type 20 | self.providersByType = providersByType 21 | self.children = children 22 | self.parent = parent 23 | self.diagnostics = diagnostics 24 | } 25 | } 26 | 27 | extension ResolvedComponent: CustomStringConvertible { 28 | public var description: String { 29 | "COMPONENT: \(type) \n" + "BINDINGS:\n\(providersByType)\n" + "CHILDREN:\n" + "\(children)" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Cleanse/WeakProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeakProvider.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 7/20/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct WeakProvider : ProviderProtocol { 12 | public typealias Element = E? 13 | 14 | fileprivate let getter: () -> Element 15 | 16 | public init(getter: @escaping () -> Element) { 17 | self.getter = getter 18 | } 19 | 20 | /// - returns: provides an instance of `Element` 21 | public func get() -> Element { 22 | return self.getter() 23 | } 24 | } 25 | 26 | protocol AnyWeakProvider : AnyProvider { 27 | static var standardProviderType: AnyProvider.Type { get } 28 | } 29 | 30 | extension WeakProvider : AnyProvider, AnyWeakProvider { 31 | static func makeNew(getter: @escaping () -> Any) -> AnyProvider { 32 | return WeakProvider(getter: { 33 | getter() as? E 34 | }) 35 | } 36 | 37 | var anyGetterProvider: AnyProvider? { 38 | preconditionFailure("Should not get here") 39 | } 40 | 41 | static var standardProviderType: AnyProvider.Type { 42 | return Provider.self 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Cleanse/WrappedBinder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WrappedBinder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 3/14/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Makes it easy to wrap binders w/ each other 12 | public protocol WrappedBinder : BinderBase { 13 | var binder: BinderBase { get } 14 | init(binder: BinderBase) 15 | } 16 | 17 | 18 | extension WrappedBinder { 19 | public func _internalBind(binding: RawProviderBinding) { 20 | binder._internalBind(binding: binding) 21 | } 22 | 23 | public func include(module: M.Type) where M.Scope == Unscoped { 24 | return binder.include(module: module) 25 | } 26 | 27 | public func install(dependency: C.Type) { 28 | return binder.install(dependency: dependency) 29 | } 30 | 31 | public func install(dependency: C.Type) { 32 | return binder.install(dependency: dependency) 33 | } 34 | 35 | public func _internalProvider(_ type: Element.Type, debugInfo: ProviderRequestDebugInfo?) -> Provider { 36 | return binder._internalProvider(type, debugInfo: debugInfo) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Cleanse/TaggedProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaggedProvider.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/3/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct TaggedProvider : ProviderProtocol { 12 | public typealias Element = Tag.Element 13 | 14 | let getter: () -> Element 15 | 16 | public init(getter: @escaping () -> Element) { 17 | self.getter = getter 18 | } 19 | 20 | public func get() -> Element { 21 | return getter() 22 | } 23 | 24 | public func asProvider() -> Provider { 25 | return Provider(getter: getter) 26 | } 27 | } 28 | 29 | protocol AnyTaggedProvider : AnyProvider { 30 | static var tag: _AnyTag.Type { get } 31 | } 32 | 33 | extension TaggedProvider : AnyTaggedProvider { 34 | static func makeNew(getter: @escaping () -> Any) -> AnyProvider { 35 | return TaggedProvider(getter: { getter() as! Element }) 36 | } 37 | 38 | /// Cannot be represented w/o tags 39 | var anyGetterProvider: AnyProvider? { 40 | return nil 41 | } 42 | 43 | static var tag: _AnyTag.Type { 44 | return Tag.self 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Cleanse/ScopedProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScopedProvider.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 7/6/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | private var weakProviderAssociatedObjectKey = 0 12 | 13 | class ScopedProvider { 14 | fileprivate let rawProvider : AnyProvider 15 | 16 | fileprivate let lock = NSLock() 17 | 18 | fileprivate var cachedValue: Any? 19 | 20 | init(rawProvider: AnyProvider) { 21 | self.rawProvider = rawProvider 22 | } 23 | 24 | 25 | /// This retains self 26 | var wrappedProvider: AnyProvider { 27 | return type(of: rawProvider).makeNew(getter: self.provide) 28 | } 29 | 30 | fileprivate func provide() -> Any { 31 | // If we already have it we can avoid locking 32 | if let cachedValue = cachedValue { 33 | return cachedValue 34 | } 35 | 36 | return lock.with { 37 | if let cachedValue = cachedValue { 38 | return cachedValue 39 | } 40 | 41 | let newValue = rawProvider.getAny() 42 | 43 | self.cachedValue = newValue 44 | 45 | return newValue 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Cleanse-CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | test: 11 | runs-on: macos-latest 12 | env: 13 | DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer 14 | steps: 15 | - uses: maxim-lobanov/setup-xcode@v1 16 | with: 17 | xcode-version: latest-stable 18 | - uses: actions/checkout@v2 19 | - name: Test 20 | run: xcodebuild test -project Cleanse.xcodeproj -scheme Cleanse -enableCodeCoverage=YES -destination "platform=iOS Simulator,name=iPhone 8" 21 | - name: Test CleanseGithubBrowser Sample App 22 | run: xcodebuild test -project Examples/CleanseGithubBrowser/CleanseGithubBrowser.xcodeproj -scheme CleanseGithubBrowser -destination "platform=iOS Simulator,name=iPhone 8" 23 | - name: Test CleanseSwiftUI Sample App 24 | run: xcodebuild -project Examples/CleanseSwiftUIExample/CleanseSwiftUIExample.xcodeproj -scheme adoptme -destination "platform=iOS Simulator,name=iPhone 8" 25 | - name: Test cleansec 26 | run: xcodebuild test -workspace cleansec.xcworkspace -scheme cleansec -enableCodeCoverage=YES -destination "platform=macos" 27 | working-directory: cleansec 28 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParserTests/SwiftAstParserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftAstParserTests.swift 3 | // SwiftAstParserTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/7/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftAstParser 11 | 12 | class SwiftAstParserTests: XCTestCase { 13 | func testUnknownNode() { 14 | let fixture = " (unknown )" 15 | let result = SyntaxParser.parse(text: fixture) 16 | XCTAssertEqual(result.count, 1) 17 | let isType = result.first as? UnknownSyntax 18 | XCTAssertNotNil(isType) 19 | } 20 | 21 | func testSoureFileNode() { 22 | let fixture = "(source_file " 23 | let result = SyntaxParser.parse(text: fixture) 24 | XCTAssertEqual(result.count, 1) 25 | let isType = result.first as? SourceFileDecl 26 | XCTAssertNotNil(isType) 27 | } 28 | 29 | func testParsesKnownNode() { 30 | let node = NodeIdentifier.var_decl 31 | let fixture = " (\(node.rawValue) " 32 | let result = SyntaxParser.parse(text: fixture) 33 | XCTAssertEqual(result.count, 1) 34 | let isType = result.first as? VarDecl 35 | XCTAssertNotNil(isType) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Cleanse/PropertyInjectionReceiptBinder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyInjectionReceiptBinder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 1/6/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct PropertyInjectionReceiptBinder : PropertyInjectorBindingBuilderProtocol { 12 | public typealias Element = E 13 | public typealias B = AnyBinder 14 | 15 | public let binder: AnyBinder 16 | 17 | init(_ underlyingBindingBuilder: BB) where BB.Element == Element { 18 | self.binder = AnyBinder(binder: underlyingBindingBuilder.binder) 19 | } 20 | 21 | public func toPropertyInjectorBindingBuilder() -> PropertyInjectorBindingBuilder { 22 | return PropertyInjectorBindingBuilder(binder: binder) 23 | } 24 | } 25 | 26 | public extension BindToable where Input: PropertyInjectorProtocol { 27 | func propertyInjector(configuredWith configurationFunction: (PropertyInjectionReceiptBinder) -> BindingReceipt>) -> BindingReceipt> { 28 | return configurationFunction(PropertyInjectionReceiptBinder(PropertyInjectorBindingBuilder(binder: self.binder))) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cleansec/script/create-fixtures.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'erb' 4 | require 'pathname' 5 | 6 | class Fixture 7 | attr_accessor :var_name, :contents 8 | 9 | def initialize(var_name, contents) 10 | @var_name = var_name 11 | @contents = contents 12 | end 13 | end 14 | 15 | class Renderer 16 | attr_accessor :fixtures 17 | 18 | def initialize(fixtures) 19 | @fixtures = fixtures 20 | end 21 | 22 | def get_binding 23 | binding() 24 | end 25 | end 26 | 27 | def main 28 | ast_file_path = ARGV[0] 29 | template_path = ARGV[1] 30 | output_path = ARGV[2] 31 | ast_file_contents = File.read(ast_file_path) 32 | source_files = ast_file_contents.split(/(?=\(source_file)/) 33 | filename_regex = %r{\(source_file "(.*)"} 34 | fixtures = [] 35 | source_files.each do |f| 36 | if found = f.match(filename_regex) 37 | fixture_name = Pathname.new(found[1]).basename('.swift') 38 | if fixture_name.to_s != "main" 39 | fixtures += [Fixture.new(fixture_name, f)] 40 | end 41 | end 42 | end 43 | renderer = Renderer.new(fixtures) 44 | generated_path = Pathname.new(output_path) 45 | erb_template = ERB.new(File.read(template_path)) 46 | output = erb_template.result(renderer.get_binding) 47 | swift_file = File.open(generated_path, 'w') 48 | swift_file.puts output 49 | end 50 | 51 | main 52 | -------------------------------------------------------------------------------- /CleanseTests/TaggedProviderTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaggedProviderTests.swift 3 | // Cleanse 4 | // 5 | // Created by holmes on 3/21/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Cleanse 10 | import Foundation 11 | import XCTest 12 | 13 | fileprivate struct TestTag : Tag { 14 | typealias Element = Int 15 | } 16 | 17 | fileprivate class TagHolder { 18 | fileprivate var value = 42 19 | 20 | func magicNumber() -> Int { 21 | return value 22 | } 23 | } 24 | 25 | class TaggedProviderTests: XCTestCase { 26 | fileprivate var tagHolder: TagHolder! 27 | fileprivate var taggedProvider: TaggedProvider! 28 | 29 | override func setUp() { 30 | tagHolder = TagHolder() 31 | taggedProvider = TaggedProvider(getter: tagHolder.magicNumber) 32 | } 33 | 34 | func testTaggedProviderProvidesCorrectValue() { 35 | XCTAssertEqual(42, taggedProvider.get()) 36 | } 37 | 38 | func testAsProviderWorksCorrectly() { 39 | let provider = taggedProvider.asProvider() 40 | 41 | let tagValue = taggedProvider.get() 42 | let providerValue = provider.get() 43 | XCTAssertEqual(tagValue, providerValue) 44 | 45 | tagHolder.value = 1 46 | XCTAssertEqual(1, taggedProvider.get()) 47 | XCTAssertEqual(provider.get(), taggedProvider.get()) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/README.md: -------------------------------------------------------------------------------- 1 | # SwiftAstParser 2 | 3 | Parsing tool to inspect and traverse the typed-AST generated by `swiftc -dump-ast` mode. This tool is helpful if you would like to inspect the fully typed AST tree when `swift-syntax` or `SourceKit` doesn't provide the information you need. It's important to note that the `-dump-ast` output is not stable and changes between swift versions, which means any parsing implementations written on top of this library may break between swift versions. There are some discussions that discourage parsing the `-dump-ast` output due to no guarantees around stability, and it appears that [`libSyntax` would ideally handle this role one day](https://github.com/apple/swift/tree/master/lib/Syntax), so use this tool at your own risk if you find it useful. 4 | 5 | ### API 6 | _Note:_ API is influenced heavily by Apple's [swift-syntax](https://github.com/apple/swift-syntax) 7 | 8 | #### SyntaxParser 9 | Object responsible for parsing `Data` or raw `String` input from the emitted `-dump-ast` mode. 10 | * `public static func parse(data: Data) -> [Syntax]` 11 | * `public static func parse(text: String) -> [Syntax]` 12 | 13 | #### SyntaxVisitor 14 | Provide an implementation conforming to `SyntaxVisitor` to traverse any `Syntax` node and its children. 15 | 16 | Once you create a `SyntaxVisitor` implementation, you can walk a `Syntax` node by calling `walk(_:)` on it. 17 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Visitors/Provider Visitor/ComponentRootVisitor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComponentRootVisitor.swift 3 | // Cleansec 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftAstParser 11 | 12 | /** 13 | Responsible for extracting out the root provider instance and seed type for a given component body. 14 | */ 15 | public struct ComponentRootVisitor: SyntaxVisitor { 16 | public init() {} 17 | 18 | private var seed = "Void" 19 | private var rootProvider: DanglingProvider? 20 | 21 | public mutating func visit(node: Typealias) { 22 | if node.raw.contains("\"Seed\"") { 23 | if let type = node.type.firstCapture(#"(.*)"#), type != "Void" { 24 | seed = type 25 | } 26 | } 27 | } 28 | 29 | public mutating func visit(node: FuncDecl) { 30 | if node.raw.contains("configureRoot(binder:)") { 31 | var rootProviderVisitor = RootProviderVisitor() 32 | rootProviderVisitor.walk(node) 33 | if let danglingRoot = rootProviderVisitor.finalize() { 34 | rootProvider = danglingRoot 35 | } 36 | } 37 | } 38 | 39 | public func finalize() -> (String, DanglingProvider?) { 40 | return (seed, rootProvider) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Visitors/Representations/ProviderModels.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Full provider representation bound into object graph. 4 | public struct StandardProvider: Equatable, Codable { 5 | public let type: String 6 | public let dependencies: [String] 7 | public let tag: String? 8 | public let scoped: String? 9 | public let collectionType: String? 10 | public let debugData: DebugData 11 | 12 | public init(type: String, dependencies: [String], tag: String?, scoped: String?, collectionType: String?, debugData: DebugData = .empty) { 13 | self.type = type 14 | self.dependencies = dependencies 15 | self.tag = tag 16 | self.scoped = scoped 17 | self.collectionType = collectionType 18 | self.debugData = debugData 19 | } 20 | } 21 | 22 | /// Partial provider presentation with known dependencies, but isn't bound into object graph yet. 23 | /// In Cleanse this is usually a provider implementation created as a function. 24 | public struct DanglingProvider: Equatable, Codable { 25 | public let type: String 26 | public let dependencies: [String] 27 | public let debugData: DebugData 28 | 29 | public init(type: String, dependencies: [String], debugData: DebugData = .empty) { 30 | self.type = type 31 | self.dependencies = dependencies 32 | self.debugData = debugData 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/GithubMemberService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GithubService.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct GithubMember { 13 | let login: String 14 | 15 | static func fromJSON(json: [String: AnyObject]) -> GithubMember { 16 | let username = json["login"] as! String 17 | return GithubMember(login: username) 18 | } 19 | } 20 | 21 | /// Service that lists "Member" for the current organization 22 | protocol GithubMembersService { 23 | func list(handler: @escaping (Result<[GithubMember], Error>) -> Void) 24 | } 25 | 26 | struct GithubMembersServiceImpl : GithubMembersService { 27 | let githubURL: TaggedProvider 28 | let githubOrganizationName: TaggedProvider 29 | 30 | let urlSession: URLSession 31 | 32 | /// Lists members of an organization 33 | func list(handler: @escaping (Result<[GithubMember], Error>) -> Void) { 34 | urlSession.jsonListTask( 35 | baseURL: githubURL.get(), 36 | pathComponents: "orgs", githubOrganizationName.get(), "public_members") { result in 37 | handler(result.map { 38 | $0.map(GithubMember.fromJSON) 39 | }) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Cleanse/ProviderProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProviderProvider.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/26/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /** 13 | Portion of the binder protocol used to request future providers. This is only used internally and will probably go away 14 | */ 15 | public protocol ProviderProvider { 16 | /// Raw inner function to request a provider. One should call standard provider methods instead 17 | func _internalProvider(_ type: Element.Type, debugInfo: ProviderRequestDebugInfo?) -> Provider 18 | } 19 | 20 | extension ProviderProvider { 21 | /// - parameter providerRequiredFor: Only used for debugging 22 | /// - returns: the provider used to obtain instances for the key 23 | func provider( 24 | _ type: Element.Type, 25 | file: StaticString=#file, 26 | line: Int=#line, 27 | function: StaticString=#function, 28 | providerRequiredFor: Any.Type? = nil 29 | ) -> Provider { 30 | 31 | let debugInfo = ProviderRequestDebugInfo( 32 | requestedType: type, 33 | providerRequiredFor: providerRequiredFor, 34 | sourceLocation: SourceLocation(file: file, line: line, function: function)) 35 | 36 | return _internalProvider(type, debugInfo: debugInfo) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Cleanse/CollectionBindingBuilderDecorator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionProvider.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/6/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public struct CollectionBindingBuilderDecorator : BindingBuilderDecorator where Wrapped.CollectionOrUnique == _UniqueBinding, Wrapped.FinalProvider: _StandardProvider, Wrapped.MaybeScope == Unscoped { 13 | public typealias FinalProvider = Provider<[Wrapped.FinalProvider.Element]> 14 | public typealias Input = [Wrapped.Input] 15 | public typealias CollectionOrUnique = _CollectionBinding 16 | 17 | public let wrapped: Wrapped 18 | 19 | public init(wrapped: Wrapped) { 20 | self.wrapped = wrapped 21 | } 22 | 23 | public static func mapElement(input: Input) -> FinalProvider.Element { 24 | return input.map(Wrapped.mapElement) 25 | } 26 | 27 | public static var collectionMergeFunc: Optional<([FinalProvider.Element]) -> FinalProvider.Element> { 28 | return { Array($0.joined()) } 29 | } 30 | } 31 | 32 | public extension BindingBuilder where CollectionOrUnique == _UniqueBinding, FinalProvider: _StandardProvider, MaybeScope == Unscoped { 33 | /// If makes it bind Element to [Element] 34 | func intoCollection() -> CollectionBindingBuilderDecorator { 35 | return with() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Screens/HomeView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/7/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct HomeScreen: View { 12 | @EnvironmentObject private var userData: UserData 13 | @State var navBarHidden: Bool = true 14 | var body: some View { 15 | NavigationView { 16 | List { 17 | HomeHeader().padding(EdgeInsets(top: 32, leading: 0, bottom: 0, trailing: 0)) 18 | ForEach(userData.pets) { pet in 19 | PetRow(pet: pet) 20 | } 21 | }.environment(\.defaultMinListRowHeight, 132).listSeparatorStyleNone() 22 | .navigationBarTitle("") 23 | .navigationBarHidden(self.navBarHidden) 24 | .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in 25 | self.navBarHidden = true 26 | } 27 | .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in 28 | self.navBarHidden = false 29 | } 30 | } 31 | } 32 | } 33 | 34 | struct ContentView_Previews: PreviewProvider { 35 | static var previews: some View { 36 | HomeScreen().environmentObject(UserData()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Cleanse/ReceiptBinder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReceiptBinder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 1/6/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public struct ReceiptBinder : BindToable { 13 | public typealias Input = Element 14 | public typealias Binder = AnyBinder 15 | 16 | private let innerTo: (_ file: StaticString, _ line: Int, _ function: StaticString, _ provider: Provider) -> BindingReceipt 17 | public let binder: AnyBinder 18 | 19 | public let _finalProviderType : Any.Type 20 | 21 | 22 | init(_ underlyingBindingBuilder: BB) where BB.Input == Input { 23 | self.innerTo = underlyingBindingBuilder._innerTo 24 | self.binder = AnyBinder(binder: underlyingBindingBuilder.binder) 25 | self._finalProviderType = underlyingBindingBuilder._finalProviderType 26 | } 27 | 28 | public func _innerTo(file: StaticString, line: Int, function: StaticString, provider: Provider) -> BindingReceipt { 29 | return innerTo(file, line, function, provider) 30 | } 31 | } 32 | 33 | public extension BindToable { 34 | @discardableResult 35 | func configured(with configurationFunction: (ReceiptBinder) -> BindingReceipt) -> BindingReceipt { 36 | return configurationFunction(ReceiptBinder(self)) 37 | } 38 | } 39 | 40 | //public extension BindToable where 41 | -------------------------------------------------------------------------------- /cleansec/CleansecFramework/Visitors/Provider Visitor/APITypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APITypes.swift 3 | // CleansecFramework 4 | // 5 | // Created by Sebastian Edward Shanus on 9/24/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftAstParser 11 | 12 | enum BaseBindingType: String, CaseIterable { 13 | case provider = "BaseBindingBuilder" 14 | case taggedProvider = "TaggedBindingBuilderDecorator" 15 | case scopedProvider = "ScopedBindingDecorator" 16 | case propertyInjector = "PropertyInjectorBindingBuilder" 17 | case assistedInjectionProvider = "AssistedInjectionSeedDecorator" 18 | case singularCollectionProvider = "SingularCollectionBindingBuilderDecorator" 19 | case collectionProvider = "CollectionBindingBuilderDecorator" 20 | } 21 | 22 | enum BindingAPI: String, CaseIterable { 23 | case toValue = "decl=Cleanse.(file).BindToable extension.to(value:file:line:function:)" 24 | case toFactory = "decl=Cleanse.(file).BindToable extension.to(file:line:function:factory:)" 25 | case toFactoryPropertyInjector = "decl=Cleanse.(file).PropertyInjectorBindingBuilderProtocol extension.to(file:line:function:injector:)" 26 | case toFactoryAssistedInjection = "decl=Cleanse.(file).AssistedInjectionBuilder extension.to(file:line:function:factory:)" 27 | } 28 | 29 | 30 | extension CallExpr { 31 | var isCleanseBinding: Bool { 32 | return type.firstCapture("BindingReceipt<(.*)>") != nil 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /CleanseTests/SPITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPITests.swift 3 | // CleanseTests 4 | // 5 | // Created by Sebastian Edward Shanus on 11/18/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | import XCTest 12 | 13 | final class SPITests: XCTestCase { 14 | struct MyRoot { 15 | let name: String 16 | } 17 | 18 | struct MyRootComponent: RootComponent { 19 | typealias Root = MyRoot 20 | 21 | static func configure(binder: Binder) { 22 | 23 | } 24 | 25 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 26 | return bind.to(factory: { MyRoot(name: "Caroline") }) 27 | } 28 | } 29 | 30 | struct MyPlugin: CleanseBindingPlugin { 31 | let expectation: XCTestExpectation 32 | func visit(root: ComponentBinding, errorReporter: CleanseErrorReporter) { 33 | expectation.fulfill() 34 | } 35 | } 36 | 37 | func testPluginRuns() { 38 | let expectation = XCTestExpectation(description: "Plugin should run") 39 | let plugin = MyPlugin(expectation: expectation) 40 | let serviceLoader = CleanseServiceLoader([plugin]) 41 | 42 | let _ = try! ComponentFactory.of(MyRootComponent.self, validate: true, serviceLoader: serviceLoader) 43 | wait(for: [expectation], timeout: 1.0) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Cleanse/SingularCollectionBindingBuilderDecorator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SingularCollectionBindingBuilderDecorator.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/9/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct SingularCollectionBindingBuilderDecorator : BindingBuilderDecorator 12 | where 13 | Wrapped.CollectionOrUnique == _UniqueBinding, 14 | Wrapped.FinalProvider: _StandardProvider, 15 | Wrapped.MaybeScope == Unscoped 16 | { 17 | public typealias FinalProvider = Provider<[Wrapped.FinalProvider.Element]> 18 | public typealias CollectionOrUnique = _CollectionBinding 19 | 20 | public let wrapped: Wrapped 21 | 22 | public init(wrapped: Wrapped) { 23 | self.wrapped = wrapped 24 | } 25 | 26 | public static func mapElement(input: Wrapped.Input) -> FinalProvider.Element { 27 | return [Wrapped.mapElement(input: input)] 28 | } 29 | 30 | public static var collectionMergeFunc: Optional<([FinalProvider.Element]) -> FinalProvider.Element> { 31 | return { Array($0.joined()) } 32 | } 33 | } 34 | 35 | 36 | public extension BindingBuilder where CollectionOrUnique == _UniqueBinding, FinalProvider: _StandardProvider, MaybeScope == Unscoped { 37 | /// If makes it bind `Element` to `[Element]` 38 | func intoCollection() -> SingularCollectionBindingBuilderDecorator { 39 | return with() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Cleanse/ScopedBinder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Binder.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 3/14/17. 6 | // Copyright © 2017 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// This is a Binder that is Scope aware 13 | public protocol BinderType : BinderBase { 14 | associatedtype Scope: Cleanse._ScopeBase 15 | } 16 | 17 | public struct Binder : BinderType, WrappedBinder { 18 | public let binder: BinderBase 19 | 20 | public init(binder: BinderBase) { 21 | // Optimization to reduce nesting of wrapped binders 22 | if let binder = binder as? WrappedBinder { 23 | self.binder = binder.binder 24 | } else { 25 | self.binder = binder 26 | } 27 | } 28 | 29 | public typealias Scope = S 30 | } 31 | 32 | extension BinderType { 33 | /// For including scoped modules 34 | public func include(module: M.Type) where M.Scope == Self.Scope, M.Scope: Cleanse.Scope { 35 | return include(module: AnyScopedModule.self) 36 | } 37 | } 38 | 39 | /// Used for making a module looks unscoped. This is so we can disambiguate includes 40 | private struct AnyScopedModule : Module { 41 | typealias Scope = Unscoped 42 | 43 | fileprivate static func configure(binder: UnscopedBinder) { 44 | M.configure(binder: .init(binder: binder)) 45 | } 46 | } 47 | 48 | /// Default binder used 49 | public typealias UnscopedBinder = Binder 50 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Models/ImageStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageStore.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/8/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import SwiftUI 12 | 13 | final class ImageStore { 14 | typealias _ImageDictionary = [String: CGImage] 15 | fileprivate var images: _ImageDictionary = [:] 16 | 17 | fileprivate static var scale = 2 18 | 19 | static var shared = ImageStore() 20 | 21 | func image(name: String) -> Image { 22 | let index = _guaranteeImage(name: name) 23 | 24 | return Image(images.values[index], scale: CGFloat(ImageStore.scale), label: Text(name)) 25 | } 26 | 27 | static func loadImage(name: String) -> CGImage { 28 | guard 29 | let url = Bundle.main.url(forResource: name, withExtension: "jpg"), 30 | let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil), 31 | let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) 32 | else { 33 | fatalError("Couldn't load image \(name).jpg from main bundle.") 34 | } 35 | return image 36 | } 37 | 38 | fileprivate func _guaranteeImage(name: String) -> _ImageDictionary.Index { 39 | if let index = images.index(forKey: name) { return index } 40 | 41 | images[name] = ImageStore.loadImage(name: name) 42 | return images.index(forKey: name)! 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Cleanse/PropertyInjector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PropertyInjector.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 4/29/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public protocol PropertyInjectorProtocol { 13 | associatedtype Element: AnyObject 14 | func injectProperties(into instance: Element) 15 | } 16 | 17 | 18 | /// This the mechanism property injection is done underneath the hood 19 | public struct PropertyInjector : PropertyInjectorProtocol { 20 | let injectionClosure: (Element) -> Void 21 | 22 | /// Call this to inject properties into an instance of an object. 23 | public func injectProperties(into instance: Element) { 24 | injectionClosure(instance) 25 | } 26 | } 27 | 28 | 29 | #if SUPPORT_LEGACY_OBJECT_GRAPH 30 | 31 | /// This is used to for legacy support 32 | protocol AnyPropertyInjectorProtocol { 33 | func untypedInjectProperties(into instance: AnyObject) 34 | 35 | static var injectedType: AnyClass { get } 36 | } 37 | 38 | 39 | 40 | extension PropertyInjectorProtocol { 41 | func untypedInjectProperties(into instance: AnyObject) { 42 | injectProperties(into: instance as! Element) 43 | } 44 | 45 | static var injectedType: AnyClass { 46 | return Element.self 47 | } 48 | } 49 | 50 | extension PropertyInjector : AnyPropertyInjectorProtocol { 51 | 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/GithubRepositoriesService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GithubRepositoriesService.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | struct GithubRepository { 13 | let name: String 14 | let watchersCount: Int 15 | 16 | static func fromJSON(_ json: [String: AnyObject]) -> GithubRepository { 17 | return .init( 18 | name: json["name"] as! String, 19 | watchersCount: json["watchers_count"] as! Int 20 | ) 21 | } 22 | } 23 | 24 | /// Service that lists repositories for the current user 25 | protocol GithubRepositoriesService { 26 | func list(_ handler: @escaping (Result<[GithubRepository], Error>) -> Void) 27 | } 28 | 29 | struct GithubRepositoriesServiceImpl : GithubRepositoriesService { 30 | let githubURL: TaggedProvider 31 | let githubOrganizationName: TaggedProvider 32 | 33 | let urlSession: URLSession 34 | 35 | func list(_ handler: @escaping (Result<[GithubRepository], Error>) -> Void) { 36 | urlSession.jsonListTask( 37 | baseURL: githubURL.get(), 38 | pathComponents: "users", githubOrganizationName.get(), "repos", 39 | query: "sort=updated") { result in 40 | handler(result.map { 41 | $0.map(GithubRepository.fromJSON) 42 | }) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Cleanse/ComponentFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComponentFactory.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 7/6/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ComponentFactoryProtocol { 12 | associatedtype ComponentElement: Cleanse.ComponentBase 13 | 14 | func build(_ seed: ComponentElement.Seed) -> ComponentElement.Root 15 | } 16 | 17 | public final class ComponentFactory : ComponentFactoryProtocol { 18 | public typealias ComponentElement = C 19 | fileprivate let factoryFunction: (_ seed: ComponentElement.Seed, _ subgraph: Graph) -> C.Root 20 | fileprivate let parent: Graph? 21 | fileprivate var subgraphs: [Graph] = [] 22 | 23 | init(parent: Graph?, factoryFunction: @escaping (_ seed: ComponentElement.Seed, _ subgraph: Graph) -> C.Root) { 24 | self.factoryFunction = factoryFunction 25 | self.parent = parent 26 | } 27 | 28 | /// Builds the Component and returns its root object. 29 | public func build(_ seed: ComponentElement.Seed) -> ComponentElement.Root { 30 | let subgraph = Graph(scope: C.Scope.scopeOrNil, parent: parent) 31 | subgraphs.append(subgraph) 32 | return factoryFunction(seed, subgraph) 33 | } 34 | } 35 | 36 | extension ComponentFactoryProtocol where ComponentElement.Seed: ProviderProtocol { 37 | public func build(_ seed: ComponentElement.Seed.Element) -> ComponentElement.Root { 38 | return build(ComponentElement.Seed.init(value: seed)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Sandbox 4 | // 5 | // Created by Sebastian Edward Shanus on 5/13/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Cleanse 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | // MARK: UISceneSession Lifecycle 23 | 24 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 25 | // Called when a new scene session is being created. 26 | // Use this method to select a configuration to create the new scene with. 27 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 28 | } 29 | 30 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 31 | // Called when the user discards a scene session. 32 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 33 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 34 | } 35 | 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /cleansec/SwiftAstParser/script/SyntaxVisitor.template: -------------------------------------------------------------------------------- 1 | // This file is generated! DO NOT EDIT!! 2 | 3 | public extension SyntaxVisitor { 4 | mutating func walk(_ node: Syntax) { 5 | var shouldVisitChildren = true 6 | if false { 7 | // Noop 8 | <% for @item in @decl_items %> 9 | } else if let node = node as? <%= @item.class_name %> { 10 | visit(node: node) 11 | shouldVisitChildren = visitChildren(node: node) 12 | <% end %> 13 | } else if let node = node as? UnknownSyntax { 14 | visit(node: node) 15 | shouldVisitChildren = visitChildren(node: node) 16 | } 17 | 18 | if shouldVisitChildren { 19 | node.children.forEach { walk($0) } 20 | } 21 | } 22 | } 23 | 24 | public protocol SyntaxVisitor { 25 | <% for @item in @decl_items %> 26 | mutating func visit(node: <%= @item.class_name %>) 27 | mutating func visitChildren(node: <%= @item.class_name %>) -> Bool 28 | <% end %> 29 | mutating func visit(node: UnknownSyntax) 30 | mutating func visitChildren(node: UnknownSyntax) -> Bool 31 | } 32 | 33 | public extension SyntaxVisitor { 34 | <% for @item in @decl_items %> 35 | mutating func visit(node: <%= @item.class_name %>) { 36 | // Noop 37 | } 38 | mutating func visitChildren(node: <%= @item.class_name %>) -> Bool { 39 | true 40 | } 41 | <% end %> 42 | mutating func visit(node: UnknownSyntax) { 43 | // Noop 44 | } 45 | 46 | mutating func visitChildren(node: UnknownSyntax) -> Bool { 47 | true 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cleansec/CleansecFrameworkTests/LinkerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkerTests.swift 3 | // CleansecFrameworkTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/12/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import CleansecFramework 12 | 13 | class LinkerTests: XCTestCase { 14 | func testLinking() { 15 | let componentA = Component( 16 | type: "MyComponent", 17 | rootType: "Int", 18 | providers: [ 19 | StandardProvider(type: "Int", dependencies: [], tag: nil, scoped: nil, collectionType: nil) 20 | ], 21 | seed: "Void", 22 | includedModules: [], 23 | subcomponents: [], 24 | isRoot: true 25 | ) 26 | let componentB = Component( 27 | type: "SecondComponent", 28 | rootType: "Float", 29 | providers: [ 30 | StandardProvider(type: "Float", dependencies: [], tag: nil, scoped: nil, collectionType: nil) 31 | ], 32 | seed: "Void", 33 | includedModules: [], 34 | subcomponents: [], 35 | isRoot: true 36 | ) 37 | let fileA = FileRepresentation(components: [componentA], modules: []) 38 | let fileB = FileRepresentation(components: [componentB], modules: []) 39 | let moduleA = ModuleRepresentation(files: [fileA]) 40 | let moduleB = ModuleRepresentation(files: [fileB]) 41 | let interface = Linker.link(modules: [moduleA, moduleB]) 42 | XCTAssertEqual(interface.components.count, 2) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cleansec/CleansecFrameworkTests/PluginTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PluginTests.swift 3 | // CleansecFrameworkTests 4 | // 5 | // Created by Sebastian Edward Shanus on 5/18/20. 6 | // Copyright © 2020 Square. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import CleansecFramework 12 | 13 | class PluginTests: XCTestCase { 14 | func testBadPluginPath() { 15 | XCTAssertNil(Cleansec.run(plugin: "badecho", astFilePath: ".")) 16 | } 17 | 18 | func testPluginOutput() { 19 | let provider = StandardProvider(type: "String", dependencies: [], tag: nil, scoped: nil, collectionType: nil) 20 | let module = Module(type: "Module", providers: [provider], includedModules: [], subcomponents: []) 21 | let file = FileRepresentation(components: [], modules: [module]) 22 | let moduleRepresentation = ModuleRepresentation(files: [file]) 23 | let encoder = JSONEncoder() 24 | encoder.outputFormatting = .prettyPrinted 25 | let data = try! encoder.encode(moduleRepresentation) 26 | let outputString = String(data: data, encoding: .utf8)! 27 | 28 | let pluginOutput = Cleansec.run(plugin: "/bin/echo", astFilePath: outputString) 29 | XCTAssertNotNil(pluginOutput) 30 | XCTAssertNotNil(pluginOutput?.files.first?.modules.first) 31 | XCTAssertEqual(pluginOutput?.files.first?.modules.first?.providers.first, provider) 32 | } 33 | 34 | func testPluginBadOutput() { 35 | let pluginOutput = Cleansec.run(plugin: "/bin/echo", astFilePath: "{\"something\": \"else\"}") 36 | XCTAssertNil(pluginOutput) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CleanseTests/DebuggingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GraphTests.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/10/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | @testable import Cleanse 10 | import Foundation 11 | import XCTest 12 | 13 | struct Singleton : Scope { 14 | } 15 | 16 | class DebuggingTests: XCTestCase { 17 | struct FooModule : Module { 18 | static func configure(binder: UnscopedBinder) { 19 | binder.bind().to(value: 3) 20 | binder.bind().to(value: "Imma string") 21 | } 22 | } 23 | 24 | func testGraphDebugDescription() { 25 | // The graph's description should list providers. This may be useful for deubgging. This test is also to exercise code coverage of description methods 26 | let g = Graph(scope: Singleton.self) 27 | 28 | // TODO: make it more descriptive 29 | g.include(module: FooModule.self) 30 | 31 | try! g.finalize() 32 | let description = g.debugDescription 33 | 34 | Assert(description, contains: "Provider") 35 | Assert(description, contains: "Provider") 36 | Assert(description, contains: "Provider<() -> Int>") 37 | Assert(description, contains: "Provider<() -> String>") 38 | } 39 | } 40 | 41 | func Assert(_ entireString: @autoclosure () throws -> String, contains expectedContents: @autoclosure () throws -> String, file: StaticString = #file, line: UInt = #line) { 42 | XCTAssertTrue(try entireString().contains(expectedContents()), "Expected \(try! entireString())\nto contain \(try! expectedContents())", file: file, line: line) 43 | } 44 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/Views/Components/PetRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PetRow.swift 3 | // Exam1 4 | // 5 | // Created by Abdul Chathil on 6/7/20. 6 | // Copyright © 2020 Abdul Chathil. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | 12 | 13 | struct PetRow: View { 14 | @EnvironmentObject var userData: UserData 15 | var pet: Pet 16 | var petIndex: Int { 17 | userData.pets.firstIndex(where: { $0.id == pet.id })! 18 | } 19 | var body: some View { 20 | HStack { 21 | pet.image.resizable().scaledToFill().frame(width: 112, height: 112, alignment: .center).clipped() 22 | VStack(alignment: .leading) { 23 | Text(pet.name) 24 | .font(.headline) 25 | .fontWeight(.bold) 26 | .foregroundColor(.black) 27 | Text(pet.location).foregroundColor(.black) 28 | HStack { 29 | LikeButton(isLiked: self.userData.pets[self.petIndex].isLiked).padding().onTapGesture { 30 | self.userData.pets[self.petIndex].isLiked.toggle() 31 | } 32 | PetBadge(type: pet.type) 33 | } 34 | } 35 | Spacer() 36 | }.clipShape(RoundedRectangle(cornerRadius: 16.0)) 37 | } 38 | static let gradientStart = Color(red: 0.0 / 255, green: 150.0 / 255, blue: 136.0 / 255) 39 | static let gradientEnd = Color(red: 224.0 / 255, green: 242.0 / 255, blue: 241.0 / 255) 40 | } 41 | 42 | struct PetRow_Previews: PreviewProvider { 43 | static var previews: some View { 44 | PetRow(pet: petData[0]).environmentObject(UserData()) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/GithubServicesModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GithubServicesModule.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cleanse 11 | 12 | 13 | protocol GithubServicesModule : Module { 14 | static func configureGithubMembersService(binder bind: ReceiptBinder) -> BindingReceipt 15 | static func configureRepositoriesMembersService(binder bind: ReceiptBinder) -> BindingReceipt 16 | } 17 | 18 | 19 | /// Wires up common definitions shared across services as well as installing the services's modules 20 | struct RealeaseGithubServicesModule : GithubServicesModule { 21 | static func configure(binder: SingletonBinder) { 22 | binder.include(module: NetworkModule.self) 23 | } 24 | 25 | static func configureGithubMembersService(binder bind: ReceiptBinder) -> BindingReceipt { 26 | return bind.to(factory: GithubMembersServiceImpl.init) 27 | } 28 | 29 | static func configureRepositoriesMembersService(binder bind: ReceiptBinder) -> BindingReceipt { 30 | return bind.to(factory: GithubRepositoriesServiceImpl.init) 31 | } 32 | } 33 | 34 | struct GithubBaseURL : Tag { 35 | typealias Element = URL 36 | } 37 | 38 | /// Represents the github user name we want to query. 39 | struct GithubUserName : Tag { 40 | typealias Element = String 41 | } 42 | 43 | struct GithubOrganizationName : Tag { 44 | typealias Element = String 45 | } 46 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Cleanse CHANGELOG 2 | 3 | ## Master 4 | 5 | #### Features & Updates 6 | 7 | * New Example: CleanseSwiftUIExample. 8 | [Abdul Chathil](https://github.com/chathil) 9 | [#176](https://github.com/square/Cleanse/pull/176) 10 | 11 | #### Bug Fixes 12 | 13 | * None 14 | 15 | ## 4.2.6 16 | 17 | #### Features & Updates 18 | 19 | * cleansec: Cleanse Compiler ([README](https://github.com/square/Cleanse/blob/master/cleansec/README.md)) 20 | [Sebastian Shanus](https://github.com/sebastianv1) 21 | 22 | #### Bug Fixes 23 | 24 | * Fix Assisted Injection `SourceLocation` info. 25 | [Sebastian Shanus](https://github.com/sebastianv1) 26 | [#166](https://github.com/square/Cleanse/pull/166) 27 | 28 | * Fix `WeakProviders` becoming deinitialized. 29 | [Sebastian Shanus](https://github.com/sebastianv1) 30 | [#98](https://github.com/square/Cleanse/issues/98) 31 | 32 | ## 4.2.5 33 | 34 | #### Features & Updates 35 | 36 | * Replace demo app's ErrorOptional type with Swift Foundation Result type 37 | [Sihao Lu](https://github.com/DJBen) 38 | [#126](https://github.com/square/Cleanse/pull/126) 39 | 40 | * Xcode 11.2 Support 41 | [Sebastian Shanus](https://github.com/sebastianv1) 42 | [#125](https://github.com/square/Cleanse/issues/125) 43 | 44 | * Service Provider Interface (SPI) 45 | [Sebastian Shanus](https://github.com/sebastianv1) 46 | [#118](https://github.com/square/Cleanse/issues/118) 47 | 48 | * Assisted Injection 49 | [Sebastian Shanus](https://github.com/sebastianv1) 50 | [#112](https://github.com/square/Cleanse/issues/112) 51 | 52 | #### Bug Fixes 53 | 54 | * Retain subcomponent graphs 55 | [Sebastian Shanus](https://github.com/sebastianv1) 56 | [#42](https://github.com/square/Cleanse/issues/42) 57 | -------------------------------------------------------------------------------- /CleanseTests/SubcomponentTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SubcomponentTests.swift 3 | // CleanseTests 4 | // 5 | // Created by Sebastian Edward Shanus on 12/16/19. 6 | // Copyright © 2019 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | import Cleanse 12 | 13 | struct A { 14 | let b: Provider 15 | } 16 | 17 | struct B { 18 | let subcomponent: ComponentFactory 19 | } 20 | 21 | struct RootType { 22 | let a: A 23 | } 24 | 25 | struct Subroot { 26 | let name: String 27 | } 28 | 29 | struct AppRootComponent: RootComponent { 30 | static func configure(binder: Binder) { 31 | binder.install(dependency: SubComponent.self) 32 | binder.bind(A.self).to(factory: A.init) 33 | binder.bind(B.self).to(factory: B.init) 34 | } 35 | 36 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 37 | return bind.to(factory: RootType.init) 38 | } 39 | 40 | typealias Root = RootType 41 | } 42 | 43 | struct SubComponent: Component { 44 | static func configure(binder: Binder) { 45 | binder 46 | .bind(String.self) 47 | .to(value: "Hello") 48 | } 49 | 50 | static func configureRoot(binder bind: ReceiptBinder) -> BindingReceipt { 51 | return bind.to(factory: Subroot.init) 52 | } 53 | 54 | typealias Root = Subroot 55 | } 56 | 57 | 58 | class SubcomponentTests: XCTestCase { 59 | func testNestedSubcomponents() { 60 | let root = try! ComponentFactory.of(AppRootComponent.self).build(()) 61 | let subcomponent = root.a.b.get().subcomponent.build(()) 62 | XCTAssert(subcomponent.name == "Hello") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /cleansec/Sandbox/Sandbox/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Examples/CleanseSwiftUIExample/CleanseSwiftUIExample/SupportingFiles/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | adoptme 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | 30 | UIApplicationSupportsIndirectInputEvents 31 | 32 | UILaunchScreen 33 | 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CleansePlayground.playground/playground.xcworkspace/xcshareddata/CleansePlayground.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "FA78EFA588CAAA527A39EFF7FEB4200B880E2491", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "FA78EFA588CAAA527A39EFF7FEB4200B880E2491" : 9223372036854775807, 8 | "C29DD0E89C17000393FD71820E9E7C86451DD28A" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "C9383146-7609-43F6-A193-8ABE1B105154", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "FA78EFA588CAAA527A39EFF7FEB4200B880E2491" : "Cleanse\/", 13 | "C29DD0E89C17000393FD71820E9E7C86451DD28A" : ".." 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "CleansePlayground", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CleansePlayground.playground", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/git.corp.squareup.com\/ios\/appointments.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "C29DD0E89C17000393FD71820E9E7C86451DD28A" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/git.corp.squareup.com\/ml\/cleanse.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "FA78EFA588CAAA527A39EFF7FEB4200B880E2491" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /Cleanse/BindingBuilderDecorator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BindingBuilderDecorator.swift 3 | // Cleanse 4 | // 5 | // Created by Mike Lewis on 5/9/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public protocol BindingBuilderDecorator : BindingBuilder { 13 | associatedtype Wrapped: BindingBuilder 14 | 15 | init(wrapped: Wrapped) 16 | var wrapped: Wrapped { get } 17 | 18 | /// Support for collection binding. Users probably don't have to worry about this. Also they have default implementations 19 | /// TODO: Move elsewhere perhaps 20 | associatedtype MaybeScope = Wrapped.MaybeScope 21 | associatedtype Input = Wrapped.Input 22 | associatedtype Binder = Wrapped.Binder 23 | associatedtype FinalProvider = Wrapped.FinalProvider 24 | 25 | associatedtype CollectionOrUnique = Wrapped.CollectionOrUnique 26 | 27 | static var collectionMergeFunc: Optional<([FinalProvider.Element]) -> FinalProvider.Element> { get } 28 | } 29 | 30 | 31 | extension BindingBuilderDecorator where FinalProvider.Element == Wrapped.FinalProvider.Element { 32 | public static var collectionMergeFunc: Optional<([FinalProvider.Element]) -> FinalProvider.Element> { 33 | guard let wrappedF = Wrapped.collectionMergeFunc else { 34 | return nil 35 | } 36 | 37 | return wrappedF 38 | } 39 | } 40 | 41 | extension BindingBuilderDecorator where Self.Binder == Wrapped.Binder { 42 | public var binder: Self.Binder { 43 | return wrapped.binder 44 | } 45 | } 46 | 47 | extension BindingBuilderDecorator where Input == Wrapped.Input, FinalProvider.Element == Wrapped.FinalProvider.Element { 48 | public static func mapElement(input: Input) -> FinalProvider.Element { 49 | return Wrapped.mapElement(input: input) 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/NSURLSessionAdditions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSURLSessionAdditions.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/12/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension URLSession { 13 | func jsonTask(baseURL: URL, pathComponents: String..., resultHandler: @escaping (Result) -> Void) -> URLSessionDataTask { 14 | let url = baseURL.appendingPathComponent(pathComponents.joined(separator: "/")) 15 | return jsonTask(url: url as URL, resultHandler: resultHandler) 16 | } 17 | 18 | private func jsonTask(url: URL, resultHandler: @escaping (Result) -> Void) -> URLSessionDataTask { 19 | let task = self.dataTask(with: url as URL) { (data, response, error) in 20 | if let error: Error = error ?? HTTPError(statusCode: (response as! HTTPURLResponse).statusCode) { 21 | resultHandler(.failure(error)) 22 | return 23 | } 24 | 25 | do { 26 | try resultHandler(.success(JSONSerialization.jsonObject(with: data!, options: []))) 27 | } catch let e { 28 | resultHandler(.failure(e)) 29 | return 30 | } 31 | } 32 | 33 | task.resume() 34 | return task 35 | } 36 | 37 | @discardableResult 38 | func jsonListTask( 39 | baseURL: URL, 40 | pathComponents: String..., 41 | query: String? = nil, 42 | resultHandler: @escaping (Result<[[String: AnyObject]], Error>) -> Void 43 | ) -> URLSessionDataTask { 44 | var url = baseURL.appendingPathComponent(pathComponents.joined(separator: "/")) 45 | 46 | if let query = query { 47 | url = URL(string: url.absoluteString + "?" + query)! 48 | } 49 | 50 | return jsonTask(url: url) { resultHandler($0.map { $0 as! [[String: AnyObject]] }) } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Examples/CleanseGithubBrowser/CleanseGithubBrowser/UIKitCommonModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppModule.swift 3 | // CleanseGithubBrowser 4 | // 5 | // Created by Mike Lewis on 6/10/16. 6 | // Copyright © 2016 Square, Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Cleanse 11 | 12 | /// Define common UIKit bindings. 13 | public struct UIKitCommonModule : Module { 14 | public static func configure(binder: UnscopedBinder) { 15 | 16 | binder.include(module: UIScreen.Module.self) 17 | binder.include(module: UIWindow.Module.self) 18 | } 19 | } 20 | 21 | extension UIScreen { 22 | /// This is a simple module that binds UIScreen.mainScreen() to UIScreen 23 | public struct Module : Cleanse.Module { 24 | public static func configure(binder: UnscopedBinder) { 25 | binder 26 | .bind(UIScreen.self) 27 | .to { UIScreen.main } 28 | } 29 | } 30 | } 31 | 32 | extension UIWindow { 33 | /// This is the module that configures how we build our main window. It ias assumed when one requests 34 | /// injection of an un-tagged UIWindow, we will be giving them the "main" or "key" window. 35 | public struct Module : Cleanse.Module { 36 | public static func configure(binder: UnscopedBinder) { 37 | binder 38 | .bind(UIWindow.self) 39 | // .sharedInScope() FIXME what does this break? 40 | .to { (rootViewController: TaggedProvider, mainScreen: UIScreen) in 41 | let window = UIWindow(frame: mainScreen.bounds) 42 | window.rootViewController = rootViewController.get() 43 | return window 44 | } 45 | } 46 | } 47 | } 48 | 49 | extension UIViewController { 50 | /// This will represent the rootViewController that is assigned to our main window 51 | public struct Root : Tag { 52 | public typealias Element = UIViewController 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cleansec/script/swiftc-ast.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'pathname' 4 | require 'fileutils' 5 | 6 | DISALLOWED_ARGUMENTS = { 7 | '-emit-dependencies' => :none, 8 | '-emit-module' => :none, 9 | '-emit-module-path' => :arg, 10 | '-emit-objc-header' => :none, 11 | '-emit-objc-header-path' => :arg, 12 | '-c' => :none, 13 | '-incremental' => :none, 14 | '-parseable-output' => :none 15 | } 16 | 17 | def swiftc_executable 18 | Pathname.new(ENV['DEVELOPER_DIR']).join('Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc') 19 | end 20 | 21 | def strip_disallowed_arguments(disallowed_args, input) 22 | input.each_index.select do |idx| 23 | disallowed_args.key?(input[idx]) 24 | end 25 | end 26 | 27 | 28 | def main 29 | input = ARGV 30 | og_command = [swiftc_executable] + input 31 | ast_input = input.clone 32 | indices_to_remove = strip_disallowed_arguments(DISALLOWED_ARGUMENTS, ast_input).flat_map do |idx| 33 | if DISALLOWED_ARGUMENTS[input[idx]] == :arg 34 | [idx, idx+1] 35 | else 36 | [idx] 37 | end 38 | end 39 | 40 | indices_to_remove.sort.reverse.each do |idx| 41 | ast_input.delete_at(idx) 42 | end 43 | 44 | pipe_to_file_command = ['2>&1'] 45 | if output_file = input.grep(/DAST_FILE/).first 46 | outpath_file_path = output_file.split('=')[1] 47 | FileUtils.mkdir_p(Pathname.new(outpath_file_path).dirname) 48 | pipe_to_file_command = ['&>'] + [outpath_file_path] 49 | end 50 | 51 | dump_ast_command = [swiftc_executable] + ['-dump-ast', '-suppress-warnings'] + ast_input + pipe_to_file_command 52 | sanitized_og_command = og_command.map { |c| c.to_s.gsub(/\s/, "\\ ") } 53 | sanitized_ast_command = dump_ast_command.map { |c| c.to_s.gsub(/\s/, "\\ ") } 54 | if ENV["DISABLE_DUMP_AST"] 55 | status = system(sanitized_og_command.join(" ")) 56 | exit(1) unless status 57 | else 58 | pid = spawn(sanitized_ast_command.join(" ")) 59 | status = system(sanitized_og_command.join(" ")) 60 | Process.wait(pid) 61 | exit(1) unless status 62 | end 63 | end 64 | 65 | main 66 | 67 | 68 | --------------------------------------------------------------------------------