Repository: krzysztofzablocki/Sourcery Branch: master Commit: afb0782ecb5e Files: 553 Total size: 4.7 MB Directory structure: gitextract_t4znldax/ ├── .circleci/ │ └── config.yml ├── .codecov.yml ├── .github/ │ └── workflows/ │ ├── bump_homebrew.yml │ ├── docker.yml │ ├── jazzy.yml │ ├── release_macOS.yml │ ├── release_ubuntu.yml │ ├── test_macOS.yml │ └── test_ubuntu.yml ├── .gitignore ├── .gitmodules ├── .jazzy.yaml ├── .pre-commit-hooks.yaml ├── .ruby-version ├── .sourcery-macOS.yml ├── .sourcery-ubuntu.yml ├── .swift-version ├── .swiftlint.yml ├── .vscode/ │ ├── launch.json │ └── settings.json ├── ABOUT.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dangerfile ├── Dockerfile ├── Funding.yml ├── Gemfile ├── LICENSE ├── LINUX.md ├── LinuxMain.swift ├── Package.resolved ├── Package.swift ├── Plugins/ │ └── SourceryCommandPlugin/ │ └── SourceryCommandPlugin.swift ├── README.md ├── RELEASING.md ├── Rakefile ├── Scripts/ │ ├── SwiftLint.sh │ ├── bootstrap │ ├── package_content │ ├── pre-commit.sh │ └── update-placeholders ├── Sourcery/ │ ├── Configuration.swift │ ├── Generating/ │ │ └── Templates/ │ │ ├── JavaScript/ │ │ │ └── JavaScriptTemplate.swift │ │ ├── Stencil/ │ │ │ └── StencilTemplate.swift │ │ └── Swift/ │ │ └── SwiftTemplate.swift │ ├── Sourcery.swift │ ├── Templates/ │ │ ├── Coding.stencil │ │ ├── Description.stencil │ │ ├── Diffable.stencil │ │ ├── Equality.stencil │ │ ├── JSExport.ejs │ │ ├── Typed.stencil │ │ └── TypedSpec.stencil │ └── Utils/ │ ├── ByteRangeConversion.swift │ ├── BytesRange + Editing.swift │ ├── DryOutputModels.swift │ ├── FolderWatcher.swift │ ├── NSRange + Editing.swift │ └── Xcode+Extensions.swift ├── Sourcery-Example/ │ ├── CodeGenerated/ │ │ └── Basic.generated.swift │ ├── Podfile │ ├── Sourcery-Example/ │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── ViewController.swift │ ├── Sourcery-Example.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── Sourcery-Example.xcworkspace/ │ │ └── contents.xcworkspacedata │ └── Templates/ │ └── Basic.stencil ├── Sourcery.podspec ├── SourceryExecutable/ │ ├── Info.plist │ └── main.swift ├── SourceryFramework/ │ ├── Info.plist │ ├── SourceryFramework.h │ └── Sources/ │ ├── Generating/ │ │ ├── Generator.swift │ │ ├── SourceryTemplate.swift │ │ └── Template.swift │ └── Parsing/ │ ├── FileParserType.swift │ ├── String+TypeInference.swift │ ├── SwiftSyntax/ │ │ ├── AST/ │ │ │ ├── AccessLevel+SwiftSyntax.swift │ │ │ ├── Actor+SwiftSyntax.swift │ │ │ ├── Attribute+SwiftSyntax.swift │ │ │ ├── Class+SwiftSyntax.swift │ │ │ ├── Enum+SwiftSyntax.swift │ │ │ ├── EnumCase+SwiftSyntax.swift │ │ │ ├── GenericParameter+SwiftSyntax.swift │ │ │ ├── GenericRequirement+SwiftSyntax.swift │ │ │ ├── GenericType+SwiftSyntax.swift │ │ │ ├── Method+SwiftSyntax.swift │ │ │ ├── MethodParameter+SwiftSyntax.swift │ │ │ ├── Modifier+SwiftSyntax.swift │ │ │ ├── Protocol+SwiftSyntax.swift │ │ │ ├── Signature.swift │ │ │ ├── Struct+SwiftSyntax.swift │ │ │ ├── Subscript+SwiftSyntax.swift │ │ │ ├── Type+SwiftSyntax.swift │ │ │ ├── TypeName+SwiftSyntax.swift │ │ │ └── Variable+SwiftSyntax.swift │ │ ├── FileParserSyntax.swift │ │ ├── Syntax+Extensions.swift │ │ └── SyntaxTreeCollector.swift │ └── Utils/ │ ├── AnnotationsParser.swift │ ├── Bridges.swift │ ├── InlineParser.swift │ ├── StringView.swift │ └── Verifier.swift ├── SourceryFramework.podspec ├── SourceryJS/ │ ├── Info.plist │ ├── Resources/ │ │ └── ejs.js │ ├── SourceryJS.h │ └── Sources/ │ ├── EJSTemplate+Tests.swift │ └── EJSTemplate.swift ├── SourceryRuntime/ │ ├── Sources/ │ │ ├── Common/ │ │ │ ├── AST/ │ │ │ │ ├── AccessLevel.swift │ │ │ │ ├── Actor.swift │ │ │ │ ├── Annotations.swift │ │ │ │ ├── Attribute.swift │ │ │ │ ├── Class.swift │ │ │ │ ├── Definition.swift │ │ │ │ ├── Documentation.swift │ │ │ │ ├── Import.swift │ │ │ │ ├── Modifier.swift │ │ │ │ ├── PhantomProtocols.swift │ │ │ │ ├── Protocol.swift │ │ │ │ ├── ProtocolComposition.swift │ │ │ │ ├── Struct.swift │ │ │ │ ├── TypeName/ │ │ │ │ │ ├── Array.swift │ │ │ │ │ ├── Dictionary.swift │ │ │ │ │ ├── Generic.swift │ │ │ │ │ ├── Set.swift │ │ │ │ │ └── Typed.swift │ │ │ │ └── Typealias.swift │ │ │ ├── Array+Parallel.swift │ │ │ ├── BytesRange.swift │ │ │ ├── Composer/ │ │ │ │ ├── Composer.swift │ │ │ │ └── ParserResultsComposed.swift │ │ │ ├── Diffable.swift │ │ │ ├── Extensions.swift │ │ │ ├── FileParserResult.swift │ │ │ ├── Log.swift │ │ │ └── TemplateContext.swift │ │ ├── Generated/ │ │ │ ├── AutoHashable.generated.swift │ │ │ ├── Coding.generated.swift │ │ │ ├── JSExport.generated.swift │ │ │ └── Typed.generated.swift │ │ ├── Linux/ │ │ │ ├── AST/ │ │ │ │ ├── AssociatedType_Linux.swift │ │ │ │ ├── AssociatedValue_Linux.swift │ │ │ │ ├── ClosureParameter_Linux.swift │ │ │ │ ├── EnumCase_Linux.swift │ │ │ │ ├── Enum_Linux.swift │ │ │ │ ├── GenericParameter_Linux.swift │ │ │ │ ├── GenericRequirement_Linux.swift │ │ │ │ ├── MethodParameter_Linux.swift │ │ │ │ ├── Method_Linux.swift │ │ │ │ ├── Protocol_Linux.swift │ │ │ │ ├── Subscript_Linux.swift │ │ │ │ ├── TypeName/ │ │ │ │ │ ├── Closure_Linux.swift │ │ │ │ │ ├── GenericTypeParameter_Linux.swift │ │ │ │ │ ├── Tuple_Linux.swift │ │ │ │ │ └── TypeName_Linux.swift │ │ │ │ ├── Type_Linux.swift │ │ │ │ └── Variable_Linux.swift │ │ │ ├── DynamicMemberLookup_Linux.swift │ │ │ ├── NSException_Linux.swift │ │ │ ├── TypesCollection_Linux.swift │ │ │ └── Types_Linux.swift │ │ └── macOS/ │ │ ├── AST/ │ │ │ ├── AssociatedType.swift │ │ │ ├── AssociatedValue.swift │ │ │ ├── ClosureParameter.swift │ │ │ ├── Enum.swift │ │ │ ├── EnumCase.swift │ │ │ ├── GenericParameter.swift │ │ │ ├── GenericRequirement.swift │ │ │ ├── Method.swift │ │ │ ├── MethodParameter.swift │ │ │ ├── Subscript.swift │ │ │ ├── Type.swift │ │ │ ├── TypeName/ │ │ │ │ ├── Closure.swift │ │ │ │ ├── GenericTypeParameter.swift │ │ │ │ ├── Tuple.swift │ │ │ │ └── TypeName.swift │ │ │ └── Variable.swift │ │ ├── Types.swift │ │ └── TypesCollection.swift │ └── Supporting Files/ │ ├── Info.plist │ └── SourceryRuntime.h ├── SourceryRuntime.podspec ├── SourceryStencil/ │ ├── Info.plist │ ├── SourceryStencil.h │ └── Sources/ │ ├── NewLineNode.swift │ ├── StencilTemplate.swift │ └── TypedNode.swift ├── SourcerySwift/ │ ├── Info.plist │ ├── SourcerySwift.h │ └── Sources/ │ ├── SourceryRuntime.content.generated.swift │ ├── SourceryRuntime_Linux.content.generated.swift │ └── SwiftTemplate.swift ├── SourceryTests/ │ ├── ConfigurationSpec.swift │ ├── Generating/ │ │ ├── JavaScriptTemplateSpecs.swift │ │ ├── StencilTemplateSpec.swift │ │ └── SwiftTemplateSpecs.swift │ ├── GeneratorSpec.swift │ ├── Helpers/ │ │ ├── Builders.swift │ │ ├── CustomMatchers.swift │ │ └── Extensions.swift │ ├── Info.plist │ ├── Models/ │ │ ├── ActorSpec.swift │ │ ├── ArrayTypeSpec.swift │ │ ├── ClassSpec.swift │ │ ├── DiffableSpec.swift │ │ ├── EnumSpec.swift │ │ ├── MethodSpec.swift │ │ ├── ProtocolSpec.swift │ │ ├── StructSpec.swift │ │ ├── TypeSpec.swift │ │ ├── TypealiasSpec.swift │ │ ├── TypedSpec.generated.swift │ │ └── VariableSpec.swift │ ├── Output/ │ │ └── DryOutputSpec.swift │ ├── Parsing/ │ │ ├── ComposerSpec.swift │ │ ├── FileParserSpec.swift │ │ ├── FileParser_AssociatedTypeSpec.swift │ │ ├── FileParser_AttributesModifierSpec.swift │ │ ├── FileParser_MethodsSpec.swift │ │ ├── FileParser_ProtocolComposition.swift │ │ ├── FileParser_SubscriptsSpec.swift │ │ ├── FileParser_TypeNameSpec.swift │ │ ├── FileParser_VariableSpec.swift │ │ └── Helpers/ │ │ ├── AnnotationsParserSpec.swift │ │ ├── StringViewSpec.swift │ │ ├── TemplateAnnotationsParserSpec.swift │ │ ├── TemplatesAnnotationParser_ForceParseInlineCodeSpec.swift │ │ └── VerifierSpec.swift │ ├── Sourcery+PerformanceSpec.swift │ ├── SourcerySpec.swift │ └── Stub/ │ ├── Configs/ │ │ ├── invalid.yml │ │ ├── multi.yml │ │ ├── parent.yml │ │ └── valid.yml │ ├── DryRun-Code/ │ │ └── Base.swift │ ├── Errors/ │ │ └── localized-error.swift │ ├── JavaScriptTemplates/ │ │ ├── AllTypealiases.ejs │ │ ├── Equality.ejs │ │ ├── Function.ejs │ │ ├── Includes.ejs │ │ ├── Other.ejs │ │ ├── ProtocolCompositions.ejs │ │ ├── SubfolderIncludes.ejs │ │ ├── Typealiases.ejs │ │ └── lib/ │ │ ├── One.ejs │ │ └── Two.ejs │ ├── Performance-Code/ │ │ ├── Kiosk/ │ │ │ ├── Admin/ │ │ │ │ ├── AdminCardTestingViewController.swift │ │ │ │ ├── AdminLogViewController.swift │ │ │ │ ├── AdminPanelViewController.swift │ │ │ │ ├── AuctionWebViewController.swift │ │ │ │ ├── ChooseAuctionViewController.swift │ │ │ │ └── PasswordAlertViewController.swift │ │ │ ├── App/ │ │ │ │ ├── APIPingManager.swift │ │ │ │ ├── AppDelegate+GlobalActions.swift │ │ │ │ ├── AppDelegate.swift │ │ │ │ ├── AppSetup.swift │ │ │ │ ├── AppViewController.swift │ │ │ │ ├── BidderDetailsRetrieval.swift │ │ │ │ ├── CardHandler.swift │ │ │ │ ├── Constants.swift │ │ │ │ ├── GlobalFunctions.swift │ │ │ │ ├── KioskDateFormatter.h │ │ │ │ ├── KioskDateFormatter.m │ │ │ │ ├── Logger.swift │ │ │ │ ├── MarkdownParser.swift │ │ │ │ ├── Models/ │ │ │ │ │ ├── Artist.swift │ │ │ │ │ ├── Artwork.swift │ │ │ │ │ ├── Bid.swift │ │ │ │ │ ├── Bidder.swift │ │ │ │ │ ├── BidderPosition.swift │ │ │ │ │ ├── BuyersPremium.swift │ │ │ │ │ ├── Card.swift │ │ │ │ │ ├── GenericError.swift │ │ │ │ │ ├── Image.swift │ │ │ │ │ ├── JSONAble.swift │ │ │ │ │ ├── Location.swift │ │ │ │ │ ├── Sale.swift │ │ │ │ │ ├── SaleArtwork.swift │ │ │ │ │ ├── SaleArtworkViewModel.swift │ │ │ │ │ ├── SystemTime.swift │ │ │ │ │ └── User.swift │ │ │ │ ├── NSErrorExtensions.swift │ │ │ │ ├── Networking/ │ │ │ │ │ ├── APIKeys.swift │ │ │ │ │ ├── ArtsyAPI.swift │ │ │ │ │ ├── NetworkLogger.swift │ │ │ │ │ ├── Networking.swift │ │ │ │ │ ├── UserCredentials.swift │ │ │ │ │ └── XAppToken.swift │ │ │ │ ├── OfflineViewController.swift │ │ │ │ ├── STPCard+Validation.h │ │ │ │ ├── STPCard+Validation.m │ │ │ │ ├── StubResponses.h │ │ │ │ ├── StubResponses.m │ │ │ │ ├── SwiftExtensions.swift │ │ │ │ ├── UIStoryboardSegueExtensions.swift │ │ │ │ ├── UIViewControllerExtensions.swift │ │ │ │ ├── UIViewSubclassesErrorExtensions.swift │ │ │ │ └── Views/ │ │ │ │ ├── Button Subclasses/ │ │ │ │ │ └── Button.swift │ │ │ │ ├── RegisterFlowView.swift │ │ │ │ ├── SimulatorOnlyView.swift │ │ │ │ ├── Spinner.swift │ │ │ │ ├── SwitchView.swift │ │ │ │ └── Text Fields/ │ │ │ │ ├── CursorView.swift │ │ │ │ └── TextField.swift │ │ │ ├── Auction Listings/ │ │ │ │ ├── ListingsCountdownManager.swift │ │ │ │ ├── ListingsViewController.swift │ │ │ │ ├── ListingsViewModel.swift │ │ │ │ ├── MasonryCollectionViewCell.swift │ │ │ │ ├── TableCollectionViewCell.swift │ │ │ │ └── WebViewController.swift │ │ │ ├── Bid Fulfillment/ │ │ │ │ ├── AdminCCBypassNetworkModel.swift │ │ │ │ ├── BidCheckingNetworkModel.swift │ │ │ │ ├── BidDetailsPreviewView.swift │ │ │ │ ├── BidderNetworkModel.swift │ │ │ │ ├── ConfirmYourBidArtsyLoginViewController.swift │ │ │ │ ├── ConfirmYourBidEnterYourEmailViewController.swift │ │ │ │ ├── ConfirmYourBidPINViewController.swift │ │ │ │ ├── ConfirmYourBidPasswordViewController.swift │ │ │ │ ├── ConfirmYourBidViewController.swift │ │ │ │ ├── FulfillmentContainerViewController.swift │ │ │ │ ├── FulfillmentNavigationController.swift │ │ │ │ ├── GenericFormValidationViewModel.swift │ │ │ │ ├── KeypadContainerView.swift │ │ │ │ ├── KeypadView.swift │ │ │ │ ├── KeypadViewModel.swift │ │ │ │ ├── LoadingViewController.swift │ │ │ │ ├── LoadingViewModel.swift │ │ │ │ ├── ManualCreditCardInputViewController.swift │ │ │ │ ├── ManualCreditCardInputViewModel.swift │ │ │ │ ├── Models/ │ │ │ │ │ ├── BidDetails.swift │ │ │ │ │ ├── NewUser.swift │ │ │ │ │ └── RegistrationCoordinator.swift │ │ │ │ ├── PlaceBidNetworkModel.swift │ │ │ │ ├── PlaceBidViewController.swift │ │ │ │ ├── RegisterViewController.swift │ │ │ │ ├── RegistrationEmailViewController.swift │ │ │ │ ├── RegistrationMobileViewController.swift │ │ │ │ ├── RegistrationPasswordViewController.swift │ │ │ │ ├── RegistrationPasswordViewModel.swift │ │ │ │ ├── RegistrationPostalZipViewController.swift │ │ │ │ ├── StripeManager.swift │ │ │ │ ├── SwipeCreditCardViewController.swift │ │ │ │ └── YourBiddingDetailsViewController.swift │ │ │ ├── Help/ │ │ │ │ ├── HelpAnimator.swift │ │ │ │ └── HelpViewController.swift │ │ │ ├── HelperFunctions.swift │ │ │ ├── ListingsCollectionViewCell.swift │ │ │ ├── Observable+JSONAble.swift │ │ │ ├── Observable+Logging.swift │ │ │ ├── Observable+Operators.swift │ │ │ ├── Sale Artwork Details/ │ │ │ │ ├── ImageTiledDataSource.swift │ │ │ │ ├── SaleArtworkDetailsViewController.swift │ │ │ │ ├── SaleArtworkZoomViewController.swift │ │ │ │ └── WhitespaceGobbler.swift │ │ │ ├── UIKit+Rx.swift │ │ │ ├── UILabel+Fonts.swift │ │ │ ├── UIView+LongPressDisplayMessage.swift │ │ │ └── UIViewController+Bidding.swift │ │ └── LICENSE │ ├── Result/ │ │ ├── AllTypealiases.swift │ │ ├── Basic+Other+SourceryTemplates.swift │ │ ├── Basic+Other+SourceryTemplates_Linux.swift │ │ ├── Basic+Other.swift │ │ ├── Basic.swift │ │ ├── BasicFooExcluded.swift │ │ ├── Function.swift │ │ ├── Other.swift │ │ ├── ProtocolCompositions.swift │ │ └── Typealiases.swift │ ├── Source/ │ │ ├── Bar.swift │ │ ├── Foo.swift │ │ ├── FooBar.swift │ │ └── TestProject/ │ │ ├── TestProject/ │ │ │ └── Info.plist │ │ └── TestProject.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── Source_Linux/ │ │ ├── Bar.swift │ │ ├── Foo.swift │ │ ├── FooBar.swift │ │ └── TestProject/ │ │ ├── TestProject/ │ │ │ └── Info.plist │ │ └── TestProject.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── Stubs.swift │ ├── SwiftTemplates/ │ │ ├── Equality.swift │ │ ├── Equality.swifttemplate │ │ ├── Function.swifttemplate │ │ ├── IncludeCycle.swifttemplate │ │ ├── IncludeFile.swifttemplate │ │ ├── IncludeFileNoExtension.swifttemplate │ │ ├── Includes.swifttemplate │ │ ├── IncludesNoExtension.swifttemplate │ │ ├── Invalid.swifttemplate │ │ ├── InvalidTag.swifttemplate │ │ ├── Other.swifttemplate │ │ ├── Runtime.swifttemplate │ │ ├── SelfIncludeCycle.swifttemplate │ │ ├── SubfolderFileIncludes.swifttemplate │ │ ├── SubfolderIncludes.swifttemplate │ │ ├── Throws.swifttemplate │ │ ├── includeCycle/ │ │ │ ├── One.swifttemplate │ │ │ └── Two.swifttemplate │ │ └── lib/ │ │ ├── Equality.swift │ │ ├── One.swifttemplate │ │ └── Two.swifttemplate │ └── Templates/ │ ├── Basic.stencil │ ├── GenerationWays.stencil │ ├── Include.stencil │ ├── Other.stencil │ ├── Partial.stencil │ ├── SourceryTemplateEJS.sourcerytemplate │ └── SourceryTemplateStencil.sourcerytemplate ├── SourceryUtils/ │ ├── Sources/ │ │ ├── Path+Extensions.swift │ │ ├── Sha.swift │ │ ├── Time.swift │ │ └── Version.swift │ └── Supporting Files/ │ ├── Info.plist │ └── SourceryUtils.h ├── SourceryUtils.podspec ├── Templates/ │ ├── .swiftlint.yml │ ├── CodableContext/ │ │ ├── CodableContext.h │ │ └── Info.plist │ ├── CodableContextTests/ │ │ ├── CodableContextTests.swift │ │ └── Info.plist │ ├── Templates/ │ │ ├── AutoCases.stencil │ │ ├── AutoCodable.swifttemplate │ │ ├── AutoEquatable.stencil │ │ ├── AutoHashable.stencil │ │ ├── AutoLenses.stencil │ │ ├── AutoMockable.stencil │ │ ├── Decorator.swifttemplate │ │ └── LinuxMain.stencil │ ├── Templates.xcodeproj/ │ │ ├── project.pbxproj │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ └── TemplatesTests.xcscheme │ ├── Tests/ │ │ ├── Context/ │ │ │ ├── AutoCases.swift │ │ │ ├── AutoCodable.swift │ │ │ ├── AutoEquatable.swift │ │ │ ├── AutoHashable.swift │ │ │ ├── AutoLenses.swift │ │ │ ├── AutoMockable.swift │ │ │ └── LinuxMain.swift │ │ ├── Context_Linux/ │ │ │ ├── AutoCases.swift │ │ │ ├── AutoEquatable.swift │ │ │ ├── AutoHashable.swift │ │ │ ├── AutoLenses.swift │ │ │ ├── AutoMockable.swift │ │ │ └── LinuxMain.swift │ │ ├── Expected/ │ │ │ ├── AutoCases.expected │ │ │ ├── AutoCodable.expected │ │ │ ├── AutoEquatable.expected │ │ │ ├── AutoHashable.expected │ │ │ ├── AutoLenses.expected │ │ │ ├── AutoMockable.expected │ │ │ └── LinuxMain.expected │ │ ├── Generated/ │ │ │ ├── AutoCases.generated.swift │ │ │ ├── AutoCodable.generated.swift │ │ │ ├── AutoEquatable.generated.swift │ │ │ ├── AutoHashable.generated.swift │ │ │ ├── AutoLenses.generated.swift │ │ │ ├── AutoMockable.generated.swift │ │ │ └── LinuxMain.generated.swift │ │ ├── Info.plist │ │ └── TemplatesTests.swift │ └── artifactbundle.info.json.template ├── TryCatch/ │ ├── Info.plist │ ├── TryCatch.m │ └── include/ │ └── TryCatch.h ├── docs/ │ ├── Classes/ │ │ ├── Actor.html │ │ ├── ArrayType.html │ │ ├── AssociatedType.html │ │ ├── AssociatedValue.html │ │ ├── Attribute.html │ │ ├── Class.html │ │ ├── ClosureParameter.html │ │ ├── ClosureType.html │ │ ├── DictionaryType.html │ │ ├── DiffableResult.html │ │ ├── Enum.html │ │ ├── EnumCase.html │ │ ├── GenericParameter.html │ │ ├── GenericRequirement/ │ │ │ └── Relationship.html │ │ ├── GenericRequirement.html │ │ ├── GenericType.html │ │ ├── GenericTypeParameter.html │ │ ├── Import.html │ │ ├── Method.html │ │ ├── MethodParameter.html │ │ ├── Modifier.html │ │ ├── Protocol.html │ │ ├── ProtocolComposition.html │ │ ├── SetType.html │ │ ├── Struct.html │ │ ├── Subscript.html │ │ ├── TupleElement.html │ │ ├── TupleType.html │ │ ├── Type.html │ │ ├── TypeName.html │ │ ├── Types.html │ │ └── Variable.html │ ├── Enums/ │ │ └── Composer.html │ ├── Examples.html │ ├── Extensions/ │ │ ├── Array.html │ │ ├── String.html │ │ ├── StringProtocol.html │ │ └── Typealias.html │ ├── Guides.html │ ├── Other Classes.html │ ├── Other Enums.html │ ├── Other Extensions.html │ ├── Other Protocols.html │ ├── Other Typealiases.html │ ├── Protocols/ │ │ ├── Annotated.html │ │ ├── Definition.html │ │ ├── Diffable.html │ │ ├── Documented.html │ │ └── Typed.html │ ├── Types.html │ ├── codable.html │ ├── css/ │ │ ├── highlight.css │ │ └── jazzy.css │ ├── decorator.html │ ├── diffable.html │ ├── enum-cases.html │ ├── equatable.html │ ├── hashable.html │ ├── index.html │ ├── installing.html │ ├── js/ │ │ ├── jazzy.js │ │ ├── jazzy.search.js │ │ └── typeahead.jquery.js │ ├── lenses.html │ ├── linuxmain.html │ ├── mocks.html │ ├── search.json │ ├── usage.html │ └── writing-templates.html └── guides/ ├── Codable.md ├── Decorator.md ├── Diffable.md ├── Enum cases.md ├── Equatable.md ├── Hashable.md ├── Installing.md ├── Lenses.md ├── LinuxMain.md ├── Mocks.md ├── Usage.md └── Writing templates.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .circleci/config.yml ================================================ version: 2 jobs: test: macos: xcode: "14.3.1" environment: BUNDLE_JOBS: 3 BUNDLE_RETRY: 3 BUNDLE_PATH: vendor/bundle shell: /bin/bash --login -eo pipefail steps: - checkout - run: sudo defaults write com.apple.dt.Xcode IDEPackageSupportUseBuiltinSCM YES - run: rm ~/.ssh/id_rsa || true - run: for ip in $(dig @8.8.8.8 bitbucket.org +short); do ssh-keyscan bitbucket.org,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts || true - run: for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts || true - run: brew update 1> /dev/null 2> /dev/null - run: brew install sourcekitten - run: brew install coreutils - run: echo "ruby-3.0.6" > ~/.ruby-version - run: bundle install - run: bundle exec rake validate_docs - run: bundle exec danger || true - run: set -o pipefail - run: bundle exec rake build - run: bundle exec rake tests workflows: version: 2 build-test: jobs: - test ================================================ FILE: .codecov.yml ================================================ coverage: ignore: - Sourcery/main.swift - Sourcery/CodeGenerated/* - Pods/* status: patch: false changes: false project: default: target: 70 comment: false ================================================ FILE: .github/workflows/bump_homebrew.yml ================================================ name: Bump Homebrew formula on: workflow_dispatch: inputs: tag-name: description: 'The git tag name to bump the formula to' required: true jobs: homebrew: name: Bump Homebrew formula runs-on: macos-13 steps: - uses: mislav/bump-homebrew-formula-action@v3 with: formula-name: sourcery tag-name: ${{ github.event.inputs.tag-name }} env: COMMITTER_TOKEN: ${{ secrets.HOMEBREW_COMMITTER_TOKEN }} ================================================ FILE: .github/workflows/docker.yml ================================================ name: Docker permissions: contents: read packages: write on: push: branches: - master tags: - '*' # https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners jobs: build: strategy: fail-fast: false matrix: include: - os: ubuntu-24.04 platform: linux-amd64 - os: ubuntu-24.04-arm platform: linux-arm64 runs-on: ${{ matrix.os }} steps: - name: Set lowercase repository name run: | echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV} env: REPOSITORY: '${{ github.repository }}' - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - uses: docker/build-push-action@v6 id: build with: tags: ghcr.io/${{ env.REPOSITORY_LC }} outputs: type=image,push-by-digest=true,name-canonical=true,push=true - name: Export digest run: | mkdir -p ${{ runner.temp }}/digests digest="${{ steps.build.outputs.digest }}" touch "${{ runner.temp }}/digests/${digest#sha256:}" - name: Upload digest uses: actions/upload-artifact@v4 with: name: digests-${{ matrix.platform }} path: ${{ runner.temp }}/digests/* if-no-files-found: error retention-days: 1 merge: runs-on: ubuntu-24.04 needs: build steps: - name: Set lowercase repository name run: | echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV} env: REPOSITORY: '${{ github.repository }}' - name: Download digests uses: actions/download-artifact@v4 with: path: ${{ runner.temp }}/digests pattern: digests-* merge-multiple: true - name: Login to GitHub registry uses: docker/login-action@v3 with: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: ghcr.io/${{ env.REPOSITORY_LC }} - name: Create manifest list and push working-directory: ${{ runner.temp }}/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf 'ghcr.io/${{ env.REPOSITORY_LC }}@sha256:%s ' *) - name: Inspect image run: | docker buildx imagetools inspect ghcr.io/${{ env.REPOSITORY_LC }}:${{ steps.meta.outputs.version }} ================================================ FILE: .github/workflows/jazzy.yml ================================================ # This workflow will build a Swift project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift name: rake docs on: workflow_call: workflow_dispatch: inputs: ref: description: 'Ref to build (branch, tag or SHA)' required: false default: 'master' push: branches: [ "master" ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: update_docs: runs-on: macos-14 steps: - name: Set Xcode 15.3.0 run: sudo xcode-select -s /Applications/Xcode_15.3.0.app/Contents/Developer - name: Print Current Xcode run: xcode-select -p - uses: actions/checkout@v3 - name: Update Docs run: | brew install coreutils brew install sourcekitten bundle install rake docs - uses: EndBug/add-and-commit@v9.1.3 with: add: '.' message: 'Update Docs' committer_name: GitHub Actions committer_email: actions@github.com ================================================ FILE: .github/workflows/release_macOS.yml ================================================ name: release macOS on: workflow_dispatch: inputs: ref: description: 'Ref to build (branch, tag or SHA)' required: false default: 'master' push: tags: - '*' jobs: tests: uses: ./.github/workflows/test_macOS.yml build: needs: [tests] name: Build Sourcery for macOS runs-on: macos-14 steps: - name: Set Xcode 15.3.0 run: sudo xcode-select -s /Applications/Xcode_15.3.0.app/Contents/Developer - name: Print Current Xcode run: xcode-select -p - uses: actions/checkout@v3 with: ref: ${{ github.event.inputs.ref }} - name: Build it id: build run: | brew install coreutils brew install sourcekitten bundle install rake docs CLI_DIR="${HOME}/cli/" RESOURCES_DIR="${CLI_DIR}Resources/" TEMPLATES_DIR="${CLI_DIR}Templates/" BUILD_DIR="${HOME}/build/" BIN_DIR="${CLI_DIR}bin/" ARTIFACT_BUNDLE_PATH="${HOME}/artifactbundle/" path_to_sourcery_binary="${BIN_DIR}/sourcery" mkdir -p $BIN_DIR mkdir -p $RESOURCES_DIR mkdir -p $TEMPLATES_DIR mkdir -p ${ARTIFACT_BUNDLE_PATH}bin cp -r docs/docsets/Sourcery.docset $CLI_DIR cp -r "Templates/Templates/" $TEMPLATES_DIR cp Resources/daemon.gif $RESOURCES_DIR cp Resources/icon-128.png $RESOURCES_DIR cp CHANGELOG.md $CLI_DIR cp README.md $CLI_DIR cp LICENSE $CLI_DIR cp -r SourceryJS/Resources/ejs.js $BIN_DIR cp -r $CLI_DIR/ "${ARTIFACT_BUNDLE_PATH}sourcery" cp Templates/artifactbundle.info.json.template ${ARTIFACT_BUNDLE_PATH}/info.json swift build --disable-sandbox -c release --arch arm64 --build-path $BUILD_DIR swift build --disable-sandbox -c release --arch x86_64 --build-path $BUILD_DIR lipo -create -output $path_to_sourcery_binary ${BUILD_DIR}arm64-apple-macosx/release/sourcery ${BUILD_DIR}x86_64-apple-macosx/release/sourcery strip -rSTX ${path_to_sourcery_binary} cp $path_to_sourcery_binary "${ARTIFACT_BUNDLE_PATH}sourcery/bin/" pushd $CLI_DIR TAG=$GITHUB_REF_NAME FILENAME="sourcery-$TAG.zip" zip -r -X $FILENAME . mv $FILENAME "${HOME}/" popd pushd $ARTIFACT_BUNDLE_PATH sed -i '' "s/VERSION/${TAG}/g" ${ARTIFACT_BUNDLE_PATH}/info.json ARTIFACTBUNDLENAME=$FILENAME.artifactbundle.zip zip -r -X $ARTIFACTBUNDLENAME . mv $ARTIFACTBUNDLENAME "${HOME}/" popd echo "FILENAME=${FILENAME}" >> $GITHUB_OUTPUT echo "ARTIFACTBUNDLENAME=${ARTIFACTBUNDLENAME}" >> $GITHUB_OUTPUT - name: 'Upload Sourcery Artifact' uses: actions/upload-artifact@v4 with: name: ${{ steps.build.outputs.FILENAME }} path: "~/${{ steps.build.outputs.FILENAME }}" retention-days: 5 - name: 'Upload Bundle Artifact' uses: actions/upload-artifact@v4 with: name: ${{ steps.build.outputs.ARTIFACTBUNDLENAME }} path: "~/${{ steps.build.outputs.ARTIFACTBUNDLENAME }}" retention-days: 5 ================================================ FILE: .github/workflows/release_ubuntu.yml ================================================ name: release ubuntu on: workflow_dispatch: inputs: ref: description: 'Ref to build (branch, tag or SHA)' required: false default: 'master' push: tags: - '*' jobs: tests: uses: ./.github/workflows/test_ubuntu.yml build: needs: [tests] name: Build Sourcery for Ubuntu (latest) runs-on: ubuntu-22.04 outputs: filename: ${{ steps.build.outputs.filename }} steps: - uses: actions/checkout@v3 with: ref: ${{ github.event.inputs.ref }} - name: Setup Swift uses: swift-actions/setup-swift@v2 with: swift-version: "5.10" - name: Build it id: build run: | BUILD_DIR="${HOME}/build/" swift build --disable-sandbox -c release --build-path $BUILD_DIR mv "${BUILD_DIR}x86_64-unknown-linux-gnu/release/sourcery" "${BUILD_DIR}/sourcery" UNAME=$(uname -m) CODENAME=$(lsb_release -c -s) DESCRIPTION=$(lsb_release -d -s | sed "s/ /-/g" | sed "s/./\L&/g") SUFFIX=$DESCRIPTION-$CODENAME-$UNAME TAG=$GITHUB_REF_NAME FILENAME="sourcery-${TAG}-${SUFFIX}.tar.xz" pushd $BUILD_DIR tar -zcvf $FILENAME sourcery mv $FILENAME "${HOME}/" popd echo "FILENAME=${FILENAME}" >> $GITHUB_OUTPUT - name: 'Upload Artifact' uses: actions/upload-artifact@v4 with: name: ${{ steps.build.outputs.FILENAME }} path: "~/${{ steps.build.outputs.FILENAME }}" retention-days: 5 ================================================ FILE: .github/workflows/test_macOS.yml ================================================ # This workflow will build a Swift project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift name: test macOS on: workflow_call: push: branches: [ "master" ] pull_request: branches: [ "master" ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref_type != 'tag' }} jobs: macos_build: runs-on: macos-14 steps: - name: Set Xcode 15.3.0 run: sudo xcode-select -s /Applications/Xcode_15.3.0.app/Contents/Developer - name: Print Current Xcode run: xcode-select -p - uses: actions/checkout@v3 - name: Run tests run: swift test ================================================ FILE: .github/workflows/test_ubuntu.yml ================================================ # This workflow will build a Swift project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift name: test ubuntu on: workflow_call: push: branches: [ "master" ] pull_request: branches: [ "master" ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref_type != 'tag' }} jobs: linux_build: runs-on: ubuntu-22.04 steps: - name: Setup Swift uses: YOCKOW/Action-setup-swift@main with: swift-version: "5.10" - name: Get swift version run: swift --version - uses: actions/checkout@v3 - name: Run tests run: swift test ================================================ FILE: .gitignore ================================================ # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Bundler .bundle* ## macOS .DS_Store ## GitHub Token .apitoken ## Build generated build/ cli/ DerivedData/ ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata/ *.xcscmblueprint ## Other *.moved-aside *.xcuserstate *.profraw ## Obj-C/Swift specific *.hmap *.ipa *.dSYM.zip *.dSYM ## Playgrounds timeline.xctimeline playground.xcworkspace # Swift Package Manager # # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. Packages/ Package.pins .build/ .swiftpm/ # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # # Pods/ # Ruby Vendor/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md fastlane/report.xml fastlane/Preview.html fastlane/screenshots fastlane/test_output Sourcery/CodeGenerated/TypedSpec.generated.swift # jazzy docs/docsets docs/undocumented.json # IDEA based IDEs (AppCode, CLion) configuration .idea # Local binary distributions downloads distributions/ Sourcery.xcodeproj ================================================ FILE: .gitmodules ================================================ ================================================ FILE: .jazzy.yaml ================================================ author: Krzysztof Zabłocki author_url: https://twitter.com/merowing_ module: Sourcery sourcekitten_sourcefile: docs.json github_url: https://github.com/krzysztofzablocki/Sourcery copyright: 'Copyright © 2016-2021 Pixle. All rights reserved.' readme: About.md documentation: guides/*.md exclude: ["*_Linux.swift"] custom_categories: - name: Guides children: - Installing - Usage - Writing templates - name: Examples children: - Equatable - Hashable - Enum cases - Lenses - Mocks - Codable - Diffable - LinuxMain - Decorator - name: Types children: - Types - Type - Protocol - Class - Struct - Enum - EnumCase - AssociatedValue - AssociatedType - Variable - Method - MethodParameter - Subscript - TypeName - TupleType - TupleElement - ArrayType - DictionaryType - ClosureType - GenericType - GenericTypeParameter - Attribute - ProtocolComposition ================================================ FILE: .pre-commit-hooks.yaml ================================================ - id: sourcery name: Sourcery description: 'Meta-programming for Swift, stop writing boilerplate code.' language: swift entry: sourcery require_serial: true pass_filenames: false always_run: true ================================================ FILE: .ruby-version ================================================ 3.4.1 ================================================ FILE: .sourcery-macOS.yml ================================================ sources: - SourceryRuntime/Sources/Common - SourceryRuntime/Sources/macOS templates: - Sourcery/Templates/Coding.stencil - Sourcery/Templates/JSExport.ejs - Sourcery/Templates/Typed.stencil - Sourcery/Templates/TypedSpec.stencil output: SourceryRuntime/Sources/Generated ================================================ FILE: .sourcery-ubuntu.yml ================================================ sources: - SourceryRuntime/Sources/Common - SourceryRuntime/Sources/Linux templates: - Sourcery/Templates/Coding.stencil - Sourcery/Templates/JSExport.ejs - Sourcery/Templates/Typed.stencil - Sourcery/Templates/TypedSpec.stencil output: SourceryRuntime/Sources/Generated ================================================ FILE: .swift-version ================================================ 5.8 ================================================ FILE: .swiftlint.yml ================================================ disabled_rules: # rule identifiers to exclude from running - function_parameter_count - line_length - variable_name - cyclomatic_complexity - nesting - conditional_binding_cascade - large_tuple opt_in_rules: # some rules are only opt-in - force_unwrapping - force_https - empty_count - conditional_binding_cascade included: - Sourcery - SourceryRuntime - SourceryTests - Templates/Tests excluded: # paths to ignore during linting. Takes precedence over `included`. - Carthage - Pods - Packages - SourceryTests/Stub - Templates/Tests/Generated - Templates/Tests/Expected type_body_length: - 700 #warning - 1000 #error file_length: - 1000 #warning - 1200 #error function_body_length: - 125 #warning - 200 #error type_name: min_length: 3 # only warning max_length: # warning and error warning: 50 error: 50 custom_rules: force_https: name: "Force HTTPS over HTTP" regex: "((?i)http(?!s))" match_kinds: string message: "HTTPS should be favored over HTTP" severity: warning explicit_failure_calls: name: "Avoid asserting 'false'" regex: '((assert|precondition)\(false)' message: "Use assertionFailure() or preconditionFailure() instead." severity: warning ================================================ FILE: .vscode/launch.json ================================================ { "configurations": [ { "type": "lldb", "request": "launch", "sourceLanguages": [ "swift" ], "name": "Debug sourcery", "program": "${workspaceFolder:Sourcery}/.build/debug/sourcery", "args": [], "cwd": "${workspaceFolder:Sourcery}", "preLaunchTask": "swift: Build Debug sourcery" }, { "type": "lldb", "request": "launch", "sourceLanguages": [ "swift" ], "name": "Release sourcery", "program": "${workspaceFolder:Sourcery}/.build/release/sourcery", "args": [], "cwd": "${workspaceFolder:Sourcery}", "preLaunchTask": "swift: Build Release sourcery" } ] } ================================================ FILE: .vscode/settings.json ================================================ {} ================================================ FILE: ABOUT.md ================================================ ## What is Sourcery? _**Sourcery** scans your source code, applies your personal templates and generates Swift code for you, allowing you to use meta-programming techniques to save time and decrease potential mistakes._ Using it offers many benefits: - Write less repetitive code and make it easy to adhere to [DRY principle](https://en.wikipedia.org/wiki/Don't_repeat_yourself). - It allows you to create better code, one that would be hard to maintain without it, e.g. [performing automatic property level difference in tests](https://github.com/krzysztofzablocki/Sourcery/blob/master/Sourcery/Templates/Diffable.stencil) - Limits the risk of introducing human error when refactoring. - Sourcery **doesn't use runtime tricks**, in fact, it allows you to leverage compiler, even more, creating more safety. - **Immediate feedback:** Sourcery features built-in daemon support, enabling you to write your templates in real-time side-by-side with generated code. **Sourcery is so meta that it is used to code-generate its boilerplate code** ## Why? Swift features very limited runtime and no meta-programming features. Which leads our projects to contain boilerplate code. Sourcery exists to allow Swift developers to stop doing the same thing over and over again while still maintaining strong typing, preventing bugs and leveraging compiler. Have you ever? - Had to write equatable/hashable? - Had to write NSCoding support? - Had to implement JSON serialization? - Wanted to use Lenses? If you did then you probably found yourself writing repetitive code to deal with those scenarios, does this feel right? Even worse, if you ever add a new property to a type all of those implementations have to be updated, or you will end up with bugs. In those scenarios usually **compiler will not generate the error for you**, which leads to error prone code. ================================================ FILE: CHANGELOG.md ================================================ # Sourcery CHANGELOG ## 2.3.0 * Added `withExtendedLifetime` support for better lifetime management in templates (#1419) — @swiftty * Fix PBXGroup duplication while linking (#1422, #1423) — @markmax12 * Fix deadlock when using EJS templates in watch mode (#1421) — @robertjpayne * Fix `AutoMockable` Generation for a couple of cases with existential `any` (#1420) — @musiienko * Ensured compatibility with Xcode 26 (#1428, #1434, #1439) — @bo2themax * Update docker workflow to also build ARM64 image (#1436) - @Cyberbeni ## 2.2.7 * Feature/typed throws support by @alexandre-pod in https://github.com/krzysztofzablocki/Sourcery/pull/1401 * Add missing `isGeneric` dynamic member by @tayloraswift in https://github.com/krzysztofzablocki/Sourcery/pull/1408 ## 2.2.6 * Method/Initializer parameter types now resolve to the local type if it exists by @liamnichols in https://github.com/krzysztofzablocki/Sourcery/pull/1347 * Fixed wrong relative path in symbolic link by @pavel-trafimuk in https://github.com/krzysztofzablocki/Sourcery/pull/1350 * chore: add unchecked Sendable conformance to AutoMockable by @nekrich in https://github.com/krzysztofzablocki/Sourcery/pull/1355 * Fixes issue around mutable capture of 'inout' parameter 'buffer' is not allowed in concurrently-executing code by @mapierce in https://github.com/krzysztofzablocki/Sourcery/pull/1363 * chore(deps): bump rexml from 3.2.8 to 3.3.6 by @dependabot in https://github.com/krzysztofzablocki/Sourcery/pull/1360 * Updated swift-syntax package's url (#1354) by @akhmedovgg in https://github.com/krzysztofzablocki/Sourcery/pull/1364 * `Templates/AutoMockable.stencil`: fix stencil to consider nullable closures as escaping by @alexdmotoc in https://github.com/krzysztofzablocki/Sourcery/pull/1358 * Fix AutoMockable for closure with multiple parameters by @MontakOleg in https://github.com/krzysztofzablocki/Sourcery/pull/1373 * fix: AutoEquatable Stencil to use `any` for protocols by @iDevid in https://github.com/krzysztofzablocki/Sourcery/pull/1367 * Add support for child configs by @jimmya in https://github.com/krzysztofzablocki/Sourcery/pull/1338 * Try to fix associated types messing up types unification by @fabianmuecke in https://github.com/krzysztofzablocki/Sourcery/pull/1377 * Added annotations to typealiases and typealiases property to EJS template context. by @fabianmuecke in https://github.com/krzysztofzablocki/Sourcery/pull/1379 * Fix module name for xcframework by @till0xff in https://github.com/krzysztofzablocki/Sourcery/pull/1381 * Fix protocol inheritance by @till0xff in https://github.com/krzysztofzablocki/Sourcery/pull/1383 * Fixed nested type resolution by @till0xff in https://github.com/krzysztofzablocki/Sourcery/pull/1384 * fix: Fixes description of Method's genericParameters by @sergiocampama in https://github.com/krzysztofzablocki/Sourcery/pull/1386 * Ability to use custom header prefix by @ilia3546 in https://github.com/krzysztofzablocki/Sourcery/pull/1389 * Fixed tests under linux by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1390 * chore(deps): bump rexml from 3.3.6 to 3.3.9 by @dependabot in https://github.com/krzysztofzablocki/Sourcery/pull/1376 * Fixing dockerfile by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1391 ## 2.2.5 * chore(deps): bump nokogiri from 1.16.2 to 1.16.5 by @dependabot in https://github.com/krzysztofzablocki/Sourcery/pull/1331 * Fix typo in Decorator.md by @ahmedk92 in https://github.com/krzysztofzablocki/Sourcery/pull/1339 * chore(deps): bump rexml from 3.2.5 to 3.2.8 by @dependabot in https://github.com/krzysztofzablocki/Sourcery/pull/1332 * Fixed incorrect case prefix parsing by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1341 * Fixed crash when inline function has out of bound indexes by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1342 * Improved concurrency support in SwiftTemplate caching by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1344 * Fix associatedtype generics by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1345 * AutoMockable: fix generating static reset func by @MontakOleg in https://github.com/krzysztofzablocki/Sourcery/pull/1336 * Enabled lookup for generic type information in arrays by @art-divin in https://github.com/krzysztofzablocki/Sourcery/pull/1346 ## 2.2.4 - Fixed typealias resolution breaking resolution of real types. by @fabianmuecke ([#1325](https://github.com/krzysztofzablocki/Sourcery/pull/1325)) - Disabled type resolving for local method generic parameters by @art-divin ([#1327](https://github.com/krzysztofzablocki/Sourcery/pull/1327)) - Added hideVersionHeader to configuration arguments by @art-divin ([#1328](https://github.com/krzysztofzablocki/Sourcery/pull/1328)) ## 2.2.3 ## Changes - Fixed Issue when Caching of SwiftTemplate Binary Failes by @art-divin ([#1323](https://github.com/krzysztofzablocki/Sourcery/pull/1323)) ## 2.2.2 ## Changes - Improved Logging/Error Handling during SwiftTemplate Processing by @art-divin ([#1320](https://github.com/krzysztofzablocki/Sourcery/pull/1320)) ## 2.2.1 ## Changes - Set minimum platform for macOS by @art-divin ([#1319](https://github.com/krzysztofzablocki/Sourcery/pull/1319)) ## 2.2.0 ## Changes - Remove Sourcery version from header by @dcacenabes in ([#1309](https://github.com/krzysztofzablocki/Sourcery/pull/1309)) - Enable Single Print when Generating Based on Swifttemplate by @art-divin in ([#1308](https://github.com/krzysztofzablocki/Sourcery/pull/1308)) - [Bug] Annotations aren't being extracted from initializers by @liamnichols in ([#1311](https://github.com/krzysztofzablocki/Sourcery/pull/1311)) - Implemented Proper Protocol Composition Type Parsing by @art-divin in ([#1314](https://github.com/krzysztofzablocki/Sourcery/pull/1314)) - Renamed parenthesis to parentheses by @art-divin in ([#1315](https://github.com/krzysztofzablocki/Sourcery/pull/1315)) - Switched to Double for CLI argument processing by @art-divin in ([#1317](https://github.com/krzysztofzablocki/Sourcery/pull/1317)) - Added isDistributed to Actor and Method by @art-divin in ([#1318](https://github.com/krzysztofzablocki/Sourcery/pull/1318)) - Enable Quotes when parsing arguments in property wrapper parameters by @art-divin in ([#1316](https://github.com/krzysztofzablocki/Sourcery/pull/1316)) ## 2.1.8 ## Changes - ClosureParameter isVariadic Support by @art-divin in ([#1268](https://github.com/krzysztofzablocki/Sourcery/pull/1268)) - Update Usage.md to include --parseDocumentation option by @MarcoEidinger in ([#1272](https://github.com/krzysztofzablocki/Sourcery/pull/1272)) - Format processing time log message by @MontakOleg in ([#1274](https://github.com/krzysztofzablocki/Sourcery/pull/1274)) - Fixed swift-package-manager version by @art-divin in ([#1280](https://github.com/krzysztofzablocki/Sourcery/pull/1280)) - Added isSet to TypeName by @art-divin in ([#1281](https://github.com/krzysztofzablocki/Sourcery/pull/1281)) - chore(deps): bump nokogiri from 1.15.4 to 1.16.2 by @dependabot in ([#1273](https://github.com/krzysztofzablocki/Sourcery/pull/1273)) - Implement GenericRequirement support for member type disambiguation by @art-divin in ([#1283](https://github.com/krzysztofzablocki/Sourcery/pull/1283)) - Add generic requirements to Method by @art-divin in ([#1284](https://github.com/krzysztofzablocki/Sourcery/pull/1284)) - Recognize subclasses with generics by @art-divin in ([#1287](https://github.com/krzysztofzablocki/Sourcery/pull/1287)) - Implemented typealias unboxing during type resolution by @art-divin in ([#1288](https://github.com/krzysztofzablocki/Sourcery/pull/1288)) - Added documentation to typealias by @art-divin in ([#1289](https://github.com/krzysztofzablocki/Sourcery/pull/1289)) - Fix: Function with completion as parameter that contains itself an optional any parameter produces wrong mock by @paul1893 in ([#1290](https://github.com/krzysztofzablocki/Sourcery/pull/1290)) - Fix: Function with inout parameter when function has more than one parameter produces wrong mock by @paul1893 in ([#1291](https://github.com/krzysztofzablocki/Sourcery/pull/1291)) - Substitute underlying type from typealias by @art-divin in ([#1292](https://github.com/krzysztofzablocki/Sourcery/pull/1292)) - Added support for multiline documentation comments by @art-divin in ([#1293](https://github.com/krzysztofzablocki/Sourcery/pull/1293)) - Update SwiftSyntax dependency to 510.0.0 by @calda in ([#1294](https://github.com/krzysztofzablocki/Sourcery/pull/1294)) - Resolved all SwiftSyntax Warnings by @art-divin in ([#1295](https://github.com/krzysztofzablocki/Sourcery/pull/1295)) - Trailing Annotation Parsing by @art-divin in ([#1296](https://github.com/krzysztofzablocki/Sourcery/pull/1296)) - Fixed Crash in AnnotationParser by @art-divin in ([#1297](https://github.com/krzysztofzablocki/Sourcery/pull/1297)) - Disabled Optimization During Generated Code Verification by @art-divin in ([#1300](https://github.com/krzysztofzablocki/Sourcery/pull/1300)) - Adjusted file structure to accommodate two generated files by @art-divin in ([#1299](https://github.com/krzysztofzablocki/Sourcery/pull/1299)) - Expand --serialParse flag to also apply to Composer.uniqueTypesAndFunctions by @calda in ([#1301](https://github.com/krzysztofzablocki/Sourcery/pull/1301)) - Make AutoMockable Generate Compilable Swift Code by @art-divin in ([#1304](https://github.com/krzysztofzablocki/Sourcery/pull/1304)) - Fix Closure Parameter CVarArg with Existential by @art-divin in ([#1305](https://github.com/krzysztofzablocki/Sourcery/pull/1305)) ## 2.1.7 ## Changes - Podspec updates - set correct filepath for Sourcery - Fixed generated AutoMockable compilation issue due to generated variable names containing & character. Added support for existential any for throwable errors. ([#1263](https://github.com/krzysztofzablocki/Sourcery/pull/1263)) ## 2.1.6 ## Changes - Podspec updates - set specific version per supported platform ## 2.1.5 ## Changes - Podspec updates - Add support for inout parameter for AutoMockable protocols ([#1261](https://github.com/krzysztofzablocki/Sourcery/pull/1261)) ## 2.1.4 ## Changes - Added generic requirements and generic parameters to Subscript ([#1242](https://github.com/krzysztofzablocki/Sourcery/issues/1242)) - Added isAsync and throws to Subscript ([#1249](https://github.com/krzysztofzablocki/Sourcery/issues/1249)) - Initialise Subscript's returnTypeName with TypeSyntax, not String ([#1250](https://github.com/krzysztofzablocki/Sourcery/issues/1250)) - Swifty generated variable names + fixed generated mocks compilation issues due to method generic parameters ([#1252](https://github.com/krzysztofzablocki/Sourcery/issues/1252)) ## 2.1.3 ## Changes - Add support for `typealias`es in EJS templates. ([#1208](https://github.com/krzysztofzablocki/Sourcery/pull/1208)) - Add support for existential to Automockable Protocol with generic types. ([#1220](https://github.com/krzysztofzablocki/Sourcery/pull/1220)) - Add support for generic parameters and requirements in subscripts. ([#1242](https://github.com/krzysztofzablocki/Sourcery/pull/1242)) - Throw throwable error after updating mocks's calls counts and received parameters/invocations. ([#1224](https://github.com/krzysztofzablocki/Sourcery/pull/1224)) - Fix unit tests on Linux ([#1225](https://github.com/krzysztofzablocki/Sourcery/pull/1225)) - Updated XcodeProj to 8.16.0 ([#1228](https://github.com/krzysztofzablocki/Sourcery/pull/1228)) - Fixed Unable to mock a protocol with methods that differ in parameter type - Error: "Invalid redeclaration" ([#1238](https://github.com/krzysztofzablocki/Sourcery/issues/1238)) - Support for variadic arguments as method parameters ([#1222](https://github.com/krzysztofzablocki/Sourcery/issues/1222)) ## 2.1.2 ## Changes - Bump SPM version to support Swift 5.9 ([#1213](https://github.com/krzysztofzablocki/Sourcery/pull/1213)) - Add Dockerfile ([#1211](https://github.com/krzysztofzablocki/Sourcery/pull/1211)) ## 2.1.1 ## Changes - Separate EJSTemplate.swift for swift test and for swift build -c release ([#1203](https://github.com/krzysztofzablocki/Sourcery/pull/1203)) ## 2.1.0 ## Changes - Added support for Swift Package Manager config ([#1184](https://github.com/krzysztofzablocki/Sourcery/pull/1184)) - Add support to any keyword for function parameter type to AutoMockable.stencil ([#1169](https://github.com/krzysztofzablocki/Sourcery/pull/1169)) - Add support to any keyword for function return type to AutoMockable.stencil([#1186](https://github.com/krzysztofzablocki/Sourcery/pull/1186)) - Add support for protocol compositions in EJS templates. ([#1192](https://github.com/krzysztofzablocki/Sourcery/pull/1192)) - Linux Support (experimental) ([#1188](https://github.com/krzysztofzablocki/Sourcery/pull/1188)) - Add support for opaque type (some keyword) to function parameter type in AutoMockable.stencil ([#1197](https://github.com/krzysztofzablocki/Sourcery/pull/1197)) ## 2.0.3 ## Internal Changes - Modifications to included files of Swift Templates are now detected by hashing instead of using the modification date when invalidating the cache ([#1161](https://github.com/krzysztofzablocki/Sourcery/pull/1161)) - Fixes incorrectly parsed /r/n newline sequences ([#1165](https://github.com/krzysztofzablocki/Sourcery/issues/1165) and [#1138](https://github.com/krzysztofzablocki/Sourcery/issues/1138)) - Fixes incorrect parsing of annotations if there are attributes on lines preceeding declaration ([#1141](https://github.com/krzysztofzablocki/Sourcery/issues/1141)) - Fixes incorrect parsing of trailing inline comments following enum case' rawValue ([#1154](https://github.com/krzysztofzablocki/Sourcery/issues/1154)) - Fixes incorrect parsing of multibyte enum case identifiers with associated values - Improves type inference when using contained types for variables ([#1091](https://github.com/krzysztofzablocki/Sourcery/issues/1091)) ## 2.0.2 - Fixes incorrectly parsed variable names that include property wrapper and comments, closes #1140 ## 2.0.1 ## Internal Changes - Fixed non-ASCII characters handling in source code parsing [#1130](https://github.com/krzysztofzablocki/Sourcery/pull/1130) - Improved performance by about 20% ## Changes - sourcery:auto inline fragments will appear on the body definition level - added baseIndentation/base-indentation option that will be taken into as default adjustment when using those fragments - add support for type methods to AutoMockable ## 1.9.2 ## Internal Changes - Reverts part of [#1113](https://github.com/krzysztofzablocki/Sourcery/pull/1113) due to incomplete implementation breaking type complex resolution - Files that had to be parsed will be logged if their count is less than 50 (or always in verbose mode) ## 1.9.1 ## New Features - Adds support for public protocols in AutoMockable template [#1100](https://github.com/krzysztofzablocki/Sourcery/pull/1100) - Adds support for async and throwing properties to AutoMockable template [#1101](https://github.com/krzysztofzablocki/Sourcery/pull/1101) - Adds support for actors and nonisolated methods [#1112](https://github.com/krzysztofzablocki/Sourcery/pull/1112) ## Internal Changes - Fixed parsing of extensions and nested types in swiftinterface files [#1113](https://github.com/krzysztofzablocki/Sourcery/pull/1113) ## 1.9.0 - Update StencilSwiftKit to fix SPM resolving issue when building as a Command Plugin [#1023](https://github.com/krzysztofzablocki/Sourcery/issues/1023) - Adds new `--cacheBasePath` option to `SourceryExecutable` to allow for plugins setting a default cache [#1093](https://github.com/krzysztofzablocki/Sourcery/pull/1093) - Adds new `--dry` option to `SourceryExecutable` to check output without file system modifications [#1097](https://github.com/krzysztofzablocki/Sourcery/pull/1097) - Changes parser to new [SwiftSyntax Parser](https://github.com/apple/swift-syntax/pull/767) - Drops dylib dependency ## 1.8.2 ## New Features - Added `deletingLastComponent` filter to turn `/Path/Class.swift` into `/Path` - Added `directory` computed property to `Type` ## 1.8.1 ## New Features - Added a new flag `--serialParse` to support parsing the sources in serial, rather than in parallel (the default), which can address stability issues in SwiftSyntax [#1063](https://github.com/krzysztofzablocki/Sourcery/pull/1063) ## Internal Changes - Lower project requirements to allow compilation using Swift 5.5/Xcode 13.x [#1049](https://github.com/krzysztofzablocki/Sourcery/pull/1049) - Update Stencil to 0.14.2 - Use `swift build` insead of `xcodebuild` when building binary [#1057](https://github.com/krzysztofzablocki/Sourcery/pull/1057) ## 1.8.0 ## New Features - Adds `xcframework` key to `target` object in configuration file to enable processing of `swiftinterface` ## Fixes - Fixed issues generating Swift Templates when using Xcode 13.3 [#1040](https://github.com/krzysztofzablocki/Sourcery/issues/1040) - Modifications to included files of Swift Templates now correctly invalidate the cache - [#889](https://github.com/krzysztofzablocki/Sourcery/issues/889) ## Internal Changes - Swift 5.6 and Xcode 13.3 is now required to build the project - `lib_internalSwiftSyntaxParser` is now statically linked enabling better support when installing through SPM and Mint [#1037](https://github.com/krzysztofzablocki/Sourcery/pull/1037) ## 1.7.0 ## New Features - Adds `fileName` to `Type` and exposes `path` as well - Adds support for parsing async methods, closures and variables ## Fixes - correct parsing of rawValue initializer in enum cases, fixes #1010 - Use name or path parameter to parse groups to avoid duplicated group creation, fixes #904, #906 --- ## 1.6.1 ## New Features - Added `CLI-Only` subspec to `Sourcery.podspec` [#997](https://github.com/krzysztofzablocki/Sourcery/pull/997) - Added documentation comment parsing for all declarations [#1002](https://github.com/krzysztofzablocki/Sourcery/pull/1002) - Updates Yams to 4.0.6 - Enables universal binary --- ## 1.6.0 ## Fixes - Update dependencies to fix build on Xcode 13 and support Swift 5.5 [#989](https://github.com/krzysztofzablocki/Sourcery/issues/989) - Improves performance - Skips hidden files / directories and doesn't step into packages - added `after-auto:` generation mode to inline codegen - Fixes unstable ordering of `TypeName.attributes` - Fixing `Type.uniqueMethodFilter(_:_:)` so it compares return types of methods as well. ## 1.5.0 ## Features - Adds support for variadic parameters in functions - Adds support for parsing property wrappers - Added `titleCase` filter that turns `somethingNamedLikeThis` into `Something Named Like This` ## Fixes - correct passing `force-parse` argument to specific file parsers and renames it to `forceParse` to align with other naming - corrects `isMutable` regression on protocol variables #964 - Added multiple targets to link - Fix groups creation --- ## 1.4.2 ## Fixes - Fix a test failing on macOS 11.3 - Fix generation of inline:auto annotations in files with other inline annotations. - Fixes modifier access for things like `isLazy`, `isOptional`, `isConvienceInitializer`, `isFinal` - Fixes `isMutable` on subscripts - Fixes `open` access parsing - Removes symlinks in project, since these can confuse Xcode - [Fixes `inout` being incorrectly parsed for closures](https://github.com/krzysztofzablocki/Sourcery/issues/956) ## New Feature - Updated to Swift / SwiftSyntax 5.4 - Added ability to parse inline code generated by sourcery if annotation ends with argument provided in `--force-parse` option --- ## 1.4.1 ## New Feature - Extending AutoMockable template by adding handling of "autoMockableImports" and "autoMockableTestableImports" args. - Sourcery now supports [sourcerytemplates generated by Sourcery Pro](https://merowing.info/sourcery-pro/) ## Fixes - Adds trim option for Stencil template leading / trailing whitespace and replaces newline tag markers with normal newline after that - Fixes broken output for files with inline annotations from multiple templates --- ## 1.4.0 ## Features - Added `allImports` property to `Type`, which returns all imports existed in all files containing this type and all its super classes/protocols. - Added `basedTypes` property to `Type`, which contains all Types this type inherits from or implements, including unknown (not scanned) types with extensions defined. - Added inference logic for basic generics from variable initialization block - Added `newline` and `typed` stencil tags from [Sourcery Pro](https://merowing.info/sourcery-pro/) ## Fixes - Fixed inferring raw value type from inherited types for enums with no cases or with associated values - Fixed access level of protocol members - Fixes parsing indirect enum cases correctly even when inline documentation is used - Fixes TypeName.isClosure to handle composed types correctly - Fixes issue where Annotations for Protocol Composition types are empty - Fixes `sourcery:inline:auto` position calculation when the file contains UTF16 characters - Fixes `sourcery:inline:auto` position calculation when the file already contains code generated by Sourcery ## Internal changes - Removes manual parsing of `TypeName`, only explicit parser / configuration is now used - Add support for testing via `SPM` - Updted SwiftLint, Quick and Nible to latest versions ## 1.3.4 ## Fixes - `isClosure` / `isArray` / `isTuple` / `isDictionary` should now consistently report correct values, this code broke in few cases in 1.3.2 - Trivia (comments etc) will be ignored when parsing attribute description ## 1.3.3 ## Fixes - Fixes information being lost when extending unknown type more than once - Multiple configuration files can be now passed through command line arguments ## Templates - AutoEquatable will use type.accessLevel for it's function, closes #675 ## Internal changes - If you are using `.swifttemplate` in your configuration you might notice performance degradation, this is due to new composer added in `1.3.2` that can create memory graph cycles between AST with which our current persistence doesn't deal properly, to workaround this we need to perform additional work for storing copy of parsed AST and compose it later on when running SwiftTemplates. This will be fixed in future release when AST changes are brought in, if you notice too much of a performance drop you can just switch to `1.3.1`. ## 1.3.2 ## New Features - Configuration file now supports multiple configurations at once ## Fixes - When resolving extensions inherit their access level for methods/subscripts/variables and sub-types fixes #910 - When resolving Parent.ChildGenericType properly parses generic information ## Internal changes - Faster composing phase ## 1.3.1 ## Internal changes - SwiftSyntax dylib is now bundled with the binary ## 1.3.0 ## Internal changes - Sourcery is now using SwiftSyntax not SourceKit - Performance is significantly improved - Memory usage for common case (cached) is drastically lowered - If you want to use Sourcery as framework you'll need to use SPM integration since SwiftSyntax doesn't have Podspec ## Configuration changes - added `logAST` that will cause AST warnings and errors to be logged, default `false` - added `logBenchmarks` that will cause benchmark informations to be logged, default `false` ## AST Data Changes - initializers are now considered as static method not instance - typealiases and protocol compositions now provide proper `accessLevel` - if a tuple arguments are unnamed their `name` will be automatically set to index - default `accessLevel` when not provided in code is internal everywhere - Added `modifiers` to everything that had `attributes` and split them across, in sync with Swift naming - block annotations will be applied to associated values that are inside them - extensions of unknown types will not have the definition module name added in their `globalName` property. (You can still access it via `module`) - if you had some weird formatting around syntax declarations (newlines in-between etc) the AST data should be cleaned up rather than trying to reproduce that style - Imports are now proper types, with additional information - Protocol now has `genericRequirements`, it will also inherit `associatedType` from it's parent if it's not present - Single value tuples will be automatically unwrapped when parsing ### Attributes - Attributes are now of stored in dictionary of arrays `[String: [Attribute]]` since you can have multiple attributes of the same name e.g. `@available` - Name when not named will be using index same as associated value do e.g. objc(name) will have `0: name` as argument - spaces will no longer be replaced with `_` ## 1.2.1 ## Internal Changes Tweaks some warnings into info logs to not generate Xcode warnings ## 1.2.0 ### New Features - `Self` reference is resolved to correct type. [Enchancement Request](https://github.com/krzysztofzablocki/Sourcery/issues/900) - Sourcery will now attempt to resolve local type names across modules when it can be done without ambiguity. Previously we only supported fully qualified names. [Enchancement Request](https://github.com/krzysztofzablocki/Sourcery/issues/899) ## Internal Changes - Sourcery is now always distributed via SPM, this creates much nicer diffs when using CocoaPods distribution. ## 1.1.1 - Updates StencilSwiftKit to 2.8.0 ## 1.1.0 ### New Features - [PR](https://github.com/krzysztofzablocki/Sourcery/pull/897) Methods, Variables and Subscripts are now uniqued in all accessors: - `methods` and `allMethods` - `variables` and `allVariables` - `subscripts` and `allSubscripts` - New accessor is introduced that doesn't get rid of duplicates `rawMethods`, `rawVariables`, `rawSubscripts`s. - The deduping process works by priority order (highest to lowest): - base declaration - inheritance - protocol conformance - extensions ## 1.0.3 ### Internal Changes - updated xcodeproj, Stencil and StencilSwiftKit to newest versions ### Bug fixes - [Fixes type resolution when using xcode project integration](https://github.com/krzysztofzablocki/Sourcery/issues/887) - Matches the behaviour of `allMethods` to `allVariables` by only listing the same method once, even if defined in both base protocol and extended class. You could still walk the inheritance tree if you need to (to get all original methods), but for purpose of majority of codegen this is unneccessary. ## 1.0.2 ### Bug fixes - Fixes an issue when a very complicated variable initialization that contained `.init` call to unrelated case would cause the parser to assume the whole codeblock was a type and that could lead to mistakes in processing and even stack overflows ## 1.0.1 ### Internal Changes - Updated project and CI to Xcode 12.1 - Updated SourceKitten, Commander. ### Bug fixes - Fix multiline method declarations parsing - Fix an issue, where "types.implementing." did not work due to an additional module name. - Using tuple for associated values in enum case is deprecated since Swift 5.2. Fix AutoEquatable and AutoHashable templates to avoid the warning (#842) ## 1.0.0 ### New Features - Added support for associated types (#539) ### Bug fixes - Disallow protocol compositions from being considered as the `rawType` of an `enum` (#830) - Add missing documentation for the `ProtocolComposition` type. - Fix incorrectly taking closure optional return value as sign that whole variable is optional (#823) - Fix incorrectly taking return values with closure as generic type as sign that whole variable is a closure (#845) - Fix empty error at build time when using SwiftTemplate on Xcode 11.4 and higher (#817) ## 0.18.0 ### New Features - Added `optional` filter for variables - Added `json` filter to output raw JSON objects - Added `.defaultValue` to `AssociatedValue` - Added support for parsing [Protocol Compositions](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454) - Added support for parsing free functions - Added support for indirect enum cases - Added support for accessing all typealiases via `typealiases` and `typesaliasesByName` - Added support for parsing global typealiases ### Internal Changes - Improved error logging when running with `--watch` option - Updated CI to Xcode 11.4.1 ### Bug fixes - Fixed expansion of undefined environment variables (now consistent with command line behaviour, where such args are empty strings) - Fixed a bug in inferring extensions of Dictionary and Array types - Fixed a bug that was including default values as part of AssociatedValues type names - Fixed an issue with AutoMockable.stencil template when mocked function's return type was closure - Fixed missing SourceryRuntime dependency of SourceryFramework (SPM) ## 0.17.0 ### Internal Changes - Parallelized combining phase that yields 5-10x speed improvement for New York Times codebase - Switched cache logic to rely on file modification date instead of content Sha256 - Additional benchmark logs showing how long does each phase take - update dependencies to fix cocoapods setup when using Swift 5.0 everywhere. Update Quick to 2.1.0, SourceKitten to 0.23.1 and Yams to 2.0.0 ## 0.16.2 ### New Features - Support automatic linking of files generated by annotations to project target ### Bug fixes - Fixes always broken sourcery cache - Add missing SourceryFramework library product in Package.swift ## 0.16.1 ### Bug fixes - Fix ReceivedInvocations's type for the method which have only one parameter in AutoMockable.stencil - Fix missing folder error that could happen when running a Swift template with existing cache - Don't add indentation to empty line when using inline generated code. - Fix issue where errors in Swift Template would not be reported correctly when using Xcode 10.2. - Fix annotations for enum cases with associated values that wouldn't parses them correctly when commas were used ### Internal Changes - Removed dependency on SwiftTryCatch pod in order to avoid Swift Package Manager errors. ## 0.16.0 - Replaces environment variables inside .yml configurations (like ${PROJECT_NAME}), if a value is set. - Fixes warning in generated AutoMockable methods that have implicit optional return values - Support for `optional` methods in ObjC protocols - Support for parsing lazy vars into Variable's attributes. - Updated Stencil to 0.13.1 and SwiftStencilKit to 2.7.0 - In Swift templates CLI arguments should now be accessed via `argument` instead of `arguments`, to be consistent with Stencil and JS templates. - Now in swift templates you can define types, extensions and use other Swift features that require file scope, without using separate files. All templates code is now placed at the top level of the template executable code, instead of being placed inside an extension of `TemplateContext` type. - Fixed missing generated code annotated with `inline` annotation when corresponding annotation in sources are missing. This generated code will be now present in `*.generated.swift` file. - Updated AutoHashable template to use Swift 4.2's `hash(into:)` method from `Hashable`, and enable support for inheritance. - Record all method invocations in the `AutoMockable` template. - Replace `swiftc` with the Swift Package Manager to build Swift templates - Swift templates can now be used when using a SPM build of Sourcery. ## 0.15.0 ### New Features - You can now pass a json string as a command line arg or annotation and have it parsed into a Dictionary or Array to be used in the template. - Support for Xcode 10 and Swift 4.2 ## 0.14.0 ### New Features - You can now include entire Swift files in Swift templates - You can now use AutoEquatable with annotations - Content from multiple file annotations will now be concatenated instead of writing only the latest generated content. For example content generated by two following templates ``` // sourcery:file:Generated/Foo.swift line one // sourcery:end ``` and ``` // sourcery:file:Generated/Foo.swift line two // sourcery:end ``` will be written to one file: ``` line one line two ``` ### Internal Changes - Use AnyObject for class-only protocols ### Bug fixes - Fixed parsing associated enum cases in Xcode 10 - Fixed AutoEquatable access level for `==` func - Fixed path of generated files when linked to Xcode project - Fixed extraction of inline annotations in multi line comments with documentation style - Fixed compile error when used AutoHashable in NSObject subclass. ## 0.13.1 ### New Features - Added support for enums in AutoCodable template - You can now specify the base path for the Sourcery cache directory with a `cacheBasePath` key in the config file ## 0.13.0 ### New Features - Added AutoCodable template ### Bug fixes - Fixed parsing protocol method return type followed by declaration with attribute - Fixed inserting auto-inlined code on the last line of declaration body - AutoEquatable and AutoHashable templates should not add protocol conformances in extensions ## 0.12.0 ### Internal Changes - Migrate to Swift 4.1 and Xcode 9.3 ## 0.11.2 ### Bug fixes - Autocases template not respecting type access level - Ensure SPM and CocoaPods dependencies match - Improve AutoMockable template to handle methods with optional return values - Fixed crash while compiling swift templates ## 0.11.1 ### Internal changes - Do not fail the build if slather fails - Updated SourceKitten to 0.20.0 ### Bug fixes - Fixed parsing protocol methods return type (#579) ## 0.11.0 ### New Features - Supports adding new templates files while in watcher mode - Supports adding new source files while in watcher mode - Added support for subscripts - Added `isGeneric` property for `Method` - You can now pass additional arguments one by one, i.e. `--args arg1=value1 --args arg2 --args arg3=value3` - Improved support for generic types. Now you can access basic generic type information with `TypeName.generic` property - added `@objcMembers` attribute - Moved EJS and Swift templates to separate framework targets - EJS templates now can be used when building Sourcery with SPM - Added Closures to AutoMockable - You can now link generated files to projects using config file - You can now use AutoMockable with annotations - Updated to latest version of Stencil (commit 9184720) - Added support for annotation namespaces - Added `--exclude-sources` and `--exclude-templates` CLI options ** Breaking ** - @objc attribute now has a `name` argument that contains Objective-C name of attributed declaration - Type collections `types.based`, `types.implementing` and `types.inheriting` now return non-optional array. If no types found, empty array will be returned. This is a breaking change for template code like this: ```swift <% for type in (types.implementing["SomeProtocol"] ?? []) { %> ``` The new correct syntax would be: ```swift <% for type in types.implementing["SomeProtocol"] { %> ``` ### Internal changes - Migrate to Swift 4, SwiftPM 4 and Xcode 9.2 - `selectorName` for methods without parameters now will not contain `()` - `returnTypeName` for initializers will be the type name of defining type, with `?` for failable initializers - Improved compile time of AutoHashable template - Updated StencilSwiftKit and Stencil to 0.10.1 ### Bug fixes - Fixes FSEvents errors reported in #465 that happen on Sierra - JS exceptions no more override syntax errors in JS templates - Accessing unknown property on `types` now results in a better error than `undefined is not an object` in JS templates - Fixed issue in AutoMockable, where generated non-optional variables wouldn't meet protocol's requirements. For this purpose, underlying variable was introduced - Fixed `inline:auto` not inserting code if Sourcery is run with cache enabled #467 - Fixed parsing @objc attributes on types - Fixed parsing void return type in methods without spaces between method name and body open curly brace and in protocols - Fixed AutoMockable template generating throwing method with void return type - Fixed parsing throwing initializers - Fixed trying to process files which do not exist - Automockable will not generate mocks for methods defined in protocol extensions - Fixed parsing typealiases of generic types - AutoLenses template will create lenses only for stored properties - Fixed resolving actual type name for generics with inner types - Fixed parsing nested types from extensions - Fixed removing back ticks in types names - Fixed creating output folder if it does not exist - Fixed inferring variable types with closures and improved inferring types of enum default values - Fixed enum cases with empty parentheses not having () associated value ## 0.10.1 * When installing Sourcery via CocoaPods, the unneeded `file.zip` is not kept in `Pods/Sourcery/` anymore _(freeing ~12MB on each install of Sourcery made via CocoaPods!)_. ## 0.10.0 ### New Features - Added test for count Stencil filter - Added new reversed Stencil filter - Added new isEmpty Stencil filter - Added new sorted and sortedDescending Stencil filters. This can sort arrays by calling e.g. `protocol.allVariables|sorted:"name"` - Added new toArray Stencil filter - Added a console warning when a yaml is available but any parameter between 'sources', templates', 'forceParse', 'output' are provided ### Internal changes - Add release to Homebrew rake task - Fixed Swiftlint warnings - Fixed per file generation if there is long (approx. 150KB) output inside `sourcery:file` annotation - Do not generate default.profraw - Remove filters in favor of same filters from StencilSwiftKit ## 0.9.0 ### New Features - Added support for file paths in `config` parameter - Added `isDeinitializer` property for methods - Improved config file validation and error reporting - Various improvements for `AutoMockable` template: - support methods with reserved keywords name - support methods that throws - improved generated declarations names ### Bug fixes - Fixed single file generation not skipping writing the file when there is no generated content ### Internal changes - Updated dependencies for Swift 4 - Update internal ruby dependencies ## 0.8.0 ### New Features - Added support in `AutoHashable` for static variables, `[Hashable]` array and `[Hashable: Hashable]` dictionary - Added `definedInType` property for `Method` and `Variable` - Added `extensions` filter for stencil template - Added include support in Swift templates - Swift templates now can throw errors. You can also throw just string literals. - Added support for TypeName in string filters (except filters from StencilSwiftKit). ### Bug fixes - Fixed linker issue when using Swift templates - Updated `AutoMockable` to exclude generated code collisions - Fixed parsing of default values for variables that also have a body (e.g. for `didSet`) - Fixed line number display when an error occur while parsing a Swift template - Fixed `rsync` issue on `SourceryRuntime.framework` when using Swift templates - Fixed `auto:inline` for nested types (this concerns the first time the code is inserted) ### Internal changes - Fix link for template in docs - Fix running Sourcery in the example app - Add step to update internal boilerplate code during the release ## 0.7.2 ### Internal changes - Add Version.swift to represent CLI tool version ## 0.7.1 ### Bug fixes - Fixed regression in parsing templates from config file - Removed meaningless `isMutating` property for `Variable` ### Internal changes - Improvements in release script - Updated boilerplate code to reflect latest changes ## 0.7.0 ### New Features - Added `inout` flag for `MethodParameter` - Added parsing `mutating` and `final` attributes with convenience `isMutating` and `isFinal` properties - Added support for `include` Stencil tag - Added support for excluded paths ### Bug fixes - Fixed inserting generated code inline automatically at wrong position - Fixed regression in AutoEquatable & AutoHashable template with private computed variables ### Internal changes - Internal release procedure improvements - Improved `TemplatesTests` scheme running - Fixed swiftlint warnings (version 0.19.0) ## 0.6.1 ### New Features - Paths in config file are now relative to config file path by default, absolute paths should start with `/` - Improved logging and error reporting, added `--quiet` CLI option, added runtime errors for using invalid types in `implementing` and `inheriting` - Added support for includes in EJS templates (for example: `<%- include('myTemplate.js') %>`) - Add the `lowerFirst` filter for Stencil templates. - Added `isRequired` property for `Method` - Improved parsing of closure types - Check if Current Project Version match version in podspec in release task - Improved swift templates performance - Added `// sourcery:file` annotation for source code ### Bug fixes - Fixed detecting computed properties - Fixed typo in `isConvenienceInitialiser` property - Fixed creating cache folder when cache is disabled - Fixed parsing multiple enum cases annotations - Fixed parsing inline annotations when there is an access level or attribute - Fixed parsing `required` attribute - Fixed typo in `guides/Writing templates.md` ### Internal changes - Improved `AutoMockable.stencil` to support protocols with `init` methods - Improved `AutoCases.stencil` to use `let` instead of computed `var` - Updated StencilSwiftKit to 1.0.2 which includes Stencil 0.9.0 - Adding docset to release archive - Add tests for bundled stencil templates - Moved to CocoaPods 1.2.1 - Made Array.parallelMap's block non-escaping ## 0.6.0 ### New Features - Added some convenience accessors for classic, static and instance methods, and types and contained types grouped by names ## 0.6 ### New Features - Added support for inline code generation without requiring explicit `// sourcery:inline` comments in the source files. To use, use `sourcery:inline:auto` in a template: `// sourcery:inline:auto:MyType.TemplateName` - Added `isMutable` property for `Variable` - Added support for scanning multiple targets - Added access level filters and disabled filtering private declarations - Added support for inline comments for annotations with `/*` and `*/` - Added annotations for enum case associated values and method parameters - Added `isConvenienceInitializer` property for `Method` - Added `defaultValue` for variables and method parameters - Added docs generated with jazzy - Sourcery now will not create empty files and will remove existing generated files with empty content if CLI flag `prune` is set to `true` (`false` by default) - Sourcery now will remove inline annotation comments from generated code. - Added `rethrows` property to `Method` - Allow duplicated annotations to be agregated into array - Added ejs-style tags to control whitespaces and new lines in swift templates - Added CLI option to provide path to config file ### Bug Fixes - Inserting multiple inline code block in one file - Suppress warnings when compiling swift templates - Accessing protocols in Swift templates - Crash that would happen sometimes when parsing typealiases ### Internal changes - Replaced `TypeReflectionBox` and `GenerationContext` types with common `TemplateContext`. ## 0.5.9 ### New Features - Added flag to check if `TypeName` is dictionary - Added support for multiple sources and templates paths, sources, templates and output paths now should be provided with `--sources`, `--templates` and `--output` options - Added support for YAML file configuration - Added generation of non-swift files using `sourcery:file` annotation ### Bug Fixes - Fixed observing swift and js templates - Fixed parsing generic array types - Fixed using dictionary in annotations ## 0.5.8 ### New Features - Added parsing array types - Added support for JavaScript templates (using EJS) ### Bug Fixes - Fixed escaping variables with reserved names - Fixed duplicated methods and variables in `allMethods` and `allVariables` - Fixed trimming attributes in type names ## 0.5.7 ### Bug Fixes - Cache initial file contents, including the inline generated ranges so that they are always up to date ## 0.5.6 ### New Features - Added per file code generation ### Bug Fixes - Fixed parsing annotations with complex content - Fixed inline parser using wrong caching logic ## 0.5.5 ### New Features - Sourcery will no longer write files if content didn't change, this improves behaviour of things depending on modification date like Xcode, Swiftlint. ### Internal changes - Improved support for contained types ### Bug Fixes - Fixes cache handling that got broken in 0.5.4 ## 0.5.4 ### New Features - Added inline code generation - Added `isClosure` property to `TypeName` to detect closure types ### Bug Fixes - Fixed parsing of associated values separater by newlines - Fixed preserving order of inherited types - Improved support for throwing methods in protocols - Fixed extracting parameters of methods with closures in their bodies - Fixed extracting method return types of tuple types - Improved support for typealises as tuple elements types - Method parameters with `_` argument label will now have `nil` in `argumentLabel` property - Improved support for generic methods - Improved support for contained types ### Internal changes - adjusted internal templates and updated generated code - moved methods parsing related tests in a separate spec ## 0.5.3 ### New Features - Added support for method return types with `throws` and `rethrows` - Added a new filter `replace`. Usage: `{{ name|replace:"substring","replacement" }}` - replaces occurrences of `substring` with `replacement` in `name` (case sensitive) - Improved support for inferring types of variables with initial values - Sourcery is now bundling a set of example templates, you can access them in Templates folder. - We now use parallel parsing and cache source artifacts. This leads to massive performance improvements: - e.g. on big codebase of over 300 swift files: ``` Sourcery 0.5.2 Processing time 8.69941002130508 seconds Sourcery 0.5.3 First time 4.69904798269272 seconds Subsequent time: 0.882099032402039 seconds ``` ### Bug Fixes - Method `accessLevel` was not exposed as string so not accessible properly via templates, fixed that. - Fixes on Swift Templates ## 0.5.2 ### New Features - Added support for `ImplicitlyUnwrappedOptional` - `actualTypeName` property of `Method.Parameter`, `Variable`, `Enum.Case.AssociatedValue`, `TupleType.Element` now returns `typeName` if type is not a type alias - `Enum` now contains type information for its raw value type. `rawType` now return `Type` object, `rawTypeName` returns its `TypeName` - Added `annotated` filter to filter by annotations - Added negative filters counterparts - Added support for attributes, i.e. `@escaping` - Experimental support for Swift Templates - Swift Templates are now supported ``` <% for type in types.classes { %> extension <%= type.name %>: Equatable {} <% if type.annotations["showComment"] != nil { %> // <%= type.name %> has Annotations <% } %> func == (lhs: <%= type.name %>, rhs: <%= type.name %>) -> Bool { <% for variable in type.variables { %> if lhs.<%= variable.name %> != rhs.<%= variable.name %> { return false } <% } %> return true } <% } %> ``` ### 0.5.1 ### New Features - Variables with default initializer are now supported, e.g. `var variable = Type(...)` - Added support for special escaped names in enum cases e.g. `default` or `for` - Added support for tuple types and `tuple` filter for variables - Enum associated values now have `localName` and `externalName` properties. - Added `actualTypeName` for `TypeName` that is typealias - Added `implements`, `inherits` and `based` filters ### Bug Fixes - Using protocols doesn't expose variables using KVC, which meant some of the typeName properties weren't accessible via Templates, we fixed that using Sourcery itself to generate specific functions. - Fixed parsing typealiases for tuples and closure types - Fixed parsing associated values of generic types ### Internal Changes - Performed significant refactoring and simplified mutations in parsers ## 0.5.0 - You can now pass arbitrary values to templates with `--args` argument. - Added `open` access level - Type `inherits` and `implements` now allow you to access full type information, not just name - Type `allVariables` will now include all variables, including those inherited from supertype and known protocols. - Type `allMethods` will now include all methods, including those inherited from supertype and known protocols. - AssociatedValue exposes `unwrappedTypeName`, `isOptional` - New Available stencil filters: - `static`, `instance`, `computed`, `stored` for Variables - `enum`, `class`, `struct`, `protocol` for Types - `class`, `initializer`, `static`, `instance` for Methods - `count` for Arrays, this is used when chaining arrays with filters where Stencil wouldn't allow us to do `.count`, e.g. `{{ variables|instance|count }}` - Now you can avoid inferring unknown protocols as enum raw types by adding conformance in extension (instead of `enum Foo: Equatable {}` do `enum Foo {}; extension Foo: Equatable {}`) ### Internal changes - Refactor code around typenames ## 0.4.9 ### New Features - Watch mode now works with folders, reacting to source-code changes and adding templates/source files. - When using watch mode, status info will be displayed in the generated code so that you don't need to look at console at all. - You can now access types of enum's associated values - You can now access type's `methods` and `initializers` ## 0.4.8 ### New Features - You can now access `supertype` of a class - Associated values will now automatically use idx as name if no name is provided ### Bug Fixes - Fix dealing with multibyte characters - `types.implementing` and `types.based` should include protocols that are based on other protocols ### Internal changes - TDD Development is now easier thanks to Diffable results, no longer we need to scan wall of text on failures, instead we see exactly what's different. ## 0.4.7 ### New Features - Added `contains`, `hasPrefix`, `hasPrefix` filters ### Bug Fixes - AccessLevel is now stored as string ## 0.4.6 ### Bug Fixes - Typealiases parsing could cause crash, implemented a workaround for that until we can find a little more reliable solution ## 0.4.5 ### New Features * Swift Package Manager support. ## 0.4.4 ### New Features * Enum cases also have annotation support ### Internal changes * Improved handling of global and local typealiases. ## 0.4.3 ### New Features * Add upperFirst stencil filter ## 0.4.2 ### Bug Fixes * Fixes a bug with flattening `inherits`, `implements` for protocols implementing other protocols * Improve `rawType` logic for Enums ### New Features * Annotations can now be declared also with sections e.g. `sourcery:begin: attribute1, attribute2 = 234` * Adds scanning class variables as static ### Internal changes * Refactored models * Improved performance of annotation scanning ## 0.4.1 ### New Features * Implements inherits, implements, based reflection on each Type * Flattens inheritance, e.g. Foo implements Decodable, then FooSubclass also implements it ### Internal changes * Stop parsing private variables as they wouldn't be accessible to code-generated code ## 0.4.0 ### New Features * improve detecting raw type * add `isGeneric` property ## 0.3.9 ### New Features * Enables support for scanning extensions of unknown type, providing partial metadata via types.based or types.all reflection ## 0.3.8 ### New Features * Adds real type reflection into Variable, not only it's name * Resolves known typealiases ## 0.3.7 ### Bug Fixes * Fixes a bug that caused Sourcery to drop previous type information when encountering generated code, closes #33 ## 0.3.6 ### Bug Fixes * Fixes bug in escaping path * Fixes missing protocol variant in kind ## 0.3.5 ### New Features * added support for type/variable source annotations * added property kind to Type, it contains info whether this is struct, class or enum entry * Automatically skips .swift files that were generated with Sourcery ### Internal changes * improved detecting enums with rawType ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at krzysztof.zablocki@pixle.pl. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Sourcery Sourcery is an open source project started by Krzysztof Zabłocki and open to the entire Cocoa community. I really appreciate your help! ## Filing issues When filing an issue, make sure to answer these questions: 1. What version of Swift are you using (`swift --version`)? 2. What did you do? 3. What did you expect to see? 4. What did you see instead? ## Contributing code Before submitting changes, please follow these guidelines: 1. Check the open issues and pull requests for existing discussions. 2. Open an issue to discuss a new feature. 3. Write tests. 4. Make sure your changes pass existing tests. 5. Make sure the entire test suite passes locally and on Circle CI. 6. Open a Pull Request. Unless otherwise noted, the Sourcery source files are distributed under the MIT-style [LICENSE](LICENSE). [Please review our Code of Conduct](https://github.com/krzysztofzablocki/Sourcery/blob/master/CODE_OF_CONDUCT.md) ================================================ FILE: Dangerfile ================================================ # Sometimes it's a README fix, or something like that - which isn't relevant for # including in a project's CHANGELOG for example not_declared_trivial = !(github.pr_title.include? "#trivial") has_app_changes = !git.modified_files.grep(/(Sourcery|Templates)/).empty? # Make it more obvious that a PR is a work in progress and shouldn't be merged yet warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]" # Warn when there is a big PR warn("Big PR") if git.lines_of_code > 500 # Don't let testing shortcuts get into master by accident fail("fit left in tests") if `grep -rI "fit(" SourceryTests/`.length > 1 fail("fdescribe left in tests") if `grep -rI "fdescribe(" SourceryTests/`.length > 1 fail("fcontext left in tests") if `grep -rI "fcontext(" SourceryTests/`.length > 1 # Changelog entries are required for changes to library files. no_changelog_entry = !git.modified_files.include?("CHANGELOG.md") if has_app_changes && no_changelog_entry && not_declared_trivial fail("Any changes to library code need a summary in the Changelog.") end # New templates must be covered with tests has_new_stencil_template = !git.added_files.grep(/Templates\/Templates.*\.stencil$/).empty? has_new_template_test = !git.added_files.grep(/Templates\/Tests\/Generated/).empty? && !git.added_files.grep(/Templates\/Tests\/Context/).empty? && !git.added_files.grep(/Templates\/Tests\/Expected/).empty? if has_new_stencil_template && !has_new_template_test fail("Any new stencil template must be covered with test.") end ================================================ FILE: Dockerfile ================================================ ARG BUILDER_IMAGE=swift:6.0-jammy ARG RUNTIME_IMAGE=swift:6.0-jammy-slim # Builder image FROM ${BUILDER_IMAGE} AS builder RUN apt-get update && apt-get install -y \ build-essential \ libffi-dev \ libncurses5-dev \ libsqlite3-dev \ && rm -r /var/lib/apt/lists/* WORKDIR /workdir/ COPY Sourcery Sourcery/ COPY SourceryExecutable SourceryExecutable/ COPY SourceryFramework SourceryFramework/ COPY SourceryJS SourceryJS/ COPY SourceryRuntime SourceryRuntime/ COPY SourceryStencil SourceryStencil/ COPY SourcerySwift SourcerySwift/ COPY SourceryTests SourceryTests/ COPY SourceryUtils SourceryUtils/ COPY Plugins Plugins/ COPY Templates Templates/ COPY Tests Tests/ COPY Package.* ./ RUN swift package --only-use-versions-from-resolved-file resolve ARG SWIFT_FLAGS="-c release" RUN swift build $SWIFT_FLAGS --product sourcery RUN mv `swift build $SWIFT_FLAGS --show-bin-path`/sourcery /usr/bin RUN sourcery --version # Runtime image FROM ${RUNTIME_IMAGE} LABEL org.opencontainers.image.source https://github.com/krzysztofzablocki/Sourcery RUN apt-get update && apt-get install -y \ libcurl4 \ libsqlite3-0 \ libxml2 \ && rm -r /var/lib/apt/lists/* COPY --from=builder /usr/bin/sourcery /usr/bin RUN sourcery --version CMD ["sourcery"] ================================================ FILE: Funding.yml ================================================ github: krzysztofzablocki custom: https://www.merowing.info/membership ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' gem 'cocoapods', '1.14.3' gem 'danger' gem 'rake' gem 'slather' gem 'xcpretty' gem 'ffi', '1.15.3' gem 'json', '2.5.1' gem 'jazzy', '0.14.0' ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2016-2021 Krzysztof Zabłocki Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: LINUX.md ================================================ ## Linux Support Currently (as per 2.1.0 release), Linux Support is **experimental**. This means the following: 1. Running `sourcery` in the root folder of Sourcery project was generating `Equatable.generated.swift` and other autogenerated files with extensions of classes used by `SourceryRuntime`, but they were moved to class definitions due to the abscense of `@objc` attribute on non-Darwin platforms. Thus, `.sourcery.yaml` file was disabled for the moment, until #1198 is resolved. 2. Some unit tests were disabled with `#if canImport(ObjectiveC)`, that is some due to Swift compiler crashes, some due to abscence of `JavaScriptCore`. 3. `FileWatcher` needs to be re-implemented (see [this comment](https://github.com/krzysztofzablocki/Sourcery/pull/1188#issue-1828038476) for a possible fix) All issues related to Linux will be mentioned in #1198 ## Using Sourcery under Linux Simply add package dependency of Sourcery as described in the [README](README.md). ## Using Sourcery with Docker You can build Docker container with Sourcery installed using this command: ```console docker build -t sourcery-image . ``` Then you can run this Docker image passing the arguments you'd like: ```console docker run sourcery-image sourcery --help ``` ## Contributing ### Installation of Linux Environment I have installed ubuntu VM through [tart](https://github.com/cirruslabs/tart/issues/62#issuecomment-1225956540) and updated to 22.04 according to [this guide](https://www.linuxtechi.com/upgrade-ubuntu-20-04-to-ubuntu-22-04/). I had to run the following commands prior to being able to run `bundle install` in Sourcery: 1. `sudo apt install libffi-dev` 2. `sudo apt install build-essential` 3. `sudo apt install libsqlite3-dev` 4. `sudo apt-get install libncurses5-dev` Then, `swiftly` needs to be installed to easily manage Swift installation under Linux. How to install Swiftly is described [in this README](https://github.com/swift-server/swiftly). ### Running Tests Under Linux To run tests, you can use either Visual Studio Code distribution, or simply `swift test` in Sourcery root directory. #### Visual Studio Code To install VS Code, you can follow [the official guide](https://code.visualstudio.com/docs/setup/linux), which mentions the following commands: ```bash sudo apt-get install wget gpg wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list' rm -f packages.microsoft.gpg # Then update the package cache and install the package using: sudo apt install apt-transport-https sudo apt update sudo apt install code # or code-insiders ``` ### Test Discovery Under Linux Due to a missing feature in Swift Package Manager, tests under Linux are not discovered if the root class, from which tests are inherited, is located "in another Package/Module". Details regarding this [can be found here](https://github.com/apple/swift-package-manager/issues/5573). And so, if a new `Spec` needs to be added, that Spec file needs to be put into `LinuxMain.swift` similarly to what is there already, mentioning the new class name accordingly. ================================================ FILE: LinuxMain.swift ================================================ import XCTest import Quick @testable import SourceryLibTests @testable import TemplatesTests @testable import CodableContextTests @main struct Main { static func main() { Quick.QCKMain([ ActorSpec.self, AnnotationsParserSpec.self, ClassSpec.self, ConfigurationSpec.self, DiffableSpec.self, DryOutputSpec.self, EnumSpec.self, FileParserAssociatedTypeSpec.self, FileParserAttributesSpec.self, FileParserMethodsSpec.self, FileParserProtocolCompositionSpec.self, FileParserSpec.self, FileParserSubscriptsSpec.self, FileParserVariableSpec.self, GeneratorSpec.self, MethodSpec.self, ParserComposerSpec.self, ProtocolSpec.self, SourcerySpecTests.self, StencilTemplateSpec.self, StringViewSpec.self, StructSpec.self, SwiftTemplateTests.self, TemplateAnnotationsParserSpec.self, TemplatesAnnotationParserPassInlineCodeSpec.self, TypeNameSpec.self, TypeSpec.self, TypealiasSpec.self, TypedSpec.self, VariableSpec.self, VerifierSpec.self, CodableContextTests.self, TemplatesTests.self ], configurations: [], testCases: [ testCase(ActorSpec.allTests), testCase(AnnotationsParserSpec.allTests), testCase(ClassSpec.allTests), testCase(ConfigurationSpec.allTests), testCase(DiffableSpec.allTests), testCase(DryOutputSpec.allTests), testCase(EnumSpec.allTests), testCase(FileParserAssociatedTypeSpec.allTests), testCase(FileParserAttributesSpec.allTests), testCase(FileParserMethodsSpec.allTests), testCase(FileParserProtocolCompositionSpec.allTests), testCase(FileParserSpec.allTests), testCase(FileParserSubscriptsSpec.allTests), testCase(FileParserVariableSpec.allTests), testCase(GeneratorSpec.allTests), testCase(MethodSpec.allTests), testCase(ParserComposerSpec.allTests), testCase(ProtocolSpec.allTests), testCase(SourcerySpecTests.allTests), testCase(StencilTemplateSpec.allTests), testCase(StringViewSpec.allTests), testCase(StructSpec.allTests), testCase(SwiftTemplateTests.allTests), testCase(TemplateAnnotationsParserSpec.allTests), testCase(TemplatesAnnotationParserPassInlineCodeSpec.allTests), testCase(TypeNameSpec.allTests), testCase(TypeSpec.allTests), testCase(TypealiasSpec.allTests), testCase(TypedSpec.allTests), testCase(VariableSpec.allTests), testCase(VerifierSpec.allTests), testCase(CodableContextTests.allTests), testCase(TemplatesTests.allTests) ]) } } ================================================ FILE: Package.resolved ================================================ { "pins" : [ { "identity" : "aexml", "kind" : "remoteSourceControl", "location" : "https://github.com/tadija/AEXML.git", "state" : { "revision" : "38f7d00b23ecd891e1ee656fa6aeebd6ba04ecc3", "version" : "4.6.1" } }, { "identity" : "commander", "kind" : "remoteSourceControl", "location" : "https://github.com/kylef/Commander.git", "state" : { "revision" : "4b6133c3071d521489a80c38fb92d7983f19d438", "version" : "0.9.1" } }, { "identity" : "cwlcatchexception", "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlCatchException.git", "state" : { "revision" : "07b2ba21d361c223e25e3c1e924288742923f08c", "version" : "2.2.1" } }, { "identity" : "cwlpreconditiontesting", "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git", "state" : { "revision" : "0139c665ebb45e6a9fbdb68aabfd7c39f3fe0071", "version" : "2.2.2" } }, { "identity" : "nimble", "kind" : "remoteSourceControl", "location" : "https://github.com/Quick/Nimble.git", "state" : { "revision" : "e491a6731307bb23783bf664d003be9b2fa59ab5", "version" : "9.0.0" } }, { "identity" : "pathkit", "kind" : "remoteSourceControl", "location" : "https://github.com/kylef/PathKit.git", "state" : { "revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574", "version" : "1.0.1" } }, { "identity" : "quick", "kind" : "remoteSourceControl", "location" : "https://github.com/Quick/Quick.git", "state" : { "revision" : "8cce6acd38f965f5baa3167b939f86500314022b", "version" : "3.1.2" } }, { "identity" : "spectre", "kind" : "remoteSourceControl", "location" : "https://github.com/kylef/Spectre.git", "state" : { "revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7", "version" : "0.10.1" } }, { "identity" : "stencil", "kind" : "remoteSourceControl", "location" : "https://github.com/art-divin/Stencil.git", "state" : { "revision" : "03a1dca8923bef5a34c08f5a560fb420326f7244", "version" : "0.15.3" } }, { "identity" : "stencilswiftkit", "kind" : "remoteSourceControl", "location" : "https://github.com/art-divin/StencilSwiftKit.git", "state" : { "revision" : "6b07f85def6984e7015d65502d41b91f3f8db6d5", "version" : "2.10.4" } }, { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", "version" : "1.2.3" } }, { "identity" : "swift-asn1", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { "revision" : "7faebca1ea4f9aaf0cda1cef7c43aecd2311ddf6", "version" : "1.3.0" } }, { "identity" : "swift-certificates", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { "revision" : "01d7664523af5c169f26038f1e5d444ce47ae5ff", "version" : "1.0.1" } }, { "identity" : "swift-collections", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", "version" : "1.1.4" } }, { "identity" : "swift-crypto", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { "revision" : "629f0b679d0fd0a6ae823d7f750b9ab032c00b80", "version" : "3.0.0" } }, { "identity" : "swift-driver", "kind" : "remoteSourceControl", "location" : "https://github.com/art-divin/swift-driver.git", "state" : { "revision" : "1c07ced84c1dfc1f9c3253dcbaa216fc9c76ee25", "version" : "1.0.1" } }, { "identity" : "swift-llbuild", "kind" : "remoteSourceControl", "location" : "https://github.com/art-divin/swift-llbuild.git", "state" : { "revision" : "783aec21649a6c47d1a8314db4144bdceb11df30", "version" : "1.0.0" } }, { "identity" : "swift-package-manager", "kind" : "remoteSourceControl", "location" : "https://github.com/art-divin/swift-package-manager.git", "state" : { "revision" : "7df9321541e544d711dd93f5b97dd4e8bf7e100e", "version" : "1.0.8" } }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { "revision" : "0687f71944021d616d34d922343dcef086855920", "version" : "600.0.1" } }, { "identity" : "swift-system", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { "revision" : "836bc4557b74fe6d2660218d56e3ce96aff76574", "version" : "1.1.1" } }, { "identity" : "swift-tools-support-core", "kind" : "remoteSourceControl", "location" : "https://github.com/art-divin/swift-tools-support-core.git", "state" : { "revision" : "930e82e5ae2432c71fe05f440b5d778285270bdb", "version" : "1.0.0" } }, { "identity" : "xcodeproj", "kind" : "remoteSourceControl", "location" : "https://github.com/tuist/xcodeproj", "state" : { "revision" : "f6c9cb05835086af13f91317f92693848b43ea47", "version" : "8.24.6" } }, { "identity" : "yams", "kind" : "remoteSourceControl", "location" : "https://github.com/jpsim/Yams.git", "state" : { "revision" : "c7facc5ccb8c5a4577ea8c491aa875762cdee57a", "version" : "5.0.3" } } ], "version" : 2 } ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription import Foundation var sourceryLibDependencies: [Target.Dependency] = [ "SourceryFramework", "SourceryRuntime", "SourceryStencil", "SourceryJS", "SourcerySwift", "Commander", "PathKit", "Yams", "StencilSwiftKit", .product(name: "SwiftSyntax", package: "swift-syntax"), "XcodeProj", .product(name: "SwiftPM-auto", package: "swift-package-manager"), ] // Note: when Swift Linux doesn't bug out on [String: String], add a test back for it // See https://github.com/krzysztofzablocki/Sourcery/pull/1208#issuecomment-1752185381 #if canImport(ObjectiveC) sourceryLibDependencies.append("TryCatch") let templatesTestsResourcesCopy: [Resource] = [ .copy("Templates"), .copy("Tests/Context"), .copy("Tests/Expected") ] #else sourceryLibDependencies.append(.product(name: "Crypto", package: "swift-crypto")) let templatesTestsResourcesCopy: [Resource] = [ .copy("Templates"), .copy("Tests/Context_Linux"), .copy("Tests/Expected") ] #endif // Note: when Swift Linux doesn't bug out on [String: String], add a test back for it // See https://github.com/krzysztofzablocki/Sourcery/pull/1208#issuecomment-1752185381 #if canImport(ObjectiveC) let sourceryLibTestsResources: [Resource] = [ .copy("Stub/Configs"), .copy("Stub/Errors"), .copy("Stub/JavaScriptTemplates"), .copy("Stub/SwiftTemplates"), .copy("Stub/Performance-Code"), .copy("Stub/DryRun-Code"), .copy("Stub/Result"), .copy("Stub/Templates"), .copy("Stub/Source") ] #else let sourceryLibTestsResources: [Resource] = [ .copy("Stub/Configs"), .copy("Stub/Errors"), .copy("Stub/JavaScriptTemplates"), .copy("Stub/SwiftTemplates"), .copy("Stub/Performance-Code"), .copy("Stub/DryRun-Code"), .copy("Stub/Result"), .copy("Stub/Templates"), .copy("Stub/Source_Linux") ] #endif var targets: [Target] = [ .executableTarget( name: "SourceryExecutable", dependencies: ["SourceryLib"], path: "SourceryExecutable", exclude: [ "Info.plist" ] ), .target( // Xcode doesn't like when a target has the same name as a product but in different case. name: "SourceryLib", dependencies: sourceryLibDependencies, path: "Sourcery", exclude: [ "Templates", ] ), .target( name: "SourceryRuntime", dependencies: [ "StencilSwiftKit" ], path: "SourceryRuntime", exclude: [ "Supporting Files/Info.plist" ] ), .target( name: "SourceryFramework", dependencies: [ "PathKit", .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftParser", package: "swift-syntax"), "SourceryUtils", "SourceryRuntime" ], path: "SourceryFramework", exclude: [ "Info.plist" ] ), .target( name: "SourceryStencil", dependencies: [ "PathKit", "SourceryRuntime", "StencilSwiftKit", ], path: "SourceryStencil", exclude: [ "Info.plist" ] ), .target( name: "SourceryJS", dependencies: [ "PathKit" ], path: "SourceryJS", exclude: [ "Info.plist" ], resources: [ .copy("Resources/ejs.js") ] ), .target( name: "SourcerySwift", dependencies: [ "PathKit", "SourceryRuntime", "SourceryUtils" ], path: "SourcerySwift", exclude: [ "Info.plist" ] ), .target( name: "CodableContext", path: "Templates/Tests", exclude: [ "Context/AutoCases.swift", "Context/AutoEquatable.swift", "Context/AutoHashable.swift", "Context/AutoLenses.swift", "Context/AutoMockable.swift", "Context/LinuxMain.swift", "Generated/AutoCases.generated.swift", "Generated/AutoEquatable.generated.swift", "Generated/AutoHashable.generated.swift", "Generated/AutoLenses.generated.swift", "Generated/AutoMockable.generated.swift", "Generated/LinuxMain.generated.swift", "Expected", "Info.plist", "TemplatesTests.swift" ], sources: [ "Context/AutoCodable.swift", "Generated/AutoCodable.generated.swift" ] ), .testTarget( name: "SourceryLibTests", dependencies: [ "SourceryLib", "Quick", "Nimble" ], exclude: [ "Info.plist" ], resources: sourceryLibTestsResources, swiftSettings: [.unsafeFlags(["-enable-testing"])] ), .testTarget( name: "CodableContextTests", dependencies: [ "CodableContext", "Quick", "Nimble" ], path: "Templates/CodableContextTests", exclude: [ "Info.plist" ], swiftSettings: [.unsafeFlags(["-enable-testing"])] ), .testTarget( name: "TemplatesTests", dependencies: [ "Quick", "Nimble", "PathKit" ], path: "Templates", exclude: [ "CodableContext", "CodableContextTests", "Tests/Generated", "Tests/Info.plist" ], sources: [ // LinuxMain is not compiled as part of the target // since there is no way to run script before compilation begins. "Tests/TemplatesTests.swift" ], resources: templatesTestsResourcesCopy, swiftSettings: [.unsafeFlags(["-enable-testing"])] ), .plugin( name: "SourceryCommandPlugin", capability: .command( intent: .custom( verb: "sourcery-command", description: "Sourcery command plugin for code generation" ), permissions: [ .writeToPackageDirectory(reason: "Need permission to write generated files to package directory") ] ), dependencies: ["SourceryExecutable"] ) ] #if canImport(ObjectiveC) let sourceryUtilsDependencies: [Target.Dependency] = ["PathKit"] targets.append(.target(name: "TryCatch", path: "TryCatch", exclude: ["Info.plist"])) #else let sourceryUtilsDependencies: [Target.Dependency] = [ "PathKit", .product(name: "Crypto", package: "swift-crypto") ] #endif targets.append( .target( name: "SourceryUtils", dependencies: sourceryUtilsDependencies, path: "SourceryUtils", exclude: [ "Supporting Files/Info.plist" ] ) ) var dependencies: [Package.Dependency] = [ .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.3"), .package(url: "https://github.com/kylef/Commander.git", exact: "0.9.1"), // PathKit needs to be exact to avoid a SwiftPM bug where dependency resolution takes a very long time. .package(url: "https://github.com/kylef/PathKit.git", exact: "1.0.1"), .package(url: "https://github.com/art-divin/StencilSwiftKit.git", exact: "2.10.4"), .package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.24.6"), .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0"), .package(url: "https://github.com/Quick/Quick.git", from: "3.0.0"), .package(url: "https://github.com/Quick/Nimble.git", from: "9.0.0"), ] #if compiler(>=6.2) dependencies.append(.package(url: "https://github.com/swiftlang/swift-package-manager.git", revision: "swift-6.2-RELEASE")) #else dependencies.append(.package(url: "https://github.com/art-divin/swift-package-manager.git", exact: "1.0.8")) #endif #if !canImport(ObjectiveC) dependencies.append(.package(url: "https://github.com/apple/swift-crypto.git", from: "3.0.0")) #endif let package = Package( name: "Sourcery", platforms: [ .macOS(.v13), ], products: [ // SPM won't generate .swiftmodule for a target directly used by a product, // hence it can't be imported by tests. Executable target can't be imported too. .executable(name: "sourcery", targets: ["SourceryExecutable"]), .library(name: "SourceryRuntime", targets: ["SourceryRuntime"]), .library(name: "SourceryStencil", targets: ["SourceryStencil"]), .library(name: "SourceryJS", targets: ["SourceryJS"]), .library(name: "SourcerySwift", targets: ["SourcerySwift"]), .library(name: "SourceryFramework", targets: ["SourceryFramework"]), .library(name: "SourceryLib", targets: ["SourceryLib"]), .plugin(name: "SourceryCommandPlugin", targets: ["SourceryCommandPlugin"]) ], dependencies: dependencies, targets: targets ) ================================================ FILE: Plugins/SourceryCommandPlugin/SourceryCommandPlugin.swift ================================================ import PackagePlugin import Foundation @main struct SourceryCommandPlugin { private func run(_ sourcery: String, withConfig configFilePath: String, cacheBasePath: String) throws { let sourceryURL = URL(fileURLWithPath: sourcery) let process = Process() process.executableURL = sourceryURL process.arguments = [ "--config", configFilePath, "--cacheBasePath", cacheBasePath ] try process.run() process.waitUntilExit() let gracefulExit = process.terminationReason == .exit && process.terminationStatus == 0 if !gracefulExit { throw "🛑 The plugin execution failed with reason: \(process.terminationReason.rawValue) and status: \(process.terminationStatus) " } } } // MARK: - CommandPlugin extension SourceryCommandPlugin: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { // Run one per target for target in context.package.targets { let configFilePath = target.directory.appending(subpath: ".sourcery.yml").string let sourcery = try context.tool(named: "SourceryExecutable").path.string guard FileManager.default.fileExists(atPath: configFilePath) else { Diagnostics.warning("⚠️ Could not find `.sourcery.yml` for target \(target.name)") continue } try run(sourcery, withConfig: configFilePath, cacheBasePath: context.pluginWorkDirectory.string) } } } // MARK: - XcodeProjectPlugin #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension SourceryCommandPlugin: XcodeCommandPlugin { func performCommand(context: XcodePluginContext, arguments: [String]) throws { for target in context.xcodeProject.targets { guard let configFilePath = target .inputFiles .filter({ $0.path.lastComponent == ".sourcery.yml" }) .first? .path .string else { Diagnostics.warning("⚠️ Could not find `.sourcery.yml` in Xcode's input file list") return } let sourcery = try context.tool(named: "SourceryExecutable").path.string try run(sourcery, withConfig: configFilePath, cacheBasePath: context.pluginWorkDirectory.string) } } } #endif extension String: LocalizedError { public var errorDescription: String? { return self } } ================================================ FILE: README.md ================================================ [![macOS 13](https://github.com/krzysztofzablocki/Sourcery/actions/workflows/test_macOS.yml/badge.svg)](https://github.com/krzysztofzablocki/Sourcery/actions/workflows/test_macOS.yml) [![ubuntu x86_64](https://github.com/krzysztofzablocki/Sourcery/actions/workflows/test_ubuntu.yml/badge.svg?branch=master)](https://github.com/krzysztofzablocki/Sourcery/actions/workflows/test_ubuntu.yml) [![docs](https://krzysztofzablocki.github.io/Sourcery/badge.svg)](https://krzysztofzablocki.github.io/Sourcery/index.html) [![Version](https://img.shields.io/cocoapods/v/Sourcery.svg?style=flat)](http://cocoapods.org/pods/Sourcery) [![License](https://img.shields.io/cocoapods/l/Sourcery.svg?style=flat)](http://cocoapods.org/pods/Sourcery) [![Platform](https://img.shields.io/cocoapods/p/Sourcery.svg?style=flat)](http://cocoapods.org/pods/Sourcery) [**In-Depth Sourcery guide is covered as part of my SwiftyStack engineering course.**](https://www.swiftystack.com/) **Sourcery Pro provides a powerful Stencil editor and extends Xcode with the ability to handle live AST templates: [available on Mac App Store](https://apps.apple.com/us/app/sourcery-pro/id1561780836?mt=12)** https://user-images.githubusercontent.com/1468993/114271090-f6c19200-9a0f-11eb-9bd8-d7bb15129eb2.mp4 [Learn more about Sourcery Pro](http://merowing.info/sourcery-pro/) **Sourcery** is a code generator for Swift language, built on top of Apple's own SwiftSyntax. It extends the language abstractions to allow you to generate boilerplate code automatically. It's used in over 40,000 projects on both iOS and macOS and it powers some of the most popular and critically-acclaimed apps you have used (including Airbnb, Bumble, New York Times). Its massive community adoption was one of the factors that pushed Apple to implement derived Equality and automatic Codable conformance. Sourcery is maintained by a growing community of [contributors](https://github.com/krzysztofzablocki/Sourcery/graphs/contributors). Try **Sourcery** for your next project or add it to an existing one -- you'll save a lot of time and be happy you did! ## TL;DR Sourcery allows you to get rid of repetitive code and create better architecture and developer workflows. An example might be implementing `Mocks` for all your protocols, without Sourcery you will need to write **hundreds lines of code per each protocol** like this: ```swift class MyProtocolMock: MyProtocol { //MARK: - sayHelloWith var sayHelloWithNameCallsCount = 0 var sayHelloWithNameCalled: Bool { return sayHelloWithNameCallsCount > 0 } var sayHelloWithNameReceivedName: String? var sayHelloWithNameReceivedInvocations: [String] = [] var sayHelloWithNameClosure: ((String) -> Void)? func sayHelloWith(name: String) { sayHelloWithNameCallsCount += 1 sayHelloWithNameReceivedName = name sayHelloWithNameReceivedInvocations.append(name) sayHelloWithNameClosure?(name) } } ``` and with Sourcery ? ```swift extension MyProtocol: AutoMockable {} ``` Sourcery removes the need to write any of the mocks code, how many protocols do you have in your project? Imagine how much time you'll save, using Sourcery will also make every single mock consistent and if you refactor or add properties, the mock code will be automatically updated for you, eliminating possible human errors. Sourcery can be applied to arbitrary problems across your codebase, if you can describe an algorithm to another human, you can automate it using Sourcery. Most common uses are: - [Equality](https://krzysztofzablocki.github.io/Sourcery/equatable.html) & [Hashing](https://krzysztofzablocki.github.io/Sourcery/hashable.html) - [Enum cases & Counts](https://krzysztofzablocki.github.io/Sourcery/enum-cases.html) - [Lenses](https://krzysztofzablocki.github.io/Sourcery/lenses.html) - [Mocks & Stubs](https://krzysztofzablocki.github.io/Sourcery/mocks.html) - [LinuxMain](https://krzysztofzablocki.github.io/Sourcery/linuxmain.html) - [Decorators](https://krzysztofzablocki.github.io/Sourcery/decorator.html) - [Persistence and advanced Codable](https://krzysztofzablocki.github.io/Sourcery/codable.html) - [Property level diffing](https://krzysztofzablocki.github.io/Sourcery/diffable.html) But how about more specific use-cases, like automatically generating all the UI for your app `BetaSetting`? [you can use Sourcery for that too](https://github.com/krzysztofzablocki/AutomaticSettings) Once you start writing your own template and learn the power of Sourcery you won't be able to live without it. ## How To Get Started There are plenty of tutorials for different uses of Sourcery, and you can always ask for help in our [Swift Forum Category](https://forums.swift.org/c/related-projects/sourcery). - [The Magic of Sourcery](https://www.caseyliss.com/2017/3/31/the-magic-of-sourcery) is a great starting tutorial - [Generating Swift Code for iOS](https://www.raywenderlich.com/158803/sourcery-tutorial-generating-swift-code-ios) deals with JSON handling code - [How To Automate Swift Boilerplate with Sourcery](https://atomicrobot.io/blog/sourcery/) generates conversions to dictionaries - [Codable Enums](https://littlebitesofcocoa.com/318-codable-enums) implements Codable support for Enumerations - [Sourcery Workshops](https://github.com/krzysztofzablocki/SourceryWorkshops) ### Quick Mocking Intro & Getting Started Video You can also watch this quick getting started and intro to mocking video by Inside iOS Dev:
[![Watch the video](Resources/Inside-iOS-Dev-Sourcery-Intro-To-Mocking-Video-Thumbnail.png)](https://youtu.be/-ZbBNuttlt4?t=214) ## Installation - _Binary form_ Download the latest release with the prebuilt binary from [release tab](https://github.com/krzysztofzablocki/Sourcery/releases/latest). Unzip the archive into the desired destination and run `bin/sourcery` - _[Homebrew](https://brew.sh)_ `brew install sourcery` - _[CocoaPods](https://cocoapods.org)_ Add `pod 'Sourcery'` to your `Podfile` and run `pod update Sourcery`. This will download the latest release binary and will put it in your project's CocoaPods path so you will run it with `$PODS_ROOT/Sourcery/bin/sourcery` If you only want to install the `sourcery` binary, you may want to use the `CLI-Only` subspec: `pod 'Sourcery', :subspecs => ['CLI-Only']`. - _[Mint](https://github.com/yonaskolb/Mint)_ `mint run krzysztofzablocki/Sourcery` - _Building from Source_ Download the latest release source code from [the release tab](https://github.com/krzysztofzablocki/Sourcery/releases/latest) or clone the repository and build Sourcery manually. - _Building with Swift Package Manager_ Run `swift build -c release` in the root folder and then copy `.build/release/sourcery` to your desired destination. > Note: JS templates are not supported when building with SPM yet. - _Building with Xcode_ Run `xcodebuild -scheme sourcery -destination generic/platform=macOS -archivePath sourcery.xcarchive archive` and export the binary from the archive. - _SPM (for plugin use only)_ Add the package dependency to your `Package.swift` manifest from version `1.8.3`. ``` .package(url: "https://github.com/krzysztofzablocki/Sourcery.git", from: "1.8.3") ``` - _[pre-commit](https://pre-commit.com/)_ Add the dependency to `.pre-commit-config.yaml`. ``` - repo: https://github.com/krzysztofzablocki/Sourcery rev: 1.9.1 hooks: - id: sourcery ``` ## Documentation Full documentation for the latest release is available [here](https://krzysztofzablocki.github.io/Sourcery/). ## Linux Support Linux support is [described on this page](LINUX.md). ## Usage ### Running the executable Sourcery is a command line tool; you can either run it manually or in a custom build phase using the following command: ``` $ ./bin/sourcery --sources --templates --output ``` > Note: this command differs depending on how you installed Sourcery (see [Installation](#installation)) ### Swift Package command Sourcery can now be used as a Swift package command plugin. In order to do this, the package must be added as a dependency to your Swift package or Xcode project (see [Installation](#installation) above). To provide a configuration for the plugin to use, place a `.sourcery.yml` file at the root of the target's directory (in the sources folder rather than the root of the package). #### Running from the command line To verify the plugin can be found by SwiftPM, use: ``` $ swift package plugin --list ``` To run the code generator, you need to allow changes to the project with the `--allow-writing-to-package-directory` flag: ``` $ swift package --allow-writing-to-package-directory sourcery-command ``` #### Running in Xcode Inside a project/package that uses this command plugin, right-click the project and select "SourceryCommand" from the "SourceryPlugins" menu group. > ⚠️ Note that this is only available from Xcode 14 onwards. ### Command line options - `--sources` - Path to a source swift files or directories. You can provide multiple paths using multiple `--sources` option. - `--templates` - Path to templates. File or Directory. You can provide multiple paths using multiple `--templates` options. - `--force-parse` - File extensions of Sourcery generated file you want to parse. You can provide multiple extension using multiple `--force-parse` options. (i.e. `file.toparse.swift` will be parsed even if generated by Sourcery if `--force-parse toparse`). Useful when trying to implement a multiple phases generation. `--force-parse` can also be used to process within a sourcery annotation. For example to process code within `sourcery:inline:auto:Type.AutoCodable` annotation you can use `--force-parse AutoCodable` - `--output` [default: current path] - Path to output. File or Directory. - `--config` [default: current path] - Path to config file. File or Directory. See [Configuration file](#configuration-file). - `--args` - Additional arguments to pass to templates. Each argument can have an explicit value or will have implicit `true` value. Arguments should be separated with `,` without spaces (i.e. `--args arg1=value,arg2`). Arguments are accessible in templates via `argument.name` - `--watch` [default: false] - Watch both code and template folders for changes and regenerate automatically. - `--verbose` [default: false] - Turn on verbose logging - `--quiet` [default: false] - Turn off any logging, only emit errors - `--disableCache` [default: false] - Turn off caching of parsed data - `--prune` [default: false] - Prune empty generated files - `--version` - Display the current version of Sourcery - `--help` - Display help information - `--cacheBasePath` - Base path to the cache directory. Can be overriden by the config file. - `--buildPath` - Path to directory used when building from .swifttemplate files. This defaults to system temp directory - `--hideVersionHeader` [default: false] - Stop adding the Sourcery version to the generated files headers. - `--headerPrefix` - Additional prefix for headers. ### Configuration file Instead of CLI arguments, you can use a `.sourcery.yml` configuration file: ```yaml sources: - - templates: - - forceParse: - - output: args: : ``` Read more about this configuration file [here](https://krzysztofzablocki.github.io/Sourcery/usage.html#configuration-file). ## Issues If you get an unverified developer warning when using binary zip distribution try: `xattr -dr com.apple.quarantine Sourcery-1.1.1` ## Contributing Contributions to Sourcery are welcomed and encouraged! It is easy to get involved. Please see the [Contributing guide](CONTRIBUTING.md) for more details. [A list of contributors is available through GitHub](https://github.com/krzysztofzablocki/Sourcery/graphs/contributors). To clarify what is expected of our community, Sourcery has adopted the code of conduct defined by the Contributor Covenant. This document is used across many open source communities, and articulates my values well. For more, see the [Code of Conduct](CODE_OF_CONDUCT.md). ## Sponsoring If you'd like to support Sourcery development you can do so through [GitHub Sponsors](https://github.com/sponsors/krzysztofzablocki) or [Open Collective](https://opencollective.com/sourcery), it's highly appreciated 🙇‍ If you are a company and would like to sponsor the project directly and get it's logo here, you can [contact me directly](mailto:krzysztof.zablocki@pixle.pl?subject=[Sourcery-Sponsorship]) ### Sponsors [Bumble Inc](https://team.bumble.com/teams/engineering) [Airbnb Engineering](https://airbnb.io/) ## License Sourcery is available under the MIT license. See [LICENSE](LICENSE) for more information. ## Attributions This tool is powered by - [Stencil](https://github.com/kylef/Stencil) and few other libs by [Kyle Fuller](https://github.com/kylef) Thank you! to: - [Mariusz Ostrowski](http://twitter.com/faktory) for creating the logo. - [Artsy Eidolon](https://github.com/artsy/eidolon) team, because we use their codebase as a stub data for performance testing the parser. - [Olivier Halligon](https://github.com/AliSoftware) for showing me his setup scripts for CLI tools which are powering our rakefile. - [JP Simard](https://github.com/jpsim) for creating [SourceKitten](https://github.com/jpsim/SourceKitten) that originally powered Sourcery and was instrumental in making this project happen. ## Other Libraries / Tools If you want to generate code for asset related data like .xib, .storyboards etc. use [SwiftGen](https://github.com/AliSoftware/SwiftGen). SwiftGen and Sourcery are complementary tools. Make sure to check my other libraries and tools, especially: - [KZPlayground](https://github.com/krzysztofzablocki/KZPlayground) - Powerful playgrounds for Swift and Objective-C - [KZFileWatchers](https://github.com/krzysztofzablocki/KZFileWatchers) - Daemon for observing local and remote file changes, used for building other developer tools (Sourcery uses it) You can [follow me on Twitter][1] for news/updates about other projects I am creating. [1]: http://twitter.com/merowing_ ================================================ FILE: RELEASING.md ================================================ # Releasing Sourcery ## Note See https://github.com/krzysztofzablocki/Sourcery/issues/1247#issuecomment-1892571851 for the exact, step by step guide how to release a new version. # Releasing Sourcery (Deprecated) There're no hard rules about when to release Sourcery. Release bug fixes frequently, features not so frequently and breaking API changes rarely. Following the [Semantic Versioning](http://semver.org/): * Increment the third number if the release has bug fixes and/or very minor features with backward compatibility, only (eg. change `0.6.0` to `0.6.1`). * Increment the second number if the release contains major features or breaking API changes (eg. change `0.6.1` to `0.7.0`). Make sure you've been added as owner for [CocoaPods Trunk](https://guides.cocoapods.org/making/getting-setup-with-trunk.html) and have push access to the [Sourcery](https://github.com/krzysztofzablocki/Sourcery) repository. To create automatic GitHub releases, set up [API Token](https://github.com/settings/tokens/new). We recommend giving the token the smallest scope possible. This means just `public_repo`. After getting the token add the following ENV variables: ``` export SOURCERY_GITHUB_USERNAME=YOUR_GITHUB_USERNAME export SOURCERY_GITHUB_API_TOKEN=YOUR_TOKEN ``` To be able to release a [Homebrew](https://github.com/Homebrew/homebrew-core) formula update, install [brew](https://brew.sh/). ### Release Example is for releasing `0.6.1` version of the Sourcery. To release a new version of the Sourcery please rake task and follow the commands. ``` rake release:new ``` It will perform the following steps: 1. Install Bundler and CocoaPods dependencies; 2. Check if the docs are up-to-date or not; 3. Check if the master branch is green on [CI](https://circleci.com/gh/krzysztofzablocki/Sourcery); 4. Update internal boilerplate code; 5. Run tests; 6. Ask for the new release version and updates metadata for it; 7. Create a new release on [GitHub](https://github.com/krzysztofzablocki/Sourcery/releases); 8. Push new release to [CocoaPods Trunk](https://guides.cocoapods.org/making/getting-setup-with-trunk.html); 9. Push new formula to [Homebrew](https://github.com/Homebrew/homebrew-core), this will ask you for manual input of your username and password to open a GitHub PR; 10. Prepare a new development iteration. Some tasks require manual approvement or input, please pay attention to the automatic changes before confirming them. ================================================ FILE: Rakefile ================================================ #!/usr/bin/rake ## Most of this code is adapted from Sourcery https://github.com/AliSoftware/Sourcery/blob/master/Rakefile require 'pathname' require 'yaml' require 'json' require 'net/http' require 'uri' require 'rbconfig' BUILD_DIR = 'build/' CLI_DIR = 'cli/' VERSION_FILE = 'SourceryUtils/Sources/Version.swift' ## [ Utils ] ################################################################## def version_select latest_xcode_version = `xcode-select -p`.chomp %Q(DEVELOPER_DIR="#{latest_xcode_version}" TOOLCHAINS=com.apple.dt.toolchain.XcodeDefault.xctoolchain) end def xcpretty(cmd) if `which xcpretty` && $?.success? sh "set -o pipefail && #{cmd} | xcpretty -c" else sh cmd end end def print_info(str) (red,clr) = (`tput colors`.chomp.to_i >= 8) ? %W(\e[33m \e[m) : ["", ""] puts red, "== #{str.chomp} ==", clr end ## [ Bundler ] #################################################### desc "Install dependencies" task :install_dependencies do sh %Q(bundle install) end ## [ Tests & Clean ] ########################################################## desc "Run the Unit Tests on all projects" task :tests do print_info "Running Unit Tests" sh %Q(swift test) end desc "Delete the build/ directory" task :clean do print_info "Cleaning build folder" sh %Q(rm -fr build) end def build_framework(fat_library) print_info "Building project (fat: #{fat_library})" # Prepare the export directory sh %Q(rm -fr #{CLI_DIR}) sh %Q(mkdir -p "#{CLI_DIR}bin") output_path="#{CLI_DIR}bin/sourcery" if fat_library sh %Q(swift build --disable-sandbox -c release --arch arm64 --build-path #{BUILD_DIR}) sh %Q(swift build --disable-sandbox -c release --arch x86_64 --build-path #{BUILD_DIR}) sh %Q(lipo -create -output #{output_path} #{BUILD_DIR}arm64-apple-macosx/release/sourcery #{BUILD_DIR}x86_64-apple-macosx/release/sourcery) sh %Q(strip -rSTX #{output_path}) else sh %Q(swift build --disable-sandbox -c release --build-path #{BUILD_DIR}) sh %Q(cp #{BUILD_DIR}release/sourcery #{output_path}) end # Export the build products and clean up sh %Q(cp SourceryJS/Resources/ejs.js #{CLI_DIR}bin) sh %Q(rm -fr #{BUILD_DIR}) end task :build do build_framework(false) end task :fat_build do build_framework(true) end ## [ Code Generated ] ################################################ task :run_sourcery do print_info "Generating internal boilerplate code" sh "#{CLI_DIR}bin/sourcery --config .sourcery-macOS.yml" sh "#{CLI_DIR}bin/sourcery --config .sourcery-ubuntu.yml" end desc "Update internal boilerplate code" task :generate_internal_boilerplate_code => [:build, :run_sourcery] do sh "Scripts/package_content \"SourceryRuntime/Sources/Common,SourceryRuntime/Sources/macOS,SourceryRuntime/Sources/Generated\" \"true\" > \"SourcerySwift/Sources/SourceryRuntime.content.generated.swift\"" sh "Scripts/package_content \"SourceryRuntime/Sources/Common,SourceryRuntime/Sources/Linux,SourceryRuntime/Sources/Generated\" \"false\" > \"SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift\"" generated_files = `git status --porcelain` .split("\n") .select { |item| item.include?('.generated.') } .map { |item| item.split.last } manual_commit(generated_files, "update internal boilerplate code.") end ## [ Docs ] ########################################################## def clean_jazzy # jazzy divs are broken, so we need to fix them sh "find docs -type f -name '*.html' -print0 | xargs -0 -I % sh -c \"tac '%' | sed '2d' | tac > tmp && mv tmp '%';\"" end desc "Update docs" task :docs do print_info "Updating docs" temp_build_dir = "#{BUILD_DIR}tmp/" # tac Enum.html | sed '2d' | tac > Enum.html sh "bundle exec sourcekitten doc --spm --module-name SourceryRuntime > docs.json && bundle exec jazzy --clean --skip-undocumented && rm docs.json" clean_jazzy sh "rm -fr #{temp_build_dir}" end desc "Validate docs" task :validate_docs do print_info "Checking docs are up to date" temp_build_dir = "#{BUILD_DIR}tmp/" ## TODO: RA this step is disabled due to error comming only on CI and only sometimes locally: ## [1/1] Compiling plugin SourceryCommandPlugin ## Building for debugging... ## error: command /Users/art-divin/Documents/Projects/Sourcery/.build/arm64-apple-macosx/debug/Sourcery_SourceryJS.bundle/ejs.js not registered ## [1/12] Copying ejs.js ## [1/12] Compiling scanner.c ## ... #sh "bundle exec sourcekitten doc --spm --module-name SourceryRuntime -- --very-verbose > docs.json && bundle exec jazzy --skip-undocumented && rm docs.json" ## clean_jazzy sh "rm -fr #{temp_build_dir}" end ## [ Release ] ########################################################## namespace :release do desc 'Perform pre-release tasks' task :prepare => [:clean, :install_dependencies, :check_environment_variables, :check_docs, :update_metadata, :generate_internal_boilerplate_code, :tests] desc 'Build the current version and release it to GitHub, CocoaPods' task :build_and_deploy => [:check_versions, :fat_build, :tag_release, :push_to_origin, :github, :cocoapods] desc 'Create a new release on GitHub, CocoaPods' task :new => [:prepare, :build_and_deploy] def podspec_update_version(version, file = 'Sourcery.podspec') # The code is mainly taken from https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/helper/podspec_helper.rb podspec_content = File.read(file) version_var_name = 'version' version_regex = /^(?[^#]*version\s*=\s*['"])(?(?[0-9]+)(\.(?[0-9]+))?(\.(?[0-9]+))?)(?['"])/i version_match = version_regex.match(podspec_content) updated_podspec_content = podspec_content.gsub(version_regex, "#{version_match[:begin]}#{version}#{version_match[:end]}") File.open(file, "w") { |f| f.puts updated_podspec_content } end def podspec_version(file = 'Sourcery') JSON.parse(`bundle exec pod ipc spec #{file}.podspec`)["version"] end VERSION_REGEX = /(?public static let current\s*=\s*SourceryVersion\(value:\s*.*")(?(?[0-9]+)(\.(?[0-9]+))?(\.(?[0-9]+))?)(?"\))/i.freeze def command_line_tool_update_version(version, file = VERSION_FILE) version_content = File.read(file) version_match = VERSION_REGEX.match(version_content) updated_version_content = version_content.gsub(VERSION_REGEX, "#{version_match[:begin]}#{version}#{version_match[:end]}") File.open(file, "w") { |f| f.puts updated_version_content } end def command_line_tool_version(file = VERSION_FILE) version_content = File.read(file) version_match = VERSION_REGEX.match(version_content) version_match[:value] end def log_result(result, label, error_msg) if result puts "#{label.ljust(25)} \u{2705}" else puts "#{label.ljust(25)} \u{274C} - #{error_msg}" end result end def get(url, content_type = 'application/json') uri = URI.parse(url) req = Net::HTTP::Get.new(uri, initheader = {'Content-Type' => content_type}) yield req if block_given? response = Net::HTTP.start(uri.host, uri.port, :use_ssl => (uri.scheme == 'https')) do |http| http.request(req) end unless response.code == '200' puts "Error: #{response.code} - #{response.message}" puts response.body exit 3 end JSON.parse(response.body) end def post(url, content_type = 'application/json') uri = URI.parse(url) req = Net::HTTP::Post.new(uri, initheader = {'Content-Type' => content_type}) yield req if block_given? response = Net::HTTP.start(uri.host, uri.port, :use_ssl => (uri.scheme == 'https')) do |http| http.request(req) end unless response.code == '201' || response.code == '202' puts "Error: #{response.code} - #{response.message}" puts response.body exit 3 end JSON.parse(response.body) end def manual_commit(files, message) print_info "Preparing commit" system(%Q{git --no-pager diff #{files.join(" ")}}) print "Now review the above diff. Do you wish to commit the changes? [Y/n] " commit_changes = STDIN.gets.chomp == 'Y' if commit_changes then system(%Q{git add #{files.join(" ")}}) system(%Q{git commit -m '#{message}'}) else puts "Aborting commit, checkout pending changes" system(%Q{git checkout #{files.join(" ")}}) exit 2 end end def git_tag(tag) system(%Q{git tag #{tag}}) end def git_push(remote = 'origin', branch = 'master') system(%Q{git push #{remote} #{branch} --tags}) end def sourcery_targz_url(version) "https://github.com/krzysztofzablocki/Sourcery/archive/#{version}.tar.gz" end def extract_sha256(archive_url) sha256_res = `curl -L #{archive_url} | shasum -a 256` sha256 = /^[A-Fa-f0-9]+/.match(sha256_res) if sha256.nil? then print "Unable to extract SHA256" exit 3 end sha256 end desc 'Check ENV variables required for release' task :check_environment_variables do print_info "Checking ENV variables" results = [] results << log_result(!ENV['SOURCERY_GITHUB_USERNAME'].nil?, "SOURCERY_GITHUB_USERNAME is set up", "Please add SOURCERY_GITHUB_USERNAME environment variable") results << log_result(!ENV['SOURCERY_GITHUB_API_TOKEN'].nil?, "SOURCERY_GITHUB_API_TOKEN is set up", "Please add SOURCERY_GITHUB_API_TOKEN environment variable") exit 1 unless results.all? end desc 'Check if CI is green' task :check_ci do print_info "Checking Circle CI master branch status" results = [] json = get('https://circleci.com/api/v1.1/project/github/krzysztofzablocki/Sourcery/tree/master') master_branch_status = json[0]['status'] results << log_result(master_branch_status == 'success' || master_branch_status == 'fixed', 'Master branch is green on CI', 'Please check master branch CI status first') exit 1 unless results.all? end desc 'Check if docs are up to date' task :check_docs => [:validate_docs] do results = [] docs_not_changed = `git diff --name-only docs` == "" results << log_result(docs_not_changed, 'Docs are up to date', 'Please push updated docs first') exit 1 unless results.all? end desc 'Check if all versions from the podspecs, CHANGELOG and build settings match' task :check_versions do print_info "Checking versions match" results = [] # Check if bundler is installed first, as we'll need it for the cocoapods task (and we prefer to fail early) `which bundle` results << log_result( $?.success?, 'Bundler installed', 'Please install bundler using `gem install bundler` and run `bundle install` first.') # Extract version from Sourcery.podspec version = podspec_version puts "#{'Sourcery.podspec'.ljust(25)} \u{1F449} #{version}" # Check if entry present in CHANGELOG changelog_entry = system(%Q{grep -q '^## #{Regexp.quote(version)}$' CHANGELOG.md}) results << log_result(changelog_entry, "CHANGELOG, Entry added", "Please add an entry for #{version} in CHANGELOG.md") changelog_master = system(%q{grep -qi '^## Master' CHANGELOG.md}) results << log_result(!changelog_master, "CHANGELOG, No master", 'Please remove entry for master in CHANGELOG') # Check if Command Line Tool version match podspec version results << log_result(version == command_line_tool_version, "Command line tool version correct", "Please update current version in #{VERSION_FILE} to #{version}") exit 1 unless results.all? print "Release version #{version} [Y/n]? " exit 2 unless (STDIN.gets.chomp == 'Y') end desc 'Updates metadata for the new release' task :update_metadata do print "New version of Sourcery in sematic format major.minor.patch? " new_version = STDIN.gets.chomp unless new_version =~ /^\d+\.\d+\.\d+$/ then print "Please set version following the semantic format http://semver.org/\n" exit 3 end print_info "Updating metadata for #{new_version} release\n" # Replace master with the new release version in CHANGELOG.md system(%Q{sed -i '' -e 's/## Master/## #{new_version}/' CHANGELOG.md}) # Update podspec version podspec_update_version(new_version, 'Sourcery.podspec') podspec_update_version(new_version, 'SourceryFramework.podspec') podspec_update_version(new_version, 'SourceryRuntime.podspec') podspec_update_version(new_version, 'SourceryUtils.podspec') # Update command line tool version command_line_tool_update_version(new_version) manual_commit(["CHANGELOG.md", "Sourcery.podspec", "SourceryFramework.podspec", "SourceryRuntime.podspec", "SourceryUtils.podspec", VERSION_FILE], "docs: update metadata for #{new_version} release") end desc 'Create a tag for the project version and push to remote' task :tag_release do print_info "Tagging the release" git_tag(podspec_version) end desc 'Create a zip containing all the prebuilt binaries' task :zip => [:clean] do print_info "Creating zip" sh %Q(mkdir -p "build") sh %Q(mkdir -p "build/sourcery") sh %Q(mkdir -p "build/sourcery/Resources") sh %Q(cp -r #{CLI_DIR} build/sourcery/) sh %Q(cp -r Templates/Templates build/sourcery/) sh %Q(cp -r docs/docsets/Sourcery.docset build/sourcery/) `cp LICENSE README.md CHANGELOG.md build/sourcery` `cp Resources/daemon.gif Resources/icon-128.png build/sourcery/Resources` `cd build/sourcery; zip -r -X ../sourcery-#{podspec_version}.zip .` end desc 'Create a zip containing all the prebuilt binaries in the artifact bundle format (for SwiftPM Package Plugins)' task :artifactbundle => :zip do bundle_dir = 'build/sourcery.artifactbundle' bin_dir = "#{bundle_dir}/sourcery/bin" # Copy the built product to an artifact bundle `mkdir -p #{bin_dir}` `cp -Rf build/sourcery #{bin_dir}` # Write the `info.json` artifact bundle manifest info_template = File.read("Templates/artifactbundle.info.json.template") info_file_content = info_template.gsub(/(VERSION)/, podspec_version) File.open("#{bundle_dir}/info.json", "w") do |f| f.write(info_file_content) end # Zip the bundle `cd build; zip -r -X sourcery-#{podspec_version}.artifactbundle.zip sourcery.artifactbundle/` end def upload_zip(filename) upload_url = json['upload_url'].gsub(/\{.*\}/, "?name=#{filename}") zipfile = "build/#{filename}" zipsize = File.size(zipfile) print_info "Uploading ZIP (#{zipsize} bytes)" post(upload_url, 'application/zip') do |req| req.body_stream = File.open(zipfile, 'rb') req.add_field('Content-Length', zipsize) req.add_field('Content-Transfer-Encoding', 'binary') req.basic_auth ENV['SOURCERY_GITHUB_USERNAME'], ENV['SOURCERY_GITHUB_API_TOKEN'].chomp end end desc 'Upload the zipped binaries to a new GitHub release' task :github => :artifactbundle do v = podspec_version changelog = `sed -n /'^## #{v}$'/,/'^## '/p CHANGELOG.md`.gsub(/^## .*$/,'').strip print_info "Releasing version #{v} on GitHub" puts changelog json = post('https://api.github.com/repos/krzysztofzablocki/Sourcery/releases', 'application/json') do |req| req.body = { :tag_name => v, :name => v, :body => changelog, :draft => false, :prerelease => false }.to_json req.basic_auth ENV['SOURCERY_GITHUB_USERNAME'], ENV['SOURCERY_GITHUB_API_TOKEN'].chomp end upload_zip("Sourcery-#{v}.zip") upload_zip("Sourcery-#{v}.artifactbundle.zip") end desc 'pod trunk push Sourcery to CocoaPods' task :cocoapods do print_info "Pushing pod to CocoaPods Trunk" sh 'bundle exec pod trunk push Sourcery.podspec --allow-warnings --verbose --skip-tests' end desc 'Push the pending master changes to origin' task :push_to_origin do git_push end desc 'prepare for the new development iteration' task :prepare_next_development_iteration do print_info "Preparing for the next development iteration" `sed -i '' -e '3 a \\ ## Master\\ \\ \\ ' CHANGELOG.md` manual_commit(["CHANGELOG.md"], "docs: preparing for next development iteration.") end end ================================================ FILE: Scripts/SwiftLint.sh ================================================ #!/bin/zsh if which swiftlint >/dev/null; then swiftlint autocorrect swiftlint else echo "warning: SwiftLint not installed. Install using brew update && brew install swiftlint or download from https://github.com/realm/SwiftLint." fi ================================================ FILE: Scripts/bootstrap ================================================ #!/usr/bin/env bash # Usage: scripts/bootstrap # Prepares git and pods integration by providing pre-commit hook and isolated CocoaPods environment via Bundler set -eu if [ -h .git/hooks/pre-commit ]; then rm .git/hooks/pre-commit fi if [ -f .git/hooks/pre-commit ]; then echo "A git pre-commit hook already exists. Please remove it and re-run this script." fi ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit bundle install --path Vendor/bundle bundle exec pod install ================================================ FILE: Scripts/package_content ================================================ #!/usr/bin/env swift /// Usage: $0 FOLDER /// Description: /// Merge all Swift files contained in FOLDER into swift code that can be used by the FolderSynchronizer. /// Example: $0 Sources/SourceryRuntime > file.swift /// Options: /// FOLDERS: the paths where the Swift files to merge are, separated with comma "," /// isForDarwinPlatform: if true, the generated code will be compilable on Darwin platforms /// -h: Display this help message import Foundation func printUsage() { guard let scriptPath = CommandLine.arguments.first else { fatalError("Could not find script path in arguments (\(CommandLine.arguments))") } guard let lines = (try? String(contentsOfFile: scriptPath, encoding: .utf8))? .components(separatedBy: .newlines) else { fatalError("Could not read the script at path \(scriptPath)") } let documentationPrefix = "/// " lines .filter { $0.hasPrefix(documentationPrefix) } .map { $0.dropFirst(documentationPrefix.count) } .map { $0.replacingOccurrences(of: "$0", with: scriptPath) } .forEach { print("\($0)") } } extension String { func escapedSwiftTokens() -> String { // return self let replacements = [ "\\(": "\\\\(", "\\\"": "\\\\\"", "\\n": "\\\\n", ] var escapedString = self replacements.forEach { escapedString = escapedString.replacingOccurrences(of: $0, with: $1) } return escapedString } } func package(folders folderPaths: [String], isForDarwinPlatform: Bool) throws { if !isForDarwinPlatform { print("#if !canImport(ObjectiveC)") } else { print("#if canImport(ObjectiveC)") } print("let sourceryRuntimeFiles: [FolderSynchronizer.File] = [") for folderPath in folderPaths { let folderURL = URL(fileURLWithPath: folderPath) guard let enumerator = FileManager.default.enumerator(at: folderURL, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { print("Unable to retrieve file enumerator") exit(1) } var files = [URL]() for case let fileURL as URL in enumerator { do { let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey]) if fileAttributes.isRegularFile! { files.append(fileURL) } } catch { print(error, fileURL) } } try files .sorted(by: { $0.lastPathComponent < $1.lastPathComponent }) .forEach { sourceFileURL in print(" .init(name: \"\(sourceFileURL.lastPathComponent)\", content:") print("\"\"\"") let content = try String(contentsOf: sourceFileURL, encoding: .utf8) .escapedSwiftTokens() print(content) print("\"\"\"),") } } print("]") print("#endif") } func main() { if CommandLine.arguments.contains("-h") { printUsage() exit(0) } guard CommandLine.arguments.count > 1 else { print("Missing folderPath argument") exit(1) } guard CommandLine.arguments.count > 2 else { print("Missing isForDarwinPlatform argument") exit(1) } let foldersPaths = CommandLine.arguments[1] let isForDarwinPlatform = Bool(CommandLine.arguments[2]) ?? false let folders = foldersPaths.split(separator: ",").map(String.init) do { try package(folders: folders, isForDarwinPlatform: isForDarwinPlatform) } catch { print("Failed with error: \(error)") exit(1) } } main() ================================================ FILE: Scripts/pre-commit.sh ================================================ #!/usr/bin/env bash set -eu failed=0 test_pattern='\b(fdescribe|fit|fcontext|xdescribe|xit|xcontext)\b' if git diff-index -p -M --cached HEAD -- '*Tests.swift' '*Specs.swift' | grep '^+' | egrep "$test_pattern" >/dev/null 2>&1 then echo "COMMIT REJECTED for fdescribe/fit/fcontext/xdescribe/xit/xcontext." >&2 echo "Remove focused and disabled tests before committing." >&2 echo '----' >&2 git grep --cached -E "$test_pattern" '*Tests.swift' '*Specs.swift' >&2 echo '----' >&2 failed=1 fi misplaced_pattern='misplaced="YES"' if git diff-index -p -M --cached HEAD -- '*.xib' '*.storyboard' | grep '^+' | egrep "$misplaced_pattern" >/dev/null 2>&1 then echo "COMMIT REJECTED for misplaced views. Correct them before committing." >&2 echo '----' >&2 git grep --cached -E "$misplaced_pattern" '*.xib' '*.storyboard' >&2 echo '----' >&2 failed=1 fi exit $failed ================================================ FILE: Scripts/update-placeholders ================================================ #!/usr/bin/swift // // main.swift // UpdateAutogenerated // // Created by Krunoslav Zaher on 1/6/17. // Copyright © 2017 Krunoslav Zaher. All rights reserved. // import Foundation if CommandLine.argc < 2 { print("find Sourcery -name \"*.swift\" | xargs ./Scripts/update-placeholders ./Sourcery/CodeGenerated/Coding.Generated.swift") exit(-1) } let finalVersions = CommandLine.arguments[1] let targetFiles = CommandLine.arguments.dropFirst(2) func escape(_ text: String) -> String { return NSRegularExpression.escapedPattern(for: text) } extension NSString { var entireRange: NSRange { return NSRange(location: 0, length: self.length) } } func placeholderRegex(name: String) -> NSRegularExpression { let startPattern = "\(escape("//"))\\s+(\(name))\\s+\(escape("{"))" let endPattern = "\(escape("//"))\\s+\(escape("}"))\\s+(\(name))" let ignoreMiddle = "(?:(?!\(endPattern)).)*" return try! NSRegularExpression(pattern: startPattern + ignoreMiddle + endPattern, options: [.allowCommentsAndWhitespace, .dotMatchesLineSeparators]) } func placeholderNames(content: String) -> [String] { let regex = placeholderRegex(name: "\\S+") // if this cast doesn't exist, it will crash, Swift :( let nsContent = content as NSString return regex.matches(in: nsContent as String, options: [], range: nsContent.entireRange).map { match in return (content as NSString).substring(with: match.rangeAt(1)) } } extension String { func getPlaceholderValue(name: String) -> String? { let regex = placeholderRegex(name: escape(name)) let range = regex.matches(in: self, options: [], range: self.entireRange).first! return (self as NSString).substring(with: range.rangeAt(0)) } func setPlaceholder(name: String, value: String) -> String { let regex = placeholderRegex(name: escape(name)) let first = regex.matches(in: self, options: [], range: self.entireRange).first! return (self as NSString).replacingCharacters(in: first.rangeAt(0), with: value) } } let content = try! String(contentsOfFile: finalVersions) var placeholders: [String: String] = [:] for name in placeholderNames(content: content) { placeholders[name] = content.getPlaceholderValue(name: name) } var replacedPlaceholders = Set() for filePath in targetFiles { let targetFile = try! String(contentsOfFile: filePath) if targetFile.hasPrefix("// Generated using Sourcery") { continue } let finalFile = placeholderNames(content: targetFile).reduce(targetFile){ (content, name) -> String in replacedPlaceholders.insert(name) guard let value = placeholders[name] else { fatalError("\(filePath): \(name) placeholder not found") } return content.setPlaceholder(name: name, value: value) } try! finalFile.write(toFile: filePath, atomically: true, encoding: .utf8) } let notReplaced = Set(placeholders.keys).subtracting(replacedPlaceholders) if !notReplaced.isEmpty { print("We've not been able to find files to update \(notReplaced)") exit(-1) } ================================================ FILE: Sourcery/Configuration.swift ================================================ import Foundation import XcodeProj import PathKit import Yams import SourceryRuntime import Basics import TSCBasic import Workspace import PackageModel import SourceryFramework import SourceryUtils public struct Project { public let file: XcodeProj public let root: Path public let targets: [Target] public let exclude: [Path] public struct Target { public struct XCFramework { public let path: Path public let swiftInterfacePath: Path public let module: String public init(rawPath: String, relativePath: Path) throws { let frameworkRelativePath = Path(rawPath, relativeTo: relativePath) guard let framework = frameworkRelativePath.components.last else { throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected String.") } let `extension` = Path(framework).`extension` guard `extension` == "xcframework" else { throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected path to xcframework file.") } let moduleName = Path(framework).lastComponentWithoutExtension guard let simulatorSlicePath = frameworkRelativePath.glob("*") .first(where: { $0.lastComponent.contains("simulator") }) else { throw Configuration.Error.invalidXCFramework(path: frameworkRelativePath, message: "Framework path invalid. Expected to find simulator slice.") } let modulePath = simulatorSlicePath + Path("\(moduleName).framework/Modules/\(moduleName).swiftmodule/") guard let interfacePath = modulePath.glob("*.swiftinterface").first(where: { $0.lastComponent.contains("simulator") }) else { throw Configuration.Error.invalidXCFramework(path: frameworkRelativePath, message: "Framework path invalid. Expected to find .swiftinterface.") } self.path = frameworkRelativePath self.swiftInterfacePath = interfacePath self.module = moduleName } } public let name: String public let module: String public let xcframeworks: [XCFramework] public init(dict: [String: Any], relativePath: Path) throws { guard let name = dict["name"] as? String else { throw Configuration.Error.invalidSources(message: "Target name is not provided. Expected string.") } self.name = name self.module = (dict["module"] as? String) ?? name do { self.xcframeworks = try (dict["xcframeworks"] as? [String])? .map { try XCFramework(rawPath: $0, relativePath: relativePath) } ?? [] } catch let error as Configuration.Error { Log.warning(error.description) self.xcframeworks = [] } } } public init(dict: [String: Any], relativePath: Path) throws { guard let file = dict["file"] as? String else { throw Configuration.Error.invalidSources(message: "Project file path is not provided. Expected string.") } let targetsArray: [Target] if let targets = dict["target"] as? [[String: Any]] { targetsArray = try targets.map({ try Target(dict: $0, relativePath: relativePath) }) } else if let target = dict["target"] as? [String: Any] { targetsArray = try [Target(dict: target, relativePath: relativePath)] } else { throw Configuration.Error.invalidSources(message: "'target' key is missing. Expected object or array of objects.") } guard !targetsArray.isEmpty else { throw Configuration.Error.invalidSources(message: "No targets provided.") } self.targets = targetsArray let exclude = (dict["exclude"] as? [String])?.map({ Path($0, relativeTo: relativePath) }) ?? [] self.exclude = exclude.flatMap { $0.allPaths } let path = Path(file, relativeTo: relativePath) self.file = try XcodeProj(path: path) self.root = path.parent() } } public struct Paths { public let include: [Path] public let exclude: [Path] public let allPaths: [Path] public var isEmpty: Bool { return allPaths.isEmpty } public init(dict: Any, relativePath: Path) throws { if let sources = dict as? [String: [String]], let include = sources["include"]?.map({ Path($0, relativeTo: relativePath) }) { let exclude = sources["exclude"]?.map({ Path($0, relativeTo: relativePath) }) ?? [] self.init(include: include, exclude: exclude) } else if let sources = dict as? [String] { let sources = sources.map({ Path($0, relativeTo: relativePath) }) guard !sources.isEmpty else { throw Configuration.Error.invalidPaths(message: "No paths provided.") } self.init(include: sources) } else { throw Configuration.Error.invalidPaths(message: "No paths provided. Expected list of strings or object with 'include' and optional 'exclude' keys.") } } public init(include: [Path], exclude: [Path] = []) { self.include = include self.exclude = exclude let include = self.include.parallelFlatMap { $0.processablePaths } let exclude = self.exclude.parallelFlatMap { $0.processablePaths } self.allPaths = Array(Set(include).subtracting(Set(exclude))).sorted() } } extension Path { public var processablePaths: [Path] { if isDirectory { return (try? recursiveUnhiddenChildren()) ?? [] } else { return [self] } } public func recursiveUnhiddenChildren() throws -> [Path] { FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.pathKey], options: [.skipsHiddenFiles, .skipsPackageDescendants], errorHandler: nil)?.compactMap { object in if let url = object as? URL { return self + Path(url.path) } return nil } ?? [] } } public struct Package { public let root: Path public let targets: [Target] public struct Target { let name: String let root: Path let excludes: [Path] } public init(dict: [String: Any], relativePath: Path) throws { guard let packageRootPath = dict["path"] as? String else { throw Configuration.Error.invalidSources(message: "Package file directory path is not provided. Expected string.") } let path = Path(packageRootPath, relativeTo: relativePath) let packagePath = try Basics.AbsolutePath(validating: path.string) let observability = ObservabilitySystem { Log.verbose("\($0): \($1)") } let workspace = try Workspace(forRootPackage: packagePath) var manifestResult: Result? let semaphore = DispatchSemaphore(value: 0) workspace.loadRootManifest(at: packagePath, observabilityScope: observability.topScope, completion: { result in manifestResult = result semaphore.signal() }) semaphore.wait() guard let manifest = try manifestResult?.get() else { throw Configuration.Error.invalidSources(message: "Unable to load manifest") } self.root = path let targetNames: [String] if let targets = dict["target"] as? [String] { targetNames = targets } else if let target = dict["target"] as? String { targetNames = [target] } else { throw Configuration.Error.invalidSources(message: "'target' key is missing. Expected object or array of objects.") } let sourcesPath = Path("Sources", relativeTo: path) self.targets = manifest.targets.compactMap({ target in guard targetNames.contains(target.name) else { return nil } let rootPath = target.path.map { Path($0, relativeTo: path) } ?? Path(target.name, relativeTo: sourcesPath) let excludePaths = target.exclude.map { path in Path(path, relativeTo: rootPath) } return Target(name: target.name, root: rootPath, excludes: excludePaths) }) } } public enum Source { case projects([Project]) case sources(Paths) case packages([Package]) public init(dict: [String: Any], relativePath: Path) throws { if let projects = (dict["project"] as? [[String: Any]]) ?? (dict["project"] as? [String: Any]).map({ [$0] }) { guard !projects.isEmpty else { throw Configuration.Error.invalidSources(message: "No projects provided.") } self = try .projects(projects.map({ try Project(dict: $0, relativePath: relativePath) })) } else if let sources = dict["sources"] { do { self = try .sources(Paths(dict: sources, relativePath: relativePath)) } catch { throw Configuration.Error.invalidSources(message: "\(error)") } } else if let packages = (dict["package"] as? [[String: Any]]) ?? (dict["package"] as? [String: Any]).map({ [$0] }) { guard !packages.isEmpty else { throw Configuration.Error.invalidSources(message: "No packages provided.") } self = try .packages(packages.map({ try Package(dict: $0, relativePath: relativePath) })) } else if dict["child"] != nil { throw Configuration.Error.internalError(message: "'child' should have been parsed already.") } else { throw Configuration.Error.invalidSources(message: "'sources', 'project' or 'package' key are missing.") } } public var isEmpty: Bool { switch self { case let .sources(paths): return paths.allPaths.isEmpty case let .projects(projects): return projects.isEmpty case let .packages(packages): return packages.isEmpty } } } public struct Output { public struct LinkTo { public let project: XcodeProj public let projectPath: Path public let targets: [String] public let group: String? public init(dict: [String: Any], relativePath: Path) throws { guard let project = dict["project"] as? String else { throw Configuration.Error.invalidOutput(message: "No project file path provided.") } if let target = dict["target"] as? String { self.targets = [target] } else if let targets = dict["targets"] as? [String] { self.targets = targets } else { throw Configuration.Error.invalidOutput(message: "No target(s) provided.") } let projectPath = Path(project, relativeTo: relativePath) self.projectPath = projectPath self.project = try XcodeProj(path: projectPath) self.group = dict["group"] as? String } } public let path: Path public let linkTo: LinkTo? public var isDirectory: Bool { guard path.exists else { return path.lastComponentWithoutExtension == path.lastComponent || path.string.hasSuffix("/") } return path.isDirectory } public init(dict: [String: Any], relativePath: Path) throws { guard let path = dict["path"] as? String else { throw Configuration.Error.invalidOutput(message: "No path provided.") } self.path = Path(path, relativeTo: relativePath) if let linkToDict = dict["link"] as? [String: Any] { do { self.linkTo = try LinkTo(dict: linkToDict, relativePath: relativePath) } catch { self.linkTo = nil Log.warning(error) } } else { self.linkTo = nil } } public init(_ path: Path, linkTo: LinkTo? = nil) { self.path = path self.linkTo = linkTo } } public struct Configuration { public enum Error: Swift.Error, CustomStringConvertible { case invalidFormat(message: String) case invalidSources(message: String) case invalidXCFramework(path: Path? = nil, message: String) case invalidTemplates(message: String) case invalidOutput(message: String) case invalidCacheBasePath(message: String) case invalidPaths(message: String) case internalError(message: String) public var description: String { switch self { case .invalidFormat(let message): return "Invalid config file format. \(message)" case .invalidSources(let message): return "Invalid sources. \(message)" case .invalidXCFramework(let path, let message): return "Invalid xcframework\(path.map { " at path '\($0)'" } ?? "")'. \(message)" case .invalidTemplates(let message): return "Invalid templates. \(message)" case .invalidOutput(let message): return "Invalid output. \(message)" case .invalidCacheBasePath(let message): return "Invalid cacheBasePath. \(message)" case .invalidPaths(let message): return "\(message)" case .internalError(let message): return "\(message)" } } } public let source: Source public let templates: Paths public let output: Output public let cacheBasePath: Path public let forceParse: [String] public let parseDocumentation: Bool public let baseIndentation: Int public let args: [String: NSObject] public init( path: Path, relativePath: Path, env: [String: String] = [:] ) throws { guard let dict = try Yams.load(yaml: path.read(), .default, Constructor.sourceryContructor(env: env)) as? [String: Any] else { throw Configuration.Error.invalidFormat(message: "Expected dictionary.") } try self.init(dict: dict, relativePath: relativePath) } public init(dict: [String: Any], relativePath: Path) throws { let source = try Source(dict: dict, relativePath: relativePath) guard !source.isEmpty else { throw Configuration.Error.invalidSources(message: "No sources provided.") } self.source = source let templates: Paths guard let templatesDict = dict["templates"] else { throw Configuration.Error.invalidTemplates(message: "'templates' key is missing.") } do { templates = try Paths(dict: templatesDict, relativePath: relativePath) } catch { throw Configuration.Error.invalidTemplates(message: "\(error)") } guard !templates.isEmpty else { throw Configuration.Error.invalidTemplates(message: "No templates provided.") } self.templates = templates self.forceParse = dict["forceParse"] as? [String] ?? [] self.parseDocumentation = dict["parseDocumentation"] as? Bool ?? false if let output = dict["output"] as? String { self.output = Output(Path(output, relativeTo: relativePath)) } else if let output = dict["output"] as? [String: Any] { self.output = try Output(dict: output, relativePath: relativePath) } else { throw Configuration.Error.invalidOutput(message: "'output' key is missing or is not a string or object.") } if let cacheBasePath = dict["cacheBasePath"] as? String { self.cacheBasePath = Path(cacheBasePath, relativeTo: relativePath) } else if dict["cacheBasePath"] != nil { throw Configuration.Error.invalidCacheBasePath(message: "'cacheBasePath' key is not a string.") } else { self.cacheBasePath = Path.defaultBaseCachePath } self.baseIndentation = dict["baseIndentation"] as? Int ?? 0 self.args = dict["args"] as? [String: NSObject] ?? [:] } public init(sources: Paths, templates: Paths, output: Path, cacheBasePath: Path, forceParse: [String], parseDocumentation: Bool, baseIndentation: Int, args: [String: NSObject]) { self.source = .sources(sources) self.templates = templates self.output = Output(output, linkTo: nil) self.cacheBasePath = cacheBasePath self.forceParse = forceParse self.parseDocumentation = parseDocumentation self.baseIndentation = baseIndentation self.args = args } } public enum Configurations { public static func make( path: Path, relativePath: Path, env: [String: String] = [:] ) throws -> [Configuration] { guard let dict = try Yams.load(yaml: path.read(), .default, Constructor.sourceryContructor(env: env)) as? [String: Any] else { throw Configuration.Error.invalidFormat(message: "Expected dictionary.") } let start = currentTimestamp() defer { Log.benchmark("Resolving configurations took \(currentTimestamp() - start)") } if let configurations = dict["configurations"] as? [[String: Any]] { return try configurations.flatMap { dict in if let child = dict["child"] as? String { let childPath = Path(child, relativeTo: relativePath) let childRelativePath = Path(components: childPath.components.dropLast()) return try Configurations.make(path: childPath, relativePath: childRelativePath, env: env) } else { return try [Configuration(dict: dict, relativePath: relativePath)] } } } else { return try [Configuration(dict: dict, relativePath: relativePath)] } } } // Copied from https://github.com/realm/SwiftLint/blob/0.29.2/Source/SwiftLintFramework/Models/YamlParser.swift // and https://github.com/SwiftGen/SwiftGen/blob/6.1.0/Sources/SwiftGenKit/Utils/YAML.swift private extension Constructor { static func sourceryContructor(env: [String: String]) -> Constructor { return Constructor(customScalarMap(env: env)) } static func customScalarMap(env: [String: String]) -> ScalarMap { var map = defaultScalarMap map[.str] = String.constructExpandingEnvVars(env: env) return map } } private extension String { static func constructExpandingEnvVars(env: [String: String]) -> (_ scalar: Node.Scalar) -> String? { return { (scalar: Node.Scalar) -> String? in scalar.string.expandingEnvVars(env: env) } } func expandingEnvVars(env: [String: String]) -> String? { // check if entry has an env variable guard let match = self.range(of: #"\$\{(.)\w+\}"#, options: .regularExpression) else { return self } // get the env variable as "${ENV_VAR}" let key = String(self[match]) // get the env variable as "ENV_VAR" - note missing $ and brackets let keyString = String(key[2..) -> SubSequence { let start = index(startIndex, offsetBy: bounds.lowerBound) let end = index(start, offsetBy: bounds.count) return self[start..) -> SubSequence { let start = index(startIndex, offsetBy: bounds.lowerBound) let end = index(start, offsetBy: bounds.count) return self[start.. String { return try render(context.jsContext) } } private extension JSContext { // this will catch errors accessing types through wrong collections (i.e. using `implementing` instead of `based`) func catchTypesAccessErrors() { let valueForKey: @convention(block) (TypesCollection, String) -> Any? = { target, key in do { return try target.types(forKey: key) } catch { JSContext.current().evaluateScript("throw \"\(error)\"") return nil } } setObject(valueForKey, forKeyedSubscript: "valueForKey" as NSString) evaluateScript("templateContext.types.implementing = new Proxy(templateContext.types.implementing, { get: valueForKey })") evaluateScript("templateContext.types.inheriting = new Proxy(templateContext.types.inheriting, { get: valueForKey })") evaluateScript("templateContext.types.based = new Proxy(templateContext.types.based, { get: valueForKey })") } // this will catch errors when accessing context types properties (i.e. using `implements` instead of `implementing`) func catchTemplateContextTypesUnknownProperties() { evaluateScript(""" templateContext.types = new Proxy(templateContext.types, { get(target, propertyKey, receiver) { if (!(propertyKey in target)) { throw new TypeError('Unknown property `'+propertyKey+'`'); } // Make sure we don’t block access to Object.prototype return Reflect.get(target, propertyKey, receiver); } }); """) } } #endif ================================================ FILE: Sourcery/Generating/Templates/Stencil/StencilTemplate.swift ================================================ import Foundation import SourceryFramework import SourceryRuntime import SourceryStencil extension StencilTemplate: SourceryFramework.Template { public func render(_ context: TemplateContext) throws -> String { do { return try self.render(context.stencilContext) } catch { throw "\(sourcePath): \(error)" } } } ================================================ FILE: Sourcery/Generating/Templates/Swift/SwiftTemplate.swift ================================================ // // SwiftTemplate.swift // Sourcery // // Created by Krunoslav Zaher on 12/30/16. // Copyright © 2016 Pixle. All rights reserved. // import Foundation import SourceryFramework import SourceryRuntime import SourcerySwift extension SwiftTemplate: Template { public func render(_ context: TemplateContext) throws -> String { return try self.render(context as Any) } } ================================================ FILE: Sourcery/Sourcery.swift ================================================ // // Created by Krzysztof Zablocki on 14/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import PathKit import SourceryFramework import SourceryUtils import SourceryRuntime import SourceryJS import SourcerySwift import SourceryStencil #if canImport(ObjectiveC) import TryCatch #endif import XcodeProj public class Sourcery { public static let version: String = SourceryVersion.current.value public static let generationMarker: String = "// Generated using Sourcery" public let generationHeader: String enum Error: Swift.Error { case containsMergeConflictMarkers } fileprivate let verbose: Bool fileprivate let watcherEnabled: Bool fileprivate let arguments: [String: NSObject] fileprivate let cacheDisabled: Bool fileprivate let cacheBasePath: Path? fileprivate let buildPath: Path? fileprivate let prune: Bool fileprivate let serialParse: Bool fileprivate let hideVersionHeader: Bool fileprivate var status = "" fileprivate var templatesPaths = Paths(include: []) fileprivate var outputPath = Output("", linkTo: nil) fileprivate var isDryRun: Bool = false fileprivate lazy var dryOutputBuffer = [DryOutputValue]() internal var dryOutput: (String) -> Void = Log.output(_:) // content annotated with file annotations per file path to write it to fileprivate var fileAnnotatedContent: [Path: [String]] = [:] /// Creates Sourcery processor public init( verbose: Bool = false, watcherEnabled: Bool = false, cacheDisabled: Bool = false, cacheBasePath: Path? = nil, buildPath: Path? = nil, prune: Bool = false, serialParse: Bool = false, hideVersionHeader: Bool = false, arguments: [String: NSObject] = [:], logConfiguration: Log.Configuration? = nil, headerPrefix: String? = nil ) { self.verbose = verbose self.arguments = arguments self.watcherEnabled = watcherEnabled self.cacheDisabled = cacheDisabled self.cacheBasePath = cacheBasePath self.buildPath = buildPath self.prune = prune self.serialParse = serialParse if let hideVersionHeader = arguments["hideVersionHeader"] { self.hideVersionHeader = (hideVersionHeader as? NSNumber)?.boolValue == true } else { self.hideVersionHeader = hideVersionHeader } if let logConfiguration { Log.setup(using: logConfiguration) } var prefix = "" if let headerPrefix { prefix += headerPrefix + "\n" } prefix += Sourcery.generationMarker if !self.hideVersionHeader { prefix += " \(Sourcery.version)" } self.generationHeader = "\(prefix) — https://github.com/krzysztofzablocki/Sourcery\n" + "// DO NOT EDIT\n" } /// Processes source files and generates corresponding code. /// /// - Parameters: /// - files: Path of files to process, can be directory or specific file. /// - templatePath: Specific Template to use for code generation. /// - output: Path to output source code to. /// - forceParse: extensions of generated sourcery file that can be parsed /// - watcherEnabled: Whether daemon watcher should be enabled. /// - Throws: Potential errors. public func processFiles(_ source: Source, usingTemplates templatesPaths: Paths, output: Output, isDryRun: Bool = false, forceParse: [String] = [], parseDocumentation: Bool = false, baseIndentation: Int) throws -> [FolderWatcher.Local]? { self.templatesPaths = templatesPaths self.outputPath = output self.isDryRun = isDryRun let hasSwiftTemplates = templatesPaths.allPaths.contains(where: { $0.extension == "swifttemplate" }) let watchPaths: Paths switch source { case let .sources(paths): watchPaths = paths case let .projects(projects): watchPaths = Paths(include: projects.map(\.root), exclude: projects.flatMap(\.exclude)) case let .packages(packages): watchPaths = Paths(include: packages.flatMap({ $0.targets.map(\.root) }), exclude: packages.flatMap({ $0.targets.flatMap(\.excludes) })) } let process: (Source) throws -> ParsingResult = { source in var result: ParsingResult switch source { case let .sources(paths): result = try self.parse(from: paths.include, exclude: paths.exclude, forceParse: forceParse, parseDocumentation: parseDocumentation, modules: nil, requiresFileParserCopy: hasSwiftTemplates) case let .projects(projects): var paths: [Path] = [] var modules = [String]() projects.forEach { project in project.targets.forEach { target in guard let projectTarget = project.file.target(named: target.name) else { return } let files: [Path] = project.file.sourceFilesPaths(target: projectTarget, sourceRoot: project.root) files.forEach { file in guard !project.exclude.contains(file) else { return } paths.append(file) modules.append(target.module) } for framework in target.xcframeworks { paths.append(framework.swiftInterfacePath) modules.append(framework.module) } } } result = try self.parse(from: paths, forceParse: forceParse, parseDocumentation: parseDocumentation, modules: modules, requiresFileParserCopy: hasSwiftTemplates) case let .packages(packages): let paths: [Path] = packages.flatMap({ $0.targets.map(\.root) }) let excludePaths: [Path] = packages.flatMap({ $0.targets.flatMap(\.excludes) }) let modules = packages.flatMap({ $0.targets.map(\.name) }) result = try self.parse(from: paths, exclude: excludePaths, forceParse: forceParse, parseDocumentation: parseDocumentation, modules: modules, requiresFileParserCopy: hasSwiftTemplates) } try self.generate(source: source, templatePaths: templatesPaths, output: output, parsingResult: &result, forceParse: forceParse, baseIndentation: baseIndentation) return result } var result = try process(source) if isDryRun { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data: Data = try encoder.encode(DryOutputSuccess(outputs: self.dryOutputBuffer)) self.dryOutput(String(data: data, encoding: .utf8) ?? "") } guard watcherEnabled else { return nil } Log.info("Starting watching sources.") #if canImport(ObjectiveC) let sourceWatchers = topPaths(from: watchPaths.allPaths).map({ watchPath in return FolderWatcher.Local(path: watchPath.string) { events in let eventPaths: [Path] = events .filter { $0.flags.contains(.isFile) } .compactMap { let path = Path($0.path) return path.isSwiftSourceFile ? path : nil } var pathThatForcedRegeneration: Path? for path in eventPaths { guard let file = try? path.read(.utf8) else { continue } if !file.hasPrefix(Sourcery.generationMarker) { pathThatForcedRegeneration = path break } } if let path = pathThatForcedRegeneration { do { Log.info("Source changed at \(path.string)") result = try process(source) } catch { Log.error(error) } } } }) Log.info("Starting watching templates.") let templateWatchers = topPaths(from: templatesPaths.allPaths).map({ templatesPath in return FolderWatcher.Local(path: templatesPath.string) { events in let events = events .filter { $0.flags.contains(.isFile) && Path($0.path).isTemplateFile } if !events.isEmpty { do { if events.count == 1 { Log.info("Template changed \(events[0].path)") } else { Log.info("Templates changed: ") } try self.generate(source: source, templatePaths: Paths(include: [templatesPath]), output: output, parsingResult: &result, forceParse: forceParse, baseIndentation: baseIndentation) } catch { Log.error(error) } } } }) return Array([sourceWatchers, templateWatchers].joined()) #else return [] #endif } private func topPaths(from paths: [Path]) -> [Path] { var top: [(Path, [Path])] = [] paths.forEach { path in // See if its already contained by the topDirectories guard top.first(where: { (_, children) -> Bool in return children.contains(path) }) == nil else { return } if path.isDirectory { top.append((path, (try? path.recursiveUnhiddenChildren()) ?? [])) } else { let dir = path.parent() let children = (try? dir.recursiveUnhiddenChildren()) ?? [] if children.contains(path) { top.append((dir, children)) } else { top.append((path, [])) } } } return top.map { $0.0 } } /// This function should be used to retrieve the path to the cache instead of `Path.cachesDir`, /// as it considers the `--cacheDisabled` and `--cacheBasePath` command line parameters. fileprivate func cachesDir(sourcePath: Path, createIfMissing: Bool = true) -> Path? { return cacheDisabled ? nil : Path.cachesDir(sourcePath: sourcePath, basePath: cacheBasePath, createIfMissing: createIfMissing) } /// Remove the existing cache artifacts if it exists. /// Currently this is only called from tests, and the `--cacheDisabled` and `--cacheBasePath` command line parameters are not considered. /// /// - Parameter sources: paths of the sources you want to delete the static func removeCache(for sources: [Path], cacheDisabled: Bool = false, cacheBasePath: Path? = nil) { if cacheDisabled { return } sources.forEach { path in let cacheDir = Path.cachesDir(sourcePath: path, basePath: cacheBasePath, createIfMissing: false) _ = try? cacheDir.delete() } } private func templatePaths(from: Paths) -> [Path] { return from.allPaths.filter { $0.isTemplateFile } } } #if canImport(ObjectiveC) private extension Sourcery { func templates(from: Paths) throws -> [Template] { return try templatePaths(from: from).compactMap { if $0.extension == "sourcerytemplate" { let template = try JSONDecoder().decode(SourceryTemplate.self, from: $0.read()) switch template.instance.kind { case .ejs: guard let ejsPath = EJSTemplate.ejsPath else { Log.warning("Skipping template \($0). JavaScript templates require EJS path to be set manually when using Sourcery built with Swift Package Manager. Use `--ejsPath` command line argument to set it.") return nil } return try JavaScriptTemplate(path: $0, templateString: template.instance.content, ejsPath: ejsPath) case .stencil: return try StencilTemplate(path: $0, templateString: template.instance.content) } } else if $0.extension == "swifttemplate" { let cachePath = cachesDir(sourcePath: $0) return try SwiftTemplate(path: $0, cachePath: cachePath, version: type(of: self).version, buildPath: buildPath) } else if $0.extension == "ejs" { guard let ejsPath = EJSTemplate.ejsPath else { Log.warning("Skipping template \($0). JavaScript templates require EJS path to be set manually when using Sourcery built with Swift Package Manager. Use `--ejsPath` command line argument to set it.") return nil } return try JavaScriptTemplate(path: $0, ejsPath: ejsPath) } else { return try StencilTemplate(path: $0) } } } } #else private extension Sourcery { func templates(from: Paths) throws -> [Template] { return try templatePaths(from: from).compactMap { if $0.extension == "sourcerytemplate" { let template = try JSONDecoder().decode(SourceryTemplate.self, from: $0.read()) return try StencilTemplate(path: $0, templateString: template.instance.content) } else if $0.extension == "swifttemplate" { let cachePath = cachesDir(sourcePath: $0) return try SwiftTemplate(path: $0, cachePath: cachePath, version: type(of: self).version, buildPath: buildPath) } else { return try StencilTemplate(path: $0) } } } } #endif // MARK: - Parsing extension Sourcery { typealias ParsingResult = ( parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], inlineRanges: [(file: String, ranges: [String: NSRange], indentations: [String: String])]) typealias ParserWrapper = (path: Path, parse: () throws -> FileParserResult?) fileprivate func parse(from: [Path], exclude: [Path] = [], forceParse: [String] = [], parseDocumentation: Bool, modules: [String]?, requiresFileParserCopy: Bool) throws -> ParsingResult { if let modules = modules { precondition(from.count == modules.count, "There should be module for each file to parse") } let startScan = currentTimestamp() Log.info("Scanning sources...") var inlineRanges = [(file: String, ranges: [String: NSRange], indentations: [String: String])]() var allResults = [(changed: Bool, result: FileParserResult)]() let excludeSet = Set(exclude .map { $0.processablePaths } .compactMap({ $0 }).flatMap({ $0 })) try from.enumerated().forEach { index, from in let fileList = from.processablePaths let parserGenerator: [ParserWrapper] = fileList .filter { $0.isSwiftSourceFile } .filter { return !excludeSet.contains($0) } .map { path in return (path: path, parse: { let module = modules?[index] guard path.exists else { return nil } let content = try path.read(.utf8) let status = Verifier.canParse(content: content, path: path, generationMarker: Sourcery.generationMarker, forceParse: forceParse) switch status { case .containsConflictMarkers: throw Error.containsMergeConflictMarkers case .isCodeGenerated: return nil case .approved: return try makeParser(for: content, forceParse: forceParse, parseDocumentation: parseDocumentation, path: path, module: module).parse() } }) } var lastError: Swift.Error? let transform: (ParserWrapper) -> (changed: Bool, result: FileParserResult)? = { parser in do { return try self.loadOrParse(parser: parser, cachesPath: self.cachesDir(sourcePath: from)) } catch { lastError = error Log.error("Unable to parse \(parser.path), error \(error)") return nil } } let results: [(changed: Bool, result: FileParserResult)] if serialParse { results = parserGenerator.compactMap(transform) } else { results = parserGenerator.parallelCompactMap(transform: transform) } if let error = lastError { throw error } if !results.isEmpty { allResults.append(contentsOf: results) } } Log.benchmark("\tloadOrParse: \(currentTimestamp() - startScan)") let reduceStart = currentTimestamp() var allTypealiases = [Typealias]() var allTypes = [Type]() var allFunctions = [SourceryMethod]() for pair in allResults { let next = pair.result allTypealiases += next.typealiases allTypes += next.types allFunctions += next.functions // swiftlint:disable:next force_unwrapping inlineRanges.append((next.path!, next.inlineRanges, next.inlineIndentations)) } let parserResult = FileParserResult(path: nil, module: nil, types: allTypes, functions: allFunctions, typealiases: allTypealiases) var parserResultCopy: FileParserResult? if requiresFileParserCopy { let data = try NSKeyedArchiver.archivedData(withRootObject: parserResult, requiringSecureCoding: false) parserResultCopy = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? FileParserResult } let uniqueTypeStart = currentTimestamp() // ! All files have been scanned, time to join extensions with base class let (types, functions, typealiases) = Composer.uniqueTypesAndFunctions(parserResult, serial: serialParse) let filesThatHadToBeParsed = allResults .filter { $0.changed } .compactMap { $0.result.path } Log.benchmark("\treduce: \(uniqueTypeStart - reduceStart)\n\tcomposer: \(currentTimestamp() - uniqueTypeStart)\n\ttotal: \(currentTimestamp() - startScan)") Log.info("Found \(types.count) types in \(allResults.count) files, \(filesThatHadToBeParsed.count) changed from last run.") if !filesThatHadToBeParsed.isEmpty, (filesThatHadToBeParsed.count < 50 || Log.level == .verbose) { let files = filesThatHadToBeParsed .joined(separator: "\n") Log.info("Files changed:\n\(files)") } return (parserResultCopy, Types(types: types, typealiases: typealiases), functions, inlineRanges) } private func loadOrParse(parser: ParserWrapper, cachesPath: @autoclosure () -> Path?) throws -> (changed: Bool, result: FileParserResult)? { guard let cachesPath = cachesPath() else { return try parser.parse().map { (changed: true, result: $0) } } let path = parser.path let artifactsPath = cachesPath + "\(path.string.sha256()?.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "\(path.string.hash)").srf" guard artifactsPath.exists, let modifiedDate = path.modifiedDate, let unarchived = load(artifacts: artifactsPath.string, modifiedDate: modifiedDate, path: path) else { guard let result = try parser.parse() else { return nil } do { let data = try NSKeyedArchiver.archivedData(withRootObject: result, requiringSecureCoding: false) try artifactsPath.write(data) } catch { fatalError("Unable to save artifacts for \(path) under \(artifactsPath), error: \(error)") } return (changed: true, result: result) } return (changed: false, result: unarchived) } private func load(artifacts: String, modifiedDate: Date, path: Path) -> FileParserResult? { var unarchivedResult: FileParserResult? #if canImport(ObjectiveC) SwiftTryCatch.try({ // this deprecation can't be removed atm, new API is 10x slower if let unarchived = NSKeyedUnarchiver.unarchiveObject(withFile: artifacts) as? FileParserResult { if unarchived.sourceryVersion == Sourcery.version, unarchived.modifiedDate == modifiedDate { unarchivedResult = unarchived } } }, catch: { _ in Log.warning("Failed to unarchive cache for \(path.string) due to error, re-parsing file") }, finallyBlock: {}) #else // this deprecation can't be removed atm, new API is 10x slower if let unarchived = NSKeyedUnarchiver.unarchiveObject(withFile: artifacts) as? FileParserResult { if unarchived.sourceryVersion == Sourcery.version, unarchived.modifiedDate == modifiedDate { unarchivedResult = unarchived } } #endif return unarchivedResult } } // MARK: - Generation extension Sourcery { private typealias SourceChange = (path: String, rangeInFile: NSRange, newRangeInFile: NSRange) private typealias GenerationResult = (String, [SourceChange]) fileprivate func generate(source: Source, templatePaths: Paths, output: Output, parsingResult: inout ParsingResult, forceParse: [String], baseIndentation: Int) throws { let generationStart = currentTimestamp() Log.info("Loading templates...") let allTemplates = try templates(from: templatePaths) Log.info("Loaded \(allTemplates.count) templates.") Log.benchmark("\tLoading took \(currentTimestamp() - generationStart)") Log.info("Generating code...") status = "" if output.isDirectory { try allTemplates.forEach { template in let (result, sourceChanges) = try generate(template, forParsingResult: parsingResult, outputPath: output.path, forceParse: forceParse, baseIndentation: baseIndentation) updateRanges(in: &parsingResult, sourceChanges: sourceChanges) let outputPath = output.path + generatedPath(for: template.sourcePath) let isEmptyFile = result.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty let willSkipResultFile = prune && isEmptyFile try self.output(type: .template(template.sourcePath.string), result: result, to: outputPath, isEmptyFile: isEmptyFile) if !isDryRun, !willSkipResultFile, let linkTo = output.linkTo { linkTo.targets.forEach { target in link(outputPath, to: linkTo, target: target) } } } } else { let result = try allTemplates.reduce((contents: "", parsingResult: parsingResult)) { state, template in var (result, parsingResult) = state let (generatedCode, sourceChanges) = try generate(template, forParsingResult: parsingResult, outputPath: output.path, forceParse: forceParse, baseIndentation: baseIndentation) result += "\n" + generatedCode updateRanges(in: &parsingResult, sourceChanges: sourceChanges) return (result, parsingResult) } parsingResult = result.parsingResult let isEmptyFile = result.contents.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty let willSkipResultFile = prune && isEmptyFile try self.output(type: .allTemplates, result: result.contents, to: output.path, isEmptyFile: isEmptyFile) if !isDryRun, !willSkipResultFile, let linkTo = output.linkTo { linkTo.targets.forEach { target in link(output.path, to: linkTo, target: target) } } } try fileAnnotatedContent.forEach { (path, contents) in let result = contents.joined(separator: "\n") let isEmptyFile = result.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty let willSkipResultFile = prune && isEmptyFile try self.output(type: .path(path.string), result: result, to: path, isEmptyFile: isEmptyFile) if !isDryRun, !willSkipResultFile, let linkTo = output.linkTo { linkTo.targets.forEach { target in link(path, to: linkTo, target: target) } } } if !isDryRun, let linkTo = output.linkTo { try linkTo.project.writePBXProj(path: linkTo.projectPath, outputSettings: .init()) } Log.benchmark("\tGeneration took \(currentTimestamp() - generationStart)") Log.info("Finished.") } private func updateRanges(in parsingResult: inout ParsingResult, sourceChanges: [SourceChange]) { for (path, rangeInFile, newRangeInFile) in sourceChanges { if let inlineRangesIndex = parsingResult.inlineRanges.firstIndex(where: { $0.file == path }) { let inlineRanges = parsingResult.inlineRanges[inlineRangesIndex].ranges .mapValues { inlineRange -> NSRange in let change = NSRange( location: newRangeInFile.location, length: newRangeInFile.length - rangeInFile.length ) return inlineRange.changingContent(change) } parsingResult.inlineRanges[inlineRangesIndex].ranges = inlineRanges } func stringViewForContent(at path: String) -> StringView? { do { return StringView(try Path(path).read(.utf8)) } catch { return nil } } for type in parsingResult.types.types { guard type.path == path, let bytesRange = type.bodyBytesRange, let completeDeclarationRange = type.completeDeclarationRange, let content = stringViewForContent(at: path), let byteRangeInFile = content.NSRangeToByteRange(rangeInFile), let newByteRangeInFile = content.NSRangeToByteRange(newRangeInFile) else { continue } let change = ByteRange( location: newByteRangeInFile.location, length: newByteRangeInFile.length - byteRangeInFile.length ) type.bodyBytesRange = bytesRange.changingContent(change) type.completeDeclarationRange = completeDeclarationRange.changingContent(change) } } } private func link(_ output: Path, to linkTo: Output.LinkTo, target targetName: String) { guard let target = linkTo.project.target(named: targetName) else { Log.warning("Unable to find target \(targetName)") return } let sourceRoot = linkTo.projectPath.parent() guard let fileGroup = linkTo.project.createGroupIfNeeded(named: linkTo.group, sourceRoot: sourceRoot) else { Log.warning("Unable to create group \(String(describing: linkTo.group))") return } do { try linkTo.project.addSourceFile(at: output, toGroup: fileGroup, target: target, sourceRoot: sourceRoot) } catch { Log.warning("Failed to link file at \(output) to \(linkTo.projectPath). \(error)") } } private func output(type: DryOutputType, result: consuming String, to outputPath: Path, isEmptyFile: Bool) throws { var result = result if !isEmptyFile, outputPath.extension == "swift" { result = generationHeader + result } if isDryRun { dryOutputBuffer.append(.init(type: type, outputPath: outputPath.string, value: result)) return } if !isEmptyFile { if !outputPath.parent().exists { try outputPath.parent().mkpath() } try writeIfChanged(result, to: outputPath) } else { if prune && outputPath.exists { Log.verbose("Removing \(outputPath) as it is empty.") do { try outputPath.delete() } catch { Log.error("\(error)") } } else { Log.verbose("Skipping \(outputPath) as it is empty.") } } } private func output(range: NSRange, in file: String, insertedContent: String, updatedContent: @autoclosure () -> String, to path: Path) throws { if isDryRun { dryOutputBuffer.append(.init(type: .range(range, in: file), outputPath: path.string, value: insertedContent)) return } try writeIfChanged(updatedContent(), to: path) } private func generate(_ template: Template, forParsingResult parsingResult: ParsingResult, outputPath: Path, forceParse: [String], baseIndentation: Int) throws -> GenerationResult { guard watcherEnabled else { let generationStart = currentTimestamp() let result = try Generator.generate(parsingResult.parserResult, types: parsingResult.types, functions: parsingResult.functions, template: template, arguments: self.arguments) Log.benchmark("\tGenerating \(template.sourcePath.lastComponent) took \(currentTimestamp() - generationStart)") return try processRanges(in: parsingResult, result: result, outputPath: outputPath, forceParse: forceParse, baseIndentation: baseIndentation) } var result: String = "" #if canImport(ObjectiveC) SwiftTryCatch.try({ do { result = try Generator.generate(parsingResult.parserResult, types: parsingResult.types, functions: parsingResult.functions, template: template, arguments: self.arguments) } catch { Log.error(error) } }, catch: { error in result = error?.description ?? "" }, finallyBlock: {}) #else do { result = try Generator.generate(parsingResult.parserResult, types: parsingResult.types, functions: parsingResult.functions, template: template, arguments: self.arguments) } catch { Log.error(error) } #endif return try processRanges(in: parsingResult, result: result, outputPath: outputPath, forceParse: forceParse, baseIndentation: baseIndentation) } private func processRanges(in parsingResult: ParsingResult, result: String, outputPath: Path, forceParse: [String], baseIndentation: Int) throws -> GenerationResult { let start = currentTimestamp() defer { Log.benchmark("\t\tProcessing Ranges took \(currentTimestamp() - start)") } var result = result result = processFileRanges(for: parsingResult, in: result, outputPath: outputPath, forceParse: forceParse) let sourceChanges: [SourceChange] (result, sourceChanges) = try processInlineRanges(for: parsingResult, in: result, forceParse: forceParse, baseIndentation: baseIndentation) return (TemplateAnnotationsParser.removingEmptyAnnotations(from: result), sourceChanges) } private func processInlineRanges(`for` parsingResult: ParsingResult, in contents: String, forceParse: [String], baseIndentation: Int) throws -> GenerationResult { var (annotatedRanges, rangesToReplace) = TemplateAnnotationsParser.annotationRanges("inline", contents: contents, forceParse: forceParse) typealias MappedInlineAnnotations = ( range: NSRange, filePath: String, rangeInFile: NSRange, toInsert: String, indentation: String ) var sourceChanges: [SourceChange] = [] try annotatedRanges .map { (key: $0, range: $1[0].range) } .compactMap { (key, range) -> MappedInlineAnnotations? in let generatedBody = contents.bridge().substring(with: range) if let (filePath, inlineRanges, inlineIndentations) = parsingResult.inlineRanges.first(where: { $0.ranges[key] != nil }) { // swiftlint:disable:next force_unwrapping return MappedInlineAnnotations(range, filePath, inlineRanges[key]!, generatedBody, inlineIndentations[key] ?? "") } guard let autoRange = key.range(of: "auto:") else { rangesToReplace.remove(range) return nil } enum AutoType: String { case after = "after-" case normal = "" } let autoKey = key[.. rhs.rangeInFile.location }.forEach { (arg) in let (_, filePath, rangeInFile, toInsert, indentation) = arg let path = Path(filePath) let content = try path.read(.utf8) let newContent = indent(toInsert: toInsert, indentation: indentation) try output(range: rangeInFile, in: filePath, insertedContent: newContent, updatedContent: content.bridge().replacingCharacters(in: rangeInFile, with: newContent), to: path) let newLength = newContent.bridge().length sourceChanges.append(( path: filePath, rangeInFile: rangeInFile, newRangeInFile: NSRange(location: rangeInFile.location, length: newLength) )) } var bridged = contents.bridge() if isDryRun { // fix file ranges, cause they not changed sourceChanges = sourceChanges.map{ (path, rangeInFile, newRangeInFile) in (path, rangeInFile, .init(location: newRangeInFile.location, length: 0)) } } rangesToReplace .sorted(by: { $0.location > $1.location }) .forEach { bridged = bridged.replacingCharacters(in: $0, with: "") as NSString } return (bridged as String, sourceChanges) } private func bodyRange(for type: Type, contentsView: StringView) -> NSRange? { guard let bytesRange = type.bodyBytesRange else { return nil } return contentsView.byteRangeToNSRange(ByteRange(location: ByteCount(bytesRange.offset), length: ByteCount(bytesRange.length))) } private func processFileRanges(`for` parsingResult: ParsingResult, in contents: String, outputPath: Path, forceParse: [String]) -> String { let files = TemplateAnnotationsParser.parseAnnotations("file", contents: contents, aggregate: true, forceParse: forceParse) files .annotatedRanges .map { ($0, $1) } .forEach({ (filePath, ranges) in let generatedBody = ranges.map { contents.bridge().substring(with: $0.range) }.joined(separator: "\n") let path = outputPath + (Path(filePath).extension == nil ? "\(filePath).generated.swift" : filePath) var fileContents = fileAnnotatedContent[path] ?? [] fileContents.append(generatedBody) fileAnnotatedContent[path] = fileContents }) return files.contents } fileprivate func writeIfChanged(_ content: String, to path: Path) throws { guard path.exists else { return try path.write(content) } let existing = try path.read(.utf8) if existing != content { try path.write(content) } } private func indent(toInsert: String, indentation: String) -> String { guard indentation.isEmpty == false else { return toInsert } let lines = toInsert.components(separatedBy: "\n") return lines.enumerated() .map { index, line in guard !line.isEmpty else { return line } return index == lines.count - 1 ? line : indentation + line } .joined(separator: "\n") } internal func generatedPath(`for` templatePath: Path) -> Path { return Path("\(templatePath.lastComponentWithoutExtension).generated.swift") } } ================================================ FILE: Sourcery/Templates/Coding.stencil ================================================ // swiftlint:disable vertical_whitespace trailing_newline import Foundation extension NSCoder { @nonobjc func decode(forKey: String) -> String? { return self.maybeDecode(forKey: forKey) as String? } @nonobjc func decode(forKey: String) -> TypeName? { return self.maybeDecode(forKey: forKey) as TypeName? } @nonobjc func decode(forKey: String) -> AccessLevel? { return self.maybeDecode(forKey: forKey) as AccessLevel? } @nonobjc func decode(forKey: String) -> Bool { return self.decodeBool(forKey: forKey) } @nonobjc func decode(forKey: String) -> Int { return self.decodeInteger(forKey: forKey) } func decode(forKey: String) -> E? { return maybeDecode(forKey: forKey) as E? } fileprivate func maybeDecode(forKey: String) -> E? { guard let object = self.decodeObject(forKey: forKey) else { return nil } return object as? E } } {% for type in types.implementing.AutoCoding|class|!annotated:"skipCoding" %} {% if not type.supertype.implements.AutoCoding %}extension {{ type.name }}: NSCoding {}{% endif %} // sourcery:inline:{{ type.name }}.AutoCoding /// :nodoc: required {{ type.accessLevel }} init?(coder aDecoder: NSCoder) { {% for variable in type.storedVariables|!annotated:"skipCoding" %}{% if variable.typeName.name == "Bool" or variable.typeName.name == "Int" %}self.{{variable.name}} = aDecoder.decode(forKey: "{{variable.name}}"){% elif variable.typeName.name == "Int32" or variable.typeName.name == "Int64" %}self.{{variable.name}} = aDecoder.decode{{variable.typeName.name}}(forKey: "{{variable.name}}"){% else %}{% if not variable.typeName.isOptional %}guard let {{variable.name}}: {{ variable.typeName.unwrappedTypeName }} = aDecoder.decode(forKey: "{{variable.name}}") else { withVaList(["{{ variable.name }}"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.{{variable.name}} = {{variable.name}}{% else %}self.{{variable.name}} = aDecoder.{% if variable.typeName.unwrappedTypeName == "Any" %}decodeObject{% else %}decode{% endif %}(forKey: "{{variable.name}}"){% endif %}{% endif %} {% endfor %}{% if type.supertype.implements.AutoCoding %}super.init(coder: aDecoder){% endif %} } /// :nodoc: {% if type.supertype.implements.AutoCoding %}override {% endif %}{{ type.accessLevel }} func encode(with aCoder: NSCoder) { {% if type.supertype.implements.AutoCoding %}super.encode(with: aCoder){% endif %} {% for variable in type.storedVariables|!annotated:"skipCoding" %}aCoder.encode(self.{{variable.name}}, forKey: "{{variable.name}}") {% endfor %} } // sourcery:end {% endfor %} ================================================ FILE: Sourcery/Templates/Description.stencil ================================================ // swiftlint:disable vertical_whitespace {% for type in types.implementing.AutoDescription|class %} {% if type.variables.count %} extension {{ type.name }} { /// :nodoc: override {{ type.accessLevel }} var description: String { var string = {% if type.inheritedTypes.first == "NSObject" %}"\(Swift.type(of: self)): "{% else %}super.description string += ", "{% endif %} {% for variable in type.variables|!annotated:"skipDescription" %}string += "{{ variable.name }} = \(String(describing: self.{{ variable.name }})){% if not forloop.last %}, {% endif %}" {% endfor %}return string } } {% endif %}{% endfor %} ================================================ FILE: Sourcery/Templates/Diffable.stencil ================================================ import Foundation {% for type in types.implementing.AutoDiffable|!protocol|!annotated:"skipDiffing" %} extension {{ type.name }}{% if not type.supertype.implements.AutoDiffable %}: Diffable{% endif %} { {% if type.based.Type %}override {% else %}@objc {% endif %}public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? {{ type.name }} else { results.append("Incorrect type ") return results } {% for variable in type.storedVariables|!annotated:"skipEquality" %}results.append(contentsOf: DiffableResult(identifier: "{{ variable.name }}").trackDifference(actual: self.{{ variable.name }}, expected: castObject.{{ variable.name }})) {% endfor %} {% if type.supertype.implements.AutoDiffable %}results.append(contentsOf: super.diffAgainst(castObject)) return results{% else %}return results{% endif %} } }{% endfor %} ================================================ FILE: Sourcery/Templates/Equality.stencil ================================================ // swiftlint:disable vertical_whitespace {% for type in types.implementing.AutoEquatable|class %} extension {{ type.name }} { /// :nodoc: {{ type.accessLevel }} override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? {{ type.name }} else { return false } {% for variable in type.storedVariables|!annotated:"skipEquality" %}if self.{{ variable.name }} != rhs.{{ variable.name }} { return false } {% endfor %} {% for variable in type.computedVariables|annotated:"forceEquality" %}if self.{{ variable.name }} != rhs.{{ variable.name }} { return false } {% endfor %} {% if type.inheritedTypes.first == "NSObject" %}return true{% else %}return super.isEqual(rhs){% endif %} } } {% endfor %} {% for type in types.implementing.AutoEquatable|class %} // MARK: - {{ type.name }} AutoHashable extension {{ type.name }} { {{ type.accessLevel }} override var hash: Int { var hasher = Hasher() {% for variable in type.storedVariables|!annotated:"skipEquality" %}hasher.combine(self.{{ variable.name }}) {% endfor %} {% for variable in type.computedVariables|annotated:"forceEquality" %}hasher.combine({{ variable.name }}) {% endfor %} {% if not type.inheritedTypes.first == "NSObject" %}hasher.combine(super.hash){% endif %} return hasher.finalize() } } {% endfor %} ================================================ FILE: Sourcery/Templates/JSExport.ejs ================================================ // swiftlint:disable vertical_whitespace trailing_newline #if canImport(JavaScriptCore) import JavaScriptCore <%_ for (type of types.implementing.AutoJSExport) { -%> <%_ if (type.kind != "protocol" && !type.annotations.skipJSExport) { -%> @objc protocol <%= type.name %>AutoJSExport: JSExport { <%_ for (variable of type.allVariables) { -%> <%_ if (!variable.annotations.skipJSExport) { -%> var <%= variable.name %>: <%= variable.typeName.name %> { get } <%_ } -%> <%_ } -%> } extension <%= type.name %>: <%= type.name %>AutoJSExport {} <%_ } %> <%_ } %> #endif ================================================ FILE: Sourcery/Templates/Typed.stencil ================================================ // swiftlint:disable vertical_whitespace {% for type in types.implementing.Typed %} extension {{ type.name }} { /// Whether type is optional. Shorthand for `typeName.isOptional` {{ type.accessLevel }} var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` {{ type.accessLevel }} var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` {{ type.accessLevel }} var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` {{ type.accessLevel }} var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` {{ type.accessLevel }} var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` {{ type.accessLevel }} var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` {{ type.accessLevel }} var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` {{ type.accessLevel }} var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` {{ type.accessLevel }} var isDictionary: Bool { return typeName.isDictionary } }{% endfor %} ================================================ FILE: Sourcery/Templates/TypedSpec.stencil ================================================ //sourcery:file:../../../SourceryTests/Models/TypedSpec import Quick import Nimble #if SWIFT_PACKAGE import SourceryLib #else import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime // swiftlint:disable function_body_length class TypedSpec: QuickSpec { override func spec() { {% for type in types.implementing.Typed %} describe("{{ type.name }}") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect({{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect({{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect({{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect({{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect({{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = {{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = {{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = {{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = {{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = {{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = {{ type.name }}({% if type.name == "MethodParameter" %}index: 0, {% endif %}typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } {% endfor %} } } //sourcery:end ================================================ FILE: Sourcery/Utils/ByteRangeConversion.swift ================================================ // // ByteRangeConversion.swift // Sourcery // // Created by Evgeniy Gubin on 16.04.2021. // Copyright © 2021 Pixle. All rights reserved. // import class SourceryRuntime.BytesRange import struct SourceryFramework.ByteRange import struct SourceryFramework.ByteCount extension ByteRange { init(bytesRange: BytesRange) { self.init(location: ByteCount(bytesRange.offset), length: ByteCount(bytesRange.length)) } } extension BytesRange { convenience init(byteRange: ByteRange) { self.init(offset: Int64(byteRange.location.value), length: Int64(byteRange.length.value)) } } ================================================ FILE: Sourcery/Utils/BytesRange + Editing.swift ================================================ // // BytesRange + Editing.swift // Sourcery // // Created by Evgeniy Gubin on 16.04.2021. // Copyright © 2021 Pixle. All rights reserved. // import class SourceryRuntime.BytesRange import struct SourceryFramework.ByteRange import struct SourceryFramework.ByteCount extension BytesRange { /* See ByteRange.changingContent(_:) */ func changingContent(_ change: ByteRange) -> BytesRange { let byteRange = ByteRange(bytesRange: self) let result = byteRange.editingContent(change) return BytesRange(byteRange: result) } } ================================================ FILE: Sourcery/Utils/DryOutputModels.swift ================================================ import Foundation struct DryOutputType: Codable { enum SubType: String, Codable { case allTemplates case template case path case range } let id: String? let subType: SubType static var allTemplates: DryOutputType { .init(id: nil, subType: .allTemplates) } static func template(_ path: String) -> DryOutputType { .init(id: path, subType: .template) } static func path(_ path: String) -> DryOutputType { .init(id: path, subType: .path) } static func range(_ range: NSRange, in file: String) -> DryOutputType { let startIndex = range.location let endIndex = range.location + range.length if startIndex == endIndex { return .init(id: "\(file):\(startIndex)", subType: .range) } return .init(id: "\(file):\(startIndex)-\(endIndex)", subType: .range) } } struct DryOutputValue: Codable { let type: DryOutputType let outputPath: String let value: String } struct DryOutputSuccess: Codable { let outputs: [DryOutputValue] } public struct DryOutputFailure: Codable { public let error: String public let log: [String] public init(error: String, log: [String]) { self.error = error self.log = log } } ================================================ FILE: Sourcery/Utils/FolderWatcher.swift ================================================ // // FolderWatcher.swift // Sourcery // // Created by Krzysztof Zabłocki on 24/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation #if canImport(ObjectiveC) public enum FolderWatcher { struct Event { let path: String let flags: Flag struct Flag: OptionSet { let rawValue: FSEventStreamEventFlags init(rawValue: FSEventStreamEventFlags) { self.rawValue = rawValue } init(_ value: Int) { self.rawValue = FSEventStreamEventFlags(value) } static let isDirectory = Flag(kFSEventStreamEventFlagItemIsDir) static let isFile = Flag(kFSEventStreamEventFlagItemIsFile) static let created = Flag(kFSEventStreamEventFlagItemCreated) static let modified = Flag(kFSEventStreamEventFlagItemModified) static let removed = Flag(kFSEventStreamEventFlagItemRemoved) static let renamed = Flag(kFSEventStreamEventFlagItemRenamed) static let isHardlink = Flag(kFSEventStreamEventFlagItemIsHardlink) static let isLastHardlink = Flag(kFSEventStreamEventFlagItemIsLastHardlink) static let isSymlink = Flag(kFSEventStreamEventFlagItemIsSymlink) static let changeOwner = Flag(kFSEventStreamEventFlagItemChangeOwner) static let finderInfoModified = Flag(kFSEventStreamEventFlagItemFinderInfoMod) static let inodeMetaModified = Flag(kFSEventStreamEventFlagItemInodeMetaMod) static let xattrsModified = Flag(kFSEventStreamEventFlagItemXattrMod) var description: String { var names: [String] = [] if self.contains(.isDirectory) { names.append("isDir") } if self.contains(.isFile) { names.append("isFile") } if self.contains(.created) { names.append("created") } if self.contains(.modified) { names.append("modified") } if self.contains(.removed) { names.append("removed") } if self.contains(.renamed) { names.append("renamed") } if self.contains(.isHardlink) { names.append("isHardlink") } if self.contains(.isLastHardlink) { names.append("isLastHardlink") } if self.contains(.isSymlink) { names.append("isSymlink") } if self.contains(.changeOwner) { names.append("changeOwner") } if self.contains(.finderInfoModified) { names.append("finderInfoModified") } if self.contains(.inodeMetaModified) { names.append("inodeMetaModified") } if self.contains(.xattrsModified) { names.append("xattrsModified") } return names.joined(separator: ", ") } } } public class Local { private let path: String private var stream: FSEventStreamRef! private let closure: (_ events: [Event]) -> Void /// Creates folder watcher. /// /// - Parameters: /// - path: Path to observe /// - latency: Latency to use /// - closure: Callback closure init(path: String, latency: TimeInterval = 1/60, closure: @escaping (_ events: [Event]) -> Void) { self.path = path self.closure = closure func handler(_ stream: ConstFSEventStreamRef, clientCallbackInfo: UnsafeMutableRawPointer?, numEvents: Int, eventPaths: UnsafeMutableRawPointer, eventFlags: UnsafePointer, eventIDs: UnsafePointer) { let eventStream = unsafeBitCast(clientCallbackInfo, to: Local.self) let paths = unsafeBitCast(eventPaths, to: NSArray.self) let events = (0.. Void /// Creates folder watcher. /// /// - Parameters: /// - path: Path to observe /// - latency: Latency to use /// - closure: Callback closure init(path: String, latency: TimeInterval = 1/60, closure: @escaping (_ events: [Event]) -> Void) { self.path = path self.closure = closure } } } #endif ================================================ FILE: Sourcery/Utils/NSRange + Editing.swift ================================================ // // Created by hemet_000 on 14.04.2021. // import Foundation import struct SourceryFramework.ByteRange import struct SourceryFramework.ByteCount extension NSRange { /* See ByteRange.changingContent(_:) */ func changingContent(_ change: NSRange) -> NSRange { let byteRange = ByteRange(location: ByteCount(location), length: ByteCount(length)) let changeByteRange = ByteRange(location: ByteCount(change.location), length: ByteCount(change.length)) let result = byteRange.editingContent(changeByteRange) return NSRange(location: result.location.value, length: result.length.value) } } ================================================ FILE: Sourcery/Utils/Xcode+Extensions.swift ================================================ import Foundation import PathKit import XcodeProj import SourceryRuntime private struct UnableToAddSourceFile: Error { var targetName: String var path: String } extension XcodeProj { func target(named targetName: String) -> PBXTarget? { return pbxproj.targets(named: targetName).first } func fullPath(fileElement: E, sourceRoot: Path) -> Path? { return try? fileElement.fullPath(sourceRoot: sourceRoot) } func sourceFilesPaths(target: PBXTarget, sourceRoot: Path) -> [Path] { let sourceFiles = (try? target.sourceFiles()) ?? [] return sourceFiles .compactMap({ fullPath(fileElement: $0, sourceRoot: sourceRoot) }) } var rootGroup: PBXGroup? { do { return try pbxproj.rootGroup() } catch { Log.error("Can't find root group for pbxproj") return nil } } func addGroup(named groupName: String, to toGroup: PBXGroup, options: GroupAddingOptions = []) -> PBXGroup? { do { return try toGroup.addGroup(named: groupName, options: options).last } catch { Log.error("Can't add group \(groupName) to group (uuid: \(toGroup.uuid), name: \(String(describing: toGroup.name))") return nil } } func addSourceFile(at filePath: Path, toGroup: PBXGroup, target: PBXTarget, sourceRoot: Path) throws { let fileReference = try toGroup.addFile(at: filePath, sourceRoot: sourceRoot) let file = PBXBuildFile(file: fileReference, product: nil, settings: nil) guard let fileElement = file.file, let sourcePhase = try target.sourcesBuildPhase() else { throw UnableToAddSourceFile(targetName: target.name, path: filePath.string) } let buildFile = try sourcePhase.add(file: fileElement) pbxproj.add(object: buildFile) } func createGroupIfNeeded(named group: String? = nil, sourceRoot: Path) -> PBXGroup? { guard let rootGroup = rootGroup else { Log.warning("Unable to find rootGroup for the project") return nil } guard let group = group else { return rootGroup } var fileGroup: PBXGroup = rootGroup var parentGroup: PBXGroup = rootGroup let components = group.components(separatedBy: "/") // Find existing group to reuse // Having `ProjectRoot/Data/` exists and given group to create `ProjectRoot/Data/Generated` // will create `Generated` group under ProjectRoot/Data to link files to let existingGroup = findGroup(in: fileGroup, components: components, validate: { $0?.path == $1 || $0?.name == $1 }) var groupName: String? switch existingGroup { case let (group, components) where group != nil: if components.isEmpty { // Group path is already exists fileGroup = group! } else { // Create rest of the group and attach to last found parent groupName = components.joined(separator: "/") parentGroup = group! } default: // Create new group from scratch groupName = group } if let groupName = groupName { do { if let addedGroup = addGroup(named: groupName, to: parentGroup), let groupPath = fullPath(fileElement: addedGroup, sourceRoot: sourceRoot) { fileGroup = addedGroup try groupPath.mkpath() } } catch { Log.warning("Failed to create a folder for group '\(fileGroup.name ?? "")'. \(error)") } } return fileGroup } } private extension XcodeProj { func findGroup(in group: PBXGroup, components: [String], validate: (PBXFileElement?, String?) -> Bool) -> (group: PBXGroup?, components: [String]) { return components.reduce((group: group as PBXGroup?, components: components)) { current, name in let first = current.group?.children.first { validate($0, name) } as? PBXGroup let result = first ?? current.group return (result, current.components.filter { !validate(result, $0) }) } } } ================================================ FILE: Sourcery-Example/CodeGenerated/Basic.generated.swift ================================================ // Found 2 Types // AppDelegate ViewController ================================================ FILE: Sourcery-Example/Podfile ================================================ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' target 'Sourcery-Example' do # Uncomment the next line if you're using Swift or would like to use dynamic frameworks use_frameworks! pod 'Sourcery' end ================================================ FILE: Sourcery-Example/Sourcery-Example/AppDelegate.swift ================================================ // // AppDelegate.swift // Sourcery-Example // // Created by Krzysztof Zablocki on 11/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } ================================================ FILE: Sourcery-Example/Sourcery-Example/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Sourcery-Example/Sourcery-Example/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Sourcery-Example/Sourcery-Example/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Sourcery-Example/Sourcery-Example/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Sourcery-Example/Sourcery-Example/ViewController.swift ================================================ // // ViewController.swift // Sourcery-Example // // Created by Krzysztof Zablocki on 11/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } ================================================ FILE: Sourcery-Example/Sourcery-Example.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 34CCB887B3207379DB00C8C5 /* Pods_Sourcery_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49752C023C6E494348990AB1 /* Pods_Sourcery_Example.framework */; }; CDE744371DFDBEE4008F034F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE744361DFDBEE4008F034F /* AppDelegate.swift */; }; CDE744391DFDBEE4008F034F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE744381DFDBEE4008F034F /* ViewController.swift */; }; CDE7443C1DFDBEE4008F034F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDE7443A1DFDBEE4008F034F /* Main.storyboard */; }; CDE7443E1DFDBEE4008F034F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CDE7443D1DFDBEE4008F034F /* Assets.xcassets */; }; CDE744411DFDBEE4008F034F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDE7443F1DFDBEE4008F034F /* LaunchScreen.storyboard */; }; CDE7444D1DFDBF1E008F034F /* Basic.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE7444A1DFDBF1E008F034F /* Basic.generated.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 1EFEACB54B4325DABA1DBB07 /* Pods-Sourcery-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sourcery-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sourcery-Example/Pods-Sourcery-Example.debug.xcconfig"; sourceTree = ""; }; 49752C023C6E494348990AB1 /* Pods_Sourcery_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sourcery_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CDE744331DFDBEE4008F034F /* Sourcery-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Sourcery-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; CDE744361DFDBEE4008F034F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; CDE744381DFDBEE4008F034F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; CDE7443B1DFDBEE4008F034F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; CDE7443D1DFDBEE4008F034F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; CDE744401DFDBEE4008F034F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; CDE744421DFDBEE4008F034F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CDE7444A1DFDBF1E008F034F /* Basic.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Basic.generated.swift; sourceTree = ""; }; CDE7444C1DFDBF1E008F034F /* Basic.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Basic.stencil; sourceTree = ""; }; E4A9E5091819FB951D4B3A46 /* Pods-Sourcery-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sourcery-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sourcery-Example/Pods-Sourcery-Example.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ CDE744301DFDBEE4008F034F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 34CCB887B3207379DB00C8C5 /* Pods_Sourcery_Example.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ A178E0EAA2A3D943868853A9 /* Frameworks */ = { isa = PBXGroup; children = ( 49752C023C6E494348990AB1 /* Pods_Sourcery_Example.framework */, ); name = Frameworks; sourceTree = ""; }; A8996A44841590FAAE2A4932 /* Pods */ = { isa = PBXGroup; children = ( 1EFEACB54B4325DABA1DBB07 /* Pods-Sourcery-Example.debug.xcconfig */, E4A9E5091819FB951D4B3A46 /* Pods-Sourcery-Example.release.xcconfig */, ); name = Pods; sourceTree = ""; }; CDE7442A1DFDBEE4008F034F = { isa = PBXGroup; children = ( CDE744491DFDBF1E008F034F /* CodeGenerated */, CDE7444B1DFDBF1E008F034F /* Templates */, CDE744351DFDBEE4008F034F /* Sourcery-Example */, CDE744341DFDBEE4008F034F /* Products */, A8996A44841590FAAE2A4932 /* Pods */, A178E0EAA2A3D943868853A9 /* Frameworks */, ); sourceTree = ""; }; CDE744341DFDBEE4008F034F /* Products */ = { isa = PBXGroup; children = ( CDE744331DFDBEE4008F034F /* Sourcery-Example.app */, ); name = Products; sourceTree = ""; }; CDE744351DFDBEE4008F034F /* Sourcery-Example */ = { isa = PBXGroup; children = ( CDE744361DFDBEE4008F034F /* AppDelegate.swift */, CDE744381DFDBEE4008F034F /* ViewController.swift */, CDE7443A1DFDBEE4008F034F /* Main.storyboard */, CDE7443D1DFDBEE4008F034F /* Assets.xcassets */, CDE7443F1DFDBEE4008F034F /* LaunchScreen.storyboard */, CDE744421DFDBEE4008F034F /* Info.plist */, ); path = "Sourcery-Example"; sourceTree = ""; }; CDE744491DFDBF1E008F034F /* CodeGenerated */ = { isa = PBXGroup; children = ( CDE7444A1DFDBF1E008F034F /* Basic.generated.swift */, ); path = CodeGenerated; sourceTree = ""; }; CDE7444B1DFDBF1E008F034F /* Templates */ = { isa = PBXGroup; children = ( CDE7444C1DFDBF1E008F034F /* Basic.stencil */, ); path = Templates; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ CDE744321DFDBEE4008F034F /* Sourcery-Example */ = { isa = PBXNativeTarget; buildConfigurationList = CDE744451DFDBEE4008F034F /* Build configuration list for PBXNativeTarget "Sourcery-Example" */; buildPhases = ( CF5282FB5B7BED7A23689E75 /* [CP] Check Pods Manifest.lock */, CDE744481DFDBF02008F034F /* Sourcery */, CDE7442F1DFDBEE4008F034F /* Sources */, CDE744301DFDBEE4008F034F /* Frameworks */, CDE744311DFDBEE4008F034F /* Resources */, 4EBFAE0E1A61E496337AD26D /* [CP] Embed Pods Frameworks */, DC0863A8265E3FBE00248C74 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = "Sourcery-Example"; productName = "Sourcery-Example"; productReference = CDE744331DFDBEE4008F034F /* Sourcery-Example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ CDE7442B1DFDBEE4008F034F /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0820; LastUpgradeCheck = 0820; ORGANIZATIONNAME = Pixle; TargetAttributes = { CDE744321DFDBEE4008F034F = { CreatedOnToolsVersion = 8.2; DevelopmentTeam = 9XH89LE46J; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = CDE7442E1DFDBEE4008F034F /* Build configuration list for PBXProject "Sourcery-Example" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = CDE7442A1DFDBEE4008F034F; productRefGroup = CDE744341DFDBEE4008F034F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( CDE744321DFDBEE4008F034F /* Sourcery-Example */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ CDE744311DFDBEE4008F034F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( CDE744411DFDBEE4008F034F /* LaunchScreen.storyboard in Resources */, CDE7443E1DFDBEE4008F034F /* Assets.xcassets in Resources */, CDE7443C1DFDBEE4008F034F /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 4EBFAE0E1A61E496337AD26D /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sourcery-Example/Pods-Sourcery-Example-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; CDE744481DFDBF02008F034F /* Sourcery */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = Sourcery; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Sourcery/bin/sourcery\" --sources \"${SRCROOT}/Sourcery-Example\" --templates \"${SRCROOT}/Templates\" --output \"${SRCROOT}/CodeGenerated\""; }; CF5282FB5B7BED7A23689E75 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; DC0863A8265E3FBE00248C74 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sourcery-Example/Pods-Sourcery-Example-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ CDE7442F1DFDBEE4008F034F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CDE744391DFDBEE4008F034F /* ViewController.swift in Sources */, CDE7444D1DFDBF1E008F034F /* Basic.generated.swift in Sources */, CDE744371DFDBEE4008F034F /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ CDE7443A1DFDBEE4008F034F /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( CDE7443B1DFDBEE4008F034F /* Base */, ); name = Main.storyboard; sourceTree = ""; }; CDE7443F1DFDBEE4008F034F /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( CDE744401DFDBEE4008F034F /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ CDE744431DFDBEE4008F034F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 10.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; CDE744441DFDBEE4008F034F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 10.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; }; CDE744461DFDBEE4008F034F /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 1EFEACB54B4325DABA1DBB07 /* Pods-Sourcery-Example.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 9XH89LE46J; INFOPLIST_FILE = "Sourcery-Example/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Pixle.Sourcery-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; name = Debug; }; CDE744471DFDBEE4008F034F /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = E4A9E5091819FB951D4B3A46 /* Pods-Sourcery-Example.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 9XH89LE46J; INFOPLIST_FILE = "Sourcery-Example/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Pixle.Sourcery-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ CDE7442E1DFDBEE4008F034F /* Build configuration list for PBXProject "Sourcery-Example" */ = { isa = XCConfigurationList; buildConfigurations = ( CDE744431DFDBEE4008F034F /* Debug */, CDE744441DFDBEE4008F034F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CDE744451DFDBEE4008F034F /* Build configuration list for PBXNativeTarget "Sourcery-Example" */ = { isa = XCConfigurationList; buildConfigurations = ( CDE744461DFDBEE4008F034F /* Debug */, CDE744471DFDBEE4008F034F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = CDE7442B1DFDBEE4008F034F /* Project object */; } ================================================ FILE: Sourcery-Example/Sourcery-Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Sourcery-Example/Sourcery-Example.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Sourcery-Example/Templates/Basic.stencil ================================================ // Found {{ types.all.count }} Types // {% for type in types.all %} {{ type.name }} {% endfor %} ================================================ FILE: Sourcery.podspec ================================================ Pod::Spec.new do |s| s.name = "Sourcery" s.version = "2.3.0" s.summary = "A tool that brings meta-programming to Swift, allowing you to code generate Swift code." s.ios.deployment_target = '12' s.osx.deployment_target = '10.15' s.tvos.deployment_target = '12' s.watchos.deployment_target = '4' s.description = <<-DESC A tool that brings meta-programming to Swift, allowing you to code generate Swift code. * Featuring daemon mode that allows you to write templates side-by-side with generated code. * Using SourceKit so you can scan your regular code. DESC s.homepage = "https://github.com/krzysztofzablocki/Sourcery" s.license = 'MIT' s.author = { "Krzysztof Zabłocki" => "krzysztof.zablocki@pixle.pl" } s.social_media_url = "https://twitter.com/merowing_" s.source = { :http => "https://github.com/krzysztofzablocki/Sourcery/releases/download/#{s.version}/sourcery-#{s.version}.zip" } s.preserve_paths = '*' s.exclude_files = '**/file.zip' s.subspec 'CLI-Only' do |subspec| subspec.preserve_paths = "bin" end end ================================================ FILE: SourceryExecutable/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(CURRENT_PROJECT_VERSION) CFBundleSignature ???? CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2016 Pixle. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: SourceryExecutable/main.swift ================================================ // // main.swift // Sourcery // // Created by Krzysztof Zablocki on 09/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation import Commander import PathKit import SourceryRuntime import SourceryFramework import SourceryUtils import SourceryJS import SourceryLib extension Path: ArgumentConvertible { /// :nodoc: public init(parser: ArgumentParser) throws { if let path = parser.shift() { self.init(path) } else { throw ArgumentError.missingValue(argument: nil) } } } private enum Validators { static func isReadable(path: Path) -> Path { if !path.isReadable { Log.error("'\(path)' does not exist or is not readable.") exit(.invalidePath) } return path } static func isFileOrDirectory(path: Path) -> Path { _ = isReadable(path: path) if !(path.isDirectory || path.isFile) { Log.error("'\(path)' isn't a directory or proper file.") exit(.invalidePath) } return path } static func isWritable(path: Path) -> Path { if path.exists && !path.isWritable { Log.error("'\(path)' isn't writable.") exit(.invalidePath) } return path } } extension Configuration { func validate() { guard !source.isEmpty else { Log.error("No sources provided.") exit(.invalidConfig) } if case let .sources(sources) = source { _ = sources.allPaths.map(Validators.isReadable(path:)) } guard !templates.isEmpty else { Log.error("No templates provided.") exit(.invalidConfig) } _ = templates.allPaths.map(Validators.isReadable(path:)) _ = output.path.map(Validators.isWritable(path:)) } } enum ExitCode: Int32 { case invalidePath = 1 case invalidConfig case other } private func exit(_ code: ExitCode) -> Never { exit(code.rawValue) } #if canImport(ObjectiveC) func runCLI() { command( Flag("watch", flag: "w", description: "Watch template for changes and regenerate as needed."), Flag("disableCache", description: "Stops using cache."), Flag("verbose", flag: "v", description: "Turn on verbose logging, this causes to log everything we can."), Flag("logAST", description: "Log AST messages"), Flag("logBenchmarks", description: "Log time benchmark info"), Flag("parseDocumentation", description: "Include documentation comments for all declarations."), Flag("quiet", flag: "q", description: "Turn off any logging, only emmit errors."), Flag("prune", flag: "p", description: "Remove empty generated files"), Flag("serialParse", description: "Parses the specified sources in serial, rather than in parallel (the default), which can address stability issues in SwiftSyntax."), VariadicOption("sources", description: "Path to a source swift files. File or Directory."), VariadicOption("exclude-sources", description: "Path to a source swift files to exclude. File or Directory."), VariadicOption("templates", description: "Path to templates. File or Directory."), VariadicOption("exclude-templates", description: "Path to templates to exclude. File or Directory."), Option("output", default: "", description: "Path to output. File or Directory. Default is current path."), Flag("dry", default: false, description: "Dry run, without file system modifications, will output result and errors in JSON format. Not working with --watch."), VariadicOption("config", default: ["."], description: "Path to config file. File or Directory. Default is current path."), VariadicOption("force-parse", description: "File extensions that Sourcery will be forced to parse, even if they were generated by Sourcery."), Option("base-indentation", default: 0, description: "Base indendation to add to sourcery:auto fragments."), VariadicOption("args", description: """ Additional arguments to pass to templates. Each argument can have an explicit value or will have \ an implicit `true` value. Arguments should be comma-separated without spaces (e.g. --args arg1=value,arg2) \ or should be passed one by one (e.g. --args arg1=value --args arg2). Arguments are accessible in templates \ via `argument.`. To pass in string you should use escaped quotes (\\"). """), Option("ejsPath", default: "", description: "Path to EJS file for JavaScript templates."), Option("cacheBasePath", default: "", description: "Base path to Sourcery's cache directory"), Option("buildPath", default: "", description: "Sets a custom build path"), Flag("hideVersionHeader", description: "Do not include Sourcery version in the generated files headers."), Option("headerPrefix", default: nil, description: "Additional prefix for headers.") ) { watcherEnabled, disableCache, verboseLogging, logAST, logBenchmark, parseDocumentation, quiet, prune, serialParse, sources, excludeSources, templates, excludeTemplates, output, isDryRun, configPaths, forceParse, baseIndentation, args, ejsPath, cacheBasePath, buildPath, hideVersionHeader, headerPrefix in do { let logConfiguration = Log.Configuration( isDryRun: isDryRun, isQuiet: quiet, isVerboseLoggingEnabled: verboseLogging, isLogBenchmarkEnabled: logBenchmark, shouldLogAST: logAST ) Log.setup(using: logConfiguration) // if ejsPath is not provided use default value or executable path EJSTemplate.ejsPath = ejsPath.string.isEmpty ? (EJSTemplate.ejsPath ?? Path(ProcessInfo.processInfo.arguments[0]).parent() + "ejs.js") : ejsPath let configurations = configPaths.flatMap { configPath -> [Configuration] in let yamlPath: Path = configPath.isDirectory ? configPath + ".sourcery.yml" : configPath if !yamlPath.exists { Log.info("No config file provided or it does not exist. Using command line arguments.") let args = args.joined(separator: ",") let arguments = AnnotationsParser.parse(line: args) return [ Configuration( sources: Paths(include: sources, exclude: excludeSources) , templates: Paths(include: templates, exclude: excludeTemplates), output: output.string.isEmpty ? "." : output, cacheBasePath: cacheBasePath.string.isEmpty ? Path.defaultBaseCachePath : cacheBasePath, forceParse: forceParse, parseDocumentation: parseDocumentation, baseIndentation: baseIndentation, args: arguments ) ] } else { _ = Validators.isFileOrDirectory(path: configPath) _ = Validators.isReadable(path: yamlPath) do { let relativePath: Path = configPath.isDirectory ? configPath : configPath.parent() // Check if the user is passing parameters // that are ignored cause read from the yaml file let hasAnyYamlDuplicatedParameter = ( !sources.isEmpty || !excludeSources.isEmpty || !templates.isEmpty || !excludeTemplates.isEmpty || !forceParse.isEmpty || output != "" || !args.isEmpty ) if hasAnyYamlDuplicatedParameter { Log.info("Using configuration file at '\(yamlPath)'. WARNING: Ignoring the parameters passed in the command line.") } else { Log.info("Using configuration file at '\(yamlPath)'") } return try Configurations.make( path: yamlPath, relativePath: relativePath, env: ProcessInfo.processInfo.environment ) } catch { Log.error("while reading .yml '\(yamlPath)'. '\(error)'") exit(.invalidConfig) } } } let start = currentTimestamp() let keepAlive = try configurations.flatMap { configuration -> [FolderWatcher.Local] in configuration.validate() let shouldUseCacheBasePathArg = configuration.cacheBasePath == Path.defaultBaseCachePath && !cacheBasePath.string.isEmpty let sourcery = Sourcery(verbose: verboseLogging, watcherEnabled: watcherEnabled, cacheDisabled: disableCache, cacheBasePath: shouldUseCacheBasePathArg ? cacheBasePath : configuration.cacheBasePath, buildPath: buildPath.string.isEmpty ? nil : buildPath, prune: prune, serialParse: serialParse, hideVersionHeader: hideVersionHeader, arguments: configuration.args, headerPrefix: headerPrefix) if isDryRun, watcherEnabled { throw "--dry not compatible with --watch" } return try sourcery.processFiles( configuration.source, usingTemplates: configuration.templates, output: configuration.output, isDryRun: isDryRun, forceParse: configuration.forceParse, parseDocumentation: configuration.parseDocumentation, baseIndentation: configuration.baseIndentation ) ?? [] } if keepAlive.isEmpty { Log.info(String(format: "Processing time %.2f seconds", currentTimestamp() - start)) } else { RunLoop.current.run() withExtendedLifetime(keepAlive) { _ = keepAlive } } } catch { if isDryRun { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data = try? encoder.encode(DryOutputFailure(error: "\(error)", log: Log.messagesStack)) data.flatMap { Log.output(String(data: $0, encoding: .utf8) ?? "") } } else { Log.error("\(error)") } exit(.other) } }.run(Sourcery.version) } import AppKit if !inUnitTests { runCLI() } else { // ! Need to run something for tests to work final class TestApplicationController: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { window.setFrame(CGRect(x: 0, y: 0, width: 0, height: 0), display: false) window.makeKeyAndOrderFront(self) } func applicationWillTerminate(aNotification: NSNotification) { } } autoreleasepool { () -> Void in let app = NSApplication.shared let controller = TestApplicationController() app.delegate = controller app.run() } } #else func runCLI() { command( Flag("disableCache", description: "Stops using cache."), Flag("verbose", flag: "v", description: "Turn on verbose logging, this causes to log everything we can."), Flag("logAST", description: "Log AST messages"), Flag("logBenchmarks", description: "Log time benchmark info"), Flag("parseDocumentation", description: "Include documentation comments for all declarations."), Flag("quiet", flag: "q", description: "Turn off any logging, only emmit errors."), Flag("prune", flag: "p", description: "Remove empty generated files"), Flag("serialParse", description: "Parses the specified sources in serial, rather than in parallel (the default), which can address stability issues in SwiftSyntax."), VariadicOption("sources", description: "Path to a source swift files. File or Directory."), VariadicOption("exclude-sources", description: "Path to a source swift files to exclude. File or Directory."), VariadicOption("templates", description: "Path to templates. File or Directory."), VariadicOption("exclude-templates", description: "Path to templates to exclude. File or Directory."), Option("output", default: "", description: "Path to output. File or Directory. Default is current path."), Flag("dry", default: false, description: "Dry run, without file system modifications, will output result and errors in JSON format. Not working with --watch."), VariadicOption("config", default: ["."], description: "Path to config file. File or Directory. Default is current path."), VariadicOption("force-parse", description: "File extensions that Sourcery will be forced to parse, even if they were generated by Sourcery."), Option("base-indentation", default: 0, description: "Base indendation to add to sourcery:auto fragments."), VariadicOption("args", description: """ Additional arguments to pass to templates. Each argument can have an explicit value or will have \ an implicit `true` value. Arguments should be comma-separated without spaces (e.g. --args arg1=value,arg2) \ or should be passed one by one (e.g. --args arg1=value --args arg2). Arguments are accessible in templates \ via `argument.`. To pass in string you should use escaped quotes (\\"). """), Option("cacheBasePath", default: "", description: "Base path to Sourcery's cache directory"), Option("buildPath", default: "", description: "Sets a custom build path"), Flag("hideVersionHeader", description: "Do not include Sourcery version in the generated files headers."), Option("headerPrefix", default: nil, description: "Additional prefix for headers.") ) { disableCache, verboseLogging, logAST, logBenchmark, parseDocumentation, quiet, prune, serialParse, sources, excludeSources, templates, excludeTemplates, output, isDryRun, configPaths, forceParse, baseIndentation, args, cacheBasePath, buildPath, hideVersionHeader, headerPrefix in do { let logConfiguration = Log.Configuration( isDryRun: isDryRun, isQuiet: quiet, isVerboseLoggingEnabled: verboseLogging, isLogBenchmarkEnabled: logBenchmark, shouldLogAST: logAST ) Log.setup(using: logConfiguration) let configurations = configPaths.flatMap { configPath -> [Configuration] in let yamlPath: Path = configPath.isDirectory ? configPath + ".sourcery.yml" : configPath if !yamlPath.exists { Log.info("No config file provided or it does not exist. Using command line arguments.") let args = args.joined(separator: ",") let arguments = AnnotationsParser.parse(line: args) return [ Configuration( sources: Paths(include: sources, exclude: excludeSources) , templates: Paths(include: templates, exclude: excludeTemplates), output: output.string.isEmpty ? "." : output, cacheBasePath: cacheBasePath.string.isEmpty ? Path.defaultBaseCachePath : cacheBasePath, forceParse: forceParse, parseDocumentation: parseDocumentation, baseIndentation: baseIndentation, args: arguments ) ] } else { _ = Validators.isFileOrDirectory(path: configPath) _ = Validators.isReadable(path: yamlPath) do { let relativePath: Path = configPath.isDirectory ? configPath : configPath.parent() // Check if the user is passing parameters // that are ignored cause read from the yaml file let hasAnyYamlDuplicatedParameter = ( !sources.isEmpty || !excludeSources.isEmpty || !templates.isEmpty || !excludeTemplates.isEmpty || !forceParse.isEmpty || output != "" || !args.isEmpty ) if hasAnyYamlDuplicatedParameter { Log.info("Using configuration file at '\(yamlPath)'. WARNING: Ignoring the parameters passed in the command line.") } else { Log.info("Using configuration file at '\(yamlPath)'") } return try Configurations.make( path: yamlPath, relativePath: relativePath, env: ProcessInfo.processInfo.environment ) } catch { Log.error("while reading .yml '\(yamlPath)'. '\(error)'") exit(.invalidConfig) } } } let start = currentTimestamp() let keepAlive = try configurations.flatMap { configuration -> [FolderWatcher.Local] in configuration.validate() let shouldUseCacheBasePathArg = configuration.cacheBasePath == Path.defaultBaseCachePath && !cacheBasePath.string.isEmpty let sourcery = Sourcery(verbose: verboseLogging, watcherEnabled: false, cacheDisabled: disableCache, cacheBasePath: shouldUseCacheBasePathArg ? cacheBasePath : configuration.cacheBasePath, buildPath: buildPath.string.isEmpty ? nil : buildPath, prune: prune, serialParse: serialParse, hideVersionHeader: hideVersionHeader, arguments: configuration.args, headerPrefix: headerPrefix) return try sourcery.processFiles( configuration.source, usingTemplates: configuration.templates, output: configuration.output, isDryRun: isDryRun, forceParse: configuration.forceParse, parseDocumentation: configuration.parseDocumentation, baseIndentation: configuration.baseIndentation ) ?? [] } if keepAlive.isEmpty { Log.info(String(format: "Processing time %.2f seconds", currentTimestamp() - start)) } else { RunLoop.current.run() _ = keepAlive } } catch { if isDryRun { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data = try? encoder.encode(DryOutputFailure(error: "\(error)", log: Log.messagesStack)) data.flatMap { Log.output(String(data: $0, encoding: .utf8) ?? "") } } else { Log.error("\(error)") } exit(.other) } }.run(Sourcery.version) } runCLI() #endif ================================================ FILE: SourceryFramework/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2018 Pixle. All rights reserved. ================================================ FILE: SourceryFramework/SourceryFramework.h ================================================ // // SourceryFramework.h // SourceryFramework // // Created by Ilya Puchka on 24/12/2018. // Copyright © 2018 Pixle. All rights reserved. // #import //! Project version number for SourceryFramework. FOUNDATION_EXPORT double SourceryFrameworkVersionNumber; //! Project version string for SourceryFramework. FOUNDATION_EXPORT const unsigned char SourceryFrameworkVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: SourceryFramework/Sources/Generating/Generator.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import SourceryRuntime public enum Generator { public static func generate(_ parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], template: Template, arguments: [String: NSObject] = [:]) throws -> String { Log.verbose("Rendering template \(template.sourcePath)") return try template.render(TemplateContext(parserResult: parserResult, types: types, functions: functions, arguments: arguments)) } } ================================================ FILE: SourceryFramework/Sources/Generating/SourceryTemplate.swift ================================================ import Foundation public struct SourceryTemplate: Decodable { public struct Instance: Decodable { public enum Kind: String, Codable, Equatable { case stencil case ejs } public var content: String public var kind: Kind } enum CodingKeys: CodingKey { case instance } public let instance: Instance public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let data = try container.decode(Data.self, forKey: .instance) instance = try JSONDecoder().decode(Instance.self, from: data) } } ================================================ FILE: SourceryFramework/Sources/Generating/Template.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import PathKit import SourceryRuntime /// Generic template that can be used for any of the Sourcery output variants public protocol Template { /// Path to template var sourcePath: Path { get } /// Generate /// /// - Parameter types: List of types to generate. /// - Parameter arguments: List of template arguments. /// - Returns: Generated code. /// - Throws: `Throws` template errors func render(_ context: TemplateContext) throws -> String } ================================================ FILE: SourceryFramework/Sources/Parsing/FileParserType.swift ================================================ import Foundation import PathKit import SourceryRuntime public protocol FileParserType { var path: String? { get } var modifiedDate: Date? { get } /// Creates parser for a given contents and path. /// - Throws: parsing errors. init(contents: String, forceParse: [String], parseDocumentation: Bool, path: Path?, module: String?) throws /// Parses given file context. /// /// - Returns: All types we could find. func parse() throws -> FileParserResult } public enum ParserEngine { case swiftSyntax } public var parserEngine: ParserEngine = .swiftSyntax public func makeParser(for contents: String, forceParse: [String] = [], parseDocumentation: Bool = false, path: Path? = nil, module: String? = nil) throws -> FileParserType { switch parserEngine { case .swiftSyntax: return try FileParserSyntax(contents: contents, forceParse: forceParse, parseDocumentation: parseDocumentation, path: path, module: module) } } ================================================ FILE: SourceryFramework/Sources/Parsing/String+TypeInference.swift ================================================ import Foundation import SourceryRuntime extension String { private static let optionalTypeName: TypeName = { let t = TypeName(name: "Optional", isOptional: true) t.name = "Optional" return t }() /// infers type or return self as type if it's a single word private var inferElementType: TypeName? { if let inferred = inferType { return inferred } let trimmed = self.trimmed if trimmed.rangeOfCharacter(from: .whitespacesAndNewlines) == nil { return TypeName(trimmed) } return nil } /// Infers type from input string internal var inferType: TypeName? { let string = self .trimmingCharacters(in: .whitespacesAndNewlines) .strippingComments() .trimmingCharacters(in: .whitespacesAndNewlines) // probably lazy property or default value with closure, // we expect explicit type, as we don't know return type guard !(string.hasPrefix("{") && string.hasSuffix(")")) else { let body = String(string.dropFirst()) guard !body.contains("return") else { return nil } // if there is no return statement it means the return value is the first expression let components = body.components(separatedBy: "(", excludingDelimiterBetween: ("<[(", ")]>")) if let first = components.first { return (first + "()").inferType } return nil } var inferredType: String if string == "nil" { // TODO: add generic return Self.optionalTypeName } else if string.first == "\"" { return TypeName(name: "String") } else if Bool(string) != nil { return TypeName(name: "Bool") } else if Int(string) != nil { return TypeName(name: "Int") } else if Double(string) != nil { return TypeName(name: "Double") } else if string.isValidTupleName() { //tuple let string = string.dropFirstAndLast() let elements = string.commaSeparated() var types = [TupleElement]() var keys = [String?]() for (idx, element) in elements.enumerated() { let nameAndValue = element.colonSeparated() if nameAndValue.count == 1 { guard let type = element.inferType else { return nil } keys.append(nil) types.append(TupleElement(name: "\(idx)", typeName: type)) } else { guard let type = nameAndValue[1].inferElementType else { return nil } let name = nameAndValue[0] .replacingOccurrences(of: "_", with: "") .trimmingCharacters(in: .whitespaces) if name.isEmpty { keys.append(nil) types.append(TupleElement(name: "\(idx)", typeName: type)) } else { keys.append(name) types.append(TupleElement(name: name, typeName: type)) } } } let body = zip(keys, types).map { key, element in if let key = key { return "\(key): \(element.typeName.asSource)" } else { return element.typeName.asSource } }.joined(separator: ", ") let name = "(\(body))" let tuple = TupleType(name: name, elements: types) return TypeName(name: name, tuple: tuple) } else if string.first == "[", string.last == "]" { //collection let string = string.dropFirstAndLast() let items = string .commaSeparated() .map { $0 .trimmingCharacters(in: .whitespacesAndNewlines) .strippingComments() .trimmingCharacters(in: .whitespacesAndNewlines) } func genericType(from itemsTypes: [TypeName]) -> TypeName { var unique = Set(itemsTypes) if unique.count == 1, let type = unique.first { return type } else if unique.count == 2, unique.remove(Self.optionalTypeName) != nil, let type = unique.first { return TypeName(name: type.name, isOptional: true, isImplicitlyUnwrappedOptional: false, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic ) } return TypeName(name: "Any") } if items[0].colonSeparated().count == 1 { var itemsTypes = [TypeName]() for item in items { guard let type = item.inferElementType else { return nil } itemsTypes.append(type) } let elementType = genericType(from: itemsTypes) let arrayType = ArrayType(name: "[\(elementType.asSource)]", elementTypeName: elementType) return TypeName(name: arrayType.name, array: arrayType, generic: arrayType.asGeneric) } else { var keysTypes = [TypeName]() var valuesTypes = [TypeName]() for items in items { let keyAndValue = items.colonSeparated() guard keyAndValue.count == 2, let keyType = keyAndValue[0].inferElementType, let valueType = keyAndValue[1].inferElementType else { return nil } keysTypes.append(keyType) valuesTypes.append(valueType) } let keyType = genericType(from: keysTypes) let valueType = genericType(from: valuesTypes) let dictionaryType = DictionaryType(name: "[\(keyType.asSource): \(valueType.asSource)]", valueTypeName: valueType, keyTypeName: keyType) return TypeName(name: dictionaryType.name, dictionary: dictionaryType, generic: dictionaryType.asGeneric) } } else if let generic = string.genericType() { return TypeName(name: generic.asSource, generic: generic) } else { // Enums, i.e. `Optional.some(...)` or `Optional.none` should be inferred to `Optional` // Contained types, i.e. `Foo.Bar()` should be inferred to `Foo.Bar` // This also supports initializers i.e. `MyType.SubType.init()` // But rarely enum cases can also start with capital letters, so we still may wrongly infer them as a type func possibleEnumType(_ string: String) -> String? { let components = string.components(separatedBy: ".", excludingDelimiterBetween: ("<[(", ")]>")) if components.count > 1, let lastComponentFirstLetter = components.last?.first.map(String.init) { if lastComponentFirstLetter.lowercased() == lastComponentFirstLetter { return components .dropLast() .joined(separator: ".") } } return nil } // get everything before `(` let components = string.components(separatedBy: "(", excludingDelimiterBetween: ("<[(", ")]>")) // scenario for '}' is for property setter / getter logic // scenario for ! is for unwrapped optional let unwrappedOptional = string.last == "!" if components.count > 1 && (string.last == ")" || string.last == "}" || unwrappedOptional) { //initializer without `init` inferredType = components[0] let name = possibleEnumType(inferredType) ?? inferredType return name.inferType ?? TypeName(name + (unwrappedOptional ? "!" : "")) } else { return possibleEnumType(string).map { TypeName($0) } } } } func strippingComments() -> String { var finished: Bool var stripped = self repeat { finished = true let lines = StringView(stripped).lines if lines.count > 1 { stripped = lines.lazy .filter({ line in !line.content.hasPrefix("//") }) .map(\.content) .joined(separator: "\n") } if let annotationStart = stripped.range(of: "/*")?.lowerBound, let annotationEnd = stripped.range(of: "*/")?.upperBound { stripped = stripped.replacingCharacters(in: annotationStart ..< annotationEnd, with: "") .trimmingCharacters(in: .whitespacesAndNewlines) finished = false } } while !finished return stripped } func strippingDefaultValues() -> String { if let defaultValueRange = self.range(of: "=") { return String(self[self.startIndex ..< defaultValueRange.lowerBound]).trimmingCharacters(in: .whitespaces) } else { return self } } fileprivate func genericType() -> GenericType? { var trimmed = self.trimmed guard let initializerCall = trimmed.lastIndex(of: "(") else { return nil } trimmed = String(trimmed[..", start > trimmed.startIndex else { return nil } let body = trimmed[trimmed.index(after: start).. AccessLevel { var defaultAccess = AccessLevel.internal if let type = parent, type.isExtension || type is SourceryProtocol { defaultAccess = AccessLevel(rawValue: type.accessLevel) ?? defaultAccess } return defaultAccess } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Actor+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Actor { convenience init(_ node: ActorDeclSyntax, parent: Type?, annotationsParser: AnnotationsParser) { let modifiers = node.modifiers.map(Modifier.init) self.init( name: node.name.text.trimmingCharacters(in: .whitespaces), parent: parent, accessLevel: modifiers.lazy.compactMap(AccessLevel.init).first ?? .default(for: parent), isExtension: false, variables: [], methods: [], subscripts: [], inheritedTypes: node.inheritanceClause?.inheritedTypes.map { $0.type.description.trimmed } ?? [], containedTypes: [], typealiases: [], attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationsParser.annotations(from: node), documentation: annotationsParser.documentation(from: node), isGeneric: node.genericParameterClause?.parameters.isEmpty == false ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Attribute+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Attribute { convenience init(_ attribute: AttributeSyntax) { var arguments = [String: NSObject]() attribute.arguments?.description .split(separator: ",") .enumerated() .forEach { (idx, part) in let components = part.split(separator: ":", maxSplits: 1) switch components.count { case 2: arguments[components[0].trimmed] = components[1].trimmed as NSString case 1: arguments["\(idx)"] = components[0].trimmed as NSString default: Log.astError("Unrecognized attribute format \(attribute.arguments?.description ?? "")") return } } self.init(name: attribute.attributeName.description.trimmed, arguments: arguments, description: attribute.withoutTrivia().description.trimmed) } static func from(_ attributes: AttributeListSyntax?) -> AttributeList { let array = attributes? .compactMap { syntax -> Attribute? in if let syntax = syntax.as(AttributeSyntax.self) { return Attribute(syntax) } else { return nil } } ?? [] var final = AttributeList() array.forEach { attribute in var attributes = final[attribute.name, default: []] attributes.append(attribute) final[attribute.name] = attributes } return final } } private extension TokenKind { var isIdentifier: Bool { switch self { case .identifier: return true default: return false } } var isComma: Bool { switch self { case .comma: return true default: return false } } } private extension LabeledExprSyntax { /// Returns key and value strings for a tuple element. If the tuple does not have an argument label, /// `nil` will be returned for the key. var keyAndValue: (key: String?, value: String) { var iterator = tokens(viewMode: .fixedUp).makeIterator() if let argumentLabelToken = iterator.next(), let colonToken = iterator.next(), case let .identifier(argumentLabel) = argumentLabelToken.tokenKind, colonToken.tokenKind == .colon { // This argument has a label let valueText = getConcatenatedTokenText(iterator: &iterator) return (argumentLabel.trimmed, valueText) } else { // This argument does not have a label iterator = tokens(viewMode: .fixedUp).makeIterator() let valueText = getConcatenatedTokenText(iterator: &iterator) return (nil, valueText) } } private func getConcatenatedTokenText(iterator: inout TokenSequence.Iterator) -> String { var valueText = "" var lastTokenWasComma = false while let nextToken = iterator.next() { lastTokenWasComma = nextToken.tokenKind.isComma valueText += nextToken.text.trimmed } valueText = valueText.replacingOccurrences(of: "\"", with: "").trimmed if lastTokenWasComma && valueText.hasSuffix(",") { valueText.remove(at: valueText.index(before: valueText.endIndex)) } return valueText } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Class+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Class { convenience init(_ node: ClassDeclSyntax, parent: Type?, annotationsParser: AnnotationsParser) { let modifiers = node.modifiers.map(Modifier.init) let genericRequirements: [GenericRequirement] = node.genericWhereClause?.requirements.compactMap { requirement in if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) { return GenericRequirement(sameType) } else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) { return GenericRequirement(conformanceType) } return nil } ?? [] self.init( name: node.name.text.trimmingCharacters(in: .whitespaces), parent: parent, accessLevel: modifiers.lazy.compactMap(AccessLevel.init).first ?? .default(for: parent), isExtension: false, variables: [], methods: [], subscripts: [], inheritedTypes: node.inheritanceClause?.inheritedTypes.map { $0.type.description.trimmed } ?? [], containedTypes: [], typealiases: [], genericRequirements: genericRequirements, attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationsParser.annotations(from: node), documentation: annotationsParser.documentation(from: node), isGeneric: node.genericParameterClause?.parameters.isEmpty == false ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Enum+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Enum { convenience init(_ node: EnumDeclSyntax, parent: Type?, annotationsParser: AnnotationsParser) { let modifiers = node.modifiers.map(Modifier.init) //let rawTypeName: String? = node.inheritanceClause?.inheritedTypeCollection.first?.typeName.description.trimmed ?? nil self.init( name: node.name.text.trimmingCharacters(in: .whitespaces), parent: parent, accessLevel: modifiers.lazy.compactMap(AccessLevel.init).first ?? .default(for: parent), isExtension: false, inheritedTypes: node.inheritanceClause?.inheritedTypes.map { $0.type.description.trimmed } ?? [], // TODO: type name? rawTypeName: nil, cases: [], variables: [], methods: [], containedTypes: [], typealiases: [], attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationsParser.annotations(from: node), documentation: annotationsParser.documentation(from: node), isGeneric: node.genericParameterClause?.parameters.isEmpty == false ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/EnumCase+SwiftSyntax.swift ================================================ import Foundation import SwiftSyntax import SourceryRuntime extension EnumCase { convenience init(_ node: EnumCaseElementSyntax, parent: EnumCaseDeclSyntax, annotationsParser: AnnotationsParser) { var associatedValues: [AssociatedValue] = [] if let paramList = node.parameterClause?.parameters { let hasManyValues = paramList.count > 1 associatedValues = paramList .enumerated() .map { (idx, param) in let name = param.firstName?.text.trimmed.nilIfNotValidParameterName let secondName = param.secondName?.text.trimmed let defaultValue = param.defaultValue?.value.description.trimmed var externalName: String? = secondName if externalName == nil, hasManyValues { externalName = name ?? "\(idx)" } let collectedAnnotations = annotationsParser.annotations(fromToken: param.type) return AssociatedValue(localName: name, externalName: externalName, typeName: TypeName(param.type), type: nil, defaultValue: defaultValue, annotations: collectedAnnotations ) } } let rawValue: String? = { () -> String? in var value = node.rawValue?.value.withoutTrivia().description.trimmed if let unwrapped = value, unwrapped.hasPrefix("\""), unwrapped.hasSuffix("\""), unwrapped.count > 2 { let substring = unwrapped[unwrapped.index(after: unwrapped.startIndex) ..< unwrapped.index(before: unwrapped.endIndex)] value = String(substring) } return value }() let modifiers = parent.modifiers.map(Modifier.init) let indirect = modifiers.contains(where: { $0.tokenKind == .keyword(.indirect) }) self.init( name: node.name.text.trimmed, rawValue: rawValue, associatedValues: associatedValues, annotations: annotationsParser.annotations(from: node), documentation: annotationsParser.documentation(from: node), indirect: indirect ) } static func from(_ node: EnumCaseDeclSyntax, annotationsParser: AnnotationsParser) -> [EnumCase] { node.elements.compactMap { EnumCase($0, parent: node, annotationsParser: annotationsParser) } } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/GenericParameter+SwiftSyntax.swift ================================================ import Foundation import SwiftSyntax import SourceryRuntime extension GenericParameter { convenience init(_ node: GenericParameterSyntax) { self.init(name: node.name.description.trimmed, inheritedTypeName: node.inheritedType.flatMap(TypeName.init(_:))) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/GenericRequirement+SwiftSyntax.swift ================================================ import Foundation import SwiftSyntax import SourceryRuntime extension GenericRequirement { convenience init(_ node: SameTypeRequirementSyntax) { let leftType = node.leftType.description.trimmed let rightTypeName = TypeName(node.rightType.description.trimmed) let rightType = Type(name: rightTypeName.unwrappedTypeName, isGeneric: true) let protocolType = SourceryProtocol(name: rightTypeName.unwrappedTypeName, implements: [rightTypeName.unwrappedTypeName: rightType]) self.init(leftType: .init(name: leftType), rightType: .init(typeName: rightTypeName, type: protocolType), relationship: .equals) } convenience init(_ node: ConformanceRequirementSyntax) { let leftType = node.leftType.description.trimmed let rightTypeName = TypeName(node.rightType.description.trimmed) let rightType = Type(name: rightTypeName.unwrappedTypeName, isGeneric: true) let protocolType = SourceryProtocol(name: rightTypeName.unwrappedTypeName, implements: [rightTypeName.unwrappedTypeName: rightType]) self.init(leftType: .init(name: leftType), rightType: .init(typeName: rightTypeName, type: protocolType), relationship: .conformsTo) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/GenericType+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension GenericType { convenience init(name: String, node: GenericArgumentClauseSyntax) { #if compiler(>=6.2) // TODO: ExprSyntax may need to be handled let parameters = node.arguments.compactMap { argument -> GenericTypeParameter? in switch argument.argument { case .type(let type): let typeName = TypeName(type) guard !typeName.name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return nil } return GenericTypeParameter(typeName: typeName) default: // case .expr return nil } } #else let parameters = node.arguments.compactMap { argument -> GenericTypeParameter? in let typeName = TypeName(argument.argument) guard !typeName.name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return nil } return GenericTypeParameter(typeName: typeName) } #endif self.init(name: name, typeParameters: parameters) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Method+SwiftSyntax.swift ================================================ import Foundation import SwiftSyntax import SourceryRuntime extension SourceryMethod { convenience init(_ node: FunctionDeclSyntax, parent: Type?, typeName: TypeName?, annotationsParser: AnnotationsParser) { self.init( node: node, parent: parent, identifier: node.name.text.trimmed, typeName: typeName, signature: Signature(node.signature, annotationsParser: annotationsParser, parent: parent), modifiers: node.modifiers, attributes: node.attributes, genericParameterClause: node.genericParameterClause, genericWhereClause: node.genericWhereClause, annotationsParser: annotationsParser ) } convenience init(_ node: InitializerDeclSyntax, parent: Type, typeName: TypeName, annotationsParser: AnnotationsParser) { let signature = node.signature self.init( node: node, parent: parent, identifier: "init\(node.optionalMark?.text.trimmed ?? "")", typeName: typeName, signature: Signature( parameters: signature.parameterClause.parameters, output: nil, asyncKeyword: nil, throwsOrRethrowsKeyword: signature.effectSpecifiers?.throwsClause?.throwsSpecifier.description.trimmed, throwsTypeName: signature.effectSpecifiers?.throwsClause?.type.map { TypeName($0) }, annotationsParser: annotationsParser, parent: parent ), modifiers: node.modifiers, attributes: node.attributes, genericParameterClause: node.genericParameterClause, genericWhereClause: node.genericWhereClause, annotationsParser: annotationsParser ) } convenience init(_ node: DeinitializerDeclSyntax, parent: Type, typeName: TypeName, annotationsParser: AnnotationsParser) { self.init( node: node, parent: parent, identifier: "deinit", typeName: typeName, signature: Signature( parameters: nil, output: nil, asyncKeyword: nil, throwsOrRethrowsKeyword: nil, throwsTypeName: nil, annotationsParser: annotationsParser, parent: parent ), modifiers: node.modifiers, attributes: node.attributes, genericParameterClause: nil, genericWhereClause: nil, annotationsParser: annotationsParser ) } convenience init( node: DeclSyntaxProtocol, parent: Type?, identifier: String, typeName: TypeName?, signature: Signature, modifiers: DeclModifierListSyntax?, attributes: AttributeListSyntax?, genericParameterClause: GenericParameterClauseSyntax?, genericWhereClause: GenericWhereClauseSyntax?, annotationsParser: AnnotationsParser ) { let initializerNode = node as? InitializerDeclSyntax let modifiers = modifiers?.map(Modifier.init) ?? [] let baseModifiers = modifiers.baseModifiers(parent: parent) var returnTypeName: TypeName if let initializer = initializerNode, let typeName = typeName { if let optional = initializer.optionalMark { returnTypeName = TypeName(name: typeName.name + optional.text.trimmed) } else { returnTypeName = typeName } } else { returnTypeName = signature.output ?? TypeName(name: "Void") } let funcName = identifier.last == "?" ? String(identifier.dropLast()) : identifier var fullName = identifier if let generics = genericParameterClause?.parameters { fullName = funcName + "<\(generics.description.trimmed)>" } let genericParameters = genericParameterClause?.parameters.compactMap { parameter in return GenericParameter(parameter) } ?? [] var genericRequirements: [GenericRequirement] = [] if let genericWhereClause = genericWhereClause { genericRequirements = genericWhereClause.requirements.compactMap { requirement in if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) { return GenericRequirement(sameType) } else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) { return GenericRequirement(conformanceType) } return nil } if !genericParameters.isEmpty { // assign types from `where` clause to the associated generic parameters for parameter in genericParameters where parameter.inheritedTypeName == nil { if let lookupInGenericReqs = genericRequirements.first(where: { $0.leftType.name == parameter.name }) { parameter.inheritedTypeName = lookupInGenericReqs.rightType.typeName } } } // TODO: TBR returnTypeName = TypeName(name: returnTypeName.name + " \(genericWhereClause.withoutTrivia().description.trimmed)", unwrappedTypeName: returnTypeName.unwrappedTypeName, attributes: returnTypeName.attributes, isOptional: returnTypeName.isOptional, isImplicitlyUnwrappedOptional: returnTypeName.isImplicitlyUnwrappedOptional, tuple: returnTypeName.tuple, array: returnTypeName.array, dictionary: returnTypeName.dictionary, closure: returnTypeName.closure, set: returnTypeName.set, generic: returnTypeName.generic ) } let name = signature.definition(with: fullName) let selectorName = signature.selector(with: funcName) let annotations: Annotations let documentation: Documentation if let function = node as? FunctionDeclSyntax { annotations = annotationsParser.annotations(from: function) documentation = annotationsParser.documentation(from: function) } else { annotations = annotationsParser.annotations(fromToken: node) documentation = annotationsParser.documentation(fromToken: node) } self.init( name: name, selectorName: selectorName, parameters: signature.input, returnTypeName: returnTypeName, isAsync: signature.asyncKeyword == "async", throws: signature.throwsOrRethrowsKeyword == "throws" && !(signature.throwsTypeName?.isNever ?? false), throwsTypeName: signature.throwsOrRethrowsKeyword == "throws" ? signature.throwsTypeName : nil, rethrows: signature.throwsOrRethrowsKeyword == "rethrows", accessLevel: baseModifiers.readAccess, isStatic: initializerNode != nil ? true : baseModifiers.isStatic, isClass: baseModifiers.isClass, isFailableInitializer: initializerNode?.optionalMark != nil, attributes: Attribute.from(attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotations, documentation: documentation, definedInTypeName: typeName, genericRequirements: genericRequirements, genericParameters: genericParameters ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/MethodParameter+SwiftSyntax.swift ================================================ import SwiftSyntax import SourceryRuntime extension MethodParameter { convenience init(_ node: FunctionParameterSyntax, index: Int, annotationsParser: AnnotationsParser, parent: Type?) { let firstName = node.firstName.text.trimmed.nilIfNotValidParameterName let isVisitingTypeSourceryProtocol = parent is SourceryProtocol let specifiers = TypeName.specifiers(from: node.type) // NOTE: This matches implementation in Variable+SwiftSyntax.swift // TODO: Walk up the `parent` in the event that there are multiple levels of nested types var typeName = TypeName(node.type) if !isVisitingTypeSourceryProtocol { // we are in a custom type, which may contain other types // in order to assign correct type to the variable, we need to match // all of the contained types against the variable type if let matchingContainedType = parent?.containedTypes.first(where: { $0.localName == typeName.name }) { typeName = TypeName(matchingContainedType.name) } } if specifiers.isInOut { // TODO: TBR typeName.name = "inout \(typeName.name)" } self.init( argumentLabel: firstName, name: node.secondName?.text.trimmed ?? firstName ?? "", index: index, typeName: typeName, type: nil, defaultValue: node.defaultValue?.value.description.trimmed, annotations: node.firstToken(viewMode: .sourceAccurate).map { annotationsParser.annotations(fromToken: $0) } ?? [:], isInout: specifiers.isInOut, isVariadic: node.ellipsis != nil ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Modifier+SwiftSyntax.swift ================================================ import Foundation import SwiftSyntax import SourceryRuntime /// modifier can be thing like `private`, `class`, `nonmutating` /// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` struct Modifier { /// The declaration modifier name. public let name: String /// The modifier detail, if any. public let detail: String? /// The modifier token kind public let tokenKind: TokenKind /// Creates an instance initialized with the given syntax node. public init(_ node: DeclModifierSyntax) { name = node.name.text.trimmed tokenKind = node.name.tokenKind detail = node.detail?.detail.description.trimmed } } extension SourceryModifier { convenience init(modifier: Modifier) { self.init(name: modifier.name, detail: modifier.detail) } convenience init(_ node: DeclModifierSyntax) { self.init(name: node.name.text.trimmed, detail: node.detail?.description.trimmed) } } extension Array where Element == Modifier { func baseModifiers(parent: Type?) -> (readAccess: AccessLevel, writeAccess: AccessLevel, isStatic: Bool, isClass: Bool) { var readAccess: AccessLevel = .none var writeAccess: AccessLevel = .none var isStatic: Bool = false var isClass: Bool = false forEach { modifier in if modifier.tokenKind == .keyword(.static) { isStatic = true } else if modifier.tokenKind == .keyword(.class) { isClass = true } guard let accessLevel = AccessLevel(modifier) else { return } if let detail = modifier.detail, detail == "set" { writeAccess = accessLevel } else { readAccess = accessLevel if writeAccess == .none { writeAccess = accessLevel } } } if readAccess == .none { readAccess = .default(for: parent) } if writeAccess == .none { writeAccess = readAccess } return (readAccess: readAccess, writeAccess: writeAccess, isStatic: isStatic, isClass: isClass) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Protocol+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension SourceryProtocol { convenience init(_ node: ProtocolDeclSyntax, parent: Type?, annotationsParser: AnnotationsParser) { let modifiers = node.modifiers.map(Modifier.init) let genericRequirements: [GenericRequirement] = node.genericWhereClause?.requirements.compactMap { requirement in if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) { return GenericRequirement(sameType) } else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) { return GenericRequirement(conformanceType) } return nil } ?? [] self.init( name: node.name.text.trimmingCharacters(in: .whitespaces), parent: parent, accessLevel: modifiers.lazy.compactMap(AccessLevel.init).first ?? .internal, isExtension: false, variables: [], methods: [], subscripts: [], inheritedTypes: node.inheritanceClause?.inheritedTypes.map { $0.type.description.trimmed } ?? [], containedTypes: [], typealiases: [], genericRequirements: genericRequirements, attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationsParser.annotations(from: node), documentation: annotationsParser.documentation(from: node) ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Signature.swift ================================================ import SwiftSyntax import SourceryRuntime public struct Signature { /// The function inputs. public let input: [MethodParameter] /// The function output, if any. public let output: TypeName? /// The `async` keyword, if any. public let asyncKeyword: String? /// The `throws` or `rethrows` keyword, if any. public let throwsOrRethrowsKeyword: String? /// The ThrownError type in `throws(ThrownError)` public let throwsTypeName: TypeName? public init(_ node: FunctionSignatureSyntax, annotationsParser: AnnotationsParser, parent: Type?) { let isVisitingTypeSourceryProtocol = parent is SourceryProtocol // NOTE: This matches implementation in Variable+SwiftSyntax.swift // TODO: Walk up the `parent` in the event that there are multiple levels of nested types var returnTypeName = node.returnClause.map { TypeName($0.type) } if !isVisitingTypeSourceryProtocol { // we are in a custom type, which may contain other types // in order to assign correct type to the variable, we need to match // all of the contained types against the variable type if let matchingContainedType = parent?.containedTypes.first(where: { $0.localName == returnTypeName?.name }) { returnTypeName = TypeName(matchingContainedType.name) } } self.init(parameters: node.parameterClause.parameters, output: returnTypeName, asyncKeyword: node.effectSpecifiers?.asyncSpecifier?.text, throwsOrRethrowsKeyword: node.effectSpecifiers?.throwsClause?.throwsSpecifier.description.trimmed, throwsTypeName: node.effectSpecifiers?.throwsClause?.type.map { TypeName($0) }, annotationsParser: annotationsParser, parent: parent ) } public init( parameters: FunctionParameterListSyntax?, output: TypeName?, asyncKeyword: String?, throwsOrRethrowsKeyword: String?, throwsTypeName: TypeName?, annotationsParser: AnnotationsParser, parent: Type? ) { var methodParameters: [MethodParameter] = [] if let parameters { for (idx, param) in parameters.enumerated() { methodParameters.append(MethodParameter(param, index: idx, annotationsParser: annotationsParser, parent: parent)) } } input = methodParameters self.output = output self.asyncKeyword = asyncKeyword self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword self.throwsTypeName = throwsTypeName } public func definition(with name: String) -> String { let parameters = input .map { $0.asSource } .joined(separator: ", ") let final = "\(name)(\(parameters))" return final } public func selector(with name: String) -> String { if input.isEmpty { return name } let parameters = input .map { "\($0.argumentLabel ?? "_"):" } .joined(separator: "") return "\(name)(\(parameters))" } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Struct+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Struct { convenience init(_ node: StructDeclSyntax, parent: Type?, annotationsParser: AnnotationsParser) { let modifiers = node.modifiers.map(Modifier.init) let genericRequirements: [GenericRequirement] = node.genericWhereClause?.requirements.compactMap { requirement in if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) { return GenericRequirement(sameType) } else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) { return GenericRequirement(conformanceType) } return nil } ?? [] self.init( name: node.name.text.trimmed, parent: parent, accessLevel: modifiers.lazy.compactMap(AccessLevel.init).first ?? .default(for: parent), isExtension: false, variables: [], methods: [], subscripts: [], inheritedTypes: node.inheritanceClause?.inheritedTypes.map { $0.type.description.trimmed } ?? [], containedTypes: [], typealiases: [], genericRequirements: genericRequirements, attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationsParser.annotations(from: node), documentation: annotationsParser.documentation(from: node), isGeneric: node.genericParameterClause?.parameters.isEmpty == false ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Subscript+SwiftSyntax.swift ================================================ import Foundation import SwiftSyntax import SourceryRuntime extension Subscript { convenience init(_ node: SubscriptDeclSyntax, parent: Type, annotationsParser: AnnotationsParser) { let modifiers = node.modifiers.map(Modifier.init) let baseModifiers = modifiers.baseModifiers(parent: parent) let parentAccess = AccessLevel(rawValue: parent.accessLevel) ?? .internal var writeAccess = baseModifiers.writeAccess var readAccess = baseModifiers.readAccess var hadGetter = false var hadSetter = false var hadAsync = false var hadThrowable = false var hadThrowsTypeName: TypeName? if let block = node .accessorBlock { enum Kind: Hashable { case get(isAsync: Bool, throws: Bool, throwsTypeName: TypeName?) case set } let computeAccessors: Set switch block.accessors { case .getter: computeAccessors = [.get(isAsync: false, throws: false, throwsTypeName: nil)] case .accessors(let accessors): computeAccessors = Set(accessors.compactMap { accessor -> Kind? in let kindRaw = accessor.accessorSpecifier.text.trimmed if kindRaw == "get" { return Kind.get( isAsync: accessor.effectSpecifiers?.asyncSpecifier != nil, throws: accessor.effectSpecifiers?.throwsClause?.throwsSpecifier != nil, throwsTypeName: accessor.effectSpecifiers?.throwsClause?.type.map { TypeName($0) } ) } if kindRaw == "set" { return Kind.set } return nil }) } if !computeAccessors.isEmpty { if !computeAccessors.contains(Kind.set) { writeAccess = .none } else { hadSetter = true } for accessor in computeAccessors { if case let .get(isAsync: isAsync, throws: `throws`, throwsTypeName: throwsTypeName) = accessor { hadGetter = true hadAsync = isAsync hadThrowable = `throws` hadThrowsTypeName = throwsTypeName break } } } } else if node.accessorBlock != nil { hadGetter = true } let isComputed = hadGetter && !(parent is SourceryProtocol) let isWritable = (!(parent is SourceryProtocol) && !isComputed) || hadSetter if parent is SourceryProtocol { writeAccess = parentAccess readAccess = parentAccess } let genericParameters = node.genericParameterClause?.parameters.compactMap { parameter in return GenericParameter(parameter) } ?? [] let genericRequirements: [GenericRequirement] = node.genericWhereClause?.requirements.compactMap { requirement in if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) { return GenericRequirement(sameType) } else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) { return GenericRequirement(conformanceType) } return nil } ?? [] var parameters: [MethodParameter] = [] for (idx, param) in node.parameterClause.parameters.enumerated() { parameters.append(MethodParameter(param, index: idx, annotationsParser: annotationsParser, parent: parent)) } self.init( parameters: parameters, returnTypeName: TypeName(node.returnClause.type), accessLevel: (read: readAccess, write: isWritable ? writeAccess : .none), isAsync: hadAsync, throws: hadThrowable && !(hadThrowsTypeName?.isNever ?? false), throwsTypeName: hadThrowsTypeName, genericParameters: genericParameters, genericRequirements: genericRequirements, attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: node.firstToken(viewMode: .sourceAccurate).map { annotationsParser.annotations(fromToken: $0) } ?? [:], documentation: node.firstToken(viewMode: .sourceAccurate).map { annotationsParser.documentation(fromToken: $0) } ?? [], definedInTypeName: TypeName(parent.name) ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Type+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Type { convenience init?(_ node: TypeSyntax) { guard let typeIdentifier = node.as(IdentifierTypeSyntax.self) else { return nil } let name = typeIdentifier.name.text.trimmed let generic = typeIdentifier.genericArgumentClause.map { GenericType(name: typeIdentifier.name.text, node: $0) } self.init(name: name, isGeneric: generic != nil) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/TypeName+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension SyntaxProtocol { @inlinable var sourcerySafeTypeIdentifier: String { let content = description return String(content[content.utf8.index(content.startIndex, offsetBy: leadingTriviaLength.utf8Length)..", elementTypeName: elementTypeName) self.init(name: array.name, array: array, generic: array.asGeneric) case ("Dictionary", 2?): let keyTypeName = generic!.typeParameters[0].typeName let valueTypeName = generic!.typeParameters[1].typeName let dictionary = DictionaryType(name: "Dictionary<\(keyTypeName.asSource), \(valueTypeName.asSource)>", valueTypeName: valueTypeName, keyTypeName: keyTypeName) self.init(name: dictionary.name, dictionary: dictionary, generic: dictionary.asGeneric) case ("Set", 1?): let elementTypeName = generic!.typeParameters[0].typeName let set = SetType(name: "Set<\(elementTypeName.asSource)>", elementTypeName: elementTypeName) self.init(name: set.name, set: set, generic: set.asGeneric) default: self.init(name: typeIdentifier.sourcerySafeTypeIdentifier, generic: generic) } } } else if let typeIdentifier = node.as(MemberTypeSyntax.self) { let base = TypeName(typeIdentifier.baseType) // TODO: VERIFY IF THIS SHOULD FULLY WRAP let fullName = "\(base.name).\(typeIdentifier.name.text.trimmed)" let generic = typeIdentifier.genericArgumentClause.map { GenericType(name: fullName, node: $0) } if let genericComponent = generic?.typeParameters.map({ $0.typeName.asSource }).joined(separator: ", ") { self.init(name: "\(fullName)<\(genericComponent)>", generic: generic) } else { self.init(name: fullName, generic: generic) } } else if let typeIdentifier = node.as(CompositionTypeSyntax.self) { let types = typeIdentifier.elements.map { TypeName($0.type) } let name = types.map({ $0.name }).joined(separator:" & ") self.init(name: name, isProtocolComposition: true) } else if let typeIdentifier = node.as(OptionalTypeSyntax.self) { let type = TypeName(typeIdentifier.wrappedType) let needsWrapping = type.isClosure || type.isProtocolComposition self.init(name: needsWrapping ? "(\(type.asSource))" : type.name, isOptional: true, isImplicitlyUnwrappedOptional: false, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if let typeIdentifier = node.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) { let type = TypeName(typeIdentifier.wrappedType) let needsWrapping = type.isClosure || type.isProtocolComposition self.init(name: needsWrapping ? "(\(type.asSource))" : type.name, isOptional: false, isImplicitlyUnwrappedOptional: true, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if let typeIdentifier = node.as(ArrayTypeSyntax.self) { let elementType = TypeName(typeIdentifier.element) let name = typeIdentifier.sourcerySafeTypeIdentifier let array = ArrayType(name: name, elementTypeName: elementType) self.init(name: name, array: array, generic: array.asGeneric) } else if let typeIdentifier = node.as(DictionaryTypeSyntax.self) { let keyType = TypeName(typeIdentifier.key) let valueType = TypeName(typeIdentifier.value) let name = typeIdentifier.sourcerySafeTypeIdentifier let dictionary = DictionaryType(name: name, valueTypeName: valueType, keyTypeName: keyType) self.init(name: name, dictionary: dictionary, generic: dictionary.asGeneric) } else if let typeIdentifier = node.as(TupleTypeSyntax.self) { let elements = typeIdentifier.elements.enumerated().map { idx, element -> TupleElement in var firstName = element.firstName?.text.trimmed let secondName = element.secondName?.text.trimmed if firstName?.nilIfNotValidParameterName == nil, secondName == nil { firstName = "\(idx)" } return TupleElement(name: firstName, typeName: TypeName(element.type)) } let name = typeIdentifier.sourcerySafeTypeIdentifier // TODO: TBR if elements.count == 1, let type = elements.first?.typeName { self.init(name: type.name, attributes: type.attributes, isOptional: type.isOptional, isImplicitlyUnwrappedOptional: type.isImplicitlyUnwrappedOptional, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if elements.count == 0 { // Void self.init(name: "()") } else { self.init(name: name, tuple: TupleType(name: name, elements: elements)) } } else if let typeIdentifier = node.as(FunctionTypeSyntax.self) { let elements = typeIdentifier.parameters.map { node -> ClosureParameter in let firstName = node.firstName?.text.trimmed.nilIfNotValidParameterName let typeName = TypeName(node.type) let specifiers = TypeName.specifiers(from: node.type) return ClosureParameter( argumentLabel: firstName, name: node.secondName?.text.trimmed ?? firstName, typeName: typeName, isInout: specifiers.isInOut, isVariadic: node.ellipsis != nil ) } let returnTypeName = TypeName(typeIdentifier.returnClause.type) let asyncKeyword = typeIdentifier.effectSpecifiers?.asyncSpecifier.map { $0.text.trimmed } let throwsOrRethrows = typeIdentifier.effectSpecifiers?.throwsClause?.throwsSpecifier.text.trimmed let throwsTypeName = typeIdentifier.effectSpecifiers?.throwsClause?.type.map { TypeName($0) } let name = "\(elements.asSource)\(asyncKeyword != nil ? " \(asyncKeyword!)" : "")\(throwsOrRethrows != nil ? " \(throwsOrRethrows!)" : "")\(throwsTypeName != nil ? "(\(throwsTypeName!.asSource))": "") -> \(returnTypeName.asSource)" self.init( name: name, closure: ClosureType( name: name, parameters: elements, returnTypeName: returnTypeName, asyncKeyword: asyncKeyword, throwsOrRethrowsKeyword: throwsOrRethrows, throwsTypeName: throwsOrRethrows == "throws" ? throwsTypeName : nil) ) } else if let typeIdentifier = node.as(AttributedTypeSyntax.self) { let type = TypeName(typeIdentifier.baseType) // TODO: add test for nested type with attributes at multiple level? let attributes = Attribute.from(typeIdentifier.attributes) self.init(name: type.name, attributes: attributes, isOptional: type.isOptional, isImplicitlyUnwrappedOptional: type.isImplicitlyUnwrappedOptional, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if node.as(ClassRestrictionTypeSyntax.self) != nil { self.init(name: "AnyObject") } else if let typeIdentifier = node.as(PackExpansionTypeSyntax.self) { self.init(typeIdentifier.repetitionPattern) } else { // assertionFailure("This is unexpected \(node)") self.init(node.sourcerySafeTypeIdentifier) } } } extension TypeName { static func specifiers(from type: TypeSyntax?) -> (isInOut: Bool, unused: Bool) { guard let type = type else { return (false, false) } var isInOut = false if let typeIdentifier = type.as(AttributedTypeSyntax.self), let specifier = typeIdentifier.specifier { if specifier.tokenKind == .keyword(.inout) { isInOut = true } else { assertionFailure("Unhandled specifier") } } return (isInOut, false) } } // TODO: when I don't need to adapt to old formats //import Foundation //import SourceryRuntime //import SwiftSyntax // //extension TypeName { // convenience init(_ node: TypeSyntax) { // /* TODO: redesign what `TypeName` represents, it can represent all those different variants // Furthermore if `TypeName` was used to store Type the whole composer process could probably be simplified / optimized? // */ // if let typeIdentifier = node.as(SimpleTypeIdentifierSyntax.self) { // let name = typeIdentifier.name.text.trimmed // let generic = typeIdentifier.genericArgumentClause.map { GenericType(name: typeIdentifier.name.text, node: $0) } // // // optional gets special treatment // if name == "Optional", let wrappedTypeName = generic?.typeParameters.first?.typeName.name, generic?.typeParameters.count == 1 { // self.init(name: wrappedTypeName, isOptional: true, generic: generic) // } else { // self.init(name: name, generic: generic) // } // } else if let typeIdentifier = node.as(MemberTypeIdentifierSyntax.self) { // let base = TypeName(typeIdentifier.baseType) // TODO: VERIFY IF THIS SHOULD FULLY WRAP // self.init(name: "\(base.name).\(typeIdentifier.name.text.trimmed)") // } else if let typeIdentifier = node.as(CompositionTypeSyntax.self) { // let types = typeIdentifier.elements.map { TypeName($0.type) } // let name = types.map({ $0.name }).joined(separator:" & ") // self.init(name: name) // } else if let typeIdentifier = node.as(OptionalTypeSyntax.self) { // let type = TypeName(typeIdentifier.wrappedType) // self.init(name: type.name, // isOptional: true, // isImplicitlyUnwrappedOptional: type.isImplicitlyUnwrappedOptional, // tuple: type.tuple, // array: type.array, // dictionary: type.dictionary, // closure: type.closure, // generic: type.generic // ) // } else if let typeIdentifier = node.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) { // let type = TypeName(typeIdentifier.wrappedType) // self.init(name: type.name, // isOptional: type.isOptional, // isImplicitlyUnwrappedOptional: true, // tuple: type.tuple, // array: type.array, // dictionary: type.dictionary, // closure: type.closure, // generic: type.generic // ) // } else if let typeIdentifier = node.as(ArrayTypeSyntax.self) { // let elementType = TypeName(typeIdentifier.elementType) // let name = typeIdentifier.description.trimmed // let array = ArrayType(name: name, elementTypeName: elementType) // self.init(name: name, array: array, generic: array.asGeneric) // } else if let typeIdentifier = node.as(DictionaryTypeSyntax.self) { // let keyType = TypeName(typeIdentifier.keyType) // let valueType = TypeName(typeIdentifier.valueType) // let name = typeIdentifier.description.trimmed // let dictionary = DictionaryType(name: name, valueTypeName: valueType, keyTypeName: keyType) // self.init(name: name, dictionary: dictionary, generic: dictionary.asGeneric) // } else if let typeIdentifier = node.as(TupleTypeSyntax.self) { // let elements = typeIdentifier.elements.map { TupleElement(name: $0.name?.text.trimmed, secondName: $0.secondName?.text.trimmed, typeName: TypeName($0.type)) } // let name = typeIdentifier.description.trimmed // self.init(name: name, tuple: TupleType(name: name, elements: elements)) // } else if let typeIdentifier = node.as(FunctionTypeSyntax.self) { // let name = typeIdentifier.description.trimmed // let elements = typeIdentifier.arguments.map { TupleElement(name: $0.name?.text.trimmed, secondName: $0.secondName?.text.trimmed, typeName: TypeName($0.type)) } // self.init(name: name, closure: ClosureType(name: name, parameters: elements, returnTypeName: TypeName(typeIdentifier.returnType))) // } else if let typeIdentifier = node.as(AttributedTypeSyntax.self) { // let type = TypeName(typeIdentifier.baseType) // TODO: add test for nested type with attributes at multiple level? // let attributes = Attribute.from(typeIdentifier.attributes) // self.init(name: type.name, // attributes: attributes, // isOptional: type.isOptional, // isImplicitlyUnwrappedOptional: type.isImplicitlyUnwrappedOptional, // tuple: type.tuple, // array: type.array, // dictionary: type.dictionary, // closure: type.closure, // generic: type.generic // ) // } else if node.as(ClassRestrictionTypeSyntax.self) != nil { // self.init(name: "AnyObject") // } else { // assertionFailure("This is unexpected \(node)") // self.init(node.description.trimmed) // } // } //} ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Variable+SwiftSyntax.swift ================================================ import Foundation import SourceryRuntime import SwiftSyntax extension Variable { convenience init( _ node: PatternBindingSyntax, variableNode: VariableDeclSyntax, readAccess: AccessLevel, writeAccess: AccessLevel, isStatic: Bool, modifiers: [Modifier], visitingType: Type?, annotationParser: AnnotationsParser ) { var writeAccess = writeAccess var hadGetter = false var hadSetter = false var hadAsync = false var hadThrowable = false var hadThrowsTypeName: TypeName? if let block = node .accessorBlock { enum Kind: Hashable { case get(isAsync: Bool, throws: Bool, throwsTypeName: TypeName?) case set } let computeAccessors: Set switch block.accessors { case .getter: computeAccessors = [.get(isAsync: false, throws: false, throwsTypeName: nil)] case .accessors(let accessors): computeAccessors = Set(accessors.compactMap { accessor -> Kind? in let kindRaw = accessor.accessorSpecifier.text.trimmed if kindRaw == "get" { return Kind.get( isAsync: accessor.effectSpecifiers?.asyncSpecifier != nil, throws: accessor.effectSpecifiers?.throwsClause?.throwsSpecifier != nil, throwsTypeName: accessor.effectSpecifiers?.throwsClause?.type.map { TypeName($0) } ) } if kindRaw == "set" { return Kind.set } return nil }) } if !computeAccessors.isEmpty { if !computeAccessors.contains(Kind.set) { writeAccess = .none } else { hadSetter = true } for accessor in computeAccessors { if case let .get(isAsync: isAsync, throws: `throws`, throwsTypeName: throwsTypeName) = accessor { hadGetter = true hadAsync = isAsync hadThrowable = `throws` hadThrowsTypeName = throwsTypeName break } } } } else if node.accessorBlock != nil { hadGetter = true } let isVisitingTypeSourceryProtocol = visitingType is SourceryProtocol let isComputed = node.initializer == nil && hadGetter && !isVisitingTypeSourceryProtocol let isAsync = hadAsync let throwsTypeName = hadThrowsTypeName let `throws` = hadThrowable && !(throwsTypeName?.isNever ?? false) let isWritable = variableNode.bindingSpecifier.tokens(viewMode: .fixedUp).contains { $0.tokenKind == .keyword(.var) } && (!isComputed || hadSetter) var typeName: TypeName? = node.typeAnnotation.map { TypeName($0.type) } ?? node.initializer.flatMap { Self.inferType($0.value.description.trimmed) } if !isVisitingTypeSourceryProtocol { // we are in a custom type, which may contain other types // in order to assign correct type to the variable, we need to match // all of the contained types against the variable type if let matchingContainedType = visitingType?.containedTypes.first(where: { $0.localName == typeName?.name }) { typeName = TypeName(matchingContainedType.name) } } self.init( name: node.pattern.withoutTrivia().description.trimmed, typeName: typeName ?? TypeName.unknown(description: node.description.trimmed), type: nil, accessLevel: (read: readAccess, write: isWritable ? writeAccess : .none), isComputed: isComputed, isAsync: isAsync, throws: `throws`, throwsTypeName: throwsTypeName, isStatic: isStatic, defaultValue: node.initializer?.value.description.trimmingCharacters(in: .whitespacesAndNewlines), attributes: Attribute.from(variableNode.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationParser.annotations(fromToken: variableNode.bindingSpecifier), documentation: annotationParser.documentation(fromToken: variableNode.bindingSpecifier), definedInTypeName: visitingType.map { TypeName($0.name) } ) } static func from(_ variableNode: VariableDeclSyntax, visitingType: Type?, annotationParser: AnnotationsParser) -> [Variable] { let modifiers = variableNode.modifiers.map(Modifier.init) let baseModifiers = modifiers.baseModifiers(parent: visitingType) return variableNode.bindings.map { (node: PatternBindingSyntax) -> Variable in Variable( node, variableNode: variableNode, readAccess: baseModifiers.readAccess, writeAccess: baseModifiers.writeAccess, isStatic: baseModifiers.isStatic || baseModifiers.isClass, modifiers: modifiers, visitingType: visitingType, annotationParser: annotationParser ) } } private static func inferType(_ code: String) -> TypeName? { var code = code if code.hasSuffix("{") { code = String(code.dropLast()) .trimmingCharacters(in: .whitespaces) } return code.inferType } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/FileParserSyntax.swift ================================================ import Foundation import SwiftSyntax import SwiftParser import PathKit import SourceryRuntime import SourceryUtils public final class FileParserSyntax: SyntaxVisitor, FileParserType { public let path: String? public let modifiedDate: Date? private let module: String? private let initialContents: String fileprivate var inlineRanges: [String: NSRange]! fileprivate var inlineIndentations: [String: String]! fileprivate var forceParse: [String] = [] fileprivate var parseDocumentation: Bool = false /// Parses given contents. /// - Throws: parsing errors. public init(contents: String, forceParse: [String] = [], parseDocumentation: Bool, path: Path? = nil, module: String? = nil) throws { self.path = path?.string self.modifiedDate = path.flatMap({ (try? FileManager.default.attributesOfItem(atPath: $0.string)[.modificationDate]) as? Date }) self.module = module self.initialContents = contents self.forceParse = forceParse self.parseDocumentation = parseDocumentation super.init(viewMode: .fixedUp) } /// Parses given file context. /// /// - Returns: All types we could find. public func parse() throws -> FileParserResult { // Inline handling let inline = TemplateAnnotationsParser.parseAnnotations("inline", contents: initialContents, forceParse: self.forceParse) let contents = inline.contents inlineRanges = inline.annotatedRanges.mapValues { $0[0].range } inlineIndentations = inline.annotatedRanges.mapValues { $0[0].indentation } // Syntax walking let tree = Parser.parse(source: contents) let fileName = path ?? "in-memory" let sourceLocationConverter = SourceLocationConverter(fileName: fileName, tree: tree) let collector = SyntaxTreeCollector( file: fileName, module: module, annotations: AnnotationsParser(contents: contents, parseDocumentation: parseDocumentation, sourceLocationConverter: sourceLocationConverter), sourceLocationConverter: sourceLocationConverter) collector.walk(tree) collector.types.forEach { $0.imports = collector.imports $0.path = path } collector.typealiases.forEach { $0.imports = collector.imports } return FileParserResult( path: path, module: module, types: collector.types, functions: collector.methods, typealiases: collector.typealiases, inlineRanges: inlineRanges, inlineIndentations: inlineIndentations, modifiedDate: modifiedDate ?? Date(), sourceryVersion: SourceryVersion.current.value ) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/Syntax+Extensions.swift ================================================ import SwiftSyntax public extension TriviaPiece { /// Returns string value of a comment piece or nil otherwise var comment: String? { switch self { case .spaces, .tabs, .verticalTabs, .formfeeds, .newlines, .carriageReturns, .carriageReturnLineFeeds, .unexpectedText, .backslashes, .pounds: return nil case .lineComment(let comment), .blockComment(let comment), .docLineComment(let comment), .docBlockComment(let comment): return comment } } } protocol IdentifierSyntax: SyntaxProtocol { var identifier: TokenSyntax { get } } extension ActorDeclSyntax: IdentifierSyntax {} extension ClassDeclSyntax: IdentifierSyntax {} extension StructDeclSyntax: IdentifierSyntax {} extension EnumDeclSyntax: IdentifierSyntax {} extension ProtocolDeclSyntax: IdentifierSyntax {} extension FunctionDeclSyntax: IdentifierSyntax {} extension TypeAliasDeclSyntax: IdentifierSyntax {} extension OperatorDeclSyntax: IdentifierSyntax {} extension EnumCaseElementSyntax: IdentifierSyntax {} extension SyntaxProtocol { func withoutTrivia() -> Self { with(\.leadingTrivia, []) .with(\.trailingTrivia, []) } } ================================================ FILE: SourceryFramework/Sources/Parsing/SwiftSyntax/SyntaxTreeCollector.swift ================================================ import SwiftSyntax import SourceryRuntime import SourceryUtils import Foundation class SyntaxTreeCollector: SyntaxVisitor { var types = [Type]() var typealiases = [Typealias]() var methods = [SourceryMethod]() var imports = [Import]() private var visitingType: Type? let annotationsParser: AnnotationsParser let sourceLocationConverter: SourceLocationConverter let module: String? let file: String init(file: String, module: String?, annotations: AnnotationsParser, sourceLocationConverter: SourceLocationConverter) { self.annotationsParser = annotations self.file = file self.module = module self.sourceLocationConverter = sourceLocationConverter super.init(viewMode: .fixedUp) } private func startVisitingType(_ node: DeclSyntaxProtocol, _ builder: (_ parent: Type?) -> Type) { let type = builder(visitingType) let tokens = node.tokens(viewMode: .fixedUp) if let open = tokens.first(where: { $0.tokenKind == .leftBrace }), let close = tokens .reversed() .first(where: { $0.tokenKind == .rightBrace }) { let startLocation = open.endLocation(converter: sourceLocationConverter) let endLocation = close.startLocation(converter: sourceLocationConverter) type.bodyBytesRange = SourceryRuntime.BytesRange(offset: Int64(startLocation.offset), length: Int64(endLocation.offset - startLocation.offset)) } else { logError("Unable to find bodyRange for \(type.name)") } let startLocation = node.startLocation(converter: sourceLocationConverter, afterLeadingTrivia: true) let endLocation = node.endLocation(converter: sourceLocationConverter, afterTrailingTrivia: false) type.completeDeclarationRange = SourceryRuntime.BytesRange(offset: Int64(startLocation.offset), length: Int64(endLocation.offset - startLocation.offset)) visitingType?.containedTypes.append(type) visitingType = type types.append(type) } public override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { startVisitingType(node) { parent in Struct(node, parent: parent, annotationsParser: annotationsParser) } return .visitChildren } public override func visitPost(_ node: StructDeclSyntax) { visitingType = visitingType?.parent } public override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { startVisitingType(node) { parent in Class(node, parent: parent, annotationsParser: annotationsParser) } return .visitChildren } public override func visitPost(_ node: ClassDeclSyntax) { visitingType = visitingType?.parent } public override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { startVisitingType(node) { parent in Actor(node, parent: parent, annotationsParser: annotationsParser) } return .visitChildren } public override func visitPost(_ node: ActorDeclSyntax) { visitingType = visitingType?.parent } public override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { startVisitingType(node) { parent in Enum(node, parent: parent, annotationsParser: annotationsParser) } return .visitChildren } public override func visitPost(_ node: EnumDeclSyntax) { visitingType = visitingType?.parent } public override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { let variables = Variable.from(node, visitingType: visitingType, annotationParser: annotationsParser) if let visitingType = visitingType { visitingType.rawVariables.append(contentsOf: variables) } return .skipChildren } public override func visit(_ node: EnumCaseDeclSyntax) -> SyntaxVisitorContinueKind { guard let enumeration = visitingType as? Enum else { logError("EnumCase shouldn't appear outside of enum declaration \(node.description.trimmed)") return .skipChildren } enumeration.cases.append(contentsOf: EnumCase.from(node, annotationsParser: annotationsParser)) return .skipChildren } public override func visit(_ node: DeinitializerDeclSyntax) -> SyntaxVisitorContinueKind { guard let visitingType = visitingType else { logError("deinit shouldn't appear outside of type declaration \(node.description.trimmed)") return .skipChildren } visitingType.rawMethods.append( SourceryMethod(node, parent: visitingType, typeName: TypeName(visitingType.name), annotationsParser: annotationsParser) ) return .skipChildren } public override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { startVisitingType(node) { parent in let modifiers = node.modifiers.map(Modifier.init) let base = modifiers.baseModifiers(parent: nil) return Type( name: node.extendedType.description.trimmingCharacters(in: .whitespaces), parent: parent, accessLevel: base.readAccess, isExtension: true, variables: [], methods: [], subscripts: [], inheritedTypes: node.inheritanceClause?.inheritedTypes.map { $0.type.description.trimmed } ?? [], containedTypes: [], typealiases: [], attributes: Attribute.from(node.attributes), modifiers: modifiers.map(SourceryModifier.init), annotations: annotationsParser.annotations(fromToken: node.extensionKeyword), documentation: annotationsParser.documentation(fromToken: node.extensionKeyword), isGeneric: false ) } return .visitChildren } public override func visitPost(_ node: ExtensionDeclSyntax) { visitingType = visitingType?.parent } public override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { let method = SourceryMethod(node, parent: visitingType, typeName: visitingType.map { TypeName($0.name) }, annotationsParser: annotationsParser) if let visitingType = visitingType { visitingType.rawMethods.append(method) } else { methods.append(method) } return .skipChildren } public override func visit(_ node: ImportDeclSyntax) -> SyntaxVisitorContinueKind { imports.append(Import(path: node.path.description.trimmed, kind: node.importKindSpecifier?.text.trimmed)) return .skipChildren } public override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { guard let visitingType = visitingType else { logError("init shouldn't appear outside of type declaration \(node.description.trimmed)") return .skipChildren } let method = SourceryMethod(node, parent: visitingType, typeName: TypeName(visitingType.name), annotationsParser: annotationsParser) visitingType.rawMethods.append(method) return .skipChildren } public override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { startVisitingType(node) { parent in SourceryProtocol(node, parent: parent, annotationsParser: annotationsParser) } return .visitChildren } public override func visitPost(_ node: ProtocolDeclSyntax) { visitingType = visitingType?.parent } public override func visit(_ node: SubscriptDeclSyntax) -> SyntaxVisitorContinueKind { guard let visitingType = visitingType else { logError("subscript shouldn't appear outside of type declaration \(node.description.trimmed)") return .skipChildren } visitingType.rawSubscripts.append( Subscript(node, parent: visitingType, annotationsParser: annotationsParser) ) return .skipChildren } public override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { let localName = node.name.text.trimmed let typeName = TypeName(node.initializer.value) let modifiers = node.modifiers.map(Modifier.init) let baseModifiers = modifiers.baseModifiers(parent: visitingType) let annotations = annotationsParser.annotations(from: node) let documentation = annotationsParser.documentation(from: node) if let composition = processPossibleProtocolComposition(for: typeName.name, localName: localName, annotations: annotations, accessLevel: baseModifiers.readAccess) { if let visitingType = visitingType { visitingType.containedTypes.append(composition) } else { types.append(composition) } return .skipChildren } let alias = Typealias( aliasName: localName, typeName: typeName, accessLevel: baseModifiers.readAccess, parent: visitingType, module: module, annotations: annotations, documentation: documentation ) // TODO: add generic requirements if let visitingType = visitingType { visitingType.typealiases[localName] = alias } else { // global typealias typealiases.append(alias) } return .skipChildren } public override func visit(_ node: AssociatedTypeDeclSyntax) -> SyntaxVisitorContinueKind { guard let sourceryProtocol = visitingType as? SourceryProtocol else { return .skipChildren } let name = node.name.text.trimmed var typeName: TypeName? var type: Type? if let possibleTypeName = node.inheritanceClause?.inheritedTypes.description.trimmed { var genericRequirements: [GenericRequirement] = [] if let genericWhereClause = node.genericWhereClause { genericRequirements = genericWhereClause.requirements.compactMap { requirement in if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) { return GenericRequirement(sameType) } else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) { return GenericRequirement(conformanceType) } return nil } } if let composition = processPossibleProtocolComposition(for: possibleTypeName, localName: "") { type = composition } else { type = Protocol(name: possibleTypeName, genericRequirements: genericRequirements) } typeName = TypeName(possibleTypeName) } else if let possibleTypeName = (node.initializer?.value as? TypeSyntax)?.description.trimmed { type = processPossibleProtocolComposition(for: possibleTypeName, localName: "") typeName = TypeName(possibleTypeName) } else { type = Type(name: "Any") typeName = TypeName(name: "Any", actualTypeName: TypeName(name: "Any")) } sourceryProtocol.associatedTypes[name] = AssociatedType(name: name, typeName: typeName, type: type) return .skipChildren } public override func visit(_ node: OperatorDeclSyntax) -> SyntaxVisitorContinueKind { return .skipChildren } public override func visit(_ node: PrecedenceGroupDeclSyntax) -> SyntaxVisitorContinueKind { return .skipChildren } public override func visit(_ node: IfConfigDeclSyntax) -> SyntaxVisitorContinueKind { return .visitChildren } private func processPossibleProtocolComposition(for typeName: String, localName: String, annotations: [String: NSObject] = [:], accessLevel: AccessLevel = .internal) -> Type? { if let composedTypeNames = extractComposedTypeNames(from: typeName, trimmingCharacterSet: .whitespaces), composedTypeNames.count > 1 { let inheritedTypes = composedTypeNames.map { $0.name } let composition = ProtocolComposition( name: localName, parent: visitingType, accessLevel: accessLevel, inheritedTypes: inheritedTypes, annotations: annotations, composedTypeNames: composedTypeNames ) return composition } return nil } /// Extracts list of type names from composition e.g. `ProtocolA & ProtocolB` internal func extractComposedTypeNames(from value: String, trimmingCharacterSet: CharacterSet? = nil) -> [TypeName]? { guard case let closureComponents = value.components(separatedBy: "->"), closureComponents.count <= 1 else { return nil } guard case let components = value.components(separatedBy: CharacterSet(charactersIn: "&")), components.count > 1 else { return nil } var characterSet: CharacterSet = .whitespacesAndNewlines if let trimmingCharacterSet = trimmingCharacterSet { characterSet = characterSet.union(trimmingCharacterSet) } let suffixes = components.map { source in source.trimmingCharacters(in: characterSet) } return suffixes.map { TypeName($0) } } private func logError(_ message: Any) { let prefix = file + ": " if let module = module { Log.astError("\(prefix) \(message) in module \(module)") } else { Log.astError("\(prefix) \(message)") } } } ================================================ FILE: SourceryFramework/Sources/Parsing/Utils/AnnotationsParser.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import SwiftSyntax import SourceryRuntime /// Parser for annotations, and also documentation public struct AnnotationsParser { private enum AnnotationType { case begin(Annotations) case annotations(Annotations) case end case inlineStart case file(Annotations) } private struct Line { enum LineType { case propertyWrapper case macros case comment case documentationComment case blockStart case blockEnd case other case inlineStart case inlineEnd case file } let content: String let type: LineType let annotations: Annotations let blockAnnotations: Annotations } private let lines: [AnnotationsParser.Line] private let contents: String private var parseDocumentation: Bool internal var sourceLocationConverter: SourceLocationConverter /// Initializes parser /// /// - Parameter contents: Contents to parse init(contents: String, parseDocumentation: Bool = false, sourceLocationConverter: SourceLocationConverter) { self.parseDocumentation = parseDocumentation self.lines = AnnotationsParser.parse(contents: contents) self.sourceLocationConverter = sourceLocationConverter self.contents = contents } /// returns all annotations in the contents var all: Annotations { var all = Annotations() lines.forEach { $0.annotations.forEach { AnnotationsParser.append(key: $0.key, value: $0.value, to: &all) } } return all } func annotations(from node: IdentifierSyntax) -> Annotations { from( positionAfterLeadingTrivia: findLocationAfterLeadingTrivia(syntax: node.identifier), positionBeforeTrailingTrivia: findLocationBeforeTrailingTrivia(syntax: node.identifier) ) } func annotations(fromToken token: SyntaxProtocol) -> Annotations { from( positionAfterLeadingTrivia: findLocationAfterLeadingTrivia(syntax: token), positionBeforeTrailingTrivia: findLocationBeforeTrailingTrivia(syntax: token) ) } func documentation(from node: IdentifierSyntax) -> Documentation { guard parseDocumentation else { return [] } return documentationFrom( location: findLocationAfterLeadingTrivia(syntax: node.identifier) ) } func documentation(fromToken token: SyntaxProtocol) -> Documentation { guard parseDocumentation else { return [] } return documentationFrom( location: findLocationAfterLeadingTrivia(syntax: token) ) } private func findLocationAfterLeadingTrivia(syntax: SyntaxProtocol) -> SwiftSyntax.SourceLocation { sourceLocationConverter.location(for: syntax.positionAfterSkippingLeadingTrivia) } private func findLocationBeforeTrailingTrivia(syntax: SyntaxProtocol) -> SwiftSyntax.SourceLocation { sourceLocationConverter.location(for: syntax.endPositionBeforeTrailingTrivia) } private func from(positionAfterLeadingTrivia: SwiftSyntax.SourceLocation, positionBeforeTrailingTrivia: SwiftSyntax.SourceLocation) -> Annotations { var stop = false var position = positionAfterLeadingTrivia var (annotations, shouldUsePositionBeforeTrailing) = inlineFrom( positionAfterLeadingTrivia: (positionAfterLeadingTrivia.line, positionAfterLeadingTrivia.column), positionBeforeTrailingTrivia: (positionBeforeTrailingTrivia.line, positionBeforeTrailingTrivia.column), stop: &stop ) if shouldUsePositionBeforeTrailing { position = positionBeforeTrailingTrivia } guard !stop else { return annotations } let reversedArray = lines[0.. Documentation { guard parseDocumentation else { return [] } // Inline documentation not currently supported _ = location.column // var stop = false // var documentation = inlineDocumentationFrom(line: (lineNumber, column), stop: &stop) // guard !stop else { return annotations } var documentation: Documentation = [] for line in lines[0.. (Annotations, Bool) { var shouldUsePositionBeforeTrailing = false var position: (line: Int, character: Int) = positionAfterLeadingTrivia // first try checking for annotations in the beginning of the line (i.e. `positionAfterLeadingTrivia`) // next, try checking for annotations in the end of the line (i.e. `positionBeforeTrailingTrivia`) let findPrefix: (((line: Int, character: Int), Bool) -> (String, Line)) = { position, shouldStart in let sourceLine = lines[position.line - 1] let utf8View = sourceLine.content.utf8 var startIndex: String.UTF8View.Index var endIndex: String.UTF8View.Index guard utf8View.count > position.character else { return ("", sourceLine) } if shouldUsePositionBeforeTrailing { startIndex = utf8View.index(utf8View.startIndex, offsetBy: (position.character - 1)) endIndex = utf8View.endIndex } else { startIndex = utf8View.startIndex endIndex = utf8View.index(startIndex, offsetBy: (position.character - 1)) } let utf8Slice = utf8View[startIndex ..< endIndex] let relevantContent = String(decoding: utf8Slice, as: UTF8.self) return (relevantContent.trimmingCharacters(in: .whitespaces), sourceLine) } var (prefix, sourceLine) = findPrefix(positionAfterLeadingTrivia, shouldUsePositionBeforeTrailing) if prefix.isEmpty { shouldUsePositionBeforeTrailing = true (prefix, sourceLine) = findPrefix(positionBeforeTrailingTrivia, shouldUsePositionBeforeTrailing) if shouldUsePositionBeforeTrailing && !prefix.isEmpty { position = positionBeforeTrailingTrivia } else { shouldUsePositionBeforeTrailing = false } } guard !prefix.isEmpty else { return ([:], shouldUsePositionBeforeTrailing) } var annotations = sourceLine.blockAnnotations // get block annotations for this line sourceLine.annotations.forEach { annotation in // TODO: verify AnnotationsParser.append(key: annotation.key, value: annotation.value, to: &annotations) } // `case` is not included in the key of enum case definition, so we strip it manually let isInsideCaseDefinition = prefix.trimmingCharacters(in: .whitespacesAndNewlines).hasPrefix("case ") prefix = prefix.trimmingPrefix("case ").trimmingCharacters(in: .whitespaces) var inlineCommentFound = false while !prefix.isEmpty { guard prefix.hasSuffix("*/"), let commentStart = prefix.range(of: "/*", options: [.backwards]) else { break } inlineCommentFound = true let comment = String(prefix[commentStart.lowerBound...]) for annotation in AnnotationsParser.parse(contents: comment)[0].annotations { AnnotationsParser.append(key: annotation.key, value: annotation.value, to: &annotations) } prefix = prefix[.. 0 { let previousLine = lines[position.line - 2] let content = previousLine.content.trimmingCharacters(in: .whitespaces) guard previousLine.type == .comment || previousLine.type == .documentationComment || previousLine.type == .propertyWrapper || previousLine.type == .macros, content.hasPrefix("//") || content.hasSuffix("*/") || content.hasPrefix("@") || content.hasPrefix("#") else { stop = true return (annotations, shouldUsePositionBeforeTrailing) } } return (annotations, shouldUsePositionBeforeTrailing) } private static func parse(contents: String) -> [Line] { var annotationsBlock: Annotations? var fileAnnotationsBlock = Annotations() class MultilineCommentStack { private var lines: [String] = [] var hasOpenedComment: Bool { !lines.isEmpty && lines.last?.contains("*/") == false } func reset() { lines.removeAll() } func push(_ line: String) { lines.append(line) } func contains(_ line: String) -> Bool { lines.contains(line) } } let multilineCommentStack = MultilineCommentStack() return StringView(contents).lines .map { line in let content = line.content.trimmingCharacters(in: .whitespaces) var annotations = Annotations() var isComment = content.hasPrefix("//") || content.hasPrefix("/*") && !content.hasPrefix("/**") || content.hasPrefix("*") && !content.hasPrefix("*/") let isClosingMultilineDocumentationComment = (content.contains("*/") && multilineCommentStack.hasOpenedComment) let isOpeningMultilineDocumentationComment = content.hasPrefix("/**") let isDocumentationComment = content.hasPrefix("///") || isOpeningMultilineDocumentationComment || isClosingMultilineDocumentationComment let isPropertyWrapper = content.isPropertyWrapper let isMacros = content.hasPrefix("#") var type = Line.LineType.other if isOpeningMultilineDocumentationComment { multilineCommentStack.push(content) if content == "/**" { // ignoring the actual token which indicates the start of a multiline comment // but not stopping traversal of comments by setting the type to `comment` type = .comment isComment = true } else { type = .documentationComment } } else if isClosingMultilineDocumentationComment { if content == "*/" { // ignoring the actual token which indicates the start of a multiline comment // but not stopping traversal of comments by setting the type to `comment` type = .comment isComment = true } else { type = .documentationComment } multilineCommentStack.reset() } else if multilineCommentStack.hasOpenedComment { type = .documentationComment } else if isDocumentationComment { type = .documentationComment } else if isComment { type = .comment } else if isPropertyWrapper { type = .propertyWrapper } else if isMacros { type = .macros } if isComment || (type == .documentationComment) { switch searchForAnnotations(commentLine: content) { case let .begin(items): type = .blockStart annotationsBlock = Annotations() items.forEach { annotationsBlock?[$0.key] = $0.value } case let .annotations(items): items.forEach { annotations[$0.key] = $0.value } case .end: if annotationsBlock != nil { type = .blockEnd annotationsBlock?.removeAll() } else { type = .inlineEnd } case .inlineStart: type = .inlineStart case let .file(items): type = .file items.forEach { fileAnnotationsBlock[$0.key] = $0.value } } } else { searchForTrailingAnnotations(codeLine: content) .forEach { annotations[$0.key] = $0.value } } annotationsBlock?.forEach { annotation in annotations[annotation.key] = annotation.value } fileAnnotationsBlock.forEach { annotation in annotations[annotation.key] = annotation.value } return Line(content: line.content, type: type, annotations: annotations, blockAnnotations: annotationsBlock ?? [:]) } } private static func searchForTrailingAnnotations(codeLine: String) -> Annotations { let blockComponents = codeLine.components(separatedBy: "/*", excludingDelimiterBetween: ("", "")) if blockComponents.count > 1, let lastBlockComponent = blockComponents.last, let endBlockRange = lastBlockComponent.range(of: "*/"), let lowerBound = lastBlockComponent.range(of: "sourcery:")?.upperBound { let trailingStart = endBlockRange.upperBound let trailing = String(lastBlockComponent[trailingStart...]) if trailing.components(separatedBy: "//", excludingDelimiterBetween: ("", "")).first?.trimmed.count == 0 { let upperBound = endBlockRange.lowerBound return AnnotationsParser.parse(line: String(lastBlockComponent[lowerBound.. 1, let trailingComment = components.last?.stripped(), let lowerBound = trailingComment.range(of: "sourcery:")?.upperBound { return AnnotationsParser.parse(line: String(trailingComment[lowerBound...])) } return [:] } private static func searchForAnnotations(commentLine: String) -> AnnotationType { let comment = commentLine.trimmingPrefix("///").trimmingPrefix("//").trimmingPrefix("/**").trimmingPrefix("/*").trimmingPrefix("*").stripped() guard comment.hasPrefix("sourcery:") else { return .annotations([:]) } if comment.hasPrefix("sourcery:inline:") { return .inlineStart } let lowerBound: String.Index? let upperBound: String.Index? var insideBlock: Bool = false var insideFileBlock: Bool = false if comment.hasPrefix("sourcery:begin:") { lowerBound = commentLine.range(of: "sourcery:begin:")?.upperBound upperBound = commentLine.indices.endIndex insideBlock = true } else if comment.hasPrefix("sourcery:end") { return .end } else if comment.hasPrefix("sourcery:file") { lowerBound = commentLine.range(of: "sourcery:file:")?.upperBound upperBound = commentLine.indices.endIndex insideFileBlock = true } else { lowerBound = commentLine.range(of: "sourcery:")?.upperBound if commentLine.hasPrefix("//") || commentLine.hasPrefix("*") { upperBound = commentLine.indices.endIndex } else { upperBound = commentLine.range(of: "*/")?.lowerBound } } if let lowerBound = lowerBound, let upperBound = upperBound { let annotations = AnnotationsParser.parse(line: String(commentLine[lowerBound.. Annotations { var annotationDefinitions = line.trimmingCharacters(in: .whitespaces) .commaSeparated() .map { $0.trimmingCharacters(in: .whitespaces) } var namespaces = annotationDefinitions[0].components(separatedBy: ":", excludingDelimiterBetween: (open: "\"'", close: "\"'")) annotationDefinitions[0] = namespaces.removeLast() var annotations = Annotations() annotationDefinitions.forEach { annotation in let parts = annotation .components(separatedBy: "=", excludingDelimiterBetween: ("", "")) .map({ $0.trimmingCharacters(in: .whitespaces) }) if let name = parts.first, !name.isEmpty { guard parts.count > 1, var value = parts.last, value.isEmpty == false else { append(key: name, value: NSNumber(value: true), to: &annotations) return } if let number = Double(value) { append(key: name, value: NSNumber(value: number), to: &annotations) } else { if (value.hasPrefix("'") && value.hasSuffix("'")) || (value.hasPrefix("\"") && value.hasSuffix("\"")) { value = String(value[value.index(after: value.startIndex) ..< value.index(before: value.endIndex)]) value = value.trimmingCharacters(in: .whitespaces) } guard let data = (value as String).data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) else { append(key: name, value: value as NSString, to: &annotations) return } if let array = json as? [Any] { append(key: name, value: array as NSArray, to: &annotations) } else if let dict = json as? [String: Any] { append(key: name, value: dict as NSDictionary, to: &annotations) } else { append(key: name, value: value as NSString, to: &annotations) } } } } if namespaces.isEmpty { return annotations } else { var namespaced = Annotations() for namespace in namespaces.reversed() { namespaced[namespace] = annotations as NSObject annotations = namespaced namespaced = Annotations() } return annotations } } static func append(key: String, value: NSObject, to annotations: inout Annotations) { if let oldValue = annotations[key] { if var array = oldValue as? [NSObject] { if !array.contains(value) { array.append(value) annotations[key] = array as NSObject } } else if var oldDict = oldValue as? [String: NSObject], let newDict = value as? [String: NSObject] { newDict.forEach({ (key, value) in append(key: key, value: value, to: &oldDict) }) annotations[key] = oldDict as NSObject } else if oldValue != value { annotations[key] = [oldValue, value] as NSObject } } else { annotations[key] = value } } } // Parses string to see if it is a macros or not private extension String { /// @objc // true /// @objc var paosdjapsodji = 1 // false /// @MyAttribute(some thing) // true /// @MyAttribute(some thing) var paosdjapsodji = 1 // false /// @objc let asdasd // false var isPropertyWrapper: Bool { guard hasPrefix("@") else { return false } guard contains(")") || !contains(" ") else { return false } return true } } ================================================ FILE: SourceryFramework/Sources/Parsing/Utils/Bridges.swift ================================================ import Foundation extension Array { public func bridge() -> NSArray { return self as NSArray } } extension CharacterSet { public func bridge() -> NSCharacterSet { return self as NSCharacterSet } } extension Dictionary { public func bridge() -> NSDictionary { return self as NSDictionary } } extension NSString { public func bridge() -> String { return self as String } } extension String { public func bridge() -> NSString { return self as NSString } } ================================================ FILE: SourceryFramework/Sources/Parsing/Utils/InlineParser.swift ================================================ // // Created by Krzysztof Zablocki on 16/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation public enum TemplateAnnotationsParser { public typealias AnnotatedRanges = [String: [(range: NSRange, indentation: String)]] private static func regex(annotation: String) throws -> NSRegularExpression { let commentPattern = NSRegularExpression.escapedPattern(for: "//") let regex = try NSRegularExpression( pattern: "(^(?:\\s*?\\n)?(\\s*)\(commentPattern)\\s*?sourcery:\(annotation):)(\\S*)\\s*?(^.*?)(^\\s*?\(commentPattern)\\s*?sourcery:end)", options: [.allowCommentsAndWhitespace, .anchorsMatchLines, .dotMatchesLineSeparators] ) return regex } public static func parseAnnotations(_ annotation: String, contents: String, aggregate: Bool = false, forceParse: [String]) -> (contents: String, annotatedRanges: AnnotatedRanges) { let (annotatedRanges, rangesToReplace) = annotationRanges(annotation, contents: contents, aggregate: aggregate, forceParse: forceParse) let strigView = StringView(contents) var bridged = contents.bridge() rangesToReplace .sorted(by: { $0.location > $1.location }) .forEach { bridged = bridged.replacingCharacters(in: $0, with: String(repeating: " ", count: strigView.NSRangeToByteRange($0)!.length.value)) as NSString } return (bridged as String, annotatedRanges) } public static func annotationRanges(_ annotation: String, contents: String, aggregate: Bool = false, forceParse: [String]) -> (annotatedRanges: AnnotatedRanges, rangesToReplace: Set) { let bridged = contents.bridge() let regex = try? self.regex(annotation: annotation) var rangesToReplace = Set() var annotatedRanges = AnnotatedRanges() regex?.enumerateMatches(in: contents, options: [], range: bridged.entireRange) { result, _, _ in guard let result = result, result.numberOfRanges == 6 else { return } let indentationRange = result.range(at: 2) let nameRange = result.range(at: 3) let startLineRange = result.range(at: 4) let endLineRange = result.range(at: 5) let indentation = bridged.substring(with: indentationRange) let name = bridged.substring(with: nameRange) let range = NSRange( location: startLineRange.location, length: endLineRange.location - startLineRange.location ) if aggregate { var ranges = annotatedRanges[name] ?? [] ranges.append((range: range, indentation: indentation)) annotatedRanges[name] = ranges } else { annotatedRanges[name] = [(range: range, indentation: indentation)] } let rangeToBeRemoved = !forceParse.contains(where: { name.hasSuffix("." + $0) || name == $0 }) if rangeToBeRemoved { rangesToReplace.insert(range) } } return (annotatedRanges, rangesToReplace) } public static func removingEmptyAnnotations(from content: String) -> String { var bridged = content.bridge() let regex = try? self.regex(annotation: "\\S*") var rangesToReplace = [NSRange]() regex?.enumerateMatches(in: content, options: [], range: bridged.entireRange) { result, _, _ in guard let result = result, result.numberOfRanges == 6 else { return } let annotationStartRange = result.range(at: 1) let startLineRange = result.range(at: 4) let endLineRange = result.range(at: 5) if startLineRange.length == 0 { rangesToReplace.append(NSRange( location: annotationStartRange.location, length: NSMaxRange(endLineRange) - annotationStartRange.location )) } } rangesToReplace .reversed() .forEach { bridged = bridged.replacingCharacters(in: $0, with: "") as NSString } return bridged as String } } ================================================ FILE: SourceryFramework/Sources/Parsing/Utils/StringView.swift ================================================ import Foundation import SwiftSyntax // Represents the number of bytes in a string. Could be used to model offsets into a string, or the distance between /// two locations in a string. public struct ByteCount: ExpressibleByIntegerLiteral, Hashable { /// The byte value as an integer. public var value: Int /// Create a byte count by its integer value. /// /// - parameter value: Integer value. public init(integerLiteral value: Int) { self.value = value } /// Create a byte count by its integer value. /// /// - parameter value: Integer value. public init(_ value: Int) { self.value = value } /// Create a byte count by its integer value. /// /// - parameter value: Integer value. public init(_ value: Int64) { self.value = Int(value) } } extension ByteCount: CustomStringConvertible { public var description: String { return value.description } } extension ByteCount: Comparable { public static func < (lhs: ByteCount, rhs: ByteCount) -> Bool { return lhs.value < rhs.value } } extension ByteCount: AdditiveArithmetic { public static func - (lhs: ByteCount, rhs: ByteCount) -> ByteCount { return ByteCount(lhs.value - rhs.value) } public static func -= (lhs: inout ByteCount, rhs: ByteCount) { lhs.value -= rhs.value } public static func + (lhs: ByteCount, rhs: ByteCount) -> ByteCount { return ByteCount(lhs.value + rhs.value) } public static func += (lhs: inout ByteCount, rhs: ByteCount) { lhs.value += rhs.value } } /// Structure that represents a string range in bytes. public struct ByteRange: Equatable { /// The starting location of the range. public let location: ByteCount /// The length of the range. public let length: ByteCount /// Creates a byte range from a location and a length. /// /// - parameter location: The starting location of the range. /// - parameter length: The length of the range. public init(location: ByteCount, length: ByteCount) { self.location = location self.length = length } /// The range's upper bound. public var upperBound: ByteCount { return location + length } /// The range's lower bound. public var lowerBound: ByteCount { return location } public func contains(_ value: ByteCount) -> Bool { return location <= value && upperBound > value } public func intersects(_ otherRange: ByteRange) -> Bool { return contains(otherRange.lowerBound) || contains(otherRange.upperBound - 1) || otherRange.contains(lowerBound) || otherRange.contains(upperBound - 1) } public func intersects(_ ranges: [ByteRange]) -> Bool { return ranges.contains { intersects($0) } } public func union(with otherRange: ByteRange) -> ByteRange { let maxUpperBound = max(upperBound, otherRange.upperBound) let minLocation = min(location, otherRange.location) return ByteRange(location: minLocation, length: maxUpperBound - minLocation) } /* Returns a new range which is the receiver after inserting or removing some content before, within or after the receiver. change.length is amount of content inserted or removed. */ public func editingContent(_ change: ByteRange) -> ByteRange { // bytes inserted after type definition if change.location > upperBound { return self } // bytes inserted within type definition if change.location >= location { return ByteRange(location: location, length: length + change.length) } // bytes inserted before type definition return ByteRange(location: location + change.length, length: length) } } /// Representation of a single line in a larger String. public struct Line { /// origin = 0. public let index: Int /// Content. public let content: String /// UTF16 based range in entire String. Equivalent to `Range`. public let range: NSRange /// Byte based range in entire String. Equivalent to `Range`. public let byteRange: ByteRange } private extension RandomAccessCollection { /// Binary search assuming the collection is already sorted. /// /// - parameter comparing: Comparison function. /// /// - returns: The index in the collection of the element matching the `comparing` function. func indexAssumingSorted(comparing: (Element) throws -> ComparisonResult) rethrows -> Index? { guard !isEmpty else { return nil } var lowerBound = startIndex var upperBound = index(before: endIndex) var midIndex: Index while lowerBound <= upperBound { let boundDistance = distance(from: lowerBound, to: upperBound) midIndex = index(lowerBound, offsetBy: boundDistance / 2) let midElem = self[midIndex] switch try comparing(midElem) { case .orderedDescending: lowerBound = index(midIndex, offsetBy: 1) case .orderedAscending: upperBound = index(midIndex, offsetBy: -1) case .orderedSame: return midIndex } } return nil } } // swiftlint:disable:next line_length // According to https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/line-break // there are 3 types of line breaks: // line-break → U+000A // line-break → U+000D // line-break → U+000D followed by U+000A private let carriageReturnCharacter = "\u{000D}" private let lineFeedCharacter = "\u{000A}" private let newlinesCharacters = carriageReturnCharacter + lineFeedCharacter /// Structure that precalculates lines for the specified string and then uses this information for /// ByteRange to NSRange and NSRange to ByteRange operations public struct StringView { /// Reference to the NSString of represented string public let nsString: NSString /// Full range of nsString public let range: NSRange /// Reference to the String of the represented string public let string: String /// All lines of the original string public let lines: [Line] let utf8View: String.UTF8View let utf16View: String.UTF16View public init(_ string: String) { self.init(string, string as NSString) } public init(_ nsstring: NSString) { self.init(nsstring as String, nsstring) } // parses the given string into lines. Lines are split using // /* //sourcery: Annotation\n @MainActor\r\n protocol Something {\r\n var variable: Bool { get }\r\n }\n First iteration: [ "//sourcery: Annotation\n", "@MainActor", "protocol Something {", " var variable: Bool { get }", "}\n" ] Second iteration: [ "//sourcery: Annotation", "", "@MainActor", "protocol Something {", " var variable: Bool { get }", "}", "" ] */ private init(_ string: String, _ nsString: NSString) { self.string = string self.nsString = nsString self.range = NSRange(location: 0, length: nsString.length) utf8View = string.utf8 utf16View = string.utf16 var utf16CountSoFar = 0 var bytesSoFar: ByteCount = 0 var lines = [Line]() let lineContents = string.components(separatedBy: newlinesCharacters) .expandComponents(splitBy: lineFeedCharacter) // Be compatible with `NSString.getLineStart(_:end:contentsEnd:forRange:)` let endsWithNewLineCharacter: Bool if let lastChar = utf16View.last, let lastCharScalar = UnicodeScalar(lastChar) { endsWithNewLineCharacter = newlinesCharacters.contains(Character(lastCharScalar)) } else { endsWithNewLineCharacter = false } // if string ends with new line character, no empty line is generated after that. let enumerator = endsWithNewLineCharacter ? AnySequence(lineContents.dropLast().enumerated()) : AnySequence(lineContents.enumerated()) for (index, content) in enumerator { let index = index + 1 let rangeStart = utf16CountSoFar let utf16Count = content.utf16.count utf16CountSoFar += utf16Count let byteRangeStart = bytesSoFar let byteCount = ByteCount(content.lengthOfBytes(using: .utf8)) bytesSoFar += byteCount let newlineLength = index != lineContents.count ? 1 : 0 // FIXME: assumes \n let line = Line( index: index, content: content, range: NSRange(location: rangeStart, length: utf16Count + newlineLength), byteRange: ByteRange(location: byteRangeStart, length: byteCount + ByteCount(newlineLength)) ) lines.append(line) utf16CountSoFar += newlineLength bytesSoFar += ByteCount(newlineLength) } self.lines = lines } /// Returns substring in with UTF-16 range specified. /// /// - parameter range: UTF16 range. public func substring(with range: NSRange) -> String { return nsString.substring(with: range) } /** Returns a substring from a start and end SourceLocation. */ public func substringWithSourceRange(start: SourceLocation, end: SourceLocation) -> String? { guard start.offset < end.offset else { return nil } let byteRange = ByteRange(location: ByteCount(Int(start.offset)), length: ByteCount(Int(end.offset - start.offset))) return substringWithByteRange(byteRange) } /** Returns a substring with the provided byte range. - parameter start: Starting byte offset. - parameter length: Length of bytes to include in range. */ public func substringWithByteRange(_ byteRange: ByteRange) -> String? { return byteRangeToNSRange(byteRange).map(nsString.substring) } /// Returns a substictg, started at UTF-16 location. /// /// - parameter location: UTF-16 location. func substring(from location: Int) -> String { return nsString.substring(from: location) } /** Converts a range of byte offsets in `self` to an `NSRange` suitable for filtering `self` as an `NSString`. - parameter start: Starting byte offset. - parameter length: Length of bytes to include in range. - returns: An equivalent `NSRange`. */ public func byteRangeToNSRange(_ byteRange: ByteRange) -> NSRange? { guard !string.isEmpty else { return nil } let utf16Start = location(fromByteOffset: byteRange.location) if byteRange.length == 0 { return NSRange(location: utf16Start, length: 0) } let utf16End = location(fromByteOffset: byteRange.upperBound) return NSRange(location: utf16Start, length: utf16End - utf16Start) } /** Returns UTF8 offset from UTF16 offset. - parameter location: UTF16-based offset of string. - returns: UTF8 based offset of string. */ public func byteOffset(fromLocation location: Int) -> ByteCount { if lines.isEmpty { return 0 } let index = lines.indexAssumingSorted { line in if location < line.range.location { return .orderedAscending } else if location >= line.range.location + line.range.length { return .orderedDescending } return .orderedSame } // location may be out of bounds when NSRegularExpression points end of string. guard let line = (index.map { lines[$0] } ?? lines.last) else { fatalError() } let diff = location - line.range.location if diff == 0 { return line.byteRange.location } else if line.range.length == diff { return line.byteRange.upperBound } let utf16View = line.content.utf16 let endUTF8index = utf16View.index(utf16View.startIndex, offsetBy: diff, limitedBy: utf16View.endIndex)! .samePosition(in: line.content.utf8)! let byteDiff = line.content.utf8.distance(from: line.content.utf8.startIndex, to: endUTF8index) return ByteCount(line.byteRange.location.value + byteDiff) } /** Converts an `NSRange` suitable for filtering `self` as an `NSString` to a range of byte offsets in `self`. - parameter start: Starting character index in the string. - parameter length: Number of characters to include in range. - returns: An equivalent `NSRange`. */ public func NSRangeToByteRange(start: Int, length: Int) -> ByteRange? { guard let startUTF16Index = utf16View.index(utf16View.startIndex, offsetBy: start, limitedBy: utf16View.endIndex), let endUTF16Index = utf16View.index(startUTF16Index, offsetBy: length, limitedBy: utf16View.endIndex) else { return nil } guard let startUTF8Index = startUTF16Index.samePosition(in: utf8View), let endUTF8Index = endUTF16Index.samePosition(in: utf8View) else { return nil } let length = utf8View.distance(from: startUTF8Index, to: endUTF8Index) return ByteRange(location: byteOffset(fromLocation: start), length: ByteCount(length)) } public func NSRangeToByteRange(_ range: NSRange) -> ByteRange? { return NSRangeToByteRange(start: range.location, length: range.length) } /** Returns UTF16 offset from UTF8 offset. - parameter byteOffset: UTF8-based offset of string. - returns: UTF16 based offset of string. */ public func location(fromByteOffset byteOffset: ByteCount) -> Int { if lines.isEmpty { return 0 } let index = lines.indexAssumingSorted { line in if byteOffset < line.byteRange.location { return .orderedAscending } else if byteOffset >= line.byteRange.upperBound { return .orderedDescending } return .orderedSame } // byteOffset may be out of bounds when sourcekitd points end of string. guard let line = (index.map { lines[$0] } ?? lines.last) else { fatalError() } let diff = byteOffset - line.byteRange.location if diff == 0 { return line.range.location } else if line.byteRange.length == diff { return NSMaxRange(line.range) } let utf8View = line.content.utf8 let endUTF8Index = utf8View.index(utf8View.startIndex, offsetBy: diff.value, limitedBy: utf8View.endIndex) ?? utf8View.endIndex let utf16Diff = line.content.utf16.distance(from: line.content.utf16.startIndex, to: endUTF8Index) return line.range.location + utf16Diff } public func substringStartingLinesWithByteRange(_ byteRange: ByteRange) -> String? { return byteRangeToNSRange(byteRange).map { range in var lineStart = 0, lineEnd = 0 nsString.getLineStart(&lineStart, end: &lineEnd, contentsEnd: nil, for: range) return nsString.substring(with: NSRange(location: lineStart, length: NSMaxRange(range) - lineStart)) } } /** Returns a substring starting at the beginning of `start`'s line and ending at the end of `end`'s line. Returns `start`'s entire line if `end` is nil. - parameter start: Starting byte offset. - parameter length: Length of bytes to include in range. */ public func substringLinesWithByteRange(_ byteRange: ByteRange) -> String? { return byteRangeToNSRange(byteRange).map { range in var lineStart = 0, lineEnd = 0 nsString.getLineStart(&lineStart, end: &lineEnd, contentsEnd: nil, for: range) return nsString.substring(with: NSRange(location: lineStart, length: lineEnd - lineStart)) } } /** Returns line numbers containing starting and ending byte offsets. - parameter start: Starting byte offset. - parameter length: Length of bytes to include in range. */ public func lineRangeWithByteRange(_ byteRange: ByteRange) -> (start: Int, end: Int)? { return byteRangeToNSRange(byteRange).flatMap { range in var numberOfLines = 0, index = 0, lineRangeStart = 0 while index < nsString.length { numberOfLines += 1 if index <= range.location { lineRangeStart = numberOfLines } index = NSMaxRange(nsString.lineRange(for: NSRange(location: index, length: 1))) if index > NSMaxRange(range) { return (lineRangeStart, numberOfLines) } } return nil } } public func lineAndCharacter(forByteOffset offset: ByteCount, expandingTabsToWidth tabWidth: Int = 1) -> (line: Int, character: Int)? { let characterOffset = location(fromByteOffset: offset) return lineAndCharacter(forCharacterOffset: characterOffset, expandingTabsToWidth: tabWidth) } public func lineAndCharacter(forCharacterOffset offset: Int, expandingTabsToWidth tabWidth: Int = 1) -> (line: Int, character: Int)? { assert(tabWidth > 0) let index = lines.indexAssumingSorted { line in if offset < line.range.location { return .orderedAscending } else if offset >= line.range.location + line.range.length { return .orderedDescending } return .orderedSame } return index.map { let line = lines[$0] let prefixLength = offset - line.range.location let character: Int if tabWidth == 1 { character = prefixLength } else { character = line.content.prefix(prefixLength).reduce(0) { sum, character in if character == "\t" { return sum - (sum % tabWidth) + tabWidth } else { return sum + 1 } } } return (line: line.index, character: character + 1) } } } private extension Array where Element == String { func expandComponents(splitBy separator: String) -> [String] { flatMap { $0.components(separatedBy: separator) } } } ================================================ FILE: SourceryFramework/Sources/Parsing/Utils/Verifier.swift ================================================ // // Created by Krzysztof Zablocki on 23/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation import PathKit import SourceryUtils public enum Verifier { // swiftlint:disable:next force_try private static let conflictRegex = try! NSRegularExpression(pattern: "^\\s+?(<<<<<|>>>>>)") public enum Result { case isCodeGenerated case containsConflictMarkers case approved } public static func canParse(content: String, path: Path, generationMarker: String, forceParse: [String] = []) -> Result { guard !content.isEmpty else { return .approved } let shouldForceParse = forceParse.contains { name in return path.hasExtension(as: name) } if content.hasPrefix(generationMarker) && shouldForceParse == false { return .isCodeGenerated } if conflictRegex.numberOfMatches(in: content, options: .anchored, range: content.bridge().entireRange) > 0 { return .containsConflictMarkers } return .approved } } ================================================ FILE: SourceryFramework.podspec ================================================ Pod::Spec.new do |s| s.name = "SourceryFramework" s.version = "2.3.0" s.summary = "A tool that brings meta-programming to Swift, allowing you to code generate Swift code." s.platform = :osx, '10.15' s.description = <<-DESC A tool that brings meta-programming to Swift, allowing you to code generate Swift code. * Featuring daemon mode that allows you to write templates side-by-side with generated code. * Using SourceKit so you can scan your regular code. DESC s.homepage = "https://github.com/krzysztofzablocki/Sourcery" s.license = 'MIT' s.author = { "Krzysztof Zabłocki" => "krzysztof.zablocki@pixle.pl" } s.social_media_url = "https://twitter.com/merowing_" s.source = { :http => "https://github.com/krzysztofzablocki/Sourcery/releases/download/#{s.version}/sourcery-#{s.version}.zip" } s.source_files = "SourceryFramework/Sources/**/*.swift" s.osx.deployment_target = '10.15' s.dependency 'SourceryUtils' s.dependency 'SourceryRuntime' end ================================================ FILE: SourceryJS/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2018 Pixle. All rights reserved. NSPrincipalClass ================================================ FILE: SourceryJS/Resources/ejs.js ================================================ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o * @author Tiancheng "Timothy" Gu * @project EJS * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0} */ /** * EJS internal functions. * * Technically this "module" lies in the same file as {@link module:ejs}, for * the sake of organization all the private functions re grouped into this * module. * * @module ejs-internal * @private */ /** * Embedded JavaScript templating engine. * * @module ejs * @public */ var fs = require('fs'); var path = require('path'); var utils = require('./utils'); var scopeOptionWarned = false; var _VERSION_STRING = require('../package.json').version; var _DEFAULT_DELIMITER = '%'; var _DEFAULT_LOCALS_NAME = 'locals'; var _NAME = 'ejs'; var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)'; var _OPTS = ['delimiter', 'scope', 'context', 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace', 'strict', 'filename']; // We don't allow 'cache' option to be passed in the data obj // for the normal `render` call, but this is where Express puts it // so we make an exception for `renderFile` var _OPTS_EXPRESS = _OPTS.concat('cache'); var _BOM = /^\uFEFF/; /** * EJS template function cache. This can be a LRU object from lru-cache NPM * module. By default, it is {@link module:utils.cache}, a simple in-process * cache that grows continuously. * * @type {Cache} */ exports.cache = utils.cache; /** * Custom file loader. Useful for template preprocessing or restricting access * to a certain part of the filesystem. * * @type {fileLoader} */ exports.fileLoader = fs.readFileSync; /** * Name of the object containing the locals. * * This variable is overridden by {@link Options}`.localsName` if it is not * `undefined`. * * @type {String} * @public */ exports.localsName = _DEFAULT_LOCALS_NAME; /** * Get the path to the included file from the parent file path and the * specified path. * * @param {String} name specified path * @param {String} filename parent file path * @param {Boolean} isDir parent file path whether is directory * @return {String} */ exports.resolveInclude = function(name, filename, isDir) { var dirname = path.dirname; var extname = path.extname; var resolve = path.resolve; var includePath = resolve(isDir ? filename : dirname(filename), name); var ext = extname(name); if (!ext) { includePath += '.ejs'; } return includePath; }; /** * Get the path to the included file by Options * * @param {String} path specified path * @param {Options} options compilation options * @return {String} */ function getIncludePath(path, options){ var includePath; if (path.charAt(0) == '/') { includePath = exports.resolveInclude(path.replace(/^\/*/,''), options.root || '/', true); } else { if (!options.filename) { throw new Error('`include` use relative path requires the \'filename\' option.'); } includePath = exports.resolveInclude(path, options.filename); } return includePath; } /** * Get the template from a string or a file, either compiled on-the-fly or * read from cache (if enabled), and cache the template if needed. * * If `template` is not set, the file specified in `options.filename` will be * read. * * If `options.cache` is true, this function reads the file from * `options.filename` so it must be set prior to calling this function. * * @memberof module:ejs-internal * @param {Options} options compilation options * @param {String} [template] template source * @return {(TemplateFunction|ClientFunction)} * Depending on the value of `options.client`, either type might be returned. * @static */ function handleCache(options, template) { var func; var filename = options.filename; var hasTemplate = arguments.length > 1; if (options.cache) { if (!filename) { throw new Error('cache option requires a filename'); } func = exports.cache.get(filename); if (func) { return func; } if (!hasTemplate) { template = fileLoader(filename).toString().replace(_BOM, ''); } } else if (!hasTemplate) { // istanbul ignore if: should not happen at all if (!filename) { throw new Error('Internal EJS error: no file name or template ' + 'provided'); } template = fileLoader(filename).toString().replace(_BOM, ''); } func = exports.compile(template, options); if (options.cache) { exports.cache.set(filename, func); } return func; } /** * Try calling handleCache with the given options and data and call the * callback with the result. If an error occurs, call the callback with * the error. Used by renderFile(). * * @memberof module:ejs-internal * @param {Options} options compilation options * @param {Object} data template data * @param {RenderFileCallback} cb callback * @static */ function tryHandleCache(options, data, cb) { var result; try { result = handleCache(options)(data); } catch (err) { return cb(err); } return cb(null, result); } /** * fileLoader is independent * * @param {String} filePath ejs file path. * @return {String} The contents of the specified file. * @static */ function fileLoader(filePath){ return exports.fileLoader(filePath); } /** * Get the template function. * * If `options.cache` is `true`, then the template is cached. * * @memberof module:ejs-internal * @param {String} path path for the specified file * @param {Options} options compilation options * @return {(TemplateFunction|ClientFunction)} * Depending on the value of `options.client`, either type might be returned * @static */ function includeFile(path, options) { var opts = utils.shallowCopy({}, options); opts.filename = getIncludePath(path, opts); return handleCache(opts); } /** * Get the JavaScript source of an included file. * * @memberof module:ejs-internal * @param {String} path path for the specified file * @param {Options} options compilation options * @return {Object} * @static */ function includeSource(path, options) { var opts = utils.shallowCopy({}, options); var includePath; var template; includePath = getIncludePath(path, opts); template = fileLoader(includePath).toString().replace(_BOM, ''); opts.filename = includePath; var templ = new Template(template, opts); templ.generateSource(); return { source: templ.source, filename: includePath, template: template }; } /** * Re-throw the given `err` in context to the `str` of ejs, `filename`, and * `lineno`. * * @implements RethrowCallback * @memberof module:ejs-internal * @param {Error} err Error object * @param {String} str EJS source * @param {String} filename file name of the EJS file * @param {String} lineno line number of the error * @static */ function rethrow(err, str, flnm, lineno, esc){ var lines = str.split('\n'); var start = Math.max(lineno - 3, 0); var end = Math.min(lines.length, lineno + 3); var filename = esc(flnm); // eslint-disable-line // Error context var context = lines.slice(start, end).map(function (line, i){ var curr = i + start + 1; return (curr == lineno ? ' >> ' : ' ') + curr + '| ' + line; }).join('\n'); // Alter exception message err.path = filename; err.message = (filename || 'ejs') + ':' + lineno + '\n' + context + '\n\n' + err.message; throw err; } function stripSemi(str){ return str.replace(/;(\s*$)/, '$1'); } /** * Compile the given `str` of ejs into a template function. * * @param {String} template EJS template * * @param {Options} opts compilation options * * @return {(TemplateFunction|ClientFunction)} * Depending on the value of `opts.client`, either type might be returned. * @public */ exports.compile = function compile(template, opts) { var templ; // v1 compat // 'scope' is 'context' // FIXME: Remove this in a future version if (opts && opts.scope) { if (!scopeOptionWarned){ console.warn('`scope` option is deprecated and will be removed in EJS 3'); scopeOptionWarned = true; } if (!opts.context) { opts.context = opts.scope; } delete opts.scope; } templ = new Template(template, opts); return templ.compile(); }; /** * Render the given `template` of ejs. * * If you would like to include options but not data, you need to explicitly * call this function with `data` being an empty object or `null`. * * @param {String} template EJS template * @param {Object} [data={}] template data * @param {Options} [opts={}] compilation and rendering options * @return {String} * @public */ exports.render = function (template, d, o) { var data = d || {}; var opts = o || {}; // No options object -- if there are optiony names // in the data, copy them to options if (arguments.length == 2) { utils.shallowCopyFromList(opts, data, _OPTS); } return handleCache(opts, template)(data); }; /** * Render an EJS file at the given `path` and callback `cb(err, str)`. * * If you would like to include options but not data, you need to explicitly * call this function with `data` being an empty object or `null`. * * @param {String} path path to the EJS file * @param {Object} [data={}] template data * @param {Options} [opts={}] compilation and rendering options * @param {RenderFileCallback} cb callback * @public */ exports.renderFile = function () { var filename = arguments[0]; var cb = arguments[arguments.length - 1]; var opts = {filename: filename}; var data; if (arguments.length > 2) { data = arguments[1]; // No options object -- if there are optiony names // in the data, copy them to options if (arguments.length === 3) { // Express 4 if (data.settings && data.settings['view options']) { utils.shallowCopyFromList(opts, data.settings['view options'], _OPTS_EXPRESS); } // Express 3 and lower else { utils.shallowCopyFromList(opts, data, _OPTS_EXPRESS); } } else { // Use shallowCopy so we don't pollute passed in opts obj with new vals utils.shallowCopy(opts, arguments[2]); } opts.filename = filename; } else { data = {}; } return tryHandleCache(opts, data, cb); }; /** * Clear intermediate JavaScript cache. Calls {@link Cache#reset}. * @public */ exports.clearCache = function () { exports.cache.reset(); }; function Template(text, opts) { opts = opts || {}; var options = {}; this.templateText = text; this.mode = null; this.truncate = false; this.currentLine = 1; this.source = ''; this.dependencies = []; options.client = opts.client || false; options.escapeFunction = opts.escape || utils.escapeXML; options.compileDebug = opts.compileDebug !== false; options.debug = !!opts.debug; options.filename = opts.filename; options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; options.strict = opts.strict || false; options.context = opts.context; options.cache = opts.cache || false; options.rmWhitespace = opts.rmWhitespace; options.root = opts.root; options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; if (options.strict) { options._with = false; } else { options._with = typeof opts._with != 'undefined' ? opts._with : true; } this.opts = options; this.regex = this.createRegex(); } Template.modes = { EVAL: 'eval', ESCAPED: 'escaped', RAW: 'raw', COMMENT: 'comment', LITERAL: 'literal' }; Template.prototype = { createRegex: function () { var str = _REGEX_STRING; var delim = utils.escapeRegExpChars(this.opts.delimiter); str = str.replace(/%/g, delim); return new RegExp(str); }, compile: function () { var src; var fn; var opts = this.opts; var prepended = ''; var appended = ''; var escapeFn = opts.escapeFunction; if (!this.source) { this.generateSource(); prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n'; if (opts._with !== false) { prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; appended += ' }' + '\n'; } appended += ' return __output.join("");' + '\n'; this.source = prepended + this.source + appended; } if (opts.compileDebug) { src = 'var __line = 1' + '\n' + ' , __lines = ' + JSON.stringify(this.templateText) + '\n' + ' , __filename = ' + (opts.filename ? JSON.stringify(opts.filename) : 'undefined') + ';' + '\n' + 'try {' + '\n' + this.source + '} catch (e) {' + '\n' + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n' + '}' + '\n'; } else { src = this.source; } if (opts.debug) { console.log(src); } if (opts.client) { src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src; if (opts.compileDebug) { src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src; } } if (opts.strict) { src = '"use strict";\n' + src; } try { fn = new Function(opts.localsName + ', escapeFn, include, rethrow', src); } catch(e) { // istanbul ignore else if (e instanceof SyntaxError) { if (opts.filename) { e.message += ' in ' + opts.filename; } e.message += ' while compiling ejs\n\n'; e.message += 'If the above error is not helpful, you may want to try EJS-Lint:\n'; e.message += 'https://github.com/RyanZim/EJS-Lint'; } throw e; } if (opts.client) { fn.dependencies = this.dependencies; return fn; } // Return a callable function which will execute the function // created by the source-code, with the passed data as locals // Adds a local `include` function which allows full recursive include var returnedFn = function (data) { var include = function (path, includeData) { var d = utils.shallowCopy({}, data); if (includeData) { d = utils.shallowCopy(d, includeData); } return includeFile(path, opts)(d); }; return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]); }; returnedFn.dependencies = this.dependencies; return returnedFn; }, generateSource: function () { var opts = this.opts; if (opts.rmWhitespace) { // Have to use two separate replace here as `^` and `$` operators don't // work well with `\r`. this.templateText = this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, ''); } // Slurp spaces and tabs before <%_ and after _%> this.templateText = this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>'); var self = this; var matches = this.parseTemplateText(); var d = this.opts.delimiter; if (matches && matches.length) { matches.forEach(function (line, index) { var opening; var closing; var include; var includeOpts; var includeObj; var includeSrc; // If this is an opening tag, check for closing tags // FIXME: May end up with some false positives here // Better to store modes as k/v with '<' + delimiter as key // Then this can simply check against the map if ( line.indexOf('<' + d) === 0 // If it is a tag && line.indexOf('<' + d + d) !== 0) { // and is not escaped closing = matches[index + 2]; if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) { throw new Error('Could not find matching close tag for "' + line + '".'); } } // HACK: backward-compat `include` preprocessor directives if ((include = line.match(/^\s*include\s+(\S+)/))) { opening = matches[index - 1]; // Must be in EVAL or RAW mode if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) { includeOpts = utils.shallowCopy({}, self.opts); includeObj = includeSource(include[1], includeOpts); if (self.opts.compileDebug) { includeSrc = ' ; (function(){' + '\n' + ' var __line = 1' + '\n' + ' , __lines = ' + JSON.stringify(includeObj.template) + '\n' + ' , __filename = ' + JSON.stringify(includeObj.filename) + ';' + '\n' + ' try {' + '\n' + includeObj.source + ' } catch (e) {' + '\n' + ' rethrow(e, __lines, __filename, __line);' + '\n' + ' }' + '\n' + ' ; }).call(this)' + '\n'; }else{ includeSrc = ' ; (function(){' + '\n' + includeObj.source + ' ; }).call(this)' + '\n'; } self.source += includeSrc; self.dependencies.push(exports.resolveInclude(include[1], includeOpts.filename)); return; } } self.scanLine(line); }); } }, parseTemplateText: function () { var str = this.templateText; var pat = this.regex; var result = pat.exec(str); var arr = []; var firstPos; while (result) { firstPos = result.index; if (firstPos !== 0) { arr.push(str.substring(0, firstPos)); str = str.slice(firstPos); } arr.push(result[0]); str = str.slice(result[0].length); result = pat.exec(str); } if (str) { arr.push(str); } return arr; }, scanLine: function (line) { var self = this; var d = this.opts.delimiter; var newLineCount = 0; function _addOutput() { if (self.truncate) { // Only replace single leading linebreak in the line after // -%> tag -- this is the single, trailing linebreak // after the tag that the truncation mode replaces // Handle Win / Unix / old Mac linebreaks -- do the \r\n // combo first in the regex-or line = line.replace(/^(?:\r\n|\r|\n)/, ''); self.truncate = false; } else if (self.opts.rmWhitespace) { // rmWhitespace has already removed trailing spaces, just need // to remove linebreaks line = line.replace(/^\n/, ''); } if (!line) { return; } // Preserve literal slashes line = line.replace(/\\/g, '\\\\'); // Convert linebreaks line = line.replace(/\n/g, '\\n'); line = line.replace(/\r/g, '\\r'); // Escape double-quotes // - this will be the delimiter during execution line = line.replace(/"/g, '\\"'); self.source += ' ; __append("' + line + '")' + '\n'; } newLineCount = (line.split('\n').length - 1); switch (line) { case '<' + d: case '<' + d + '_': this.mode = Template.modes.EVAL; break; case '<' + d + '=': this.mode = Template.modes.ESCAPED; break; case '<' + d + '-': this.mode = Template.modes.RAW; break; case '<' + d + '#': this.mode = Template.modes.COMMENT; break; case '<' + d + d: this.mode = Template.modes.LITERAL; this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n'; break; case d + d + '>': this.mode = Template.modes.LITERAL; this.source += ' ; __append("' + line.replace(d + d + '>', d + '>') + '")' + '\n'; break; case d + '>': case '-' + d + '>': case '_' + d + '>': if (this.mode == Template.modes.LITERAL) { _addOutput(); } this.mode = null; this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0; break; default: // In script mode, depends on type of tag if (this.mode) { // If '//' is found without a line break, add a line break. switch (this.mode) { case Template.modes.EVAL: case Template.modes.ESCAPED: case Template.modes.RAW: if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { line += '\n'; } } switch (this.mode) { // Just executing code case Template.modes.EVAL: this.source += ' ; ' + line + '\n'; break; // Exec, esc, and output case Template.modes.ESCAPED: this.source += ' ; __append(escapeFn(' + stripSemi(line) + '))' + '\n'; break; // Exec and output case Template.modes.RAW: this.source += ' ; __append(' + stripSemi(line) + ')' + '\n'; break; case Template.modes.COMMENT: // Do nothing break; // Literal <%% mode, append as raw output case Template.modes.LITERAL: _addOutput(); break; } } // In string mode, just add the output else { _addOutput(); } } if (self.opts.compileDebug && newLineCount) { this.currentLine += newLineCount; this.source += ' ; __line = ' + this.currentLine + '\n'; } } }; /** * Escape characters reserved in XML. * * This is simply an export of {@link module:utils.escapeXML}. * * If `markup` is `undefined` or `null`, the empty string is returned. * * @param {String} markup Input string * @return {String} Escaped string * @public * @func * */ exports.escapeXML = utils.escapeXML; /** * Express.js support. * * This is an alias for {@link module:ejs.renderFile}, in order to support * Express.js out-of-the-box. * * @func */ exports.__express = exports.renderFile; // Add require support /* istanbul ignore else */ if (require.extensions) { require.extensions['.ejs'] = function (module, flnm) { var filename = flnm || /* istanbul ignore next */ module.filename; var options = { filename: filename, client: true }; var template = fileLoader(filename).toString(); var fn = exports.compile(template, options); module._compile('module.exports = ' + fn.toString() + ';', filename); }; } /** * Version of EJS. * * @readonly * @type {String} * @public */ exports.VERSION = _VERSION_STRING; /** * Name for detection of EJS. * * @readonly * @type {String} * @public */ exports.name = _NAME; /* istanbul ignore if */ if (typeof window != 'undefined') { window.ejs = exports; } },{"../package.json":4,"./utils":3,"fs":5,"path":6}],3:[function(require,module,exports){ /* * EJS Embedded JavaScript templates * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /** * Private utility functions * @module utils * @private */ 'use strict'; var regExpChars = /[|\\{}()[\]^$+*?.]/g; /** * Escape characters reserved in regular expressions. * * If `string` is `undefined` or `null`, the empty string is returned. * * @param {String} string Input string * @return {String} Escaped string * @static * @private */ exports.escapeRegExpChars = function (string) { // istanbul ignore if if (!string) { return ''; } return String(string).replace(regExpChars, '\\$&'); }; var _ENCODE_HTML_RULES = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; var _MATCH_HTML = /[&<>\'"]/g; function encode_char(c) { return _ENCODE_HTML_RULES[c] || c; } /** * Stringified version of constants used by {@link module:utils.escapeXML}. * * It is used in the process of generating {@link ClientFunction}s. * * @readonly * @type {String} */ var escapeFuncStr = 'var _ENCODE_HTML_RULES = {\n' + ' "&": "&"\n' + ' , "<": "<"\n' + ' , ">": ">"\n' + ' , \'"\': """\n' + ' , "\'": "'"\n' + ' }\n' + ' , _MATCH_HTML = /[&<>\'"]/g;\n' + 'function encode_char(c) {\n' + ' return _ENCODE_HTML_RULES[c] || c;\n' + '};\n'; /** * Escape characters reserved in XML. * * If `markup` is `undefined` or `null`, the empty string is returned. * * @implements {EscapeCallback} * @param {String} markup Input string * @return {String} Escaped string * @static * @private */ exports.escapeXML = function (markup) { return markup == undefined ? '' : String(markup) .replace(_MATCH_HTML, encode_char); }; exports.escapeXML.toString = function () { return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr; }; /** * Naive copy of properties from one object to another. * Does not recurse into non-scalar properties * Does not check to see if the property has a value before copying * * @param {Object} to Destination object * @param {Object} from Source object * @return {Object} Destination object * @static * @private */ exports.shallowCopy = function (to, from) { from = from || {}; for (var p in from) { to[p] = from[p]; } return to; }; /** * Naive copy of a list of key names, from one object to another. * Only copies property if it is actually defined * Does not recurse into non-scalar properties * * @param {Object} to Destination object * @param {Object} from Source object * @param {Array} list List of properties to copy * @return {Object} Destination object * @static * @private */ exports.shallowCopyFromList = function (to, from, list) { for (var i = 0; i < list.length; i++) { var p = list[i]; if (typeof from[p] != 'undefined') { to[p] = from[p]; } } return to; }; /** * Simple in-process cache implementation. Does not implement limits of any * sort. * * @implements Cache * @static * @private */ exports.cache = { _data: {}, set: function (key, val) { this._data[key] = val; }, get: function (key) { return this._data[key]; }, reset: function () { this._data = {}; } }; },{}],4:[function(require,module,exports){ module.exports={ "name": "ejs", "description": "Embedded JavaScript templates", "keywords": [ "template", "engine", "ejs" ], "version": "2.5.6", "author": { "name": "Matthew Eernisse", "email": "mde@fleegix.org", "url": "http://fleegix.org" }, "contributors": [ { "name": "Timothy Gu", "email": "timothygu99@gmail.com", "url": "https://timothygu.github.io" } ], "license": "Apache-2.0", "main": "./lib/ejs.js", "repository": { "type": "git", "url": "git://github.com/mde/ejs.git" }, "bugs": { "url": "https://github.com/mde/ejs/issues" }, "homepage": "https://github.com/mde/ejs", "dependencies": {}, "devDependencies": { "browserify": "^13.0.1", "eslint": "^3.0.0", "git-directory-deploy": "^1.5.1", "istanbul": "~0.4.3", "jake": "^8.0.0", "jsdoc": "^3.4.0", "lru-cache": "^4.0.1", "mocha": "^3.0.2", "uglify-js": "^2.6.2" }, "engines": { "node": ">=0.10.0" }, "scripts": { "test": "mocha", "lint": "eslint \"**/*.js\" Jakefile", "coverage": "istanbul cover node_modules/mocha/bin/_mocha", "doc": "jake doc", "devdoc": "jake doc[dev]" }, "_id": "ejs@2.5.6", "_shasum": "479636bfa3fe3b1debd52087f0acb204b4f19c88", "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.6.tgz", "_from": "ejs@*", "_npmVersion": "3.10.8", "_nodeVersion": "6.9.1", "_npmUser": { "name": "mde", "email": "mde@fleegix.org" }, "dist": { "shasum": "479636bfa3fe3b1debd52087f0acb204b4f19c88", "tarball": "https://registry.npmjs.org/ejs/-/ejs-2.5.6.tgz" }, "maintainers": [ { "name": "mde", "email": "mde@fleegix.org" } ], "_npmOperationalInternal": { "host": "packages-12-west.internal.npmjs.com", "tmp": "tmp/ejs-2.5.6.tgz_1487277787176_0.4875628533773124" }, "directories": {}, "readme": "ERROR: No README data found!" } },{}],5:[function(require,module,exports){ },{}],6:[function(require,module,exports){ (function (process){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // resolves . and .. elements in a path array with directory names there // must be no slashes, empty elements, or device names (c:\) in the array // (so also no leading and trailing slashes - it does not distinguish // relative and absolute paths) function normalizeArray(parts, allowAboveRoot) { // if the path tries to go above the root, `up` ends up > 0 var up = 0; for (var i = parts.length - 1; i >= 0; i--) { var last = parts[i]; if (last === '.') { parts.splice(i, 1); } else if (last === '..') { parts.splice(i, 1); up++; } else if (up) { parts.splice(i, 1); up--; } } // if the path is allowed to go above the root, restore leading ..s if (allowAboveRoot) { for (; up--; up) { parts.unshift('..'); } } return parts; } // Split a filename into [root, dir, basename, ext], unix version // 'root' is just a slash, or nothing. var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; var splitPath = function(filename) { return splitPathRe.exec(filename).slice(1); }; // path.resolve([from ...], to) // posix version exports.resolve = function() { var resolvedPath = '', resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path = (i >= 0) ? arguments[i] : process.cwd(); // Skip empty and invalid entries if (typeof path !== 'string') { throw new TypeError('Arguments to path.resolve must be strings'); } else if (!path) { continue; } resolvedPath = path + '/' + resolvedPath; resolvedAbsolute = path.charAt(0) === '/'; } // At this point the path should be resolved to a full absolute path, but // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { return !!p; }), !resolvedAbsolute).join('/'); return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; }; // path.normalize(path) // posix version exports.normalize = function(path) { var isAbsolute = exports.isAbsolute(path), trailingSlash = substr(path, -1) === '/'; // Normalize the path path = normalizeArray(filter(path.split('/'), function(p) { return !!p; }), !isAbsolute).join('/'); if (!path && !isAbsolute) { path = '.'; } if (path && trailingSlash) { path += '/'; } return (isAbsolute ? '/' : '') + path; }; // posix version exports.isAbsolute = function(path) { return path.charAt(0) === '/'; }; // posix version exports.join = function() { var paths = Array.prototype.slice.call(arguments, 0); return exports.normalize(filter(paths, function(p, index) { if (typeof p !== 'string') { throw new TypeError('Arguments to path.join must be strings'); } return p; }).join('/')); }; // path.relative(from, to) // posix version exports.relative = function(from, to) { from = exports.resolve(from).substr(1); to = exports.resolve(to).substr(1); function trim(arr) { var start = 0; for (; start < arr.length; start++) { if (arr[start] !== '') break; } var end = arr.length - 1; for (; end >= 0; end--) { if (arr[end] !== '') break; } if (start > end) return []; return arr.slice(start, end - start + 1); } var fromParts = trim(from.split('/')); var toParts = trim(to.split('/')); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; for (var i = 0; i < length; i++) { if (fromParts[i] !== toParts[i]) { samePartsLength = i; break; } } var outputParts = []; for (var i = samePartsLength; i < fromParts.length; i++) { outputParts.push('..'); } outputParts = outputParts.concat(toParts.slice(samePartsLength)); return outputParts.join('/'); }; exports.sep = '/'; exports.delimiter = ':'; exports.dirname = function(path) { var result = splitPath(path), root = result[0], dir = result[1]; if (!root && !dir) { // No dirname whatsoever return '.'; } if (dir) { // It has a dirname, strip trailing slash dir = dir.substr(0, dir.length - 1); } return root + dir; }; exports.basename = function(path, ext) { var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows? if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } return f; }; exports.extname = function(path) { return splitPath(path)[3]; }; function filter (xs, f) { if (xs.filter) return xs.filter(f); var res = []; for (var i = 0; i < xs.length; i++) { if (f(xs[i], i, xs)) res.push(xs[i]); } return res; } // String.prototype.substr - negative index don't work in IE8 var substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) { return str.substr(start, len) } : function (str, start, len) { if (start < 0) start = str.length + start; return str.substr(start, len); } ; }).call(this,require('_process')) },{"_process":7}],7:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout () { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } } ()) function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch(e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch(e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; },{}]},{},[1]); ================================================ FILE: SourceryJS/SourceryJS.h ================================================ // // SourceryJS.h // SourceryJS // // Created by Ilya Puchka on 25/01/2018. // Copyright © 2018 Pixle. All rights reserved. // #import //! Project version number for SourceryJS. FOUNDATION_EXPORT double SourceryJSVersionNumber; //! Project version string for SourceryJS. FOUNDATION_EXPORT const unsigned char SourceryJSVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: SourceryJS/Sources/EJSTemplate+Tests.swift ================================================ // swift test runs tests in DEBUG, thus this file will only be compiled for `swift test` #if canImport(ObjectiveC) && DEBUG import JavaScriptCore import PathKit // (c) https://forums.swift.org/t/swift-5-3-spm-resources-in-tests-uses-wrong-bundle-path/37051/46 private extension Bundle { static let mypackageResources: Bundle = { #if DEBUG if let moduleName = Bundle(for: BundleFinder.self).bundleIdentifier, let testBundlePath = ProcessInfo.processInfo.environment["XCTestBundlePath"] { if let resourceBundle = Bundle(path: testBundlePath + "/\(moduleName)_\(moduleName).bundle") { return resourceBundle } } #endif return Bundle.module }() private final class BundleFinder {} } public extension Foundation.Bundle { /// Returns the resource bundle associated with the current Swift module. static var jsModule: Bundle = { let bundleName = "Sourcery_SourceryJS" let candidates = [ // Bundle should be present here when the package is linked into an App. Bundle.main.resourceURL, // Bundle should be present here when the package is linked into a framework. Bundle(for: EJSTemplate.self).resourceURL, // For command-line tools. Bundle.main.bundleURL, ] for candidate in candidates { let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle") if let bundle = bundlePath.flatMap(Bundle.init(url:)) { return bundle } } return Bundle.mypackageResources }() } open class EJSTemplate { public struct Error: Swift.Error, CustomStringConvertible { public let description: String public init(_ value: String) { self.description = value } } /// Should be set to the path of EJS before rendering any template. /// By default reads ejs.js from framework bundle. #if SWIFT_PACKAGE static let bundle = Bundle.jsModule #else static let bundle = Bundle(for: EJSTemplate.self) #endif public static var ejsPath: Path? = { let bundle = EJSTemplate.bundle guard let path = bundle.path(forResource: "ejs", ofType: "js") else { return nil } return Path(path) }() private static let jsVm = JSVirtualMachine() public let sourcePath: Path public let templateString: String let ejs: String public private(set) lazy var jsContext: JSContext = { let jsContext = JSContext(virtualMachine: EJSTemplate.jsVm)! jsContext.setObject(self.templateString, forKeyedSubscript: "template" as NSString) jsContext.setObject(self.sourcePath.lastComponent, forKeyedSubscript: "templateName" as NSString) jsContext.setObject(self.context, forKeyedSubscript: "templateContext" as NSString) let include: @convention(block) (String) -> [String:String] = { [unowned self] in self.includeFile($0) } jsContext.setObject(include, forKeyedSubscript: "include" as NSString) return jsContext }() open var context: [String: Any] = [:] { didSet { jsContext.setObject(context, forKeyedSubscript: "templateContext" as NSString) } } public convenience init(path: Path, ejsPath: Path) throws { try self.init(path: path, templateString: try path.read(), ejsPath: ejsPath) } public init(path: Path, templateString: String, ejsPath: Path) throws { self.templateString = templateString sourcePath = path self.ejs = try ejsPath.read(.utf8) } public init(templateString: String, ejsPath: Path) throws { self.templateString = templateString sourcePath = "" self.ejs = try ejsPath.read(.utf8) } public func render(_ context: [String: Any]) throws -> String { self.context = context var error: Error? jsContext.exceptionHandler = { error = error ?? $1.map({ Error($0.toString()) }) ?? Error("Unknown JavaScript error") } jsContext.evaluateScript("var window = this; \(ejs)") if let error = error { throw Error("\(sourcePath): \(error)") } let content = jsContext.objectForKeyedSubscript("content").toString() return content ?? "" } func includeFile(_ requestedPath: String) -> [String: String] { let requestedPath = Path(requestedPath) let path = sourcePath.parent() + requestedPath var includedTemplate: String? = try? path.read() /// The template extension may be omitted, so try to read again by adding it if a template was not found if includedTemplate == nil, path.extension != "ejs" { includedTemplate = try? Path(path.string + ".ejs").read() } var templateDictionary = [String: String]() templateDictionary["template"] = includedTemplate if requestedPath.components.count > 1 { templateDictionary["basePath"] = Path(components: requestedPath.components.dropLast()).string } return templateDictionary } } #endif ================================================ FILE: SourceryJS/Sources/EJSTemplate.swift ================================================ #if canImport(ObjectiveC) && !DEBUG import JavaScriptCore import PathKit private extension Foundation.Bundle { /// Returns the resource bundle associated with the current Swift module. static var jsModule: Bundle = { let bundleName = "Sourcery_SourceryJS" let candidates = [ // Bundle should be present here when the package is linked into an App. Bundle.main.resourceURL, // Bundle should be present here when the package is linked into a framework. Bundle(for: EJSTemplate.self).resourceURL, // For command-line tools. Bundle.main.bundleURL, ] for candidate in candidates { let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle") if let bundle = bundlePath.flatMap(Bundle.init(url:)) { return bundle } } return Bundle(for: EJSTemplate.self) }() } open class EJSTemplate { public struct Error: Swift.Error, CustomStringConvertible { public let description: String public init(_ value: String) { self.description = value } } /// Should be set to the path of EJS before rendering any template. /// By default reads ejs.js from framework bundle. #if SWIFT_PACKAGE static let bundle = Bundle.jsModule #else static let bundle = Bundle(for: EJSTemplate.self) #endif public static var ejsPath: Path! = bundle.path(forResource: "ejs", ofType: "js").map({ Path($0) }) private static let jsVm = JSVirtualMachine() public let sourcePath: Path public let templateString: String let ejs: String public private(set) lazy var jsContext: JSContext = { let jsContext = JSContext(virtualMachine: EJSTemplate.jsVm)! jsContext.setObject(self.templateString, forKeyedSubscript: "template" as NSString) jsContext.setObject(self.sourcePath.lastComponent, forKeyedSubscript: "templateName" as NSString) jsContext.setObject(self.context, forKeyedSubscript: "templateContext" as NSString) let include: @convention(block) (String) -> [String:String] = { [unowned self] in self.includeFile($0) } jsContext.setObject(include, forKeyedSubscript: "include" as NSString) return jsContext }() open var context: [String: Any] = [:] { didSet { jsContext.setObject(context, forKeyedSubscript: "templateContext" as NSString) } } public convenience init(path: Path, ejsPath: Path = EJSTemplate.ejsPath) throws { try self.init(path: path, templateString: try path.read(), ejsPath: ejsPath) } public init(path: Path, templateString: String, ejsPath: Path = EJSTemplate.ejsPath) throws { self.templateString = templateString sourcePath = path self.ejs = try ejsPath.read(.utf8) } public init(templateString: String, ejsPath: Path = EJSTemplate.ejsPath) throws { self.templateString = templateString sourcePath = "" self.ejs = try ejsPath.read(.utf8) } public func render(_ context: [String: Any]) throws -> String { self.context = context var error: Error? jsContext.exceptionHandler = { error = error ?? $1.map({ Error($0.toString()) }) ?? Error("Unknown JavaScript error") } jsContext.evaluateScript("var window = this; \(ejs)") if let error = error { throw Error("\(sourcePath): \(error)") } let content = jsContext.objectForKeyedSubscript("content").toString() return content ?? "" } func includeFile(_ requestedPath: String) -> [String: String] { let requestedPath = Path(requestedPath) let path = sourcePath.parent() + requestedPath var includedTemplate: String? = try? path.read() /// The template extension may be omitted, so try to read again by adding it if a template was not found if includedTemplate == nil, path.extension != "ejs" { includedTemplate = try? Path(path.string + ".ejs").read() } var templateDictionary = [String: String]() templateDictionary["template"] = includedTemplate if requestedPath.components.count > 1 { templateDictionary["basePath"] = Path(components: requestedPath.components.dropLast()).string } return templateDictionary } } #endif ================================================ FILE: SourceryRuntime/Sources/Common/AST/AccessLevel.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation /// :nodoc: public enum AccessLevel: String { case `package` = "package" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" case `public` = "public" case `open` = "open" case none = "" } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Actor.swift ================================================ import Foundation // sourcery: skipDescription /// Descibes Swift actor #if canImport(ObjectiveC) @objc(SwiftActor) @objcMembers #endif public final class Actor: Type { // sourcery: skipJSExport public class var kind: String { return "actor" } /// Returns "actor" public override var kind: String { Self.kind } /// Whether type is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Whether method is distributed method public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Actor.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \(String(describing: self.kind)), ") string.append("isFinal = \(String(describing: self.isFinal)), ") string.append("isDistributed = \(String(describing: self.isDistributed))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Actor else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Actor else { return false } return super.isEqual(rhs) } // sourcery:inline:Actor.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Annotations.swift ================================================ import Foundation public typealias Annotations = [String: NSObject] /// Describes annotated declaration, i.e. type, method, variable, enum case public protocol Annotated { /** All annotations of declaration stored by their name. Value can be `bool`, `String`, float `NSNumber` or array of those types if you use several annotations with the same name. **Example:** ``` //sourcery: booleanAnnotation //sourcery: stringAnnotation = "value" //sourcery: numericAnnotation = 0.5 [ "booleanAnnotation": true, "stringAnnotation": "value", "numericAnnotation": 0.5 ] ``` */ var annotations: Annotations { get } } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Attribute.swift ================================================ import Foundation /// Describes Swift attribute #if canImport(ObjectiveC) @objcMembers #endif public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { /// Attribute name public let name: String /// Attribute arguments public let arguments: [String: NSObject] // sourcery: skipJSExport let _description: String // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { self.name = name self.arguments = arguments let argumentDescription = arguments.map { "\($0.key): \($0.value is String ? "\"" : "")\($0.value)\($0.value is String ? "\"" : "")" }.joined(separator: ", ") self._description = description ?? "@\(name)\(!argumentDescription.isEmpty ? "(" : "")\(argumentDescription)\(!argumentDescription.isEmpty ? ")" : "")" } /// TODO: unify `asSource` / `description`? public var asSource: String { description } /// Attribute description that can be used in a template. public override var description: String { _description } /// :nodoc: public enum Identifier: String { case convenience case required case available case discardableResult case GKInspectable = "gkinspectable" case objc case objcMembers case nonobjc case NSApplicationMain case NSCopying case NSManaged case UIApplicationMain case IBOutlet = "iboutlet" case IBInspectable = "ibinspectable" case IBDesignable = "ibdesignable" case autoclosure case convention case mutating case nonisolated case isolated case escaping case final case open case lazy case `package` = "package" case `public` = "public" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" case publicSetter = "setter_access.public" case internalSetter = "setter_access.internal" case privateSetter = "setter_access.private" case fileprivateSetter = "setter_access.fileprivate" case optional case dynamic public init?(identifier: String) { let identifier = identifier.trimmingPrefix("source.decl.attribute.") if identifier == "objc.name" { self.init(rawValue: "objc") } else { self.init(rawValue: identifier) } } public static func from(string: String) -> Identifier? { switch string { case "GKInspectable": return Identifier.GKInspectable case "objc": return .objc case "IBOutlet": return .IBOutlet case "IBInspectable": return .IBInspectable case "IBDesignable": return .IBDesignable default: return Identifier(rawValue: string) } } public var name: String { switch self { case .GKInspectable: return "GKInspectable" case .objc: return "objc" case .IBOutlet: return "IBOutlet" case .IBInspectable: return "IBInspectable" case .IBDesignable: return "IBDesignable" case .fileprivateSetter: return "fileprivate" case .privateSetter: return "private" case .internalSetter: return "internal" case .publicSetter: return "public" default: return rawValue } } public var description: String { return hasAtPrefix ? "@\(name)" : name } public var hasAtPrefix: Bool { switch self { case .available, .discardableResult, .GKInspectable, .objc, .objcMembers, .nonobjc, .NSApplicationMain, .NSCopying, .NSManaged, .UIApplicationMain, .IBOutlet, .IBInspectable, .IBDesignable, .autoclosure, .convention, .escaping: return true default: return false } } } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Attribute else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "arguments").trackDifference(actual: self.arguments, expected: castObject.arguments)) results.append(contentsOf: DiffableResult(identifier: "_description").trackDifference(actual: self._description, expected: castObject._description)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.arguments) hasher.combine(self._description) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Attribute else { return false } if self.name != rhs.name { return false } if self.arguments != rhs.arguments { return false } if self._description != rhs._description { return false } return true } // sourcery:inline:Attribute.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { withVaList(["arguments"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.arguments = arguments guard let _description: String = aDecoder.decode(forKey: "_description") else { withVaList(["_description"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._description = _description } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.arguments, forKey: "arguments") aCoder.encode(self._description, forKey: "_description") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Class.swift ================================================ import Foundation // sourcery: skipDescription /// Descibes Swift class #if canImport(ObjectiveC) @objc(SwiftClass) @objcMembers #endif public final class Class: Type { // sourcery: skipJSExport public class var kind: String { return "class" } /// Returns "class" public override var kind: String { Self.kind } /// Whether type is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Class.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \(String(describing: self.kind)), ") string.append("isFinal = \(String(describing: self.isFinal))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Class else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Class else { return false } return super.isEqual(rhs) } // sourcery:inline:Class.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Definition.swift ================================================ import Foundation /// Describes that the object is defined in a context of some `Type` public protocol Definition: AnyObject { /// Reference to type name where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc var definedInTypeName: TypeName? { get } /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown var definedInType: Type? { get } // sourcery: skipJSExport /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` var actualDefinedInTypeName: TypeName? { get } } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Documentation.swift ================================================ import Foundation public typealias Documentation = [String] /// Describes a declaration with documentation, i.e. type, method, variable, enum case public protocol Documented { var documentation: Documentation { get } } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Import.swift ================================================ import Foundation /// Defines import type #if canImport(ObjectiveC) @objcMembers #endif public class Import: NSObject, SourceryModelWithoutDescription, Diffable { /// Import kind, e.g. class, struct in `import class Module.ClassName` public var kind: String? /// Import path public var path: String /// :nodoc: public init(path: String, kind: String? = nil) { self.path = path self.kind = kind } /// Full import value e.g. `import struct Module.StructName` public override var description: String { if let kind = kind { return "\(kind) \(path)" } return path } /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` public var moduleName: String { if kind != nil { if let idx = path.lastIndex(of: ".") { return String(path[.. DiffableResult { let results = DiffableResult() guard let castObject = object as? Import else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.kind) hasher.combine(self.path) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Import else { return false } if self.kind != rhs.kind { return false } if self.path != rhs.path { return false } return true } // sourcery:inline:Import.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.kind = aDecoder.decode(forKey: "kind") guard let path: String = aDecoder.decode(forKey: "path") else { withVaList(["path"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.path = path } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.kind, forKey: "kind") aCoder.encode(self.path, forKey: "path") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Modifier.swift ================================================ import Foundation public typealias SourceryModifier = Modifier /// modifier can be thing like `private`, `class`, `nonmutating` /// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` #if canImport(ObjectiveC) @objcMembers #endif public class Modifier: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { /// The declaration modifier name. public let name: String /// The modifier detail, if any. public let detail: String? public init(name: String, detail: String? = nil) { self.name = name self.detail = detail } public var asSource: String { if let detail = detail { return "\(name)(\(detail))" } else { return name } } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Modifier else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.detail) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Modifier else { return false } if self.name != rhs.name { return false } if self.detail != rhs.detail { return false } return true } // sourcery:inline:Modifier.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.detail = aDecoder.decode(forKey: "detail") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.detail, forKey: "detail") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/PhantomProtocols.swift ================================================ // // Created by Krzysztof Zablocki on 23/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation /// Phantom protocol for diffing protocol AutoDiffable {} /// Phantom protocol for equality protocol AutoEquatable {} /// Phantom protocol for equality protocol AutoDescription {} /// Phantom protocol for NSCoding protocol AutoCoding {} protocol AutoJSExport {} /// Phantom protocol for NSCoding, Equatable and Diffable protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} ================================================ FILE: SourceryRuntime/Sources/Common/AST/Protocol.swift ================================================ // // Protocol.swift // Sourcery // // Created by Krzysztof Zablocki on 09/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation #if canImport(ObjectiveC) /// :nodoc: public typealias SourceryProtocol = Protocol /// Describes Swift protocol @objcMembers public final class Protocol: Type { // sourcery: skipJSExport public class var kind: String { return "protocol" } /// Returns "protocol" public override var kind: String { Self.kind } /// list of all declared associated types with their names as keys public var associatedTypes: [String: AssociatedType] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } // sourcery: skipCoding /// list of generic requirements public override var genericRequirements: [GenericRequirement] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], associatedTypes: [String: AssociatedType] = [:], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], implements: [String: Type] = [:], kind: String = Protocol.kind) { self.associatedTypes = associatedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \(String(describing: self.kind)), ") string.append("associatedTypes = \(String(describing: self.associatedTypes)), ") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Protocol else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.associatedTypes) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Protocol else { return false } if self.associatedTypes != rhs.associatedTypes { return false } return super.isEqual(rhs) } // sourcery:inline:Protocol.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { withVaList(["associatedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedTypes = associatedTypes super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.associatedTypes, forKey: "associatedTypes") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Common/AST/ProtocolComposition.swift ================================================ // Created by eric_horacek on 2/12/20. // Copyright © 2020 Airbnb Inc. All rights reserved. import Foundation /// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). #if canImport(ObjectiveC) @objcMembers #endif public final class ProtocolComposition: Type { // sourcery: skipJSExport public class var kind: String { return "protocolComposition" } /// Returns "protocolComposition" public override var kind: String { Self.kind } /// The names of the types composed to form this composition public let composedTypeNames: [TypeName] // sourcery: skipEquality, skipDescription /// The types composed to form this composition, if known public var composedTypes: [Type]? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], annotations: [String: NSObject] = [:], isGeneric: Bool = false, composedTypeNames: [TypeName] = [], composedTypes: [Type]? = nil, implements: [String: Type] = [:], kind: String = ProtocolComposition.kind) { self.composedTypeNames = composedTypeNames self.composedTypes = composedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, annotations: annotations, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " string += "kind = \(String(describing: self.kind)), " string += "composedTypeNames = \(String(describing: self.composedTypeNames))" return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ProtocolComposition else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.composedTypeNames) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ProtocolComposition else { return false } if self.composedTypeNames != rhs.composedTypeNames { return false } return super.isEqual(rhs) } // sourcery:inline:ProtocolComposition.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { withVaList(["composedTypeNames"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.composedTypeNames = composedTypeNames self.composedTypes = aDecoder.decode(forKey: "composedTypes") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") aCoder.encode(self.composedTypes, forKey: "composedTypes") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Struct.swift ================================================ // // Struct.swift // Sourcery // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation // sourcery: skipDescription /// Describes Swift struct #if canImport(ObjectiveC) @objcMembers #endif public final class Struct: Type { // sourcery: skipJSExport public class var kind: String { return "struct" } /// Returns "struct" public override var kind: String { Self.kind } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Struct.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " string += "kind = \(String(describing: self.kind))" return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Struct else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Struct else { return false } return super.isEqual(rhs) } // sourcery:inline:Struct.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/TypeName/Array.swift ================================================ import Foundation /// Describes array type #if canImport(ObjectiveC) @objcMembers #endif public final class ArrayType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Array element type name public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription /// Array element type, if known public var elementType: Type? /// :nodoc: public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name self.elementTypeName = elementTypeName self.elementType = elementType } /// Returns array as generic type public var asGeneric: GenericType { GenericType(name: "Array", typeParameters: [ .init(typeName: elementTypeName, type: elementType) ]) } public var asSource: String { "[\(elementTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("elementTypeName = \(String(describing: self.elementTypeName)), ") string.append("asGeneric = \(String(describing: self.asGeneric)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ArrayType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ArrayType else { return false } if self.name != rhs.name { return false } if self.elementTypeName != rhs.elementTypeName { return false } return true } // sourcery:inline:ArrayType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elementTypeName = elementTypeName self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elementTypeName, forKey: "elementTypeName") aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/TypeName/Dictionary.swift ================================================ import Foundation /// Describes dictionary type #if canImport(ObjectiveC) @objcMembers #endif public final class DictionaryType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Dictionary value type name public var valueTypeName: TypeName // sourcery: skipEquality, skipDescription /// Dictionary value type, if known public var valueType: Type? /// Dictionary key type name public var keyTypeName: TypeName // sourcery: skipEquality, skipDescription /// Dictionary key type, if known public var keyType: Type? /// :nodoc: public init(name: String, valueTypeName: TypeName, valueType: Type? = nil, keyTypeName: TypeName, keyType: Type? = nil) { self.name = name self.valueTypeName = valueTypeName self.valueType = valueType self.keyTypeName = keyTypeName self.keyType = keyType } /// Returns dictionary as generic type public var asGeneric: GenericType { GenericType(name: "Dictionary", typeParameters: [ .init(typeName: keyTypeName), .init(typeName: valueTypeName) ]) } public var asSource: String { "[\(keyTypeName.asSource): \(valueTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("valueTypeName = \(String(describing: self.valueTypeName)), ") string.append("keyTypeName = \(String(describing: self.keyTypeName)), ") string.append("asGeneric = \(String(describing: self.asGeneric)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? DictionaryType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "valueTypeName").trackDifference(actual: self.valueTypeName, expected: castObject.valueTypeName)) results.append(contentsOf: DiffableResult(identifier: "keyTypeName").trackDifference(actual: self.keyTypeName, expected: castObject.keyTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.valueTypeName) hasher.combine(self.keyTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? DictionaryType else { return false } if self.name != rhs.name { return false } if self.valueTypeName != rhs.valueTypeName { return false } if self.keyTypeName != rhs.keyTypeName { return false } return true } // sourcery:inline:DictionaryType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { withVaList(["valueTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.valueTypeName = valueTypeName self.valueType = aDecoder.decode(forKey: "valueType") guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { withVaList(["keyTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.keyTypeName = keyTypeName self.keyType = aDecoder.decode(forKey: "keyType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.valueTypeName, forKey: "valueTypeName") aCoder.encode(self.valueType, forKey: "valueType") aCoder.encode(self.keyTypeName, forKey: "keyTypeName") aCoder.encode(self.keyType, forKey: "keyType") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/TypeName/Generic.swift ================================================ import Foundation /// Descibes Swift generic type #if canImport(ObjectiveC) @objcMembers #endif public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { /// The name of the base type, i.e. `Array` for `Array` public var name: String /// This generic type parameters public let typeParameters: [GenericTypeParameter] /// :nodoc: public init(name: String, typeParameters: [GenericTypeParameter] = []) { self.name = name self.typeParameters = typeParameters } public var asSource: String { let arguments = typeParameters .map({ $0.typeName.asSource }) .joined(separator: ", ") return "\(name)<\(arguments)>" } public override var description: String { asSource } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericType else { return false } if self.name != rhs.name { return false } if self.typeParameters != rhs.typeParameters { return false } return true } // sourcery:inline:GenericType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { withVaList(["typeParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeParameters = typeParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeParameters, forKey: "typeParameters") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/TypeName/Set.swift ================================================ import Foundation /// Describes set type #if canImport(ObjectiveC) @objcMembers #endif public final class SetType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Array element type name public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription /// Array element type, if known public var elementType: Type? /// :nodoc: public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name self.elementTypeName = elementTypeName self.elementType = elementType } /// Returns array as generic type public var asGeneric: GenericType { GenericType(name: "Set", typeParameters: [ .init(typeName: elementTypeName) ]) } public var asSource: String { "[\(elementTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("elementTypeName = \(String(describing: self.elementTypeName)), ") string.append("asGeneric = \(String(describing: self.asGeneric)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? SetType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? SetType else { return false } if self.name != rhs.name { return false } if self.elementTypeName != rhs.elementTypeName { return false } return true } // sourcery:inline:SetType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elementTypeName = elementTypeName self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elementTypeName, forKey: "elementTypeName") aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/AST/TypeName/Typed.swift ================================================ import Foundation /// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value public protocol Typed { // sourcery: skipEquality, skipDescription /// Type, if known var type: Type? { get } // sourcery: skipEquality, skipDescription /// Type name var typeName: TypeName { get } // sourcery: skipEquality, skipDescription /// Whether type is optional var isOptional: Bool { get } // sourcery: skipEquality, skipDescription /// Whether type is implicitly unwrapped optional var isImplicitlyUnwrappedOptional: Bool { get } // sourcery: skipEquality, skipDescription /// Type name without attributes and optional type information var unwrappedTypeName: String { get } } ================================================ FILE: SourceryRuntime/Sources/Common/AST/Typealias.swift ================================================ import Foundation /// :nodoc: #if canImport(ObjectiveC) @objcMembers #endif public final class Typealias: NSObject, Typed, SourceryModel, Diffable { // New typealias name public let aliasName: String // Target name public let typeName: TypeName // sourcery: skipEquality, skipDescription public var type: Type? /// module in which this typealias was declared public var module: String? /// Imports that existed in the file that contained this typealias declaration public var imports: [Import] = [] /// typealias annotations public var annotations: Annotations = [:] /// typealias documentation public var documentation: Documentation = [] // sourcery: skipEquality, skipDescription public var parent: Type? { didSet { parentName = parent?.name } } /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String var parentName: String? public var name: String { if let parentName = parent?.name { return "\(module != nil ? "\(module!)." : "")\(parentName).\(aliasName)" } else { return "\(module != nil ? "\(module!)." : "")\(aliasName)" } } public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil, annotations: [String: NSObject] = [:], documentation: [String] = []) { self.aliasName = aliasName self.typeName = typeName self.accessLevel = accessLevel.rawValue self.parent = parent self.parentName = parent?.name self.module = module self.annotations = annotations self.documentation = documentation } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("aliasName = \(String(describing: self.aliasName)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("module = \(String(describing: self.module)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("parentName = \(String(describing: self.parentName)), ") string.append("name = \(String(describing: self.name)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Typealias else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.aliasName) hasher.combine(self.typeName) hasher.combine(self.module) hasher.combine(self.accessLevel) hasher.combine(self.parentName) hasher.combine(self.annotations) hasher.combine(self.documentation) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Typealias else { return false } if self.aliasName != rhs.aliasName { return false } if self.typeName != rhs.typeName { return false } if self.module != rhs.module { return false } if self.accessLevel != rhs.accessLevel { return false } if self.parentName != rhs.parentName { return false } if self.documentation != rhs.documentation { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:Typealias.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { withVaList(["aliasName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.aliasName = aliasName guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.parent = aDecoder.decode(forKey: "parent") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.parentName = aDecoder.decode(forKey: "parentName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.aliasName, forKey: "aliasName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.parentName, forKey: "parentName") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/Array+Parallel.swift ================================================ // // Created by Krzysztof Zablocki on 06/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation public extension Array { func parallelFlatMap(transform: (Element) -> [T]) -> [T] { return parallelMap(transform: transform).flatMap { $0 } } func parallelCompactMap(transform: (Element) -> T?) -> [T] { return parallelMap(transform: transform).compactMap { $0 } } func parallelMap(transform: (Element) -> T) -> [T] { var result = ContiguousArray(repeating: nil, count: count) return result.withUnsafeMutableBufferPointer { buffer in nonisolated(unsafe) let buffer = buffer DispatchQueue.concurrentPerform(iterations: buffer.count) { idx in buffer[idx] = transform(self[idx]) } return buffer.map { $0! } } } func parallelPerform(_ work: (Element) -> Void) { DispatchQueue.concurrentPerform(iterations: count) { idx in work(self[idx]) } } } ================================================ FILE: SourceryRuntime/Sources/Common/BytesRange.swift ================================================ // // Created by Sébastien Duperron on 03/01/2018. // Copyright © 2018 Pixle. All rights reserved. // import Foundation /// :nodoc: #if canImport(ObjectiveC) @objcMembers #endif public final class BytesRange: NSObject, SourceryModel, Diffable { public let offset: Int64 public let length: Int64 public init(offset: Int64, length: Int64) { self.offset = offset self.length = length } public convenience init(range: (offset: Int64, length: Int64)) { self.init(offset: range.offset, length: range.length) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string += "offset = \(String(describing: self.offset)), " string += "length = \(String(describing: self.length))" return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? BytesRange else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "offset").trackDifference(actual: self.offset, expected: castObject.offset)) results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: castObject.length)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.offset) hasher.combine(self.length) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? BytesRange else { return false } if self.offset != rhs.offset { return false } if self.length != rhs.length { return false } return true } // sourcery:inline:BytesRange.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.offset = aDecoder.decodeInt64(forKey: "offset") self.length = aDecoder.decodeInt64(forKey: "length") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.offset, forKey: "offset") aCoder.encode(self.length, forKey: "length") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/Composer/Composer.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation private func currentTimestamp() -> TimeInterval { return Date().timeIntervalSince1970 } /// Responsible for composing results of `FileParser`. public enum Composer { /// Performs final processing of discovered types: /// - extends types with their corresponding extensions; /// - replaces typealiases with actual types /// - finds actual types for variables and enums raw values /// - filters out any private types and extensions /// /// - Parameter parserResult: Result of parsing source code. /// - Parameter serial: Whether to process results serially instead of concurrently /// - Returns: Final types and extensions of unknown types. public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult, serial: Bool = false) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { let composed = ParserResultsComposed(parserResult: parserResult) let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in composed.resolveType(typeName: typeName, containingType: containingType) } let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in composed.resolveType(typeName: typeName, containingType: containingType, method: method) } let processType = { (type: Type) in type.variables.forEach { resolveVariableTypes($0, of: type, resolve: resolveType) } type.methods.forEach { resolveMethodTypes($0, of: type, resolve: methodResolveType) } type.subscripts.forEach { resolveSubscriptTypes($0, of: type, resolve: resolveType) } if let enumeration = type as? Enum { resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) } if let composition = type as? ProtocolComposition { resolveProtocolCompositionTypes(composition, resolve: resolveType) } if let sourceryProtocol = type as? SourceryProtocol { resolveAssociatedTypes(sourceryProtocol, resolve: resolveType) } } let processFunction = { (function: SourceryMethod) in resolveMethodTypes(function, of: nil, resolve: methodResolveType) } if serial { composed.types.forEach(processType) composed.functions.forEach(processFunction) } else { composed.types.parallelPerform(processType) composed.functions.parallelPerform(processFunction) } updateTypeRelationships(types: composed.types) return ( types: composed.types.sorted { $0.globalName < $1.globalName }, functions: composed.functions.sorted { $0.name < $1.name }, typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) ) } typealias TypeResolver = (TypeName, Type?) -> Type? typealias MethodArgumentTypeResolver = (TypeName, Type?, Method) -> Type? private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { variable.type = resolve(variable.typeName, type) /// The actual `definedInType` is assigned in `uniqueTypes` but we still /// need to resolve the type to correctly parse typealiases /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 if let definedInTypeName = variable.definedInTypeName { _ = resolve(definedInTypeName, type) } } private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { `subscript`.parameters.forEach { (parameter) in parameter.type = resolve(parameter.typeName, type) } `subscript`.returnType = resolve(`subscript`.returnTypeName, type) if let definedInTypeName = `subscript`.definedInTypeName { _ = resolve(definedInTypeName, type) } } private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: MethodArgumentTypeResolver) { method.parameters.forEach { parameter in parameter.type = resolve(parameter.typeName, type, method) } /// The actual `definedInType` is assigned in `uniqueTypes` but we still /// need to resolve the type to correctly parse typealiases /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 var definedInType: Type? if let definedInTypeName = method.definedInTypeName { definedInType = resolve(definedInTypeName, type, method) } guard !method.returnTypeName.isVoid else { return } if method.isInitializer || method.isFailableInitializer { method.returnType = definedInType if let type = method.actualDefinedInTypeName { if method.isFailableInitializer { method.returnTypeName = TypeName( name: type.name, isOptional: true, isImplicitlyUnwrappedOptional: false, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if method.isInitializer { method.returnTypeName = type } } } else { method.returnType = resolve(method.returnTypeName, type, method) } } private static func resolveEnumTypes(_ enumeration: Enum, types: [String: Type], resolve: TypeResolver) { enumeration.cases.forEach { enumCase in enumCase.associatedValues.forEach { associatedValue in associatedValue.type = resolve(associatedValue.typeName, enumeration) } } guard enumeration.hasRawType else { return } if let rawValueVariable = enumeration.variables.first(where: { $0.name == "rawValue" && !$0.isStatic }) { enumeration.rawTypeName = rawValueVariable.actualTypeName enumeration.rawType = rawValueVariable.type } else if let rawTypeName = enumeration.inheritedTypes.first { // enums with no cases or enums with cases that contain associated values can't have raw type guard !enumeration.cases.isEmpty, !enumeration.hasAssociatedValues else { return enumeration.rawTypeName = nil } if let rawTypeCandidate = types[rawTypeName] { if !((rawTypeCandidate is SourceryProtocol) || (rawTypeCandidate is ProtocolComposition)) { enumeration.rawTypeName = TypeName(rawTypeName) enumeration.rawType = rawTypeCandidate } } else { enumeration.rawTypeName = TypeName(rawTypeName) } } } private static func resolveProtocolCompositionTypes(_ protocolComposition: ProtocolComposition, resolve: TypeResolver) { let composedTypes = protocolComposition.composedTypeNames.compactMap { typeName in resolve(typeName, protocolComposition) } protocolComposition.composedTypes = composedTypes } private static func resolveAssociatedTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) { sourceryProtocol.associatedTypes.forEach { (_, value) in guard let typeName = value.typeName, let type = resolve(typeName, sourceryProtocol) else { return } value.type = type } sourceryProtocol.genericRequirements.forEach { requirment in if let knownAssociatedType = sourceryProtocol.associatedTypes[requirment.leftType.name] { requirment.leftType = knownAssociatedType } requirment.rightType.type = resolve(requirment.rightType.typeName, sourceryProtocol) } } private static func updateTypeRelationships(types: [Type]) { var typesByName = [String: Type]() types.forEach { typesByName[$0.globalName] = $0 } var processed = [String: Bool]() types.forEach { type in if let type = type as? Class, let supertype = type.inheritedTypes.first.flatMap({ typesByName[$0] }) as? Class { type.supertype = supertype } processed[type.globalName] = true updateTypeRelationship(for: type, typesByName: typesByName, processed: &processed) } } internal static func findBaseType(for type: Type, name: String, typesByName: [String: Type]) -> Type? { // special case to check if the type is based on one of the recognized types // and the superclass has a generic constraint in `name` part of the `TypeName` var name = name if name.contains("<") && name.contains(">") { let parts = name.split(separator: "<") name = String(parts.first!) } if let baseType = typesByName[name] { return baseType } if let module = type.module, let baseType = typesByName["\(module).\(name)"] { return baseType } for importModule in type.imports { if let baseType = typesByName["\(importModule).\(name)"] { return baseType } } guard name.contains("&") else { return nil } // this can happen for a type which consists of mutliple types composed together (i.e. (A & B)) let nameComponents = name.components(separatedBy: "&").map { $0.trimmingCharacters(in: .whitespaces) } let types: [Type] = nameComponents.compactMap { typesByName[$0] } let typeNames = types.map { TypeName(name: $0.name) } return ProtocolComposition(name: name, inheritedTypes: types.map { $0.globalName }, composedTypeNames: typeNames, composedTypes: types) } private static func updateTypeRelationship(for type: Type, typesByName: [String: Type], processed: inout [String: Bool]) { type.based.keys.forEach { name in guard let baseType = findBaseType(for: type, name: name, typesByName: typesByName) else { return } let globalName = baseType.globalName if processed[globalName] != true { processed[globalName] = true updateTypeRelationship(for: baseType, typesByName: typesByName, processed: &processed) } copyTypeRelationships(from: baseType, to: type) if let composedType = baseType as? ProtocolComposition { let implements = composedType.composedTypes?.filter({ $0 is SourceryProtocol }) implements?.forEach { updateInheritsAndImplements(from: $0, to: type) } if implements?.count == composedType.composedTypes?.count || composedType.composedTypes == nil || composedType.composedTypes?.isEmpty == true { type.implements[globalName] = baseType } } else { updateInheritsAndImplements(from: baseType, to: type) } type.basedTypes[globalName] = baseType } } private static func updateInheritsAndImplements(from baseType: Type, to type: Type) { if baseType is Class { type.inherits[baseType.name] = baseType } else if let `protocol` = baseType as? SourceryProtocol { type.implements[baseType.globalName] = baseType if let extendingProtocol = type as? SourceryProtocol { `protocol`.associatedTypes.forEach { if extendingProtocol.associatedTypes[$0.key] == nil { extendingProtocol.associatedTypes[$0.key] = $0.value } } } } } private static func copyTypeRelationships(from baseType: Type, to type: Type) { baseType.based.keys.forEach { type.based[$0] = $0 } baseType.basedTypes.forEach { type.basedTypes[$0.key] = $0.value } baseType.inherits.forEach { type.inherits[$0.key] = $0.value } baseType.implements.forEach { type.implements[$0.key] = $0.value } } } ================================================ FILE: SourceryRuntime/Sources/Common/Composer/ParserResultsComposed.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation internal struct ParserResultsComposed { private(set) var typeMap = [String: Type]() private(set) var modules = [String: [String: Type]]() private(set) var types = [Type]() let parsedTypes: [Type] let functions: [SourceryMethod] let resolvedTypealiases: [String: Typealias] let associatedTypes: [String: AssociatedType] let unresolvedTypealiases: [String: Typealias] init(parserResult: FileParserResult) { // TODO: This logic should really be more complicated // For any resolution we need to be looking at accessLevel and module boundaries // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not self.functions = parserResult.functions let aliases = Self.typealiases(parserResult) resolvedTypealiases = aliases.resolved unresolvedTypealiases = aliases.unresolved associatedTypes = Self.extractAssociatedTypes(parserResult) parsedTypes = parserResult.types var moduleAndTypeNameCollisions: Set = [] for type in parsedTypes where !type.isExtension && type.parent == nil { if let module = type.module, type.localName == module { moduleAndTypeNameCollisions.insert(module) } } // set definedInType for all methods and variables parsedTypes .forEach { type in type.variables.forEach { $0.definedInType = type } type.methods.forEach { $0.definedInType = type } type.subscripts.forEach { $0.definedInType = type } } // map all known types to their names for type in parsedTypes where !type.isExtension && type.parent == nil { let name = type.name // If a type name has the `.` prefix, and the type `.` is undefined, we can safely remove the `.` prefix if let module = type.module, name.hasPrefix(module), name.dropFirst(module.count).hasPrefix("."), !moduleAndTypeNameCollisions.contains(module) { type.localName.removeFirst(module.count + 1) } } for type in parsedTypes where !type.isExtension { typeMap[type.globalName] = type if let module = type.module { var typesByModules = modules[module, default: [:]] typesByModules[type.name] = type modules[module] = typesByModules } } /// Resolve typealiases let typealiases = Array(unresolvedTypealiases.values) typealiases.forEach { alias in alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) } /// Map associated types associatedTypes.forEach { if let globalName = $0.value.type?.globalName, let type = typeMap[globalName] { typeMap[$0.key] = type } else { typeMap[$0.key] = $0.value.type } } types = unifyTypes() } mutating private func resolveExtensionOfNestedType(_ type: Type) { var components = type.localName.components(separatedBy: ".") let rootName: String if type.parent != nil, let module = type.module { rootName = module } else { rootName = components.removeFirst() } if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { type.localName = baseType.localName type.module = baseType.module type.parent = baseType.parent } else { for _import in type.imports { let parentKey = "\(rootName).\(components.joined(separator: "."))" let parentKeyFull = "\(_import.moduleName).\(parentKey)" if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { type.localName = baseType.localName type.module = baseType.module type.parent = baseType.parent return } } } // Parent extensions should always be processed before `type`, as this affects the globalName of `type`. for parent in type.parentTypes where parent.isExtension && parent.localName.contains(".") { let oldName = parent.globalName resolveExtensionOfNestedType(parent) if oldName != parent.globalName { rewriteChildren(of: parent) } } } // if it had contained types, they might have been fully defined and so their name has to be noted in uniques private mutating func rewriteChildren(of type: Type) { // child is never an extension so no need to check for child in type.containedTypes { typeMap[child.globalName] = child rewriteChildren(of: child) } } private mutating func unifyTypes() -> [Type] { /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed parsedTypes .filter { $0.isExtension } .forEach { (type: Type) in let oldName = type.globalName if type.localName.contains(".") { resolveExtensionOfNestedType(type) } else if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name { var moduleName: String = "" if let module = type.module { moduleName = "\(module)." } type.localName = resolved.replacingOccurrences(of: moduleName, with: "") } // nothing left to do guard oldName != type.globalName else { return } rewriteChildren(of: type) } // extend all types with their extensions parsedTypes.forEach { type in let inheritedTypes: [[String]] = type.inheritedTypes.compactMap { inheritedName in if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name { return [resolvedGlobalName] } if let baseType = Composer.findBaseType(for: type, name: inheritedName, typesByName: typeMap) { if let composed = baseType as? ProtocolComposition, let composedTypes = composed.composedTypes { // ignore inheritedTypes when it is a `ProtocolComposition` and composedType is a protocol var combinedTypes = composedTypes.map { $0.globalName } combinedTypes.append(baseType.globalName) return combinedTypes } } return [inheritedName] } type.inheritedTypes = inheritedTypes.flatMap { $0 } let uniqueType: Type? if let mappedType = typeMap[type.globalName] { // this check will only fail on an extension? uniqueType = mappedType } else if let composedNameType = typeFromComposedName(type.name, modules: modules) { // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules uniqueType = composedNameType } else { uniqueType = inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] } } guard let current = uniqueType else { assert(type.isExtension, "Type \(type.globalName) should be extension") // for unknown types we still store their extensions but mark them as unknown type.isUnknownExtension = true if let existingType = typeMap[type.globalName] { existingType.extend(type) typeMap[type.globalName] = existingType } else { typeMap[type.globalName] = type } let inheritanceClause = type.inheritedTypes.isEmpty ? "" : ": \(type.inheritedTypes.joined(separator: ", "))" Log.astWarning("Found \"extension \(type.name)\(inheritanceClause)\" of type for which there is no original type declaration information.") return } if current == type { return } current.extend(type) typeMap[current.globalName] = current } let values = typeMap.values var processed = Set(minimumCapacity: values.count) return typeMap.values.filter({ let name = $0.globalName let wasProcessed = processed.contains(name) processed.insert(name) return !wasProcessed }) } // extract associated types from all types and add them to types private static func extractAssociatedTypes(_ parserResult: FileParserResult) -> [String: AssociatedType] { parserResult.types .compactMap { $0 as? SourceryProtocol } .map { $0.associatedTypes } .flatMap { $0 }.reduce(into: [:]) { $0[$1.key] = $1.value } } /// returns typealiases map to their full names, with `resolved` removing intermediate /// typealises and `unresolved` including typealiases that reference other typealiases. private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { var typealiasesByNames = [String: Typealias]() parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } parserResult.types.forEach { type in type.typealiases.forEach({ (_, alias) in // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on // maybe just handle non extension case here and extension aliases after resolving them? typealiasesByNames[alias.name] = alias }) } let unresolved = typealiasesByNames // ! if a typealias leads to another typealias, follow through and replace with final type typealiasesByNames.forEach { _, alias in var aliasNamesToReplace = [alias.name] var finalAlias = alias var visitedAliasNames = Set() visitedAliasNames.insert(alias.name) while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { if visitedAliasNames.contains(targetAlias.name) { Log.astWarning("Detected typealias cycle while resolving '\(alias.name)' -> '\(targetAlias.name)' (type name: \(finalAlias.typeName.name)).") break } aliasNamesToReplace.append(targetAlias.name) visitedAliasNames.insert(targetAlias.name) finalAlias = targetAlias } // ! replace all keys aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } } return (resolved: typealiasesByNames, unresolved: unresolved) } /// Resolves type identifier for name func resolveGlobalName( for type: String, containingType: Type? = nil, unique: [String: Type]? = nil, modules: [String: [String: Type]], typealiases: [String: Typealias], associatedTypes: [String: AssociatedType] ) -> (name: String, typealias: Typealias?)? { // if the type exists for this name and isn't an extension just return it's name // if it's extension we need to check if there aren't other options TODO: verify if let realType = unique?[type], realType.isExtension == false { return (name: realType.globalName, typealias: nil) } if let alias = typealiases[type] { return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) } if let associatedType = associatedTypes[type], let actualType = associatedType.type { let typeName = associatedType.typeName ?? TypeName(name: actualType.name) return (name: actualType.globalName, typealias: Typealias(aliasName: type, typeName: typeName)) } if let containingType = containingType { if type == "Self" { return (name: containingType.globalName, typealias: nil) } var currentContainer: Type? = containingType while currentContainer != nil, let parentName = currentContainer?.globalName { /// TODO: no parent for sure? /// manually walk the containment tree if let name = resolveGlobalName(for: "\(parentName).\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) { return name } currentContainer = currentContainer?.parent } // if let name = resolveGlobalName(for: "\(containingType.globalName).\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { // return name // } // last check it's via module // if let module = containingType.module, let name = resolveGlobalName(for: "\(module).\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { // return name // } } // TODO: is this needed? if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { return (name: inferred, typealias: nil) } return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } } private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { func fullName(for module: String) -> String { "\(module).\(typeIdentifier)" } func type(for module: String) -> Type? { return modules[module]?[typeIdentifier] } func ambiguousErrorMessage(from types: [Type]) -> String? { Log.astWarning("Ambiguous type \(typeIdentifier), found \(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") return nil } let explicitModulesAtDeclarationSite: [String] = [ containedInType?.module.map { [$0] } ?? [], // main module for this typename containedInType?.imports.map { $0.moduleName } ?? [] // imported modules ] .flatMap { $0 } let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity /// First checking explicit modules available at declaration site (so source module + all imported ones) /// If there is no ambigiuity there we can assume that module will be resolved by the compiler /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail let moduleSetsToCheck: [[String]] = [ explicitModulesAtDeclarationSite, Array(remainingModules) ] for modules in moduleSetsToCheck { let possibleTypes = modules .compactMap { type(for: $0) } if possibleTypes.count > 1 { return ambiguousErrorMessage(from: possibleTypes) } if let type = possibleTypes.first { return type.globalName } } // as last result for unknown types / extensions // try extracting type from unique array if let module = containedInType?.module { return uniqueTypes[fullName(for: module)]?.globalName } return nil } func typeFromComposedName(_ name: String, modules: [String: [String: Type]]) -> Type? { guard name.contains(".") else { return nil } let nameComponents = name.components(separatedBy: ".") let moduleName = nameComponents[0] let typeName = nameComponents.suffix(from: 1).joined(separator: ".") return modules[moduleName]?[typeName] } func resolveType(typeName: TypeName, containingType: Type?, method: Method? = nil) -> Type? { let resolveTypeWithName = { (typeName: TypeName) -> Type? in return self.resolveType(typeName: typeName, containingType: containingType) } let unique = typeMap if let name = typeName.actualTypeName { let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName return unique[resolvedIdentifier] } let retrievedName = actualTypeName(for: typeName, containingType: containingType) let lookupName = retrievedName ?? typeName if let tuple = lookupName.tuple { var needsUpdate = false tuple.elements.forEach { tupleElement in tupleElement.type = resolveTypeWithName(tupleElement.typeName) if tupleElement.typeName.actualTypeName != nil { needsUpdate = true } } if needsUpdate || retrievedName != nil { let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) tupleCopy.elements.forEach { $0.typeName = $0.actualTypeName ?? $0.typeName $0.typeName.actualTypeName = nil } tupleCopy.name = tupleCopy.elements.asTypeName typeName.tuple = tupleCopy // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: tupleCopy.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: tupleCopy, array: lookupName.array, dictionary: lookupName.dictionary, closure: lookupName.closure, set: lookupName.set, generic: lookupName.generic ) } return nil } else if let array = lookupName.array { array.elementType = resolveTypeWithName(array.elementTypeName) if array.elementTypeName.actualTypeName != nil || retrievedName != nil || array.elementType != nil { let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName array.elementTypeName.actualTypeName = nil array.name = array.asSource typeName.array = array // TODO: really don't like this old behaviour typeName.generic = array.asGeneric // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: array.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: array, dictionary: lookupName.dictionary, closure: lookupName.closure, set: lookupName.set, generic: typeName.generic ) } } else if let dictionary = lookupName.dictionary { dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour dictionary.name = dictionary.asSource typeName.dictionary = dictionary // TODO: really don't like this old behaviour typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: dictionary.asSource, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, dictionary: dictionary, closure: lookupName.closure, set: lookupName.set, generic: dictionary.asGeneric ) } } else if let closure = lookupName.closure { var needsUpdate = false closure.returnType = resolveTypeWithName(closure.returnTypeName) closure.parameters.forEach { parameter in parameter.type = resolveTypeWithName(parameter.typeName) if parameter.typeName.actualTypeName != nil { needsUpdate = true } } if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { typeName.closure = closure // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: closure.asSource, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, dictionary: lookupName.dictionary, closure: closure, set: lookupName.set, generic: lookupName.generic ) } return nil } else if let generic = lookupName.generic { var needsUpdate = false generic.typeParameters.forEach { parameter in // Detect if the generic type is local to the method if let method { for genericParameter in method.genericParameters where parameter.typeName.name == genericParameter.name { return } } parameter.type = resolveTypeWithName(parameter.typeName) if parameter.typeName.actualTypeName != nil { needsUpdate = true } } if needsUpdate || retrievedName != nil { let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) generic.typeParameters.forEach { $0.typeName = $0.typeName.actualTypeName ?? $0.typeName $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour } typeName.generic = generic // TODO: really don't like this old behaviour typeName.array = lookupName.array // TODO: really don't like this old behaviour typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") typeName.actualTypeName = TypeName(name: "\(generic.name)<\(params)>", isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, // TODO: asArray dictionary: lookupName.dictionary, // TODO: asDictionary closure: lookupName.closure, set: lookupName.set, generic: generic ) } } if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { typeName.actualTypeName = aliasedName } let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false || (method != nil && method?.genericRequirements.isEmpty == false) if hasGenericRequirements, let typeNameForLookup = typeName.name.split(separator: " ").first, !typeNameForLookup.isEmpty { // we should consider if we are looking up return type of a method with generic constraints // where `typeName` passed would include `... where ...` suffix let genericRequirements: [GenericRequirement] if let requirements = containingType?.genericRequirements, !requirements.isEmpty { genericRequirements = requirements } else { genericRequirements = method?.genericRequirements ?? [] } let relevantRequirements = genericRequirements.filter { // matched type against a generic requirement name // thus type should be replaced with a protocol composition $0.leftType.name == typeNameForLookup } if relevantRequirements.count > 1 { // compose protocols into `ProtocolComposition` and generate TypeName var implements: [String: Type] = [:] relevantRequirements.forEach { implements[$0.rightType.typeName.name] = $0.rightType.type } let composedProtocols = ProtocolComposition( inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, isGeneric: true, composedTypes: relevantRequirements.compactMap { $0.rightType.type }, implements: implements ) typeName.actualTypeName = TypeName(name: "(\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) return composedProtocols } else if let protocolRequirement = relevantRequirements.first { // create TypeName off a single generic's protocol requirement typeName.actualTypeName = TypeName(name: "(\(protocolRequirement.rightType.typeName))") return protocolRequirement.rightType.type } } // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias // i.e. // enum Module { // typealias ID = MyView // } // class MyView { // class ID: String {} // } // // let variable: Module.ID.ID // should be resolved as MyView.ID type let finalLookup = typeName.actualTypeName ?? typeName var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName if let type = unique[resolvedIdentifier] { return type } for alias in resolvedTypealiases { /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) } } // should we cache resolved typenames? if unique[resolvedIdentifier] == nil { // peek into typealiases, if any of them contain the same typeName // this is done after the initial attempt in order to prioritise local (recognized) types first // before even trying to substitute the requested type with any typealias for alias in resolvedTypealiases { /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, /// ignoring namespacing if resolvedIdentifier == alias.value.aliasName { resolvedIdentifier = alias.value.typeName.name typeName.actualTypeName = alias.value.typeName break } } } if let associatedType = associatedTypes[resolvedIdentifier] { return associatedType.type } return unique[resolvedIdentifier] ?? unique[typeName.name] } private func actualTypeName(for typeName: TypeName, containingType: Type? = nil) -> TypeName? { let unique = typeMap let typealiases = resolvedTypealiases let associatedTypes = associatedTypes var unwrapped = typeName.unwrappedTypeName if let generic = typeName.generic { unwrapped = generic.name } else if let type = associatedTypes[unwrapped] { unwrapped = type.name } guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) else { return nil } /// TODO: verify let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } generic?.name = aliased.name let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } dictionary?.name = aliased.name let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } array?.name = aliased.name let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } set?.name = aliased.name return TypeName(name: aliased.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify array: aliased.typealias?.typeName.array ?? array, dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, closure: aliased.typealias?.typeName.closure ?? typeName.closure, set: aliased.typealias?.typeName.set ?? set, generic: aliased.typealias?.typeName.generic ?? generic ) } } ================================================ FILE: SourceryRuntime/Sources/Common/Diffable.swift ================================================ // // Diffable.swift // Sourcery // // Created by Krzysztof Zabłocki on 22/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation public protocol Diffable { /// Returns `DiffableResult` for the given objects. /// /// - Parameter object: Object to diff against. /// - Returns: Diffable results. func diffAgainst(_ object: Any?) -> DiffableResult } /// :nodoc: extension NSRange: Diffable { /// :nodoc: public static func == (lhs: NSRange, rhs: NSRange) -> Bool { return NSEqualRanges(lhs, rhs) } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let rhs = object as? NSRange else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "location").trackDifference(actual: self.location, expected: rhs.location)) results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: rhs.length)) return results } } #if canImport(ObjectiveC) @objcMembers #endif public class DiffableResult: NSObject, AutoEquatable { // sourcery: skipEquality private var results: [String] internal var identifier: String? init(results: [String] = [], identifier: String? = nil) { self.results = results self.identifier = identifier } func append(_ element: String) { results.append(element) } func append(contentsOf contents: DiffableResult) { if !contents.isEmpty { results.append(contents.description) } } var isEmpty: Bool { return results.isEmpty } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.identifier) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? DiffableResult else { return false } if self.identifier != rhs.identifier { return false } return true } public override var description: String { guard !results.isEmpty else { return "" } var description = "\(identifier.flatMap { "\($0) " } ?? "")" description.append(results.joined(separator: "\n")) return description } } public extension DiffableResult { #if swift(>=4.1) #else /// :nodoc: @discardableResult func trackDifference(actual: T, expected: T) -> DiffableResult { if actual != expected { let result = DiffableResult(results: [""]) append(contentsOf: result) } return self } #endif /// :nodoc: @discardableResult func trackDifference(actual: T?, expected: T?) -> DiffableResult { if actual != expected { let expected = expected.map({ "\($0)" }) ?? "nil" let actual = actual.map({ "\($0)" }) ?? "nil" let result = DiffableResult(results: [""]) append(contentsOf: result) } return self } /// :nodoc: @discardableResult func trackDifference(actual: T, expected: T) -> DiffableResult where T: Diffable { let diffResult = actual.diffAgainst(expected) append(contentsOf: diffResult) return self } /// :nodoc: @discardableResult func trackDifference(actual: [T], expected: [T]) -> DiffableResult where T: Diffable { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { diffResult.append("Different count, expected: \(expected.count), received: \(actual.count)") return self } for (idx, item) in actual.enumerated() { let diff = DiffableResult() diff.trackDifference(actual: item, expected: expected[idx]) if !diff.isEmpty { let string = "idx \(idx): \(diff)" diffResult.append(string) } } return self } /// :nodoc: @discardableResult func trackDifference(actual: [T], expected: [T]) -> DiffableResult { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { diffResult.append("Different count, expected: \(expected.count), received: \(actual.count)") return self } for (idx, item) in actual.enumerated() where item != expected[idx] { let string = "idx \(idx): " diffResult.append(string) } return self } /// :nodoc: @discardableResult func trackDifference(actual: [K: T], expected: [K: T]) -> DiffableResult where T: Diffable { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { append("Different count, expected: \(expected.count), received: \(actual.count)") if expected.count > actual.count { let missingKeys = Array(expected.keys.filter { actual[$0] == nil }.map { String(describing: $0) }) diffResult.append("Missing keys: \(missingKeys.joined(separator: ", "))") } return self } for (key, actualElement) in actual { guard let expectedElement = expected[key] else { diffResult.append("Missing key \"\(key)\"") continue } let diff = DiffableResult() diff.trackDifference(actual: actualElement, expected: expectedElement) if !diff.isEmpty { let string = "key \"\(key)\": \(diff)" diffResult.append(string) } } return self } // MARK: - NSObject diffing /// :nodoc: @discardableResult func trackDifference(actual: [K: T], expected: [K: T]) -> DiffableResult { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { append("Different count, expected: \(expected.count), received: \(actual.count)") if expected.count > actual.count { let missingKeys = Array(expected.keys.filter { actual[$0] == nil }.map { String(describing: $0) }) diffResult.append("Missing keys: \(missingKeys.joined(separator: ", "))") } return self } for (key, actualElement) in actual { guard let expectedElement = expected[key] else { diffResult.append("Missing key \"\(key)\"") continue } if !actualElement.isEqual(expectedElement) { diffResult.append("key \"\(key)\": ") } } return self } } ================================================ FILE: SourceryRuntime/Sources/Common/Extensions.swift ================================================ import Foundation public extension StringProtocol { /// Trimms leading and trailing whitespaces and newlines var trimmed: String { self.trimmingCharacters(in: .whitespacesAndNewlines) } } public extension String { /// Returns nil if string is empty var nilIfEmpty: String? { if isEmpty { return nil } return self } /// Returns nil if string is empty or contains `_` character var nilIfNotValidParameterName: String? { if isEmpty { return nil } if self == "_" { return nil } return self } /// :nodoc: /// - Parameter substring: Instance of a substring /// - Returns: Returns number of times a substring appears in self func countInstances(of substring: String) -> Int { guard !substring.isEmpty else { return 0 } var count = 0 var searchRange: Range? while let foundRange = range(of: substring, options: [], range: searchRange) { count += 1 searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) } return count } /// :nodoc: /// Removes leading and trailing whitespace from str. Returns false if str was not altered. @discardableResult mutating func strip() -> Bool { let strippedString = stripped() guard strippedString != self else { return false } self = strippedString return true } /// :nodoc: /// Returns a copy of str with leading and trailing whitespace removed. func stripped() -> String { return String(self.trimmingCharacters(in: .whitespaces)) } /// :nodoc: @discardableResult mutating func trimPrefix(_ prefix: String) -> Bool { guard hasPrefix(prefix) else { return false } self = String(self.suffix(self.count - prefix.count)) return true } /// :nodoc: func trimmingPrefix(_ prefix: String) -> String { guard hasPrefix(prefix) else { return self } return String(self.suffix(self.count - prefix.count)) } /// :nodoc: @discardableResult mutating func trimSuffix(_ suffix: String) -> Bool { guard hasSuffix(suffix) else { return false } self = String(self.prefix(self.count - suffix.count)) return true } /// :nodoc: func trimmingSuffix(_ suffix: String) -> String { guard hasSuffix(suffix) else { return self } return String(self.prefix(self.count - suffix.count)) } /// :nodoc: func dropFirstAndLast(_ n: Int = 1) -> String { return drop(first: n, last: n) } /// :nodoc: func drop(first: Int, last: Int) -> String { return String(self.dropFirst(first).dropLast(last)) } /// :nodoc: /// Wraps brackets if needed to make a valid type name func bracketsBalancing() -> String { if hasPrefix("(") && hasSuffix(")") { let unwrapped = dropFirstAndLast() return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self } else { let wrapped = "(\(self))" return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self } } /// :nodoc: /// Returns true if given string can represent a valid tuple type name func isValidTupleName() -> Bool { guard hasPrefix("(") && hasSuffix(")") else { return false } let trimmedBracketsName = dropFirstAndLast() return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 } /// :nodoc: func isValidArrayName() -> Bool { if hasPrefix("Array<") { return true } if hasPrefix("[") && hasSuffix("]") { return dropFirstAndLast().colonSeparated().count == 1 } return false } /// :nodoc: func isValidDictionaryName() -> Bool { if hasPrefix("Dictionary<") { return true } if hasPrefix("[") && contains(":") && hasSuffix("]") { return dropFirstAndLast().colonSeparated().count == 2 } return false } /// :nodoc: func isValidClosureName() -> Bool { return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 } /// :nodoc: /// Returns true if all opening brackets are balanced with closed brackets. func isBracketsBalanced() -> Bool { var bracketsCount: Int = 0 for char in self { if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } if bracketsCount < 0 { return false } } return bracketsCount == 0 } /// :nodoc: /// Returns components separated with a comma respecting nested types func commaSeparated() -> [String] { return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) } /// :nodoc: /// Returns components separated with colon respecting nested types func colonSeparated() -> [String] { return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) } /// :nodoc: /// Returns components separated with semicolon respecting nested contexts func semicolonSeparated() -> [String] { return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) } /// :nodoc: func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) } /// :nodoc: func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { var boundingCharactersCount: Int = 0 var quotesCount: Int = 0 var item = "" var items = [String]() var i = self.startIndex while i < self.endIndex { var offset = 1 defer { i = self.index(i, offsetBy: offset) } var currentlyScannedEnd: Index = self.endIndex if let endIndex = self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) { currentlyScannedEnd = endIndex } let currentlyScanned: String = String(self[i..` if !((self[i] == ">") as Bool && (item.last == "-") as Bool) { boundingCharactersCount = max(0, boundingCharactersCount - 1) } offset = closeString.count } if (self[i] == "\"") as Bool { quotesCount += 1 } let currentIsDelimiter = (currentlyScanned == delimiter) as Bool let boundingCountIsZero = (boundingCharactersCount == 0) as Bool let hasEvenQuotes = (quotesCount % 2 == 0) as Bool if currentIsDelimiter && boundingCountIsZero && hasEvenQuotes { items.append(item) item = "" i = self.index(i, offsetBy: delimiter.count - 1) } else { let endIndex: Index = self.index(i, offsetBy: offset) item += self[i.. DiffableResult { let results = DiffableResult() guard let castObject = object as? FileParserResult else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.path) hasher.combine(self.module) hasher.combine(self.types) hasher.combine(self.functions) hasher.combine(self.typealiases) hasher.combine(self.inlineRanges) hasher.combine(self.inlineIndentations) hasher.combine(self.modifiedDate) hasher.combine(self.sourceryVersion) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? FileParserResult else { return false } if self.path != rhs.path { return false } if self.module != rhs.module { return false } if self.types != rhs.types { return false } if self.functions != rhs.functions { return false } if self.typealiases != rhs.typealiases { return false } if self.inlineRanges != rhs.inlineRanges { return false } if self.inlineIndentations != rhs.inlineIndentations { return false } if self.modifiedDate != rhs.modifiedDate { return false } if self.sourceryVersion != rhs.sourceryVersion { return false } return true } // sourcery:inline:FileParserResult.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.path = aDecoder.decode(forKey: "path") self.module = aDecoder.decode(forKey: "module") guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { withVaList(["functions"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.functions = functions guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { withVaList(["inlineRanges"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inlineRanges = inlineRanges guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { withVaList(["inlineIndentations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inlineIndentations = inlineIndentations guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { withVaList(["modifiedDate"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiedDate = modifiedDate guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { withVaList(["sourceryVersion"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.sourceryVersion = sourceryVersion } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.path, forKey: "path") aCoder.encode(self.module, forKey: "module") aCoder.encode(self.types, forKey: "types") aCoder.encode(self.functions, forKey: "functions") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.inlineRanges, forKey: "inlineRanges") aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") aCoder.encode(self.modifiedDate, forKey: "modifiedDate") aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") } // sourcery:end } ================================================ FILE: SourceryRuntime/Sources/Common/Log.swift ================================================ //import Darwin import Foundation /// :nodoc: public enum Log { public struct Configuration { let isDryRun: Bool let isQuiet: Bool let isVerboseLoggingEnabled: Bool let isLogBenchmarkEnabled: Bool let shouldLogAST: Bool public init(isDryRun: Bool, isQuiet: Bool, isVerboseLoggingEnabled: Bool, isLogBenchmarkEnabled: Bool, shouldLogAST: Bool) { self.isDryRun = isDryRun self.isQuiet = isQuiet self.isVerboseLoggingEnabled = isVerboseLoggingEnabled self.isLogBenchmarkEnabled = isLogBenchmarkEnabled self.shouldLogAST = shouldLogAST } } public static func setup(using configuration: Configuration) { Log.stackMessages = configuration.isDryRun switch (configuration.isQuiet, configuration.isVerboseLoggingEnabled) { case (true, _): Log.level = .errors case (false, let isVerbose): Log.level = isVerbose ? .verbose : .info } Log.logBenchmarks = (configuration.isVerboseLoggingEnabled || configuration.isLogBenchmarkEnabled) && !configuration.isQuiet Log.logAST = (configuration.shouldLogAST) && !configuration.isQuiet } public enum Level: Int { case errors case warnings case info case verbose } public static var level: Level = .warnings public static var logBenchmarks: Bool = false public static var logAST: Bool = false public static var stackMessages: Bool = false public private(set) static var messagesStack = [String]() public static func error(_ message: Any) { log(level: .errors, "error: \(message)") // to return error when running swift templates which is done in a different process if ProcessInfo.processInfo.processName != "Sourcery" { fputs("\(message)", stderr) } } public static func warning(_ message: Any) { log(level: .warnings, "warning: \(message)") } public static func astWarning(_ message: Any) { guard logAST else { return } log(level: .warnings, "ast warning: \(message)") } public static func astError(_ message: Any) { guard logAST else { return } log(level: .errors, "ast error: \(message)") } public static func verbose(_ message: Any) { log(level: .verbose, message) } public static func info(_ message: Any) { log(level: .info, message) } public static func benchmark(_ message: Any) { guard logBenchmarks else { return } if stackMessages { messagesStack.append("\(message)") } else { print(message) } } private static func log(level logLevel: Level, _ message: Any) { guard logLevel.rawValue <= Log.level.rawValue else { return } if stackMessages { messagesStack.append("\(message)") } else { print(message) } } public static func output(_ message: String) { print(message) } } extension String: Error {} ================================================ FILE: SourceryRuntime/Sources/Common/TemplateContext.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation /// :nodoc: // sourcery: skipCoding #if canImport(ObjectiveC) @objcMembers #endif public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { // sourcery: skipJSExport public let parserResult: FileParserResult? public let functions: [SourceryMethod] public let types: Types public let argument: [String: NSObject] // sourcery: skipDescription public var type: [String: Type] { return types.typesByName } public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { self.parserResult = parserResult self.types = types self.functions = functions self.argument = arguments } /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { withVaList(["parserResult"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) } fatalError() } guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { withVaList(["argument"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() } // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types let fileParserResultCopy: FileParserResult? = nil // fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult let composed = Composer.uniqueTypesAndFunctions(parserResult, serial: false) self.types = .init(types: composed.types, typealiases: composed.typealiases) self.functions = composed.functions self.parserResult = fileParserResultCopy self.argument = argument } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parserResult, forKey: "parserResult") aCoder.encode(self.argument, forKey: "argument") } public var stencilContext: [String: Any] { return [ "types": types, "functions": functions, "type": types.typesByName, "argument": argument ] } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("parserResult = \(String(describing: self.parserResult)), ") string.append("functions = \(String(describing: self.functions)), ") string.append("types = \(String(describing: self.types)), ") string.append("argument = \(String(describing: self.argument)), ") string.append("stencilContext = \(String(describing: self.stencilContext))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TemplateContext else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parserResult) hasher.combine(self.functions) hasher.combine(self.types) hasher.combine(self.argument) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TemplateContext else { return false } if self.parserResult != rhs.parserResult { return false } if self.functions != rhs.functions { return false } if self.types != rhs.types { return false } if self.argument != rhs.argument { return false } return true } // sourcery: skipDescription, skipEquality public var jsContext: [String: Any] { return [ "types": [ "all": types.all, "protocols": types.protocols, "classes": types.classes, "structs": types.structs, "enums": types.enums, "extensions": types.extensions, "based": types.based, "inheriting": types.inheriting, "implementing": types.implementing, "protocolCompositions": types.protocolCompositions, "typealiases": types.typealiases ] as [String : Any], "functions": functions, "type": types.typesByName, "argument": argument ] } } extension ProcessInfo { /// :nodoc: public var context: TemplateContext! { return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext } } ================================================ FILE: SourceryRuntime/Sources/Generated/AutoHashable.generated.swift ================================================ // Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable all // MARK: - AutoHashable for classes, protocols, structs // MARK: - AutoHashable for Enums ================================================ FILE: SourceryRuntime/Sources/Generated/Coding.generated.swift ================================================ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace trailing_newline import Foundation extension NSCoder { @nonobjc func decode(forKey: String) -> String? { return self.maybeDecode(forKey: forKey) as String? } @nonobjc func decode(forKey: String) -> TypeName? { return self.maybeDecode(forKey: forKey) as TypeName? } @nonobjc func decode(forKey: String) -> AccessLevel? { return self.maybeDecode(forKey: forKey) as AccessLevel? } @nonobjc func decode(forKey: String) -> Bool { return self.decodeBool(forKey: forKey) } @nonobjc func decode(forKey: String) -> Int { return self.decodeInteger(forKey: forKey) } func decode(forKey: String) -> E? { return maybeDecode(forKey: forKey) as E? } fileprivate func maybeDecode(forKey: String) -> E? { guard let object = self.decodeObject(forKey: forKey) else { return nil } return object as? E } } extension ArrayType: NSCoding {} extension AssociatedType: NSCoding {} extension AssociatedValue: NSCoding {} extension Attribute: NSCoding {} extension BytesRange: NSCoding {} extension ClosureParameter: NSCoding {} extension ClosureType: NSCoding {} extension DictionaryType: NSCoding {} extension EnumCase: NSCoding {} extension FileParserResult: NSCoding {} extension GenericParameter: NSCoding {} extension GenericRequirement: NSCoding {} extension GenericType: NSCoding {} extension GenericTypeParameter: NSCoding {} extension Import: NSCoding {} extension Method: NSCoding {} extension MethodParameter: NSCoding {} extension Modifier: NSCoding {} extension SetType: NSCoding {} extension Subscript: NSCoding {} extension TupleElement: NSCoding {} extension TupleType: NSCoding {} extension Type: NSCoding {} extension TypeName: NSCoding {} extension Typealias: NSCoding {} extension Types: NSCoding {} extension Variable: NSCoding {} ================================================ FILE: SourceryRuntime/Sources/Generated/JSExport.generated.swift ================================================ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace trailing_newline #if canImport(JavaScriptCore) import JavaScriptCore @objc protocol ActorAutoJSExport: JSExport { var kind: String { get } var isFinal: Bool { get } var isDistributed: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Actor: ActorAutoJSExport {} @objc protocol ArrayTypeAutoJSExport: JSExport { var name: String { get } var elementTypeName: TypeName { get } var elementType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension ArrayType: ArrayTypeAutoJSExport {} @objc protocol AssociatedTypeAutoJSExport: JSExport { var name: String { get } var typeName: TypeName? { get } var type: Type? { get } } extension AssociatedType: AssociatedTypeAutoJSExport {} @objc protocol AssociatedValueAutoJSExport: JSExport { var localName: String? { get } var externalName: String? { get } var typeName: TypeName { get } var type: Type? { get } var defaultValue: String? { get } var annotations: Annotations { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension AssociatedValue: AssociatedValueAutoJSExport {} @objc protocol AttributeAutoJSExport: JSExport { var name: String { get } var arguments: [String: NSObject] { get } var asSource: String { get } var description: String { get } } extension Attribute: AttributeAutoJSExport {} @objc protocol BytesRangeAutoJSExport: JSExport { var offset: Int64 { get } var length: Int64 { get } } extension BytesRange: BytesRangeAutoJSExport {} @objc protocol ClassAutoJSExport: JSExport { var kind: String { get } var isFinal: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Class: ClassAutoJSExport {} @objc protocol ClosureParameterAutoJSExport: JSExport { var argumentLabel: String? { get } var name: String? { get } var typeName: TypeName { get } var `inout`: Bool { get } var type: Type? { get } var isVariadic: Bool { get } var typeAttributes: AttributeList { get } var defaultValue: String? { get } var annotations: Annotations { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension ClosureParameter: ClosureParameterAutoJSExport {} @objc protocol ClosureTypeAutoJSExport: JSExport { var name: String { get } var parameters: [ClosureParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isAsync: Bool { get } var asyncKeyword: String? { get } var `throws`: Bool { get } var throwsOrRethrowsKeyword: String? { get } var throwsTypeName: TypeName? { get } var asSource: String { get } } extension ClosureType: ClosureTypeAutoJSExport {} @objc protocol DictionaryTypeAutoJSExport: JSExport { var name: String { get } var valueTypeName: TypeName { get } var valueType: Type? { get } var keyTypeName: TypeName { get } var keyType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension DictionaryType: DictionaryTypeAutoJSExport {} @objc protocol EnumAutoJSExport: JSExport { var kind: String { get } var cases: [EnumCase] { get } var rawTypeName: TypeName? { get } var hasRawType: Bool { get } var rawType: Type? { get } var based: [String: String] { get } var hasAssociatedValues: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Enum: EnumAutoJSExport {} @objc protocol EnumCaseAutoJSExport: JSExport { var name: String { get } var rawValue: String? { get } var associatedValues: [AssociatedValue] { get } var annotations: Annotations { get } var documentation: Documentation { get } var indirect: Bool { get } var hasAssociatedValue: Bool { get } } extension EnumCase: EnumCaseAutoJSExport {} @objc protocol GenericParameterAutoJSExport: JSExport { var name: String { get } var inheritedTypeName: TypeName? { get } } extension GenericParameter: GenericParameterAutoJSExport {} @objc protocol GenericRequirementAutoJSExport: JSExport { var leftType: AssociatedType { get } var rightType: GenericTypeParameter { get } var relationship: String { get } var relationshipSyntax: String { get } } extension GenericRequirement: GenericRequirementAutoJSExport {} @objc protocol GenericTypeAutoJSExport: JSExport { var name: String { get } var typeParameters: [GenericTypeParameter] { get } var asSource: String { get } var description: String { get } } extension GenericType: GenericTypeAutoJSExport {} @objc protocol GenericTypeParameterAutoJSExport: JSExport { var typeName: TypeName { get } var type: Type? { get } } extension GenericTypeParameter: GenericTypeParameterAutoJSExport {} @objc protocol ImportAutoJSExport: JSExport { var kind: String? { get } var path: String { get } var description: String { get } var moduleName: String { get } } extension Import: ImportAutoJSExport {} @objc protocol MethodAutoJSExport: JSExport { var name: String { get } var selectorName: String { get } var shortName: String { get } var callName: String { get } var parameters: [MethodParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var isThrowsTypeGeneric: Bool { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isAsync: Bool { get } var isDistributed: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var `rethrows`: Bool { get } var accessLevel: String { get } var isStatic: Bool { get } var isClass: Bool { get } var isInitializer: Bool { get } var isDeinitializer: Bool { get } var isFailableInitializer: Bool { get } var isConvenienceInitializer: Bool { get } var isRequired: Bool { get } var isFinal: Bool { get } var isMutating: Bool { get } var isGeneric: Bool { get } var isOptional: Bool { get } var isNonisolated: Bool { get } var isDynamic: Bool { get } var annotations: Annotations { get } var documentation: Documentation { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var genericParameters: [GenericParameter] { get } } extension Method: MethodAutoJSExport {} @objc protocol MethodParameterAutoJSExport: JSExport { var argumentLabel: String? { get } var name: String { get } var typeName: TypeName { get } var `inout`: Bool { get } var isVariadic: Bool { get } var type: Type? { get } var typeAttributes: AttributeList { get } var defaultValue: String? { get } var annotations: Annotations { get } var index: Int { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension MethodParameter: MethodParameterAutoJSExport {} @objc protocol ModifierAutoJSExport: JSExport { var name: String { get } var detail: String? { get } var asSource: String { get } } extension Modifier: ModifierAutoJSExport {} @objc protocol ProtocolAutoJSExport: JSExport { var kind: String { get } var associatedTypes: [String: AssociatedType] { get } var genericRequirements: [GenericRequirement] { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var fileName: String? { get } } extension Protocol: ProtocolAutoJSExport {} @objc protocol ProtocolCompositionAutoJSExport: JSExport { var kind: String { get } var composedTypeNames: [TypeName] { get } var composedTypes: [Type]? { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension ProtocolComposition: ProtocolCompositionAutoJSExport {} @objc protocol SetTypeAutoJSExport: JSExport { var name: String { get } var elementTypeName: TypeName { get } var elementType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension SetType: SetTypeAutoJSExport {} @objc protocol StructAutoJSExport: JSExport { var kind: String { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Struct: StructAutoJSExport {} @objc protocol SubscriptAutoJSExport: JSExport { var parameters: [MethodParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isFinal: Bool { get } var readAccess: String { get } var writeAccess: String { get } var isAsync: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var isMutable: Bool { get } var annotations: Annotations { get } var documentation: Documentation { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericParameters: [GenericParameter] { get } var genericRequirements: [GenericRequirement] { get } var isGeneric: Bool { get } } extension Subscript: SubscriptAutoJSExport {} @objc protocol TemplateContextAutoJSExport: JSExport { var functions: [SourceryMethod] { get } var types: Types { get } var argument: [String: NSObject] { get } var type: [String: Type] { get } var stencilContext: [String: Any] { get } var jsContext: [String: Any] { get } } extension TemplateContext: TemplateContextAutoJSExport {} @objc protocol TupleElementAutoJSExport: JSExport { var name: String? { get } var typeName: TypeName { get } var type: Type? { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension TupleElement: TupleElementAutoJSExport {} @objc protocol TupleTypeAutoJSExport: JSExport { var name: String { get } var elements: [TupleElement] { get } } extension TupleType: TupleTypeAutoJSExport {} @objc protocol TypeAutoJSExport: JSExport { var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var kind: String { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Type: TypeAutoJSExport {} @objc protocol TypeNameAutoJSExport: JSExport { var name: String { get } var generic: GenericType? { get } var isGeneric: Bool { get } var isProtocolComposition: Bool { get } var actualTypeName: TypeName? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } var isVoid: Bool { get } var isTuple: Bool { get } var tuple: TupleType? { get } var isArray: Bool { get } var array: ArrayType? { get } var isDictionary: Bool { get } var dictionary: DictionaryType? { get } var isClosure: Bool { get } var closure: ClosureType? { get } var isSet: Bool { get } var set: SetType? { get } var isNever: Bool { get } var asSource: String { get } var description: String { get } var debugDescription: String { get } } extension TypeName: TypeNameAutoJSExport {} @objc protocol TypealiasAutoJSExport: JSExport { var aliasName: String { get } var typeName: TypeName { get } var type: Type? { get } var module: String? { get } var imports: [Import] { get } var annotations: Annotations { get } var documentation: Documentation { get } var parent: Type? { get } var accessLevel: String { get } var parentName: String? { get } var name: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension Typealias: TypealiasAutoJSExport {} @objc protocol TypesCollectionAutoJSExport: JSExport { } extension TypesCollection: TypesCollectionAutoJSExport {} @objc protocol VariableAutoJSExport: JSExport { var name: String { get } var typeName: TypeName { get } var type: Type? { get } var isComputed: Bool { get } var isAsync: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var isStatic: Bool { get } var readAccess: String { get } var writeAccess: String { get } var isMutable: Bool { get } var defaultValue: String? { get } var annotations: Annotations { get } var documentation: Documentation { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var isFinal: Bool { get } var isLazy: Bool { get } var isDynamic: Bool { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension Variable: VariableAutoJSExport {} #endif ================================================ FILE: SourceryRuntime/Sources/Generated/Typed.generated.swift ================================================ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace extension AssociatedValue { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension ClosureParameter { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension MethodParameter { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension TupleElement { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension Typealias { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension Variable { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } ================================================ FILE: SourceryRuntime/Sources/Linux/AST/AssociatedType_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Describes Swift AssociatedType public final class AssociatedType: NSObject, SourceryModel, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "typeName": return typeName case "type": return type default: fatalError("unable to lookup: \(member) in \(self)") } } /// Associated type name public let name: String /// Associated type type constraint name, if specified public let typeName: TypeName? // sourcery: skipEquality, skipDescription /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. public var type: Type? /// :nodoc: public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedType else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:AssociatedType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.typeName = aDecoder.decode(forKey: "typeName") self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/AssociatedValue_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Defines enum case associated value public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "externalName": return externalName case "localName": return localName case "typeName": return typeName case "type": return type case "defaultValue": return defaultValue case "annotations": return annotations case "isArray": return isArray case "isClosure": return isClosure case "isDictionary": return isDictionary case "isTuple": return isTuple case "isOptional": return isOptional case "isImplicitlyUnwrappedOptional": return isImplicitlyUnwrappedOptional case "isGeneric": return typeName.isGeneric default: fatalError("unable to lookup: \(member) in \(self)") } } /// Associated value local name. /// This is a name to be used to construct enum case value public let localName: String? /// Associated value external name. /// This is a name to be used to access value in value-bindig public let externalName: String? /// Associated value type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Associated value type, if known public var type: Type? /// Associated value default value public let defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.localName = localName self.externalName = externalName self.typeName = typeName self.type = type self.defaultValue = defaultValue self.annotations = annotations } convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("localName = \(String(describing: self.localName)), ") string.append("externalName = \(String(describing: self.externalName)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedValue else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.localName) hasher.combine(self.externalName) hasher.combine(self.typeName) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedValue else { return false } if self.localName != rhs.localName { return false } if self.externalName != rhs.externalName { return false } if self.typeName != rhs.typeName { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:AssociatedValue.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.localName = aDecoder.decode(forKey: "localName") self.externalName = aDecoder.decode(forKey: "externalName") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.externalName, forKey: "externalName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/ClosureParameter_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation // sourcery: skipDiffing public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "argumentLabel": return argumentLabel case "name": return name case "typeName": return typeName case "inout": return `inout` case "type": return type case "isVariadic": return isVariadic case "defaultValue": return defaultValue default: fatalError("unable to lookup: \(member) in \(self)") } } /// Parameter external name public var argumentLabel: String? /// Parameter internal name public let name: String? /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter if the argument has a variadic type or not public let isVariadic: Bool /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let typeInfo = "\(`inout` ? "inout " : "")\(typeName.asSource)\(isVariadic ? "..." : "")" if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { return typeInfo } let typeSuffix = ": \(typeInfo)" guard argumentLabel != name else { return name ?? "" + typeSuffix } let labels = [argumentLabel ?? "_", name?.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("`inout` = \(String(describing: self.`inout`)), ") string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("asSource = \(String(describing: self.asSource))") return string } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:ClosureParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.type = aDecoder.decode(forKey: "type") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } extension Array where Element == ClosureParameter { public var asSource: String { "(\(map { $0.asSource }.joined(separator: ", ")))" } } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/EnumCase_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Defines enum case public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "hasAssociatedValue": return hasAssociatedValue case "associatedValues": return associatedValues case "indirect": return indirect case "annotations": return annotations case "rawValue": return rawValue default: fatalError("unable to lookup: \(member) in \(self)") } } /// Enum case name public let name: String /// Enum case raw value, if any public let rawValue: String? /// Enum case associated values public let associatedValues: [AssociatedValue] /// Enum case annotations public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Whether enum case is indirect public let indirect: Bool /// Whether enum case has associated value public var hasAssociatedValue: Bool { return !associatedValues.isEmpty } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { self.name = name self.rawValue = rawValue self.associatedValues = associatedValues self.annotations = annotations self.documentation = documentation self.indirect = indirect } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("rawValue = \(String(describing: self.rawValue)), ") string.append("associatedValues = \(String(describing: self.associatedValues)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("indirect = \(String(describing: self.indirect)), ") string.append("hasAssociatedValue = \(String(describing: self.hasAssociatedValue))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? EnumCase else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.rawValue) hasher.combine(self.associatedValues) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.indirect) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? EnumCase else { return false } if self.name != rhs.name { return false } if self.rawValue != rhs.rawValue { return false } if self.associatedValues != rhs.associatedValues { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.indirect != rhs.indirect { return false } return true } // sourcery:inline:EnumCase.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.rawValue = aDecoder.decode(forKey: "rawValue") guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { withVaList(["associatedValues"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedValues = associatedValues guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.indirect = aDecoder.decode(forKey: "indirect") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.rawValue, forKey: "rawValue") aCoder.encode(self.associatedValues, forKey: "associatedValues") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.indirect, forKey: "indirect") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/Enum_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Defines Swift enum public final class Enum: Type { public override subscript(dynamicMember member: String) -> Any? { switch member { case "cases": return cases case "hasAssociatedValues": return hasAssociatedValues default: return super[dynamicMember: member] } } // sourcery: skipJSExport public class var kind: String { return "enum" } // sourcery: skipDescription /// Returns "enum" public override var kind: String { Self.kind } /// Enum cases public var cases: [EnumCase] /** Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. */ public var rawTypeName: TypeName? { didSet { if let rawTypeName = rawTypeName { hasRawType = true if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { inheritedTypes.remove(at: index) } if based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } else { hasRawType = false } } } // sourcery: skipDescription, skipEquality /// :nodoc: public private(set) var hasRawType: Bool // sourcery: skipDescription, skipEquality /// Enum raw value type, if known public var rawType: Type? // sourcery: skipEquality, skipDescription, skipCoding /// Names of types or protocols this type inherits from, including unknown (not scanned) types public override var based: [String: String] { didSet { if let rawTypeName = rawTypeName, based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } } /// Whether enum contains any associated values public var hasAssociatedValues: Bool { return cases.contains(where: { $0.hasAssociatedValue }) } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, inheritedTypes: [String] = [], rawTypeName: TypeName? = nil, cases: [EnumCase] = [], variables: [Variable] = [], methods: [Method] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false) { self.cases = cases self.rawTypeName = rawTypeName self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind) if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) { self.inheritedTypes.remove(at: index) } } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("cases = \(String(describing: self.cases)), ") string.append("rawTypeName = \(String(describing: self.rawTypeName)), ") string.append("hasAssociatedValues = \(String(describing: self.hasAssociatedValues))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Enum else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.cases) hasher.combine(self.rawTypeName) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Enum else { return false } if self.cases != rhs.cases { return false } if self.rawTypeName != rhs.rawTypeName { return false } return super.isEqual(rhs) } // sourcery:inline:Enum.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { withVaList(["cases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.cases = cases self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") self.hasRawType = aDecoder.decode(forKey: "hasRawType") self.rawType = aDecoder.decode(forKey: "rawType") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.cases, forKey: "cases") aCoder.encode(self.rawTypeName, forKey: "rawTypeName") aCoder.encode(self.hasRawType, forKey: "hasRawType") aCoder.encode(self.rawType, forKey: "rawType") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/GenericParameter_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Descibes Swift generic parameter public final class GenericParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "inheritedTypeName": return inheritedTypeName default: fatalError("unable to lookup: \(member) in \(self)") } } /// Generic parameter name public var name: String /// Generic parameter inherited type public var inheritedTypeName: TypeName? /// :nodoc: public init(name: String, inheritedTypeName: TypeName? = nil) { self.name = name self.inheritedTypeName = inheritedTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("inheritedTypeName = \(String(describing: self.inheritedTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.inheritedTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericParameter else { return false } if self.name != rhs.name { return false } if self.inheritedTypeName != rhs.inheritedTypeName { return false } return true } // sourcery:inline:GenericParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/GenericRequirement_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Descibes Swift generic requirement public class GenericRequirement: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "leftType": return leftType case "rightType": return rightType case "relationship": return relationship case "relationshipSyntax": return relationshipSyntax default: fatalError("unable to lookup: \(member) in \(self)") } } public enum Relationship: String { case equals case conformsTo var syntax: String { switch self { case .equals: return "==" case .conformsTo: return ":" } } } public var leftType: AssociatedType public let rightType: GenericTypeParameter /// relationship name public let relationship: String /// Syntax e.g. `==` or `:` public let relationshipSyntax: String public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { self.leftType = leftType self.rightType = rightType self.relationship = relationship.rawValue self.relationshipSyntax = relationship.syntax } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("leftType = \(String(describing: self.leftType)), ") string.append("rightType = \(String(describing: self.rightType)), ") string.append("relationship = \(String(describing: self.relationship)), ") string.append("relationshipSyntax = \(String(describing: self.relationshipSyntax))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericRequirement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.leftType) hasher.combine(self.rightType) hasher.combine(self.relationship) hasher.combine(self.relationshipSyntax) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericRequirement else { return false } if self.leftType != rhs.leftType { return false } if self.rightType != rhs.rightType { return false } if self.relationship != rhs.relationship { return false } if self.relationshipSyntax != rhs.relationshipSyntax { return false } return true } // sourcery:inline:GenericRequirement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { withVaList(["leftType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.leftType = leftType guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { withVaList(["rightType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rightType = rightType guard let relationship: String = aDecoder.decode(forKey: "relationship") else { withVaList(["relationship"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationship = relationship guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { withVaList(["relationshipSyntax"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationshipSyntax = relationshipSyntax } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.leftType, forKey: "leftType") aCoder.encode(self.rightType, forKey: "rightType") aCoder.encode(self.relationship, forKey: "relationship") aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/MethodParameter_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Describes method parameter public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "argumentLabel": return argumentLabel case "name": return name case "typeName": return typeName case "isClosure": return isClosure case "typeAttributes": return typeAttributes case "isVariadic": return isVariadic case "asSource": return asSource case "index": return index case "isOptional": return isOptional default: fatalError("unable to lookup: \(member) in \(self)") } } /// Parameter external name public var argumentLabel: String? // Note: although method parameter can have no name, this property is not optional, // this is so to maintain compatibility with existing templates. /// Parameter internal name public let name: String /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool /// Is this variadic parameter? public let isVariadic: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// Method parameter index in the argument list public var index: Int /// :nodoc: public init(argumentLabel: String?, name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } /// :nodoc: public init(name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = name self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let values: String = defaultValue.map { " = \($0)" } ?? "" let variadicity: String = isVariadic ? "..." : "" let inoutness: String = `inout` ? "inout " : "" let typeSuffix = ": \(inoutness)\(typeName.asSource)\(values)\(variadicity)" guard argumentLabel != name else { return name + typeSuffix } let labels = [argumentLabel ?? "_", name.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("`inout` = \(String(describing: self.`inout`)), ") string.append("isVariadic = \(String(describing: self.isVariadic)), ") string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("asSource = \(String(describing: self.asSource)), ") string.append("index = \(String(describing: self.index))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? MethodParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "index").trackDifference(actual: self.index, expected: castObject.index)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? MethodParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:MethodParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations self.index = aDecoder.decode(forKey: "index") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.index, forKey: "index") } // sourcery:end } extension Array where Element == MethodParameter { public var asSource: String { "(\(map { $0.asSource }.joined(separator: ", ")))" } } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/Method_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryMethod = Method /// Describes method public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "definedInType": return definedInType case "shortName": return shortName case "name": return name case "selectorName": return selectorName case "callName": return callName case "parameters": return parameters case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isInitializer": return isInitializer case "accessLevel": return accessLevel case "isStatic": return isStatic case "returnTypeName": return returnTypeName case "isAsync": return isAsync case "attributes": return attributes case "isOptionalReturnType": return isOptionalReturnType case "actualReturnTypeName": return actualReturnTypeName case "isThrowsTypeGeneric": return isThrowsTypeGeneric case "isDynamic": return isDynamic case "genericRequirements": return genericRequirements default: fatalError("unable to lookup: \(member) in \(self)") } } /// Full method name, including generic constraints, i.e. `foo(bar: T)` public let name: String /// Method name including arguments names, i.e. `foo(bar:)` public var selectorName: String // sourcery: skipEquality, skipDescription /// Method name without arguments names and parentheses, i.e. `foo` public var shortName: String { return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name } // sourcery: skipEquality, skipDescription /// Method name without arguments names, parentheses and generic types, i.e. `foo` (can be used to generate code for method call) public var callName: String { return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName // sourcery: skipEquality, skipDescription /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Return if the throwsType is generic public var isThrowsTypeGeneric: Bool { return genericParameters.contains { $0.name == throwsTypeName?.name } } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional || isFailableInitializer } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// Whether method is distributed public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// Whether method throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether method rethrows public let `rethrows`: Bool /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Whether method is a static method public let isStatic: Bool /// Whether method is a class method public let isClass: Bool // sourcery: skipEquality, skipDescription /// Whether method is an initializer public var isInitializer: Bool { return selectorName.hasPrefix("init(") || selectorName == "init" } // sourcery: skipEquality, skipDescription /// Whether method is an deinitializer public var isDeinitializer: Bool { return selectorName == "deinit" } /// Whether method is a failable initializer public let isFailableInitializer: Bool // sourcery: skipEquality, skipDescription /// Whether method is a convenience initializer public var isConvenienceInitializer: Bool { modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is required public var isRequired: Bool { modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is mutating public var isMutating: Bool { modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is generic public var isGeneric: Bool { shortName.hasSuffix(">") } // sourcery: skipEquality, skipDescription /// Whether method is optional (in an Objective-C protocol) public var isOptional: Bool { modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is nonisolated (this modifier only applies to actor methods) public var isNonisolated: Bool { modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is dynamic public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// list of generic requirements public var genericRequirements: [GenericRequirement] /// List of generic parameters /// /// - Example: /// /// ```swift /// func method(foo: GenericParameter) /// ^ ~ a generic parameter /// ``` public var genericParameters: [GenericParameter] /// :nodoc: public init(name: String, selectorName: String? = nil, parameters: [MethodParameter] = [], returnTypeName: TypeName = TypeName(name: "Void"), isAsync: Bool = false, throws: Bool = false, throwsTypeName: TypeName? = nil, rethrows: Bool = false, accessLevel: AccessLevel = .internal, isStatic: Bool = false, isClass: Bool = false, isFailableInitializer: Bool = false, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil, genericRequirements: [GenericRequirement] = [], genericParameters: [GenericParameter] = []) { self.name = name self.selectorName = selectorName ?? name self.parameters = parameters self.returnTypeName = returnTypeName self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.rethrows = `rethrows` self.accessLevel = accessLevel.rawValue self.isStatic = isStatic self.isClass = isClass self.isFailableInitializer = isFailableInitializer self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName self.genericRequirements = genericRequirements self.genericParameters = genericParameters } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("selectorName = \(String(describing: self.selectorName)), ") string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("`rethrows` = \(String(describing: self.`rethrows`)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("isStatic = \(String(describing: self.isStatic)), ") string.append("isClass = \(String(describing: self.isClass)), ") string.append("isFailableInitializer = \(String(describing: self.isFailableInitializer)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") string.append("genericParameters = \(String(describing: self.genericParameters))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Method else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.selectorName) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.`rethrows`) hasher.combine(self.accessLevel) hasher.combine(self.isStatic) hasher.combine(self.isClass) hasher.combine(self.isFailableInitializer) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.genericRequirements) hasher.combine(self.genericParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Method else { return false } if self.name != rhs.name { return false } if self.selectorName != rhs.selectorName { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.isDistributed != rhs.isDistributed { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.`rethrows` != rhs.`rethrows` { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isStatic != rhs.isStatic { return false } if self.isClass != rhs.isClass { return false } if self.isFailableInitializer != rhs.isFailableInitializer { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.genericParameters != rhs.genericParameters { return false } return true } // sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { withVaList(["selectorName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.selectorName = selectorName guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isStatic = aDecoder.decode(forKey: "isStatic") self.isClass = aDecoder.decode(forKey: "isClass") self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.selectorName, forKey: "selectorName") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.`rethrows`, forKey: "`rethrows`") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.isClass, forKey: "isClass") aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.genericParameters, forKey: "genericParameters") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/Protocol_Linux.swift ================================================ // // Protocol.swift // Sourcery // // Created by Krzysztof Zablocki on 09/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation #if !canImport(ObjectiveC) /// :nodoc: public typealias SourceryProtocol = Protocol /// Describes Swift protocol public final class Protocol: Type { public override subscript(dynamicMember member: String) -> Any? { switch member { case "associatedTypes": return associatedTypes default: return super[dynamicMember: member] } } // sourcery: skipJSExport public class var kind: String { return "protocol" } /// Returns "protocol" public override var kind: String { Self.kind } /// list of all declared associated types with their names as keys public var associatedTypes: [String: AssociatedType] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } // sourcery: skipCoding /// list of generic requirements public override var genericRequirements: [GenericRequirement] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], associatedTypes: [String: AssociatedType] = [:], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], implements: [String: Type] = [:], kind: String = Protocol.kind) { self.associatedTypes = associatedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \(String(describing: self.kind)), ") string.append("associatedTypes = \(String(describing: self.associatedTypes)), ") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Protocol else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.associatedTypes) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Protocol else { return false } if self.associatedTypes != rhs.associatedTypes { return false } return super.isEqual(rhs) } // sourcery:inline:Protocol.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { withVaList(["associatedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedTypes = associatedTypes super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.associatedTypes, forKey: "associatedTypes") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/Subscript_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Describes subscript public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "parameters": return parameters case "returnTypeName": return returnTypeName case "actualReturnTypeName": return actualReturnTypeName case "returnType": return returnType case "isOptionalReturnType": return isOptionalReturnType case "isImplicitlyUnwrappedOptionalReturnType": return isImplicitlyUnwrappedOptionalReturnType case "unwrappedReturnTypeName": return unwrappedReturnTypeName case "isFinal": return isFinal case "readAccess": return readAccess case "writeAccess": return writeAccess case "isAsync": return isAsync case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isMutable": return isMutable case "annotations": return annotations case "documentation": return documentation case "definedInTypeName": return definedInTypeName case "actualDefinedInTypeName": return actualDefinedInTypeName case "attributes": return attributes case "modifiers": return modifiers case "genericParameters": return genericParameters case "genericRequirements": return genericRequirements case "isGeneric": return isGeneric default: fatalError("unable to lookup: \(member) in \(self)") } } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public var writeAccess: String /// Whether subscript is async public let isAsync: Bool /// Whether subscript throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] /// list of generic parameters public let genericParameters: [GenericParameter] /// list of generic requirements public let genericRequirements: [GenericRequirement] /// Whether subscript is generic or not public var isGeneric: Bool { return genericParameters.isEmpty == false } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(parameters: [MethodParameter] = [], returnTypeName: TypeName, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, genericParameters: [GenericParameter] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.parameters = parameters self.returnTypeName = returnTypeName self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.genericParameters = genericParameters self.genericRequirements = genericRequirements self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") string.append("isFinal = \(String(describing: self.isFinal)), ") string.append("readAccess = \(String(describing: self.readAccess)), ") string.append("writeAccess = \(String(describing: self.writeAccess)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.throws)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("isMutable = \(String(describing: self.isMutable)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), ") string.append("genericParameters = \(String(describing: self.genericParameters)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") string.append("isGeneric = \(String(describing: self.isGeneric)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Subscript else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.isAsync) hasher.combine(self.throws) hasher.combine(self.throwsTypeName) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.genericParameters) hasher.combine(self.genericRequirements) hasher.combine(self.attributes) hasher.combine(self.modifiers) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Subscript else { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.isAsync != rhs.isAsync { return false } if self.throws != rhs.throws { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.genericParameters != rhs.genericParameters { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } return true } // sourcery:inline:Subscript.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericParameters, forKey: "genericParameters") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/TypeName/Closure_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Describes closure type public final class ClosureType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "parameters": return parameters case "returnTypeName": return returnTypeName case "actualReturnTypeName": return actualReturnTypeName case "returnType": return returnType case "isOptionalReturnType": return isOptionalReturnType case "isImplicitlyUnwrappedOptionalReturnType": return isImplicitlyUnwrappedOptionalReturnType case "unwrappedReturnTypeName": return unwrappedReturnTypeName case "isAsync": return isAsync case "asyncKeyword": return asyncKeyword case "throws": return `throws` case "throwsOrRethrowsKeyword": return throwsOrRethrowsKeyword case "throwsTypeName": return throwsTypeName default: fatalError("unable to lookup: \(member) in \(self)") } } /// Type name used in declaration with stripped whitespaces and new lines public let name: String /// List of closure parameters public let parameters: [ClosureParameter] /// Return value type name public let returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// async keyword public let asyncKeyword: String? /// Whether closure throws public let `throws`: Bool /// throws or rethrows keyword public let throwsOrRethrowsKeyword: String? /// Type of thrown error if specified public let throwsTypeName: TypeName? /// :nodoc: public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil, throwsTypeName: TypeName? = nil) { self.name = name self.parameters = parameters self.returnTypeName = returnTypeName self.returnType = returnType self.asyncKeyword = asyncKeyword self.isAsync = asyncKeyword != nil self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword self.`throws` = throwsOrRethrowsKeyword != nil && !(throwsTypeName?.isNever ?? false) self.throwsTypeName = throwsTypeName } public var asSource: String { "\(parameters.asSource)\(asyncKeyword != nil ? " \(asyncKeyword!)" : "")\(throwsOrRethrowsKeyword != nil ? " \(throwsOrRethrowsKeyword!)\(throwsTypeName != nil ? "(\(throwsTypeName!.asSource))" : "")" : "") -> \(returnTypeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("asyncKeyword = \(String(describing: self.asyncKeyword)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsOrRethrowsKeyword = \(String(describing: self.throwsOrRethrowsKeyword)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ClosureType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.asyncKeyword) hasher.combine(self.`throws`) hasher.combine(self.throwsOrRethrowsKeyword) hasher.combine(self.throwsTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureType else { return false } if self.name != rhs.name { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.asyncKeyword != rhs.asyncKeyword { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } return true } // sourcery:inline:ClosureType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/TypeName/GenericTypeParameter_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Descibes Swift generic type parameter public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "typeName": return typeName case "type": return type default: fatalError("unable to lookup: \(member) in \(self)") } } /// Generic parameter type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Generic parameter type, if known public var type: Type? /// :nodoc: public init(typeName: TypeName, type: Type? = nil) { self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("typeName = \(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericTypeParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericTypeParameter else { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:GenericTypeParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/TypeName/Tuple_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation /// Describes tuple type public final class TupleType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "elements": return elements default: fatalError("unable to lookup: \(member) in \(self)") } } /// Type name used in declaration public var name: String /// Tuple elements public var elements: [TupleElement] /// :nodoc: public init(name: String, elements: [TupleElement]) { self.name = name self.elements = elements } /// :nodoc: public init(elements: [TupleElement]) { self.name = elements.asSource self.elements = elements } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("elements = \(String(describing: self.elements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleType else { return false } if self.name != rhs.name { return false } if self.elements != rhs.elements { return false } return true } // sourcery:inline:TupleType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { withVaList(["elements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elements = elements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elements, forKey: "elements") } // sourcery:end } /// Describes tuple type element public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "typeName": return typeName case "type": return type default: fatalError("unable to lookup: \(member) in \(self)") } } /// Tuple element name public let name: String? /// Tuple element type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Tuple element type, if known public var type: Type? /// :nodoc: public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } public var asSource: String { // swiftlint:disable:next force_unwrapping "\(name != nil ? "\(name!): " : "")\(typeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleElement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleElement else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:TupleElement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } extension Array where Element == TupleElement { public var asSource: String { "(\(map { $0.asSource }.joined(separator: ", ")))" } public var asTypeName: String { "(\(map { $0.typeName.asSource }.joined(separator: ", ")))" } } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/TypeName/TypeName_Linux.swift ================================================ // // Created by Krzysztof Zabłocki on 25/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "array": return array case "closure": return closure case "dictionary": return dictionary case "generic": return generic case "set": return set case "tuple": return tuple case "name": return name case "actualTypeName": return actualTypeName case "isOptional": return isOptional case "unwrappedTypeName": return unwrappedTypeName case "isProtocolComposition": return isProtocolComposition case "isVoid": return isVoid case "isArray": return isArray case "isClosure": return isClosure case "isDictionary": return isDictionary case "isGeneric": return isGeneric case "isSet": return isSet default: fatalError("unable to lookup: \(member) in \(self)") } } /// :nodoc: public init(name: String, actualTypeName: TypeName? = nil, unwrappedTypeName: String? = nil, attributes: AttributeList = [:], isOptional: Bool = false, isImplicitlyUnwrappedOptional: Bool = false, tuple: TupleType? = nil, array: ArrayType? = nil, dictionary: DictionaryType? = nil, closure: ClosureType? = nil, set: SetType? = nil, generic: GenericType? = nil, isProtocolComposition: Bool = false) { let optionalSuffix: String // TODO: TBR if !name.hasPrefix("Optional<") && !name.contains(" where ") { if isOptional { optionalSuffix = "?" } else if isImplicitlyUnwrappedOptional { optionalSuffix = "!" } else { optionalSuffix = "" } } else { optionalSuffix = "" } self.name = name + optionalSuffix self.actualTypeName = actualTypeName self.unwrappedTypeName = unwrappedTypeName ?? name self.tuple = tuple self.array = array self.dictionary = dictionary self.closure = closure self.generic = generic self.isOptional = isOptional || isImplicitlyUnwrappedOptional self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional self.isProtocolComposition = isProtocolComposition self.set = set self.attributes = attributes self.modifiers = [] super.init() } /// Type name used in declaration public var name: String /// The generics of this TypeName public var generic: GenericType? /// Whether this TypeName is generic public var isGeneric: Bool { actualTypeName?.generic != nil || generic != nil } /// Whether this TypeName is protocol composition public var isProtocolComposition: Bool // sourcery: skipEquality /// Actual type name if given type name is a typealias public var actualTypeName: TypeName? /// Type name attributes, i.e. `@escaping` public var attributes: AttributeList /// Modifiers, i.e. `escaping` public var modifiers: [SourceryModifier] // sourcery: skipEquality /// Whether type is optional public let isOptional: Bool // sourcery: skipEquality /// Whether type is implicitly unwrapped optional public let isImplicitlyUnwrappedOptional: Bool // sourcery: skipEquality /// Type name without attributes and optional type information public var unwrappedTypeName: String // sourcery: skipEquality /// Whether type is void (`Void` or `()`) public var isVoid: Bool { return name == "Void" || name == "()" || unwrappedTypeName == "Void" } /// Whether type is a tuple public var isTuple: Bool { actualTypeName?.tuple != nil || tuple != nil } /// Tuple type data public var tuple: TupleType? /// Whether type is an array public var isArray: Bool { actualTypeName?.array != nil || array != nil } /// Array type data public var array: ArrayType? /// Whether type is a dictionary public var isDictionary: Bool { actualTypeName?.dictionary != nil || dictionary != nil } /// Dictionary type data public var dictionary: DictionaryType? /// Whether type is a closure public var isClosure: Bool { actualTypeName?.closure != nil || closure != nil } /// Closure type data public var closure: ClosureType? /// Whether type is a Set public var isSet: Bool { actualTypeName?.set != nil || set != nil } /// Set type data public var set: SetType? /// Whether type is `Never` public var isNever: Bool { return name == "Never" } /// Prints typename as it would appear on definition public var asSource: String { // TODO: TBR special treatment let specialTreatment = isOptional && name.hasPrefix("Optional<") var description = ( attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + modifiers.map({ $0.asSource }) + [specialTreatment ? name : unwrappedTypeName] ).joined(separator: " ") if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name // description.append(dictionary.asSource) } else if let _ = self.array { // description.append(array.asSource) } else if let _ = self.generic { // let arguments = generic.typeParameters // .map({ $0.typeName.asSource }) // .joined(separator: ", ") // description.append("<\(arguments)>") } if !specialTreatment { if isImplicitlyUnwrappedOptional { description.append("!") } else if isOptional { description.append("?") } } return description } public override var description: String { ( attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + modifiers.map({ $0.asSource }) + [name] ).joined(separator: " ") } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TypeName else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.generic) hasher.combine(self.isProtocolComposition) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.tuple) hasher.combine(self.array) hasher.combine(self.dictionary) hasher.combine(self.closure) hasher.combine(self.set) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TypeName else { return false } if self.name != rhs.name { return false } if self.generic != rhs.generic { return false } if self.isProtocolComposition != rhs.isProtocolComposition { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.tuple != rhs.tuple { return false } if self.array != rhs.array { return false } if self.dictionary != rhs.dictionary { return false } if self.closure != rhs.closure { return false } if self.set != rhs.set { return false } return true } // sourcery:inline:TypeName.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.generic = aDecoder.decode(forKey: "generic") self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.isOptional = aDecoder.decode(forKey: "isOptional") self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { withVaList(["unwrappedTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.unwrappedTypeName = unwrappedTypeName self.tuple = aDecoder.decode(forKey: "tuple") self.array = aDecoder.decode(forKey: "array") self.dictionary = aDecoder.decode(forKey: "dictionary") self.closure = aDecoder.decode(forKey: "closure") self.set = aDecoder.decode(forKey: "set") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.generic, forKey: "generic") aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") aCoder.encode(self.actualTypeName, forKey: "actualTypeName") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.isOptional, forKey: "isOptional") aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") aCoder.encode(self.tuple, forKey: "tuple") aCoder.encode(self.array, forKey: "array") aCoder.encode(self.dictionary, forKey: "dictionary") aCoder.encode(self.closure, forKey: "closure") aCoder.encode(self.set, forKey: "set") } // sourcery:end // sourcery: skipEquality, skipDescription /// :nodoc: public override var debugDescription: String { return name } public convenience init(_ description: String) { self.init(name: description, actualTypeName: nil) } } extension TypeName { public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { if let description = description { Log.astWarning("Unknown type, please add type attribution to \(description)") } else { Log.astWarning("Unknown type, please add type attribution") } return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) } } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/Type_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 11/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias AttributeList = [String: [Attribute]] /// Defines Swift type public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "implements": return implements case "name": return name case "kind": return kind case "based": return based case "supertype": return supertype case "accessLevel": return accessLevel case "storedVariables": return storedVariables case "variables": return variables case "allVariables": return allVariables case "allMethods": return allMethods case "annotations": return annotations case "methods": return methods case "containedType": return containedType case "computedVariables": return computedVariables case "inherits": return inherits case "inheritedTypes": return inheritedTypes case "subscripts": return subscripts case "rawSubscripts": return rawSubscripts case "allSubscripts": return allSubscripts case "genericRequirements": return genericRequirements default: fatalError("unable to lookup: \(member) in \(self)") } } /// :nodoc: public var module: String? /// Imports that existed in the file that contained this type declaration public var imports: [Import] = [] // sourcery: skipEquality /// Imports existed in all files containing this type and all its super classes/protocols public var allImports: [Import] { return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) } private func gatherAllImports() -> [Import] { var allImports: [Import] = Array(self.imports) self.basedTypes.values.forEach { (basedType) in allImports.append(contentsOf: basedType.imports) } return allImports } // All local typealiases /// :nodoc: public var typealiases: [String: Typealias] { didSet { typealiases.values.forEach { $0.parent = self } } } // sourcery: skipJSExport /// Whether declaration is an extension of some type public var isExtension: Bool // sourcery: forceEquality /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` public var kind: String { isExtension ? "extension" : _kind } // sourcery: skipJSExport /// Kind of a backing store for `self.kind` private var _kind: String /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` public var name: String { guard let parentName = parent?.name else { return localName } return "\(parentName).\(localName)" } // sourcery: skipCoding /// Whether the type has been resolved as unknown extension public var isUnknownExtension: Bool = false // sourcery: skipDescription /// Global type name including module name, unless it's an extension of unknown type public var globalName: String { guard let module = module, !isUnknownExtension else { return name } return "\(module).\(name)" } /// Whether type is generic public var isGeneric: Bool /// Type name in its own scope. public var localName: String // sourcery: skipEquality, skipDescription /// Variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var variables: [Variable] { unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) } /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var rawVariables: [Variable] // sourcery: skipEquality, skipDescription /// All variables defined for this type, including variables defined in extensions, /// in superclasses (for classes only) and protocols public var allVariables: [Variable] { return flattenAll({ return $0.variables }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) }) } private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName } // sourcery: skipEquality, skipDescription /// Methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var methods: [Method] { unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) } /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var rawMethods: [Method] // sourcery: skipEquality, skipDescription /// All methods defined for this type, including methods defined in extensions, /// in superclasses (for classes only) and protocols public var allMethods: [Method] { return flattenAll({ $0.methods }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) }) } private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName } // sourcery: skipEquality, skipDescription /// Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var subscripts: [Subscript] { unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) } /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var rawSubscripts: [Subscript] // sourcery: skipEquality, skipDescription /// All subscripts defined for this type, including subscripts defined in extensions, /// in superclasses (for classes only) and protocols public var allSubscripts: [Subscript] { return flattenAll({ $0.subscripts }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) }) } private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess } // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the body of this type in its declaration file if available. public var bodyBytesRange: BytesRange? // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the whole declaration of this type in its declaration file if available. public var completeDeclarationRange: BytesRange? private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { let all = NSMutableOrderedSet() let allObjects = extraction(self) /// The order of importance for properties is: /// Base class /// Inheritance /// Protocol conformance /// Extension var extensions = [T]() var baseObjects = [T]() allObjects.forEach { if isExtension($0) { extensions.append($0) } else { baseObjects.append($0) } } all.addObjects(from: baseObjects) func filteredExtraction(_ target: Type) -> [T] { // swiftlint:disable:next force_cast let all = all.array as! [T] let extracted = extraction(target).filter({ filter(all, $0) }) return extracted } inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } // swiftlint:disable:next force_cast let array = all.array as! [T] all.addObjects(from: extensions.filter({ filter(array, $0) })) return all.array.compactMap { $0 as? T } } private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { let all = NSMutableOrderedSet() for nextItem in extraction(self) { // swiftlint:disable:next force_cast if !all.contains(where: { filter($0 as! T, nextItem) }) { all.add(nextItem) } } return all.array.compactMap { $0 as? T } } /// All initializers defined in this type public var initializers: [Method] { return methods.filter { $0.isInitializer } } /// All annotations for this type public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Static variables defined in this type public var staticVariables: [Variable] { return variables.filter { $0.isStatic } } /// Static methods defined in this type public var staticMethods: [Method] { return methods.filter { $0.isStatic } } /// Class methods defined in this type public var classMethods: [Method] { return methods.filter { $0.isClass } } /// Instance variables defined in this type public var instanceVariables: [Variable] { return variables.filter { !$0.isStatic } } /// Instance methods defined in this type public var instanceMethods: [Method] { return methods.filter { !$0.isStatic && !$0.isClass } } /// Computed instance variables defined in this type public var computedVariables: [Variable] { return variables.filter { $0.isComputed && !$0.isStatic } } /// Stored instance variables defined in this type public var storedVariables: [Variable] { return variables.filter { !$0.isComputed && !$0.isStatic } } /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition public var inheritedTypes: [String] { didSet { based.removeAll() inheritedTypes.forEach { name in self.based[name] = name } } } // sourcery: skipEquality, skipDescription /// Names of types or protocols this type inherits from, including unknown (not scanned) types public var based = [String: String]() // sourcery: skipEquality, skipDescription /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined public var basedTypes = [String: Type]() /// Types this type inherits from public var inherits = [String: Type]() // sourcery: skipEquality, skipDescription /// Protocols this type implements. Does not contain classes in case where composition (`&`) is used in the declaration public var implements = [String: Type]() /// Contained types public var containedTypes: [Type] { didSet { containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } } } // sourcery: skipEquality, skipDescription /// Contained types groupd by their names public private(set) var containedType: [String: Type] = [:] /// Name of parent type (for contained types only) public private(set) var parentName: String? // sourcery: skipEquality, skipDescription /// Parent type, if known (for contained types only) public var parent: Type? { didSet { parentName = parent?.name } } // sourcery: skipJSExport /// :nodoc: public var parentTypes: AnyIterator { var next: Type? = self return AnyIterator { next = next?.parent return next } } // sourcery: skipEquality, skipDescription /// Superclass type, if known (only for classes) public var supertype: Type? /// Type attributes, i.e. `@objc` public var attributes: AttributeList /// Type modifiers, i.e. `private`, `final` public var modifiers: [SourceryModifier] /// Path to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var path: String? { didSet { if let path = path { fileName = (path as NSString).lastPathComponent } } } /// Directory to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var directory: String? { get { return (path as? NSString)?.deletingLastPathComponent } } /// list of generic requirements public var genericRequirements: [GenericRequirement] { didSet { isGeneric = isGeneric || !genericRequirements.isEmpty } } /// File name where the type was defined public var fileName: String? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = "unknown") { self.localName = name self.accessLevel = accessLevel.rawValue self.isExtension = isExtension self.rawVariables = variables self.rawMethods = methods self.rawSubscripts = subscripts self.inheritedTypes = inheritedTypes self.containedTypes = containedTypes self.typealiases = [:] self.parent = parent self.parentName = parent?.name self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.isGeneric = isGeneric self.genericRequirements = genericRequirements self.implements = implements self._kind = kind super.init() containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } inheritedTypes.forEach { name in self.based[name] = name } typealiases.forEach({ $0.parent = self self.typealiases[$0.aliasName] = $0 }) } /// :nodoc: public func extend(_ type: Type) { type.annotations.forEach { self.annotations[$0.key] = $0.value } type.inherits.forEach { self.inherits[$0.key] = $0.value } type.implements.forEach { self.implements[$0.key] = $0.value } self.inheritedTypes += type.inheritedTypes self.containedTypes += type.containedTypes self.rawVariables += type.rawVariables self.rawMethods += type.rawMethods self.rawSubscripts += type.rawSubscripts } /// :nodoc: // sourcery: skipJSExport override public var description: String { let type: Type.Type = Swift.type(of: self) var string = "\(type): " string.append("module = \(String(describing: self.module)), ") string.append("imports = \(String(describing: self.imports)), ") string.append("allImports = \(String(describing: self.allImports)), ") string.append("typealiases = \(String(describing: self.typealiases)), ") string.append("isExtension = \(String(describing: self.isExtension)), ") string.append("kind = \(String(describing: self.kind)), ") string.append("_kind = \(String(describing: self._kind)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("name = \(String(describing: self.name)), ") string.append("isUnknownExtension = \(String(describing: self.isUnknownExtension)), ") string.append("isGeneric = \(String(describing: self.isGeneric)), ") string.append("localName = \(String(describing: self.localName)), ") string.append("rawVariables = \(String(describing: self.rawVariables)), ") string.append("rawMethods = \(String(describing: self.rawMethods)), ") string.append("rawSubscripts = \(String(describing: self.rawSubscripts)), ") string.append("initializers = \(String(describing: self.initializers)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("staticVariables = \(String(describing: self.staticVariables)), ") string.append("staticMethods = \(String(describing: self.staticMethods)), ") string.append("classMethods = \(String(describing: self.classMethods)), ") string.append("instanceVariables = \(String(describing: self.instanceVariables)), ") string.append("instanceMethods = \(String(describing: self.instanceMethods)), ") string.append("computedVariables = \(String(describing: self.computedVariables)), ") string.append("storedVariables = \(String(describing: self.storedVariables)), ") string.append("inheritedTypes = \(String(describing: self.inheritedTypes)), ") string.append("inherits = \(String(describing: self.inherits)), ") string.append("containedTypes = \(String(describing: self.containedTypes)), ") string.append("parentName = \(String(describing: self.parentName)), ") string.append("parentTypes = \(String(describing: self.parentTypes)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("fileName = \(String(describing: self.fileName)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Type else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.module) hasher.combine(self.imports) hasher.combine(self.typealiases) hasher.combine(self.isExtension) hasher.combine(self.accessLevel) hasher.combine(self.isUnknownExtension) hasher.combine(self.isGeneric) hasher.combine(self.localName) hasher.combine(self.rawVariables) hasher.combine(self.rawMethods) hasher.combine(self.rawSubscripts) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.inheritedTypes) hasher.combine(self.inherits) hasher.combine(self.containedTypes) hasher.combine(self.parentName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.fileName) hasher.combine(self.genericRequirements) hasher.combine(kind) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Type else { return false } if self.module != rhs.module { return false } if self.imports != rhs.imports { return false } if self.typealiases != rhs.typealiases { return false } if self.isExtension != rhs.isExtension { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isUnknownExtension != rhs.isUnknownExtension { return false } if self.isGeneric != rhs.isGeneric { return false } if self.localName != rhs.localName { return false } if self.rawVariables != rhs.rawVariables { return false } if self.rawMethods != rhs.rawMethods { return false } if self.rawSubscripts != rhs.rawSubscripts { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.inheritedTypes != rhs.inheritedTypes { return false } if self.inherits != rhs.inherits { return false } if self.containedTypes != rhs.containedTypes { return false } if self.parentName != rhs.parentName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.fileName != rhs.fileName { return false } if self.kind != rhs.kind { return false } if self.genericRequirements != rhs.genericRequirements { return false } return true } // sourcery:inline:Type.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases self.isExtension = aDecoder.decode(forKey: "isExtension") guard let _kind: String = aDecoder.decode(forKey: "_kind") else { withVaList(["_kind"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._kind = _kind guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isGeneric = aDecoder.decode(forKey: "isGeneric") guard let localName: String = aDecoder.decode(forKey: "localName") else { withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.localName = localName guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { withVaList(["rawVariables"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawVariables = rawVariables guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { withVaList(["rawMethods"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawMethods = rawMethods guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { withVaList(["rawSubscripts"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawSubscripts = rawSubscripts self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { withVaList(["inheritedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inheritedTypes = inheritedTypes guard let based: [String: String] = aDecoder.decode(forKey: "based") else { withVaList(["based"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.based = based guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { withVaList(["basedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.basedTypes = basedTypes guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { withVaList(["inherits"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inherits = inherits guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { withVaList(["implements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.implements = implements guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { withVaList(["containedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedTypes = containedTypes guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { withVaList(["containedType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedType = containedType self.parentName = aDecoder.decode(forKey: "parentName") self.parent = aDecoder.decode(forKey: "parent") self.supertype = aDecoder.decode(forKey: "supertype") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.path = aDecoder.decode(forKey: "path") guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements self.fileName = aDecoder.decode(forKey: "fileName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.isExtension, forKey: "isExtension") aCoder.encode(self._kind, forKey: "_kind") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isGeneric, forKey: "isGeneric") aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.rawVariables, forKey: "rawVariables") aCoder.encode(self.rawMethods, forKey: "rawMethods") aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") aCoder.encode(self.based, forKey: "based") aCoder.encode(self.basedTypes, forKey: "basedTypes") aCoder.encode(self.inherits, forKey: "inherits") aCoder.encode(self.implements, forKey: "implements") aCoder.encode(self.containedTypes, forKey: "containedTypes") aCoder.encode(self.containedType, forKey: "containedType") aCoder.encode(self.parentName, forKey: "parentName") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.supertype, forKey: "supertype") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.path, forKey: "path") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end } extension Type { // sourcery: skipDescription, skipJSExport /// :nodoc: var isClass: Bool { let isNotClass = self is Struct || self is Enum || self is Protocol return !isNotClass && !isExtension } } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/AST/Variable_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryVariable = Variable /// Defines variable public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "readAccess": return readAccess case "annotations": return annotations case "isOptional": return isOptional case "name": return name case "typeName": return typeName case "type": return type case "definedInType": return definedInType case "isStatic": return isStatic case "isAsync": return isAsync case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isArray": return isArray case "isDictionary": return isDictionary case "isDynamic": return isDynamic default: fatalError("unable to lookup: \(member) in \(self)") } } /// Variable name public let name: String /// Variable type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Variable type, if known, i.e. if the type is declared in the scanned sources. /// For explanation, see public var type: Type? /// Whether variable is computed and not stored public let isComputed: Bool /// Whether variable is async public let isAsync: Bool /// Whether variable throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is static public let isStatic: Bool /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public let writeAccess: String /// composed access level /// sourcery: skipJSExport public var accessLevel: (read: AccessLevel, write: AccessLevel) { (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) } /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Variable default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` public var attributes: AttributeList /// Modifiers, i.e. `private` public var modifiers: [SourceryModifier] /// Whether variable is final or not public var isFinal: Bool { return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } /// Whether variable is lazy or not public var isLazy: Bool { return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } } /// Whether variable is dynamic or not public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Reference to type name where the variable is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public internal(set) var definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// :nodoc: public init(name: String = "", typeName: TypeName, type: Type? = nil, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isComputed: Bool = false, isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, isStatic: Bool = false, defaultValue: String? = nil, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.name = name self.typeName = typeName self.type = type self.isComputed = isComputed self.isAsync = isAsync self.`throws` = `throws` self.throwsTypeName = throwsTypeName self.isStatic = isStatic self.defaultValue = defaultValue self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("isComputed = \(String(describing: self.isComputed)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("isStatic = \(String(describing: self.isStatic)), ") string.append("readAccess = \(String(describing: self.readAccess)), ") string.append("writeAccess = \(String(describing: self.writeAccess)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("isMutable = \(String(describing: self.isMutable)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("isFinal = \(String(describing: self.isFinal)), ") string.append("isLazy = \(String(describing: self.isLazy)), ") string.append("isDynamic = \(String(describing: self.isDynamic)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Variable else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.isComputed) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.isStatic) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.defaultValue) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.definedInTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Variable else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.isComputed != rhs.isComputed { return false } if self.isAsync != rhs.isAsync { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.isStatic != rhs.isStatic { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } return true } // sourcery:inline:Variable.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.isComputed = aDecoder.decode(forKey: "isComputed") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.isStatic = aDecoder.decode(forKey: "isStatic") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isComputed, forKey: "isComputed") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/DynamicMemberLookup_Linux.swift ================================================ // // Stencil // Copyright © 2022 Stencil // MIT Licence // #if !canImport(ObjectiveC) #if canImport(Stencil) import Stencil #else // This is not supposed to work at all, since in Stencil there is a protocol conformance check against `DynamicMemberLookup`, // and, of course, a substitute with the "same name" but in `Sourcery` will never satisfy that check. // Here, we are just mimicking `Stencil.DynamicMemberLookup` to showcase what is happening within the `Sourcery` during runtime. /// Marker protocol so we can know which types support `@dynamicMemberLookup`. Add this to your own types that support /// lookup by String. public protocol DynamicMemberLookup { /// Get a value for a given `String` key subscript(dynamicMember member: String) -> Any? { get } } public extension DynamicMemberLookup where Self: RawRepresentable { /// Get a value for a given `String` key subscript(dynamicMember member: String) -> Any? { switch member { case "rawValue": return rawValue default: return nil } } } #endif public protocol SourceryDynamicMemberLookup: DynamicMemberLookup {} #endif ================================================ FILE: SourceryRuntime/Sources/Linux/NSException_Linux.swift ================================================ #if !canImport(ObjectiveC) import Foundation public class NSException { static func raise(_ name: String, format: String, arguments: CVaListPointer) { fatalError ("\(name) exception: \(NSString(format: format, arguments: arguments))") } static func raise(_ name: String) { fatalError("\(name) exception") } } public extension NSExceptionName { static var parseErrorException = "parseErrorException" } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/TypesCollection_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// :nodoc: public class TypesCollection: NSObject, AutoJSExport, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { return try? types(forKey: member) } // sourcery:begin: skipJSExport let all: [Type] let types: [String: [Type]] let validate: ((Type) throws -> Void)? // sourcery:end init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { self.all = types var content = [String: [Type]]() self.all.forEach { type in collection(type).forEach { name in var list = content[name] ?? [Type]() list.append(type) content[name] = list } } self.types = content self.validate = validate } public func types(forKey key: String) throws -> [Type] { // In some configurations, the types are keyed by "ModuleName.TypeName" var longKey: String? if let validate = validate { guard let type = all.first(where: { $0.name == key }) else { throw "Unknown type \(key), should be used with `based`" } try validate(type) if let module = type.module { longKey = [module, type.name].joined(separator: ".") } } // If we find the types directly, return them if let types = types[key] { return types } // if we find a types for the longKey, return them if let longKey = longKey, let types = types[longKey] { return types } return [] } /// :nodoc: public func value(forKey key: String) -> Any? { do { return try types(forKey: key) } catch { Log.error(error) return nil } } /// :nodoc: public subscript(_ key: String) -> [Type] { do { return try types(forKey: key) } catch { Log.error(error) return [] } } } #endif ================================================ FILE: SourceryRuntime/Sources/Linux/Types_Linux.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation // sourcery: skipJSExport /// Collection of scanned types for accessing in templates public final class Types: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "types": return types case "enums": return enums case "all": return all case "protocols": return protocols case "classes": return classes case "structs": return structs case "extensions": return extensions case "implementing": return implementing case "inheriting": return inheriting case "based": return based default: fatalError("unable to lookup: \(member) in \(self)") } } /// :nodoc: public let types: [Type] /// All known typealiases public let typealiases: [Typealias] /// :nodoc: public init(types: [Type], typealiases: [Typealias] = []) { self.types = types self.typealiases = typealiases } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("types = \(String(describing: self.types)), ") string.append("typealiases = \(String(describing: self.typealiases))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Types else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.types) hasher.combine(self.typealiases) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Types else { return false } if self.types != rhs.types { return false } if self.typealiases != rhs.typealiases { return false } return true } // sourcery:inline:Types.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.types, forKey: "types") aCoder.encode(self.typealiases, forKey: "typealiases") } // sourcery:end // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesByName: [String: Type] = { var typesByName = [String: Type]() self.types.forEach { typesByName[$0.globalName] = $0 } return typesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesaliasesByName: [String: Typealias] = { var typesaliasesByName = [String: Typealias]() self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } return typesaliasesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// All known types, excluding protocols or protocol compositions. public lazy internal(set) var all: [Type] = { return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocols public lazy internal(set) var protocols: [Protocol] = { return self.types.compactMap { $0 as? Protocol } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocol compositions public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { return self.types.compactMap { $0 as? ProtocolComposition } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known classes public lazy internal(set) var classes: [Class] = { return self.all.compactMap { $0 as? Class } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known structs public lazy internal(set) var structs: [Struct] = { return self.all.compactMap { $0 as? Struct } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known enums public lazy internal(set) var enums: [Enum] = { return self.all.compactMap { $0 as? Enum } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known extensions public lazy internal(set) var extensions: [Type] = { return self.all.compactMap { $0.isExtension ? $0 : nil } }() // sourcery: skipDescription, skipEquality, skipCoding /// Types based on any other type, grouped by its name, even if they are not known. /// `types.based.MyType` returns list of types based on `MyType` public lazy internal(set) var based: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.based.keys) } ) }() // sourcery: skipDescription, skipEquality, skipCoding /// Classes inheriting from any known class, grouped by its name. /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` public lazy internal(set) var inheriting: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.inherits.keys) }, validate: { type in guard type is Class else { throw "\(type.name) is not a class and should be used with `implementing` or `based`" } }) }() // sourcery: skipDescription, skipEquality, skipCoding /// Types implementing known protocol, grouped by its name. /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` public lazy internal(set) var implementing: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.implements.keys) }, validate: { type in guard type is Protocol else { throw "\(type.name) is a class and should be used with `inheriting` or `based`" } }) }() } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/AssociatedType.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Describes Swift AssociatedType @objcMembers public final class AssociatedType: NSObject, SourceryModel { /// Associated type name public let name: String /// Associated type type constraint name, if specified public let typeName: TypeName? // sourcery: skipEquality, skipDescription /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. public var type: Type? /// :nodoc: public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedType else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:AssociatedType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.typeName = aDecoder.decode(forKey: "typeName") self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/AssociatedValue.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Defines enum case associated value @objcMembers public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable { /// Associated value local name. /// This is a name to be used to construct enum case value public let localName: String? /// Associated value external name. /// This is a name to be used to access value in value-bindig public let externalName: String? /// Associated value type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Associated value type, if known public var type: Type? /// Associated value default value public let defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.localName = localName self.externalName = externalName self.typeName = typeName self.type = type self.defaultValue = defaultValue self.annotations = annotations } convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("localName = \(String(describing: self.localName)), ") string.append("externalName = \(String(describing: self.externalName)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedValue else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.localName) hasher.combine(self.externalName) hasher.combine(self.typeName) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedValue else { return false } if self.localName != rhs.localName { return false } if self.externalName != rhs.externalName { return false } if self.typeName != rhs.typeName { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:AssociatedValue.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.localName = aDecoder.decode(forKey: "localName") self.externalName = aDecoder.decode(forKey: "externalName") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.externalName, forKey: "externalName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/ClosureParameter.swift ================================================ #if canImport(ObjectiveC) import Foundation // sourcery: skipDiffing @objcMembers public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { /// Parameter external name public var argumentLabel: String? /// Parameter internal name public let name: String? /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter if the argument has a variadic type or not public let isVariadic: Bool /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let typeInfo = "\(`inout` ? "inout " : "")\(typeName.asSource)\(isVariadic ? "..." : "")" if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { return typeInfo } let typeSuffix = ": \(typeInfo)" guard argumentLabel != name else { return name ?? "" + typeSuffix } let labels = [argumentLabel ?? "_", name?.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("`inout` = \(String(describing: self.`inout`)), ") string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("asSource = \(String(describing: self.asSource))") return string } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:ClosureParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.type = aDecoder.decode(forKey: "type") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } extension Array where Element == ClosureParameter { public var asSource: String { "(\(map { $0.asSource }.joined(separator: ", ")))" } } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/Enum.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Defines Swift enum @objcMembers public final class Enum: Type { // sourcery: skipJSExport public class var kind: String { return "enum" } // sourcery: skipDescription /// Returns "enum" public override var kind: String { Self.kind } /// Enum cases public var cases: [EnumCase] /** Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. */ public var rawTypeName: TypeName? { didSet { if let rawTypeName = rawTypeName { hasRawType = true if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { inheritedTypes.remove(at: index) } if based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } else { hasRawType = false } } } // sourcery: skipDescription, skipEquality /// :nodoc: public private(set) var hasRawType: Bool // sourcery: skipDescription, skipEquality /// Enum raw value type, if known public var rawType: Type? // sourcery: skipEquality, skipDescription, skipCoding /// Names of types or protocols this type inherits from, including unknown (not scanned) types public override var based: [String: String] { didSet { if let rawTypeName = rawTypeName, based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } } /// Whether enum contains any associated values public var hasAssociatedValues: Bool { return cases.contains(where: { $0.hasAssociatedValue }) } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, inheritedTypes: [String] = [], rawTypeName: TypeName? = nil, cases: [EnumCase] = [], variables: [Variable] = [], methods: [Method] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false) { self.cases = cases self.rawTypeName = rawTypeName self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind) if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) { self.inheritedTypes.remove(at: index) } } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("cases = \(String(describing: self.cases)), ") string.append("rawTypeName = \(String(describing: self.rawTypeName)), ") string.append("hasAssociatedValues = \(String(describing: self.hasAssociatedValues))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Enum else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.cases) hasher.combine(self.rawTypeName) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Enum else { return false } if self.cases != rhs.cases { return false } if self.rawTypeName != rhs.rawTypeName { return false } return super.isEqual(rhs) } // sourcery:inline:Enum.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { withVaList(["cases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.cases = cases self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") self.hasRawType = aDecoder.decode(forKey: "hasRawType") self.rawType = aDecoder.decode(forKey: "rawType") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.cases, forKey: "cases") aCoder.encode(self.rawTypeName, forKey: "rawTypeName") aCoder.encode(self.hasRawType, forKey: "hasRawType") aCoder.encode(self.rawType, forKey: "rawType") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/EnumCase.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Defines enum case @objcMembers public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable { /// Enum case name public let name: String /// Enum case raw value, if any public let rawValue: String? /// Enum case associated values public let associatedValues: [AssociatedValue] /// Enum case annotations public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Whether enum case is indirect public let indirect: Bool /// Whether enum case has associated value public var hasAssociatedValue: Bool { return !associatedValues.isEmpty } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { self.name = name self.rawValue = rawValue self.associatedValues = associatedValues self.annotations = annotations self.documentation = documentation self.indirect = indirect } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("rawValue = \(String(describing: self.rawValue)), ") string.append("associatedValues = \(String(describing: self.associatedValues)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("indirect = \(String(describing: self.indirect)), ") string.append("hasAssociatedValue = \(String(describing: self.hasAssociatedValue))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? EnumCase else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.rawValue) hasher.combine(self.associatedValues) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.indirect) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? EnumCase else { return false } if self.name != rhs.name { return false } if self.rawValue != rhs.rawValue { return false } if self.associatedValues != rhs.associatedValues { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.indirect != rhs.indirect { return false } return true } // sourcery:inline:EnumCase.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.rawValue = aDecoder.decode(forKey: "rawValue") guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { withVaList(["associatedValues"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedValues = associatedValues guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.indirect = aDecoder.decode(forKey: "indirect") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.rawValue, forKey: "rawValue") aCoder.encode(self.associatedValues, forKey: "associatedValues") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.indirect, forKey: "indirect") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/GenericParameter.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Descibes Swift generic parameter @objcMembers public final class GenericParameter: NSObject, SourceryModel, Diffable { /// Generic parameter name public var name: String /// Generic parameter inherited type public var inheritedTypeName: TypeName? /// :nodoc: public init(name: String, inheritedTypeName: TypeName? = nil) { self.name = name self.inheritedTypeName = inheritedTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("inheritedTypeName = \(String(describing: self.inheritedTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.inheritedTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericParameter else { return false } if self.name != rhs.name { return false } if self.inheritedTypeName != rhs.inheritedTypeName { return false } return true } // sourcery:inline:GenericParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/GenericRequirement.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Descibes Swift generic requirement @objcMembers public class GenericRequirement: NSObject, SourceryModel, Diffable { public enum Relationship: String { case equals case conformsTo var syntax: String { switch self { case .equals: return "==" case .conformsTo: return ":" } } } public var leftType: AssociatedType public let rightType: GenericTypeParameter /// relationship name public let relationship: String /// Syntax e.g. `==` or `:` public let relationshipSyntax: String public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { self.leftType = leftType self.rightType = rightType self.relationship = relationship.rawValue self.relationshipSyntax = relationship.syntax } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("leftType = \(String(describing: self.leftType)), ") string.append("rightType = \(String(describing: self.rightType)), ") string.append("relationship = \(String(describing: self.relationship)), ") string.append("relationshipSyntax = \(String(describing: self.relationshipSyntax))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericRequirement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.leftType) hasher.combine(self.rightType) hasher.combine(self.relationship) hasher.combine(self.relationshipSyntax) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericRequirement else { return false } if self.leftType != rhs.leftType { return false } if self.rightType != rhs.rightType { return false } if self.relationship != rhs.relationship { return false } if self.relationshipSyntax != rhs.relationshipSyntax { return false } return true } // sourcery:inline:GenericRequirement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { withVaList(["leftType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.leftType = leftType guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { withVaList(["rightType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rightType = rightType guard let relationship: String = aDecoder.decode(forKey: "relationship") else { withVaList(["relationship"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationship = relationship guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { withVaList(["relationshipSyntax"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationshipSyntax = relationshipSyntax } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.leftType, forKey: "leftType") aCoder.encode(self.rightType, forKey: "rightType") aCoder.encode(self.relationship, forKey: "relationship") aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/Method.swift ================================================ #if canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryMethod = Method /// Describes method @objc(SwiftMethod) @objcMembers public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { /// Full method name, including generic constraints, i.e. `foo(bar: T)` public let name: String /// Method name including arguments names, i.e. `foo(bar:)` public var selectorName: String // sourcery: skipEquality, skipDescription /// Method name without arguments names and parentheses, i.e. `foo` public var shortName: String { return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name } // sourcery: skipEquality, skipDescription /// Method name without arguments names, parentheses and generic types, i.e. `foo` (can be used to generate code for method call) public var callName: String { return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName // sourcery: skipEquality, skipDescription /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional || isFailableInitializer } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// Whether method is distributed public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// Whether method throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Return if the throwsType is generic public var isThrowsTypeGeneric: Bool { return genericParameters.contains { $0.name == throwsTypeName?.name } } /// Whether method rethrows public let `rethrows`: Bool /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Whether method is a static method public let isStatic: Bool /// Whether method is a class method public let isClass: Bool // sourcery: skipEquality, skipDescription /// Whether method is an initializer public var isInitializer: Bool { return selectorName.hasPrefix("init(") || selectorName == "init" } // sourcery: skipEquality, skipDescription /// Whether method is an deinitializer public var isDeinitializer: Bool { return selectorName == "deinit" } /// Whether method is a failable initializer public let isFailableInitializer: Bool // sourcery: skipEquality, skipDescription /// Whether method is a convenience initializer public var isConvenienceInitializer: Bool { modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is required public var isRequired: Bool { modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is mutating public var isMutating: Bool { modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is generic public var isGeneric: Bool { shortName.hasSuffix(">") } // sourcery: skipEquality, skipDescription /// Whether method is optional (in an Objective-C protocol) public var isOptional: Bool { modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is nonisolated (this modifier only applies to actor methods) public var isNonisolated: Bool { modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is dynamic public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// list of generic requirements public var genericRequirements: [GenericRequirement] /// List of generic parameters /// /// - Example: /// /// ```swift /// func method(foo: GenericParameter) /// ^ ~ a generic parameter /// ``` public var genericParameters: [GenericParameter] /// :nodoc: public init(name: String, selectorName: String? = nil, parameters: [MethodParameter] = [], returnTypeName: TypeName = TypeName(name: "Void"), isAsync: Bool = false, throws: Bool = false, throwsTypeName: TypeName? = nil, rethrows: Bool = false, accessLevel: AccessLevel = .internal, isStatic: Bool = false, isClass: Bool = false, isFailableInitializer: Bool = false, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil, genericRequirements: [GenericRequirement] = [], genericParameters: [GenericParameter] = []) { self.name = name self.selectorName = selectorName ?? name self.parameters = parameters self.returnTypeName = returnTypeName self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.rethrows = `rethrows` self.accessLevel = accessLevel.rawValue self.isStatic = isStatic self.isClass = isClass self.isFailableInitializer = isFailableInitializer self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName self.genericRequirements = genericRequirements self.genericParameters = genericParameters } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("selectorName = \(String(describing: self.selectorName)), ") string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("`rethrows` = \(String(describing: self.`rethrows`)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("isStatic = \(String(describing: self.isStatic)), ") string.append("isClass = \(String(describing: self.isClass)), ") string.append("isFailableInitializer = \(String(describing: self.isFailableInitializer)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") string.append("genericParameters = \(String(describing: self.genericParameters))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Method else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.selectorName) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.`rethrows`) hasher.combine(self.accessLevel) hasher.combine(self.isStatic) hasher.combine(self.isClass) hasher.combine(self.isFailableInitializer) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.genericRequirements) hasher.combine(self.genericParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Method else { return false } if self.name != rhs.name { return false } if self.selectorName != rhs.selectorName { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.isDistributed != rhs.isDistributed { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.`rethrows` != rhs.`rethrows` { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isStatic != rhs.isStatic { return false } if self.isClass != rhs.isClass { return false } if self.isFailableInitializer != rhs.isFailableInitializer { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.genericParameters != rhs.genericParameters { return false } return true } // sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { withVaList(["selectorName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.selectorName = selectorName guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isStatic = aDecoder.decode(forKey: "isStatic") self.isClass = aDecoder.decode(forKey: "isClass") self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.selectorName, forKey: "selectorName") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.`rethrows`, forKey: "`rethrows`") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.isClass, forKey: "isClass") aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.genericParameters, forKey: "genericParameters") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/MethodParameter.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Describes method parameter @objcMembers public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable { /// Parameter external name public var argumentLabel: String? // Note: although method parameter can have no name, this property is not optional, // this is so to maintain compatibility with existing templates. /// Parameter internal name public let name: String /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool /// Is this variadic parameter? public let isVariadic: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// Method parameter index in the argument list public var index: Int /// :nodoc: public init(argumentLabel: String?, name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } /// :nodoc: public init(name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = name self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let values: String = defaultValue.map { " = \($0)" } ?? "" let variadicity: String = isVariadic ? "..." : "" let inoutness: String = `inout` ? "inout " : "" let typeSuffix = ": \(inoutness)\(typeName.asSource)\(values)\(variadicity)" guard argumentLabel != name else { return name + typeSuffix } let labels = [argumentLabel ?? "_", name.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("argumentLabel = \(String(describing: self.argumentLabel)), ") string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("`inout` = \(String(describing: self.`inout`)), ") string.append("isVariadic = \(String(describing: self.isVariadic)), ") string.append("typeAttributes = \(String(describing: self.typeAttributes)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("asSource = \(String(describing: self.asSource)), ") string.append("index = \(String(describing: self.index))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? MethodParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "index").trackDifference(actual: self.index, expected: castObject.index)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? MethodParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:MethodParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations self.index = aDecoder.decode(forKey: "index") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.index, forKey: "index") } // sourcery:end } extension Array where Element == MethodParameter { public var asSource: String { "(\(map { $0.asSource }.joined(separator: ", ")))" } } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/Subscript.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Describes subscript @objcMembers public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public var writeAccess: String /// Whether subscript is async public let isAsync: Bool /// Whether subscript throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] /// list of generic parameters public let genericParameters: [GenericParameter] /// list of generic requirements public let genericRequirements: [GenericRequirement] /// Whether subscript is generic or not public var isGeneric: Bool { return genericParameters.isEmpty == false } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? public init(parameters: [MethodParameter] = [], returnTypeName: TypeName, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, genericParameters: [GenericParameter] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.parameters = parameters self.returnTypeName = returnTypeName self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.genericParameters = genericParameters self.genericRequirements = genericRequirements self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") string.append("isFinal = \(String(describing: self.isFinal)), ") string.append("readAccess = \(String(describing: self.readAccess)), ") string.append("writeAccess = \(String(describing: self.writeAccess)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.throws)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("isMutable = \(String(describing: self.isMutable)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName)), ") string.append("genericParameters = \(String(describing: self.genericParameters)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") string.append("isGeneric = \(String(describing: self.isGeneric)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Subscript else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.isAsync) hasher.combine(self.throws) hasher.combine(self.throwsTypeName) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.genericParameters) hasher.combine(self.genericRequirements) hasher.combine(self.attributes) hasher.combine(self.modifiers) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Subscript else { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.isAsync != rhs.isAsync { return false } if self.throws != rhs.throws { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.genericParameters != rhs.genericParameters { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } return true } // sourcery:inline:Subscript.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericParameters, forKey: "genericParameters") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/Type.swift ================================================ // // Created by Krzysztof Zablocki on 11/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// :nodoc: public typealias AttributeList = [String: [Attribute]] /// Defines Swift type @objcMembers public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { /// :nodoc: public var module: String? /// Imports that existed in the file that contained this type declaration public var imports: [Import] = [] // sourcery: skipEquality /// Imports existed in all files containing this type and all its super classes/protocols public var allImports: [Import] { return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) } private func gatherAllImports() -> [Import] { var allImports: [Import] = Array(self.imports) self.basedTypes.values.forEach { (basedType) in allImports.append(contentsOf: basedType.imports) } return allImports } // All local typealiases /// :nodoc: public var typealiases: [String: Typealias] { didSet { typealiases.values.forEach { $0.parent = self } } } // sourcery: skipJSExport /// Whether declaration is an extension of some type public var isExtension: Bool // sourcery: forceEquality /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` public var kind: String { isExtension ? "extension" : _kind } // sourcery: skipJSExport /// Kind of a backing store for `self.kind` private var _kind: String /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` public var name: String { guard let parentName = parent?.name else { return localName } return "\(parentName).\(localName)" } // sourcery: skipCoding /// Whether the type has been resolved as unknown extension public var isUnknownExtension: Bool = false // sourcery: skipDescription /// Global type name including module name, unless it's an extension of unknown type public var globalName: String { guard let module = module, !isUnknownExtension else { return name } return "\(module).\(name)" } /// Whether type is generic public var isGeneric: Bool /// Type name in its own scope. public var localName: String // sourcery: skipEquality, skipDescription /// Variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var variables: [Variable] { unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) } /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var rawVariables: [Variable] // sourcery: skipEquality, skipDescription /// All variables defined for this type, including variables defined in extensions, /// in superclasses (for classes only) and protocols public var allVariables: [Variable] { return flattenAll({ return $0.variables }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) }) } private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName } // sourcery: skipEquality, skipDescription /// Methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var methods: [Method] { unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) } /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var rawMethods: [Method] // sourcery: skipEquality, skipDescription /// All methods defined for this type, including methods defined in extensions, /// in superclasses (for classes only) and protocols public var allMethods: [Method] { return flattenAll({ $0.methods }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) }) } private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName } // sourcery: skipEquality, skipDescription /// Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var subscripts: [Subscript] { unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) } /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var rawSubscripts: [Subscript] // sourcery: skipEquality, skipDescription /// All subscripts defined for this type, including subscripts defined in extensions, /// in superclasses (for classes only) and protocols public var allSubscripts: [Subscript] { return flattenAll({ $0.subscripts }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) }) } private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess } // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the body of this type in its declaration file if available. public var bodyBytesRange: BytesRange? // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the whole declaration of this type in its declaration file if available. public var completeDeclarationRange: BytesRange? private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { let all = NSMutableOrderedSet() let allObjects = extraction(self) /// The order of importance for properties is: /// Base class /// Inheritance /// Protocol conformance /// Extension var extensions = [T]() var baseObjects = [T]() allObjects.forEach { if isExtension($0) { extensions.append($0) } else { baseObjects.append($0) } } all.addObjects(from: baseObjects) func filteredExtraction(_ target: Type) -> [T] { // swiftlint:disable:next force_cast let all = all.array as! [T] let extracted = extraction(target).filter({ filter(all, $0) }) return extracted } inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } // swiftlint:disable:next force_cast let array = all.array as! [T] all.addObjects(from: extensions.filter({ filter(array, $0) })) return all.array.compactMap { $0 as? T } } private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { let all = NSMutableOrderedSet() for nextItem in extraction(self) { // swiftlint:disable:next force_cast if !all.contains(where: { filter($0 as! T, nextItem) }) { all.add(nextItem) } } return all.array.compactMap { $0 as? T } } /// All initializers defined in this type public var initializers: [Method] { return methods.filter { $0.isInitializer } } /// All annotations for this type public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Static variables defined in this type public var staticVariables: [Variable] { return variables.filter { $0.isStatic } } /// Static methods defined in this type public var staticMethods: [Method] { return methods.filter { $0.isStatic } } /// Class methods defined in this type public var classMethods: [Method] { return methods.filter { $0.isClass } } /// Instance variables defined in this type public var instanceVariables: [Variable] { return variables.filter { !$0.isStatic } } /// Instance methods defined in this type public var instanceMethods: [Method] { return methods.filter { !$0.isStatic && !$0.isClass } } /// Computed instance variables defined in this type public var computedVariables: [Variable] { return variables.filter { $0.isComputed && !$0.isStatic } } /// Stored instance variables defined in this type public var storedVariables: [Variable] { return variables.filter { !$0.isComputed && !$0.isStatic } } /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition public var inheritedTypes: [String] { didSet { based.removeAll() inheritedTypes.forEach { name in self.based[name] = name } } } // sourcery: skipEquality, skipDescription /// Names of types or protocols this type inherits from, including unknown (not scanned) types public var based = [String: String]() // sourcery: skipEquality, skipDescription /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined public var basedTypes = [String: Type]() /// Types this type inherits from public var inherits = [String: Type]() // sourcery: skipEquality, skipDescription /// Protocols this type implements. Does not contain classes in case where composition (`&`) is used in the declaration public var implements: [String: Type] = [:] /// Contained types public var containedTypes: [Type] { didSet { containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } } } // sourcery: skipEquality, skipDescription /// Contained types groupd by their names public private(set) var containedType: [String: Type] = [:] /// Name of parent type (for contained types only) public private(set) var parentName: String? // sourcery: skipEquality, skipDescription /// Parent type, if known (for contained types only) public var parent: Type? { didSet { parentName = parent?.name } } // sourcery: skipJSExport /// :nodoc: public var parentTypes: AnyIterator { var next: Type? = self return AnyIterator { next = next?.parent return next } } // sourcery: skipEquality, skipDescription /// Superclass type, if known (only for classes) public var supertype: Type? /// Type attributes, i.e. `@objc` public var attributes: AttributeList /// Type modifiers, i.e. `private`, `final` public var modifiers: [SourceryModifier] /// Path to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var path: String? { didSet { if let path = path { fileName = (path as NSString).lastPathComponent } } } /// Directory to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var directory: String? { get { return (path as? NSString)?.deletingLastPathComponent } } /// list of generic requirements public var genericRequirements: [GenericRequirement] { didSet { isGeneric = isGeneric || !genericRequirements.isEmpty } } /// File name where the type was defined public var fileName: String? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = "unknown") { self.localName = name self.accessLevel = accessLevel.rawValue self.isExtension = isExtension self.rawVariables = variables self.rawMethods = methods self.rawSubscripts = subscripts self.inheritedTypes = inheritedTypes self.containedTypes = containedTypes self.typealiases = [:] self.parent = parent self.parentName = parent?.name self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.isGeneric = isGeneric self.genericRequirements = genericRequirements self.implements = implements self._kind = kind super.init() containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } inheritedTypes.forEach { name in self.based[name] = name } typealiases.forEach({ $0.parent = self self.typealiases[$0.aliasName] = $0 }) } /// :nodoc: public func extend(_ type: Type) { type.annotations.forEach { self.annotations[$0.key] = $0.value } type.inherits.forEach { self.inherits[$0.key] = $0.value } type.implements.forEach { self.implements[$0.key] = $0.value } self.inheritedTypes += type.inheritedTypes self.containedTypes += type.containedTypes self.rawVariables += type.rawVariables self.rawMethods += type.rawMethods self.rawSubscripts += type.rawSubscripts } /// :nodoc: // sourcery: skipJSExport override public var description: String { let type: Type.Type = Swift.type(of: self) var string = "\(type): " string.append("module = \(String(describing: self.module)), ") string.append("imports = \(String(describing: self.imports)), ") string.append("allImports = \(String(describing: self.allImports)), ") string.append("typealiases = \(String(describing: self.typealiases)), ") string.append("isExtension = \(String(describing: self.isExtension)), ") string.append("kind = \(String(describing: self.kind)), ") string.append("_kind = \(String(describing: self._kind)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("name = \(String(describing: self.name)), ") string.append("isUnknownExtension = \(String(describing: self.isUnknownExtension)), ") string.append("isGeneric = \(String(describing: self.isGeneric)), ") string.append("localName = \(String(describing: self.localName)), ") string.append("rawVariables = \(String(describing: self.rawVariables)), ") string.append("rawMethods = \(String(describing: self.rawMethods)), ") string.append("rawSubscripts = \(String(describing: self.rawSubscripts)), ") string.append("initializers = \(String(describing: self.initializers)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("staticVariables = \(String(describing: self.staticVariables)), ") string.append("staticMethods = \(String(describing: self.staticMethods)), ") string.append("classMethods = \(String(describing: self.classMethods)), ") string.append("instanceVariables = \(String(describing: self.instanceVariables)), ") string.append("instanceMethods = \(String(describing: self.instanceMethods)), ") string.append("computedVariables = \(String(describing: self.computedVariables)), ") string.append("storedVariables = \(String(describing: self.storedVariables)), ") string.append("inheritedTypes = \(String(describing: self.inheritedTypes)), ") string.append("inherits = \(String(describing: self.inherits)), ") string.append("containedTypes = \(String(describing: self.containedTypes)), ") string.append("parentName = \(String(describing: self.parentName)), ") string.append("parentTypes = \(String(describing: self.parentTypes)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("fileName = \(String(describing: self.fileName)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Type else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.module) hasher.combine(self.imports) hasher.combine(self.typealiases) hasher.combine(self.isExtension) hasher.combine(self.accessLevel) hasher.combine(self.isUnknownExtension) hasher.combine(self.isGeneric) hasher.combine(self.localName) hasher.combine(self.rawVariables) hasher.combine(self.rawMethods) hasher.combine(self.rawSubscripts) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.inheritedTypes) hasher.combine(self.inherits) hasher.combine(self.containedTypes) hasher.combine(self.parentName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.fileName) hasher.combine(self.genericRequirements) hasher.combine(kind) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Type else { return false } if self.module != rhs.module { return false } if self.imports != rhs.imports { return false } if self.typealiases != rhs.typealiases { return false } if self.isExtension != rhs.isExtension { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isUnknownExtension != rhs.isUnknownExtension { return false } if self.isGeneric != rhs.isGeneric { return false } if self.localName != rhs.localName { return false } if self.rawVariables != rhs.rawVariables { return false } if self.rawMethods != rhs.rawMethods { return false } if self.rawSubscripts != rhs.rawSubscripts { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.inheritedTypes != rhs.inheritedTypes { return false } if self.inherits != rhs.inherits { return false } if self.containedTypes != rhs.containedTypes { return false } if self.parentName != rhs.parentName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.fileName != rhs.fileName { return false } if self.kind != rhs.kind { return false } if self.genericRequirements != rhs.genericRequirements { return false } return true } // sourcery:inline:Type.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases self.isExtension = aDecoder.decode(forKey: "isExtension") guard let _kind: String = aDecoder.decode(forKey: "_kind") else { withVaList(["_kind"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._kind = _kind guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isGeneric = aDecoder.decode(forKey: "isGeneric") guard let localName: String = aDecoder.decode(forKey: "localName") else { withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.localName = localName guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { withVaList(["rawVariables"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawVariables = rawVariables guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { withVaList(["rawMethods"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawMethods = rawMethods guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { withVaList(["rawSubscripts"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawSubscripts = rawSubscripts self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { withVaList(["inheritedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inheritedTypes = inheritedTypes guard let based: [String: String] = aDecoder.decode(forKey: "based") else { withVaList(["based"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.based = based guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { withVaList(["basedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.basedTypes = basedTypes guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { withVaList(["inherits"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inherits = inherits guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { withVaList(["implements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.implements = implements guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { withVaList(["containedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedTypes = containedTypes guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { withVaList(["containedType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedType = containedType self.parentName = aDecoder.decode(forKey: "parentName") self.parent = aDecoder.decode(forKey: "parent") self.supertype = aDecoder.decode(forKey: "supertype") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.path = aDecoder.decode(forKey: "path") guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements self.fileName = aDecoder.decode(forKey: "fileName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.isExtension, forKey: "isExtension") aCoder.encode(self._kind, forKey: "_kind") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isGeneric, forKey: "isGeneric") aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.rawVariables, forKey: "rawVariables") aCoder.encode(self.rawMethods, forKey: "rawMethods") aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") aCoder.encode(self.based, forKey: "based") aCoder.encode(self.basedTypes, forKey: "basedTypes") aCoder.encode(self.inherits, forKey: "inherits") aCoder.encode(self.implements, forKey: "implements") aCoder.encode(self.containedTypes, forKey: "containedTypes") aCoder.encode(self.containedType, forKey: "containedType") aCoder.encode(self.parentName, forKey: "parentName") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.supertype, forKey: "supertype") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.path, forKey: "path") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end } extension Type { // sourcery: skipDescription, skipJSExport /// :nodoc: var isClass: Bool { let isNotClass = self is Struct || self is Enum || self is Protocol return !isNotClass && !isExtension } } /// Extends type so that inner types can be accessed via KVC e.g. Parent.Inner.Children extension Type { /// :nodoc: override public func value(forUndefinedKey key: String) -> Any? { if let innerType = containedTypes.lazy.filter({ $0.localName == key }).first { return innerType } return super.value(forUndefinedKey: key) } } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/TypeName/Closure.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Describes closure type @objcMembers public final class ClosureType: NSObject, SourceryModel, Diffable { /// Type name used in declaration with stripped whitespaces and new lines public let name: String /// List of closure parameters public let parameters: [ClosureParameter] /// Return value type name public let returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// async keyword public let asyncKeyword: String? /// Whether closure throws public let `throws`: Bool /// throws or rethrows keyword public let throwsOrRethrowsKeyword: String? /// Type of thrown error if specified public let throwsTypeName: TypeName? /// :nodoc: public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil, throwsTypeName: TypeName? = nil) { self.name = name self.parameters = parameters self.returnTypeName = returnTypeName self.returnType = returnType self.asyncKeyword = asyncKeyword self.isAsync = asyncKeyword != nil self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword self.`throws` = throwsOrRethrowsKeyword != nil && !(throwsTypeName?.isNever ?? false) self.throwsTypeName = throwsTypeName } public var asSource: String { "\(parameters.asSource)\(asyncKeyword != nil ? " \(asyncKeyword!)" : "")\(throwsOrRethrowsKeyword != nil ? " \(throwsOrRethrowsKeyword!)" : "") -> \(returnTypeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \(String(describing: self.actualReturnTypeName)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("asyncKeyword = \(String(describing: self.asyncKeyword)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsOrRethrowsKeyword = \(String(describing: self.throwsOrRethrowsKeyword)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ClosureType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.asyncKeyword) hasher.combine(self.`throws`) hasher.combine(self.throwsOrRethrowsKeyword) hasher.combine(self.throwsTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureType else { return false } if self.name != rhs.name { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.asyncKeyword != rhs.asyncKeyword { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } return true } // sourcery:inline:ClosureType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/TypeName/GenericTypeParameter.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Descibes Swift generic type parameter @objcMembers public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { /// Generic parameter type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Generic parameter type, if known public var type: Type? /// :nodoc: public init(typeName: TypeName, type: Type? = nil) { self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("typeName = \(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericTypeParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericTypeParameter else { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:GenericTypeParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/TypeName/Tuple.swift ================================================ #if canImport(ObjectiveC) import Foundation /// Describes tuple type @objcMembers public final class TupleType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Tuple elements public var elements: [TupleElement] /// :nodoc: public init(name: String, elements: [TupleElement]) { self.name = name self.elements = elements } /// :nodoc: public init(elements: [TupleElement]) { self.name = elements.asSource self.elements = elements } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("elements = \(String(describing: self.elements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleType else { return false } if self.name != rhs.name { return false } if self.elements != rhs.elements { return false } return true } // sourcery:inline:TupleType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { withVaList(["elements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elements = elements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elements, forKey: "elements") } // sourcery:end } /// Describes tuple type element @objcMembers public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { /// Tuple element name public let name: String? /// Tuple element type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Tuple element type, if known public var type: Type? /// :nodoc: public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } public var asSource: String { // swiftlint:disable:next force_unwrapping "\(name != nil ? "\(name!): " : "")\(typeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("asSource = \(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleElement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleElement else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:TupleElement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } extension Array where Element == TupleElement { public var asSource: String { "(\(map { $0.asSource }.joined(separator: ", ")))" } public var asTypeName: String { "(\(map { $0.typeName.asSource }.joined(separator: ", ")))" } } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/TypeName/TypeName.swift ================================================ // // Created by Krzysztof Zabłocki on 25/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) @objcMembers public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable { /// :nodoc: public init(name: String, actualTypeName: TypeName? = nil, unwrappedTypeName: String? = nil, attributes: AttributeList = [:], isOptional: Bool = false, isImplicitlyUnwrappedOptional: Bool = false, tuple: TupleType? = nil, array: ArrayType? = nil, dictionary: DictionaryType? = nil, closure: ClosureType? = nil, set: SetType? = nil, generic: GenericType? = nil, isProtocolComposition: Bool = false) { let optionalSuffix: String // TODO: TBR let hasPrefix: Bool = name.hasPrefix("Optional<") as Bool let containsName: Bool = name.contains(" where ") as Bool if !hasPrefix && !containsName { if isOptional { optionalSuffix = "?" } else if isImplicitlyUnwrappedOptional { optionalSuffix = "!" } else { optionalSuffix = "" } } else { optionalSuffix = "" } self.name = name + optionalSuffix self.actualTypeName = actualTypeName self.unwrappedTypeName = unwrappedTypeName ?? name self.tuple = tuple self.array = array self.dictionary = dictionary self.closure = closure self.generic = generic self.isOptional = isOptional || isImplicitlyUnwrappedOptional self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional self.isProtocolComposition = isProtocolComposition self.set = set self.attributes = attributes self.modifiers = [] super.init() } /// Type name used in declaration public var name: String /// The generics of this TypeName public var generic: GenericType? /// Whether this TypeName is generic public var isGeneric: Bool { actualTypeName?.generic != nil || generic != nil } /// Whether this TypeName is protocol composition public var isProtocolComposition: Bool // sourcery: skipEquality /// Actual type name if given type name is a typealias public var actualTypeName: TypeName? /// Type name attributes, i.e. `@escaping` public var attributes: AttributeList /// Modifiers, i.e. `escaping` public var modifiers: [SourceryModifier] // sourcery: skipEquality /// Whether type is optional public let isOptional: Bool // sourcery: skipEquality /// Whether type is implicitly unwrapped optional public let isImplicitlyUnwrappedOptional: Bool // sourcery: skipEquality /// Type name without attributes and optional type information public var unwrappedTypeName: String // sourcery: skipEquality /// Whether type is void (`Void` or `()`) public var isVoid: Bool { return name == "Void" || name == "()" || unwrappedTypeName == "Void" } /// Whether type is a tuple public var isTuple: Bool { actualTypeName?.tuple != nil || tuple != nil } /// Tuple type data public var tuple: TupleType? /// Whether type is an array public var isArray: Bool { actualTypeName?.array != nil || array != nil } /// Array type data public var array: ArrayType? /// Whether type is a dictionary public var isDictionary: Bool { actualTypeName?.dictionary != nil || dictionary != nil } /// Dictionary type data public var dictionary: DictionaryType? /// Whether type is a closure public var isClosure: Bool { actualTypeName?.closure != nil || closure != nil } /// Closure type data public var closure: ClosureType? /// Whether type is a Set public var isSet: Bool { actualTypeName?.set != nil || set != nil } /// Set type data public var set: SetType? /// Whether type is `Never` public var isNever: Bool { return name == "Never" } /// Prints typename as it would appear on definition public var asSource: String { // TODO: TBR special treatment let specialTreatment: Bool = isOptional && name.hasPrefix("Optional<") let attributeValues: [Attribute] = attributes.flatMap { $0.value } let attributeValuesUnsorted: [String] = attributeValues.map { $0.asSource } var attributes: [String] = attributeValuesUnsorted.sorted() attributes.append(contentsOf: modifiers.map({ $0.asSource })) attributes.append(contentsOf: [specialTreatment ? name : unwrappedTypeName]) var description = attributes.joined(separator: " ") // if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name // description.append(dictionary.asSource) // } else if let _ = self.array { // description.append(array.asSource) // } else if let _ = self.generic { // let arguments = generic.typeParameters // .map({ $0.typeName.asSource }) // .joined(separator: ", ") // description.append("<\(arguments)>") // } if !specialTreatment { if isImplicitlyUnwrappedOptional { description.append("!") } else if isOptional { description.append("?") } } return description } public override var description: String { var description: [String] = attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() description.append(contentsOf: modifiers.map({ $0.asSource })) description.append(contentsOf: [name]) return description.joined(separator: " ") } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TypeName else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) return results } public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.generic) hasher.combine(self.isProtocolComposition) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.tuple) hasher.combine(self.array) hasher.combine(self.dictionary) hasher.combine(self.closure) hasher.combine(self.set) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TypeName else { return false } if self.name != rhs.name { return false } if self.generic != rhs.generic { return false } if self.isProtocolComposition != rhs.isProtocolComposition { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.tuple != rhs.tuple { return false } if self.array != rhs.array { return false } if self.dictionary != rhs.dictionary { return false } if self.closure != rhs.closure { return false } if self.set != rhs.set { return false } return true } // sourcery:inline:TypeName.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.generic = aDecoder.decode(forKey: "generic") self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.isOptional = aDecoder.decode(forKey: "isOptional") self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { withVaList(["unwrappedTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.unwrappedTypeName = unwrappedTypeName self.tuple = aDecoder.decode(forKey: "tuple") self.array = aDecoder.decode(forKey: "array") self.dictionary = aDecoder.decode(forKey: "dictionary") self.closure = aDecoder.decode(forKey: "closure") self.set = aDecoder.decode(forKey: "set") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.generic, forKey: "generic") aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") aCoder.encode(self.actualTypeName, forKey: "actualTypeName") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.isOptional, forKey: "isOptional") aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") aCoder.encode(self.tuple, forKey: "tuple") aCoder.encode(self.array, forKey: "array") aCoder.encode(self.dictionary, forKey: "dictionary") aCoder.encode(self.closure, forKey: "closure") aCoder.encode(self.set, forKey: "set") } // sourcery:end // sourcery: skipEquality, skipDescription /// :nodoc: public override var debugDescription: String { return name } public convenience init(_ description: String) { self.init(name: description, actualTypeName: nil) } } extension TypeName { public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { if let description = description { Log.astWarning("Unknown type, please add type attribution to \(description)") } else { Log.astWarning("Unknown type, please add type attribution") } return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) } } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/AST/Variable.swift ================================================ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryVariable = Variable /// Defines variable @objcMembers public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable { /// Variable name public let name: String /// Variable type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Variable type, if known, i.e. if the type is declared in the scanned sources. /// For explanation, see public var type: Type? /// Whether variable is computed and not stored public let isComputed: Bool /// Whether variable is async public let isAsync: Bool /// Whether variable throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is static public let isStatic: Bool /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public let writeAccess: String /// composed access level /// sourcery: skipJSExport public var accessLevel: (read: AccessLevel, write: AccessLevel) { (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) } /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Variable default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` public var attributes: AttributeList /// Modifiers, i.e. `private` public var modifiers: [SourceryModifier] /// Whether variable is final or not public var isFinal: Bool { return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } /// Whether variable is lazy or not public var isLazy: Bool { return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } } /// Whether variable is dynamic or not public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Reference to type name where the variable is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public internal(set) var definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// :nodoc: public init(name: String = "", typeName: TypeName, type: Type? = nil, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isComputed: Bool = false, isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, isStatic: Bool = false, defaultValue: String? = nil, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.name = name self.typeName = typeName self.type = type self.isComputed = isComputed self.isAsync = isAsync self.`throws` = `throws` self.throwsTypeName = throwsTypeName self.isStatic = isStatic self.defaultValue = defaultValue self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("typeName = \(String(describing: self.typeName)), ") string.append("isComputed = \(String(describing: self.isComputed)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("isStatic = \(String(describing: self.isStatic)), ") string.append("readAccess = \(String(describing: self.readAccess)), ") string.append("writeAccess = \(String(describing: self.writeAccess)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("isMutable = \(String(describing: self.isMutable)), ") string.append("defaultValue = \(String(describing: self.defaultValue)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("isFinal = \(String(describing: self.isFinal)), ") string.append("isLazy = \(String(describing: self.isLazy)), ") string.append("isDynamic = \(String(describing: self.isDynamic)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \(String(describing: self.actualDefinedInTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Variable else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "type").trackDifference(actual: self.type, expected: castObject.type)) results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.isComputed) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.isStatic) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.defaultValue) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.definedInTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Variable else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.isComputed != rhs.isComputed { return false } if self.isAsync != rhs.isAsync { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.isStatic != rhs.isStatic { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } return true } // sourcery:inline:Variable.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.isComputed = aDecoder.decode(forKey: "isComputed") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.isStatic = aDecoder.decode(forKey: "isStatic") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isComputed, forKey: "isComputed") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") } // sourcery:end } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/Types.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation // sourcery: skipJSExport /// Collection of scanned types for accessing in templates @objcMembers public final class Types: NSObject, SourceryModel, Diffable { /// :nodoc: public let types: [Type] /// All known typealiases public let typealiases: [Typealias] /// :nodoc: public init(types: [Type], typealiases: [Typealias] = []) { self.types = types self.typealiases = typealiases } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("types = \(String(describing: self.types)), ") string.append("typealiases = \(String(describing: self.typealiases))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Types else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.types) hasher.combine(self.typealiases) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Types else { return false } if self.types != rhs.types { return false } if self.typealiases != rhs.typealiases { return false } return true } // sourcery:inline:Types.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.types, forKey: "types") aCoder.encode(self.typealiases, forKey: "typealiases") } // sourcery:end // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesByName: [String: Type] = { var typesByName = [String: Type]() self.types.forEach { typesByName[$0.globalName] = $0 } return typesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesaliasesByName: [String: Typealias] = { var typesaliasesByName = [String: Typealias]() self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } return typesaliasesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// All known types, excluding protocols or protocol compositions. public lazy internal(set) var all: [Type] = { return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocols public lazy internal(set) var protocols: [Protocol] = { return self.types.compactMap { $0 as? Protocol } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocol compositions public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { return self.types.compactMap { $0 as? ProtocolComposition } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known classes public lazy internal(set) var classes: [Class] = { return self.all.compactMap { $0 as? Class } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known structs public lazy internal(set) var structs: [Struct] = { return self.all.compactMap { $0 as? Struct } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known enums public lazy internal(set) var enums: [Enum] = { return self.all.compactMap { $0 as? Enum } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known extensions public lazy internal(set) var extensions: [Type] = { return self.all.compactMap { $0.isExtension ? $0 : nil } }() // sourcery: skipDescription, skipEquality, skipCoding /// Types based on any other type, grouped by its name, even if they are not known. /// `types.based.MyType` returns list of types based on `MyType` public lazy internal(set) var based: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.based.keys) } ) }() // sourcery: skipDescription, skipEquality, skipCoding /// Classes inheriting from any known class, grouped by its name. /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` public lazy internal(set) var inheriting: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.inherits.keys) }, validate: { type in guard type is Class else { throw "\(type.name) is not a class and should be used with `implementing` or `based`" } }) }() // sourcery: skipDescription, skipEquality, skipCoding /// Types implementing known protocol, grouped by its name. /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` public lazy internal(set) var implementing: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.implements.keys) }, validate: { type in guard type is Protocol else { throw "\(type.name) is a class and should be used with `inheriting` or `based`" } }) }() } #endif ================================================ FILE: SourceryRuntime/Sources/macOS/TypesCollection.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// :nodoc: @objcMembers public class TypesCollection: NSObject, AutoJSExport { // sourcery:begin: skipJSExport let all: [Type] let types: [String: [Type]] let validate: ((Type) throws -> Void)? // sourcery:end init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { self.all = types var content = [String: [Type]]() self.all.forEach { type in collection(type).forEach { name in var list = content[name] ?? [Type]() list.append(type) content[name] = list } } self.types = content self.validate = validate } public func types(forKey key: String) throws -> [Type] { // In some configurations, the types are keyed by "ModuleName.TypeName" var longKey: String? if let validate = validate { guard let type = all.first(where: { $0.name == key }) else { throw "Unknown type \(key), should be used with `based`" } try validate(type) if let module = type.module { longKey = [module, type.name].joined(separator: ".") } } // If we find the types directly, return them if let types = types[key] { return types } // if we find a types for the longKey, return them if let longKey = longKey, let types = types[longKey] { return types } return [] } /// :nodoc: override public func value(forKey key: String) -> Any? { do { return try types(forKey: key) } catch { Log.error(error) return nil } } /// :nodoc: public subscript(_ key: String) -> [Type] { do { return try types(forKey: key) } catch { Log.error(error) return [] } } override public func responds(to aSelector: Selector!) -> Bool { return true } } #endif ================================================ FILE: SourceryRuntime/Supporting Files/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2017 Pixle. All rights reserved. NSPrincipalClass ================================================ FILE: SourceryRuntime/Supporting Files/SourceryRuntime.h ================================================ #import //! Project version number for SourceryRuntime. FOUNDATION_EXPORT double SourceryRuntimeVersionNumber; //! Project version string for SourceryRuntime. FOUNDATION_EXPORT const unsigned char SourceryRuntimeVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: SourceryRuntime.podspec ================================================ Pod::Spec.new do |s| s.name = "SourceryRuntime" s.version = "2.3.0" s.summary = "A tool that brings meta-programming to Swift, allowing you to code generate Swift code." s.platform = :osx, '10.15' s.description = <<-DESC A tool that brings meta-programming to Swift, allowing you to code generate Swift code. * Featuring daemon mode that allows you to write templates side-by-side with generated code. * Using SourceKit so you can scan your regular code. DESC s.homepage = "https://github.com/krzysztofzablocki/Sourcery" s.license = 'MIT' s.author = { "Krzysztof Zabłocki" => "krzysztof.zablocki@pixle.pl" } s.social_media_url = "https://twitter.com/merowing_" s.source = { :http => "https://github.com/krzysztofzablocki/Sourcery/releases/download/#{s.version}/sourcery-#{s.version}.zip" } s.source_files = "SourceryRuntime/Sources/**/*.swift" s.osx.deployment_target = '10.15' s.dependency 'SourceryUtils' end ================================================ FILE: SourceryStencil/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2021 Pixle. All rights reserved. ================================================ FILE: SourceryStencil/SourceryStencil.h ================================================ // // SourceryStencil.h // SourceryStencil // // Created by merowing on 3/19/21. // Copyright © 2021 Pixle. All rights reserved. // #import //! Project version number for SourceryStencil. FOUNDATION_EXPORT double SourceryStencilVersionNumber; //! Project version string for SourceryStencil. FOUNDATION_EXPORT const unsigned char SourceryStencilVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: SourceryStencil/Sources/NewLineNode.swift ================================================ import Stencil class NewLineNode: NodeType { static let marker = "__sourcery__newline__" enum Content { case nodes([NodeType]) case reference(resolvable: Resolvable) } let token: Token? class func parse(_ parser: TokenParser, token: Token) throws -> NodeType { let components = token.components guard components.count == 1 else { throw TemplateSyntaxError( """ 'newline' tag takes no arguments """ ) } return NewLineNode() } init(token: Token? = nil) { self.token = token } func render(_ context: Context) throws -> String { return Self.marker } } ================================================ FILE: SourceryStencil/Sources/StencilTemplate.swift ================================================ import Foundation import Stencil import PathKit import StencilSwiftKit import SourceryRuntime public final class StencilTemplate: StencilSwiftKit.StencilSwiftTemplate { private(set) public var sourcePath: Path = "" /// Trim leading / trailing whitespaces until content or newline tag appears public var trimEnabled: Bool = false public convenience init(path: Path) throws { try self.init(path: path, templateString: try path.read()) } public convenience init(path: Path, templateString: String) throws { self.init(templateString: templateString, environment: StencilTemplate.sourceryEnvironment(templatePath: path)) sourcePath = path } public convenience init(templateString: String) { self.init(templateString: templateString, environment: StencilTemplate.sourceryEnvironment()) } // swiftlint:disable:next discouraged_optional_collection override public func render(_ dictionary: [String: Any]? = nil) throws -> String { var result = try super.render(dictionary) if trimEnabled { result = result.trimmed } return result.replacingOccurrences(of: NewLineNode.marker, with: "\n") } public static func sourceryEnvironment(templatePath: Path? = nil) -> Stencil.Environment { let ext = Stencil.Extension() ext.registerFilter("json") { (value, arguments) -> Any? in guard let value = value else { return nil } guard arguments.isEmpty || arguments.count == 1 && arguments.first is Bool else { throw TemplateSyntaxError("'json' filter takes a single boolean argument") } var options: JSONSerialization.WritingOptions = [] let prettyPrinted = arguments.first as? Bool ?? false if prettyPrinted { options = [.prettyPrinted] } let data = try JSONSerialization.data(withJSONObject: value, options: options) return String(data: data, encoding: .utf8) } ext.registerStringFilters() ext.registerBoolFilter("definedInExtension", filter: { (t: Definition) in t.definedInType?.isExtension ?? false }) ext.registerBoolFilter("computed", filter: { (v: SourceryVariable) in v.isComputed && !v.isStatic }) ext.registerBoolFilter("stored", filter: { (v: SourceryVariable) in !v.isComputed && !v.isStatic }) ext.registerBoolFilter("tuple", filter: { (v: SourceryVariable) in v.isTuple }) ext.registerBoolFilter("optional", filter: { (m: SourceryVariable) in m.isOptional }) ext.registerAccessLevelFilters(.open) ext.registerAccessLevelFilters(.public) ext.registerAccessLevelFilters(.private) ext.registerAccessLevelFilters(.fileprivate) ext.registerAccessLevelFilters(.internal) ext.registerAccessLevelFilters(.package) ext.registerBoolFilterOrWithArguments("based", filter: { (t: Type, name: String) in t.based[name] != nil }, other: { (t: Typed, name: String) in t.type?.based[name] != nil }) ext.registerBoolFilterOrWithArguments("implements", filter: { (t: Type, name: String) in t.implements[name] != nil }, other: { (t: Typed, name: String) in t.type?.implements[name] != nil }) ext.registerBoolFilterOrWithArguments("inherits", filter: { (t: Type, name: String) in t.inherits[name] != nil }, other: { (t: Typed, name: String) in t.type?.inherits[name] != nil }) ext.registerBoolFilterOrWithArguments("extends", filter: { (t: Type, name: String) in t.isExtension && t.name == name }, other: { (t: Typed, name: String) in guard let type = t.type else { return false }; return type.isExtension && type.name == name }) ext.registerBoolFilter("extension", filter: { (t: Type) in t.isExtension }) ext.registerBoolFilter("enum", filter: { (t: Type) in t is Enum }) ext.registerBoolFilter("struct", filter: { (t: Type) in t is Struct }) ext.registerBoolFilter("protocol", filter: { (t: Type) in t is SourceryProtocol }) ext.registerFilter("count", filter: count) ext.registerFilter("isEmpty", filter: isEmpty) ext.registerFilter("reversed", filter: reversed) ext.registerFilter("toArray", filter: toArray) ext.registerFilter("sortedValuesByKeys", filter: sortedValuesByKeys) ext.registerFilter("last", filter: last) ext.registerFilterWithArguments("push") { arg1, arg2 in var array = arg1 as? [Any] ?? [] array.append(arg2) return array } #if canImport(ObjectiveC) ext.registerFilterWithArguments("sorted") { (array, propertyName: String) -> Any? in switch array { case let array as NSArray: let sortDescriptor = NSSortDescriptor(key: propertyName, ascending: true, comparator: { guard let arg1 = $0 as? String, let arg2 = $1 as? String else { return .orderedAscending } return arg1.caseInsensitiveCompare(arg2) }) return array.sortedArray(using: [sortDescriptor]) default: return nil } } ext.registerFilterWithArguments("sortedDescending") { (array, propertyName: String) -> Any? in switch array { case let array as NSArray: let sortDescriptor = NSSortDescriptor(key: propertyName, ascending: false, comparator: { guard let arg1 = $0 as? String, let arg2 = $1 as? String else { return .orderedDescending } return arg1.caseInsensitiveCompare(arg2) }) return array.sortedArray(using: [sortDescriptor]) default: return nil } } #else ext.registerFilterWithArguments("sorted") { (array, propertyName: String) -> Any? in switch array { case let array as NSArray: return array.sortedArray { guard let arg1 = $0 as? String, let arg2 = $1 as? String else { return .orderedAscending } return arg1.caseInsensitiveCompare(arg2) } default: return nil } } ext.registerFilterWithArguments("sortedDescending") { (array, propertyName: String) -> Any? in switch array { case let array as NSArray: return array.sortedArray { guard let arg1 = $0 as? String, let arg2 = $1 as? String else { return .orderedDescending } return arg2.caseInsensitiveCompare(arg1) } default: return nil } } #endif ext.registerBoolFilter("initializer", filter: { (m: SourceryMethod) in m.isInitializer }) ext.registerBoolFilterOr("class", filter: { (t: Type) in t is Class }, other: { (m: SourceryMethod) in m.isClass }) ext.registerBoolFilterOr("static", filter: { (v: SourceryVariable) in v.isStatic }, other: { (m: SourceryMethod) in m.isStatic }) ext.registerBoolFilterOr("instance", filter: { (v: SourceryVariable) in !v.isStatic }, other: { (m: SourceryMethod) in !(m.isStatic || m.isClass) }) ext.registerBoolFilterWithArguments("annotated", filter: { (a: Annotated, annotation) in a.isAnnotated(with: annotation) }) ext.registerTag("newline", parser: NewLineNode.parse) ext.registerTag("typed", parser: TypedNode.parse) var extensions = stencilSwiftEnvironment().extensions extensions.append(ext) let loader = templatePath.map({ FileSystemLoader(paths: [$0.parent()]) }) return Environment(loader: loader, extensions: extensions, templateClass: StencilTemplate.self) } } public extension Annotated { func isAnnotated(with annotation: String) -> Bool { if annotation.contains("=") { let components = annotation.components(separatedBy: "=").map({ $0.trimmingCharacters(in: .whitespaces) }) var keyPath = components[0].components(separatedBy: ".") var annotationValue: Annotations? = annotations while !keyPath.isEmpty && annotationValue != nil { let key = keyPath.removeFirst() let value = annotationValue?[key] if keyPath.isEmpty { return value?.description == components[1] } else { annotationValue = value as? Annotations } } return false } else { return annotations[annotation] != nil } } } public extension Stencil.Extension { func registerStringFilters() { let lowercase = FilterOr.make({ $0.lowercased() }, other: { $0.name.lowercased() }) registerFilter("lowercase", filter: lowercase) let uppercase = FilterOr.make({ $0.uppercased() }, other: { $0.name.uppercased() }) registerFilter("uppercase", filter: uppercase) let capitalise = FilterOr.make({ $0.capitalized }, other: { $0.name.capitalized }) registerFilter("capitalise", filter: capitalise) let titleCase = FilterOr.make({ $0.titleCase }, other: { $0.name.titleCase }) registerFilter("titleCase", filter: titleCase) let deletingLastComponent = Filter.make({ ($0 as NSString).deletingLastPathComponent }) registerFilter("deletingLastComponent", filter: deletingLastComponent) } func registerFilterWithTwoArguments(_ name: String, filter: @escaping (T, A, B) throws -> Any?) { registerFilter(name) { (any, args) throws -> Any? in guard let type = any as? T else { return any } guard args.count == 2, let argA = args[0] as? A, let argB = args[1] as? B else { throw TemplateSyntaxError("'\(name)' filter takes two arguments: \(A.self) and \(B.self)") } return try filter(type, argA, argB) } } func registerFilterOrWithTwoArguments(_ name: String, filter: @escaping (T, A, B) throws -> Any?, other: @escaping (Y, A, B) throws -> Any?) { registerFilter(name) { (any, args) throws -> Any? in guard args.count == 2, let argA = args[0] as? A, let argB = args[1] as? B else { throw TemplateSyntaxError("'\(name)' filter takes two arguments: \(A.self) and \(B.self)") } if let type = any as? T { return try filter(type, argA, argB) } else if let type = any as? Y { return try other(type, argA, argB) } else { return any } } } func registerFilterWithArguments(_ name: String, filter: @escaping (Any?, A) throws -> Any?) { registerFilter(name) { (any: Any?, args: [Any?]) throws -> Any? in guard args.count == 1, let arg = args.first as? A else { throw TemplateSyntaxError("'\(name)' filter takes a single \(A.self) argument") } return try filter(any, arg) } } func registerBoolFilterWithArguments(_ name: String, filter: @escaping (U, A) -> Bool) { registerFilterWithArguments(name, filter: Filter.make(filter)) registerFilterWithArguments("!\(name)", filter: Filter.make({ !filter($0, $1) })) } func registerBoolFilter(_ name: String, filter: @escaping (U) -> Bool) { registerFilter(name, filter: Filter.make(filter)) registerFilter("!\(name)", filter: Filter.make({ !filter($0) })) } func registerBoolFilterOrWithArguments(_ name: String, filter: @escaping (U, A) -> Bool, other: @escaping (V, A) -> Bool) { registerFilterWithArguments(name, filter: FilterOr.make(filter, other: other)) registerFilterWithArguments("!\(name)", filter: FilterOr.make({ !filter($0, $1) }, other: { !other($0, $1) })) } func registerBoolFilterOr(_ name: String, filter: @escaping (U) -> Bool, other: @escaping (V) -> Bool) { registerFilter(name, filter: FilterOr.make(filter, other: other)) registerFilter("!\(name)", filter: FilterOr.make({ !filter($0) }, other: { !other($0) })) } func registerAccessLevelFilters(_ accessLevel: AccessLevel) { registerBoolFilterOr(accessLevel.rawValue, filter: { (t: Type) in t.accessLevel == accessLevel.rawValue && t.accessLevel != AccessLevel.none.rawValue }, other: { (m: SourceryMethod) in m.accessLevel == accessLevel.rawValue && m.accessLevel != AccessLevel.none.rawValue } ) registerBoolFilterOr("!\(accessLevel.rawValue)", filter: { (t: Type) in t.accessLevel != accessLevel.rawValue && t.accessLevel != AccessLevel.none.rawValue }, other: { (m: SourceryMethod) in m.accessLevel != accessLevel.rawValue && m.accessLevel != AccessLevel.none.rawValue } ) registerBoolFilter("\(accessLevel.rawValue)Get", filter: { (v: SourceryVariable) in v.readAccess == accessLevel.rawValue && v.readAccess != AccessLevel.none.rawValue }) registerBoolFilter("!\(accessLevel.rawValue)Get", filter: { (v: SourceryVariable) in v.readAccess != accessLevel.rawValue && v.readAccess != AccessLevel.none.rawValue }) registerBoolFilter("\(accessLevel.rawValue)Set", filter: { (v: SourceryVariable) in v.writeAccess == accessLevel.rawValue && v.writeAccess != AccessLevel.none.rawValue }) registerBoolFilter("!\(accessLevel.rawValue)Set", filter: { (v: SourceryVariable) in v.writeAccess != accessLevel.rawValue && v.writeAccess != AccessLevel.none.rawValue }) } } private func last(_ value: Any?) -> Any? { switch value { case let arr as NSArray: return arr.lastObject default: return nil } } private func sortedValuesByKeys(_ value: Any?) -> Any? { switch value { case let dict as NSDictionary: let keys = dict.allKeys.sorted { (($0 as? String) ?? "" < ($1 as? String) ?? "") } var retVal: [Any?] = [] for key in keys { retVal.append(dict[key]) } return retVal default: return nil } } private func toArray(_ value: Any?) -> Any? { switch value { case let array as NSArray: return array case .some(let something): return [something] default: return nil } } private func reversed(_ value: Any?) -> Any? { guard let array = value as? NSArray else { return value } return array.reversed() } private func count(_ value: Any?) -> Any? { guard let array = value as? NSArray else { return value } return array.count } private func isEmpty(_ value: Any?) -> Any? { switch value { case let array as NSArray: // swiftlint:disable:next empty_count array.count == 0 case let string as NSString: string.length == 0 default: false } } private struct Filter { static func make(_ filter: @escaping (T) -> Bool) -> (Any?) throws -> Any? { return { (any) throws -> Any? in switch any { case let type as T: return filter(type) case let array as NSArray: return array.compactMap { $0 as? T }.filter(filter) default: return any } } } static func make(_ filter: @escaping (T) -> U?) -> (Any?) throws -> Any? { return { (any) throws -> Any? in switch any { case let type as T: return filter(type) case let array as NSArray: return array.compactMap { $0 as? T }.compactMap(filter) default: return any } } } static func make(_ filter: @escaping (T, A) -> Bool) -> (Any?, A) throws -> Any? { return { (any, arg) throws -> Any? in switch any { case let type as T: return filter(type, arg) case let array as NSArray: return array.compactMap { $0 as? T }.filter { filter($0, arg) } default: return any } } } } private struct FilterOr { static func make(_ filter: @escaping (T) -> Bool, other: @escaping (Y) -> Bool) -> (Any?) throws -> Any? { return { (any) throws -> Any? in switch any { case let type as T: return filter(type) case let type as Y: return other(type) case let array as NSArray: if array.firstObject is T { return array.compactMap { $0 as? T }.filter(filter) } else { return array.compactMap { $0 as? Y }.filter(other) } default: return any } } } static func make(_ filter: @escaping (T) -> U?, other: @escaping (Y) -> U?) -> (Any?) throws -> Any? { return { (any) throws -> Any? in switch any { case let type as T: return filter(type) case let type as Y: return other(type) case let array as NSArray: if array.firstObject is T { return array.compactMap { $0 as? T }.compactMap(filter) } else { return array.compactMap { $0 as? Y }.compactMap(other) } default: return any } } } static func make(_ filter: @escaping (T, A) -> Bool, other: @escaping (Y, A) -> Bool) -> (Any?, A) throws -> Any? { return { (any, arg) throws -> Any? in switch any { case let type as T: return filter(type, arg) case let type as Y: return other(type, arg) case let array as NSArray: if array.firstObject is T { return array.compactMap { $0 as? T }.filter({ filter($0, arg) }) } else { return array.compactMap { $0 as? Y }.filter({ other($0, arg) }) } default: return any } } } } fileprivate extension String { /// Returns string with uppercased first character var uppercasedFirst: String { return first .map { String($0).uppercased() + dropFirst() } ?? "" } /// Changes `somethingNamedLikeThis` into `Something Named Like This` var titleCase: String { replacingOccurrences(of: "([a-z])([A-Z](?=[A-Z])[a-z]*)", with: "$1 $2", options: .regularExpression) .replacingOccurrences(of: "([A-Z])([A-Z][a-z])", with: "$1 $2", options: .regularExpression) .replacingOccurrences(of: "([a-z]vis)([A-Z][a-z])", with: "$1 $2", options: .regularExpression) .replacingOccurrences(of: "([a-z])([A-Z][a-z])", with: "$1 $2", options: .regularExpression) .uppercasedFirst } } ================================================ FILE: SourceryStencil/Sources/TypedNode.swift ================================================ import Stencil extension Array { func chunked(into size: Int) -> [[Element]] { return stride(from: 0, to: count, by: size).map { Array(self[$0 ..< Swift.min($0 + size, count)]) } } } class TypedNode: NodeType { enum Content { case nodes([NodeType]) case reference(resolvable: Resolvable) } typealias Binding = (name: String, type: String) let token: Token? let bindings: [Binding] class func parse(_ parser: TokenParser, token: Token) throws -> NodeType { let components = token.components guard components.count > 1, (components.count - 1) % 3 == 0 else { throw TemplateSyntaxError( """ 'typed' tag takes only triple of arguments e.g. name as Type """ ) } let chunks = Array(components.dropFirst()).chunked(into: 3) let bindings: [Binding] = chunks.compactMap { binding in return (name: binding[0], type: binding[2]) } return TypedNode(bindings: bindings) } init(token: Token? = nil, bindings: [Binding]) { self.token = token self.bindings = bindings } func render(_ context: Context) throws -> String { return "" } } ================================================ FILE: SourcerySwift/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2018 Pixle. All rights reserved. NSPrincipalClass ================================================ FILE: SourcerySwift/SourcerySwift.h ================================================ // // SourcerySwift.h // SourcerySwift // // Created by Ilya Puchka on 29/01/2018. // Copyright © 2018 Pixle. All rights reserved. // #import //! Project version number for SourcerySwift. FOUNDATION_EXPORT double SourcerySwiftVersionNumber; //! Project version string for SourcerySwift. FOUNDATION_EXPORT const unsigned char SourcerySwiftVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: SourcerySwift/Sources/SourceryRuntime.content.generated.swift ================================================ #if canImport(ObjectiveC) let sourceryRuntimeFiles: [FolderSynchronizer.File] = [ .init(name: "AccessLevel.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation /// :nodoc: public enum AccessLevel: String { case `package` = "package" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" case `public` = "public" case `open` = "open" case none = "" } """), .init(name: "Actor.swift", content: """ import Foundation // sourcery: skipDescription /// Descibes Swift actor #if canImport(ObjectiveC) @objc(SwiftActor) @objcMembers #endif public final class Actor: Type { // sourcery: skipJSExport public class var kind: String { return "actor" } /// Returns "actor" public override var kind: String { Self.kind } /// Whether type is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Whether method is distributed method public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Actor.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("isFinal = \\(String(describing: self.isFinal)), ") string.append("isDistributed = \\(String(describing: self.isDistributed))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Actor else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Actor else { return false } return super.isEqual(rhs) } // sourcery:inline:Actor.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } """), .init(name: "Annotations.swift", content: """ import Foundation public typealias Annotations = [String: NSObject] /// Describes annotated declaration, i.e. type, method, variable, enum case public protocol Annotated { /** All annotations of declaration stored by their name. Value can be `bool`, `String`, float `NSNumber` or array of those types if you use several annotations with the same name. **Example:** ``` //sourcery: booleanAnnotation //sourcery: stringAnnotation = "value" //sourcery: numericAnnotation = 0.5 [ "booleanAnnotation": true, "stringAnnotation": "value", "numericAnnotation": 0.5 ] ``` */ var annotations: Annotations { get } } """), .init(name: "Array+Parallel.swift", content: """ // // Created by Krzysztof Zablocki on 06/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation public extension Array { func parallelFlatMap(transform: (Element) -> [T]) -> [T] { return parallelMap(transform: transform).flatMap { $0 } } func parallelCompactMap(transform: (Element) -> T?) -> [T] { return parallelMap(transform: transform).compactMap { $0 } } func parallelMap(transform: (Element) -> T) -> [T] { var result = ContiguousArray(repeating: nil, count: count) return result.withUnsafeMutableBufferPointer { buffer in nonisolated(unsafe) let buffer = buffer DispatchQueue.concurrentPerform(iterations: buffer.count) { idx in buffer[idx] = transform(self[idx]) } return buffer.map { $0! } } } func parallelPerform(_ work: (Element) -> Void) { DispatchQueue.concurrentPerform(iterations: count) { idx in work(self[idx]) } } } """), .init(name: "Array.swift", content: """ import Foundation /// Describes array type #if canImport(ObjectiveC) @objcMembers #endif public final class ArrayType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Array element type name public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription /// Array element type, if known public var elementType: Type? /// :nodoc: public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name self.elementTypeName = elementTypeName self.elementType = elementType } /// Returns array as generic type public var asGeneric: GenericType { GenericType(name: "Array", typeParameters: [ .init(typeName: elementTypeName, type: elementType) ]) } public var asSource: String { "[\\(elementTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") string.append("asGeneric = \\(String(describing: self.asGeneric)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ArrayType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ArrayType else { return false } if self.name != rhs.name { return false } if self.elementTypeName != rhs.elementTypeName { return false } return true } // sourcery:inline:ArrayType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elementTypeName = elementTypeName self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elementTypeName, forKey: "elementTypeName") aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } """), .init(name: "Attribute.swift", content: """ import Foundation /// Describes Swift attribute #if canImport(ObjectiveC) @objcMembers #endif public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { /// Attribute name public let name: String /// Attribute arguments public let arguments: [String: NSObject] // sourcery: skipJSExport let _description: String // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { self.name = name self.arguments = arguments let argumentDescription = arguments.map { "\\($0.key): \\($0.value is String ? "\\"" : "")\\($0.value)\\($0.value is String ? "\\"" : "")" }.joined(separator: ", ") self._description = description ?? "@\\(name)\\(!argumentDescription.isEmpty ? "(" : "")\\(argumentDescription)\\(!argumentDescription.isEmpty ? ")" : "")" } /// TODO: unify `asSource` / `description`? public var asSource: String { description } /// Attribute description that can be used in a template. public override var description: String { _description } /// :nodoc: public enum Identifier: String { case convenience case required case available case discardableResult case GKInspectable = "gkinspectable" case objc case objcMembers case nonobjc case NSApplicationMain case NSCopying case NSManaged case UIApplicationMain case IBOutlet = "iboutlet" case IBInspectable = "ibinspectable" case IBDesignable = "ibdesignable" case autoclosure case convention case mutating case nonisolated case isolated case escaping case final case open case lazy case `package` = "package" case `public` = "public" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" case publicSetter = "setter_access.public" case internalSetter = "setter_access.internal" case privateSetter = "setter_access.private" case fileprivateSetter = "setter_access.fileprivate" case optional case dynamic public init?(identifier: String) { let identifier = identifier.trimmingPrefix("source.decl.attribute.") if identifier == "objc.name" { self.init(rawValue: "objc") } else { self.init(rawValue: identifier) } } public static func from(string: String) -> Identifier? { switch string { case "GKInspectable": return Identifier.GKInspectable case "objc": return .objc case "IBOutlet": return .IBOutlet case "IBInspectable": return .IBInspectable case "IBDesignable": return .IBDesignable default: return Identifier(rawValue: string) } } public var name: String { switch self { case .GKInspectable: return "GKInspectable" case .objc: return "objc" case .IBOutlet: return "IBOutlet" case .IBInspectable: return "IBInspectable" case .IBDesignable: return "IBDesignable" case .fileprivateSetter: return "fileprivate" case .privateSetter: return "private" case .internalSetter: return "internal" case .publicSetter: return "public" default: return rawValue } } public var description: String { return hasAtPrefix ? "@\\(name)" : name } public var hasAtPrefix: Bool { switch self { case .available, .discardableResult, .GKInspectable, .objc, .objcMembers, .nonobjc, .NSApplicationMain, .NSCopying, .NSManaged, .UIApplicationMain, .IBOutlet, .IBInspectable, .IBDesignable, .autoclosure, .convention, .escaping: return true default: return false } } } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Attribute else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "arguments").trackDifference(actual: self.arguments, expected: castObject.arguments)) results.append(contentsOf: DiffableResult(identifier: "_description").trackDifference(actual: self._description, expected: castObject._description)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.arguments) hasher.combine(self._description) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Attribute else { return false } if self.name != rhs.name { return false } if self.arguments != rhs.arguments { return false } if self._description != rhs._description { return false } return true } // sourcery:inline:Attribute.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { withVaList(["arguments"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.arguments = arguments guard let _description: String = aDecoder.decode(forKey: "_description") else { withVaList(["_description"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._description = _description } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.arguments, forKey: "arguments") aCoder.encode(self._description, forKey: "_description") } // sourcery:end } """), .init(name: "BytesRange.swift", content: """ // // Created by Sébastien Duperron on 03/01/2018. // Copyright © 2018 Pixle. All rights reserved. // import Foundation /// :nodoc: #if canImport(ObjectiveC) @objcMembers #endif public final class BytesRange: NSObject, SourceryModel, Diffable { public let offset: Int64 public let length: Int64 public init(offset: Int64, length: Int64) { self.offset = offset self.length = length } public convenience init(range: (offset: Int64, length: Int64)) { self.init(offset: range.offset, length: range.length) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string += "offset = \\(String(describing: self.offset)), " string += "length = \\(String(describing: self.length))" return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? BytesRange else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "offset").trackDifference(actual: self.offset, expected: castObject.offset)) results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: castObject.length)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.offset) hasher.combine(self.length) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? BytesRange else { return false } if self.offset != rhs.offset { return false } if self.length != rhs.length { return false } return true } // sourcery:inline:BytesRange.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.offset = aDecoder.decodeInt64(forKey: "offset") self.length = aDecoder.decodeInt64(forKey: "length") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.offset, forKey: "offset") aCoder.encode(self.length, forKey: "length") } // sourcery:end } """), .init(name: "Class.swift", content: """ import Foundation // sourcery: skipDescription /// Descibes Swift class #if canImport(ObjectiveC) @objc(SwiftClass) @objcMembers #endif public final class Class: Type { // sourcery: skipJSExport public class var kind: String { return "class" } /// Returns "class" public override var kind: String { Self.kind } /// Whether type is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Class.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("isFinal = \\(String(describing: self.isFinal))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Class else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Class else { return false } return super.isEqual(rhs) } // sourcery:inline:Class.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } """), .init(name: "Composer.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation private func currentTimestamp() -> TimeInterval { return Date().timeIntervalSince1970 } /// Responsible for composing results of `FileParser`. public enum Composer { /// Performs final processing of discovered types: /// - extends types with their corresponding extensions; /// - replaces typealiases with actual types /// - finds actual types for variables and enums raw values /// - filters out any private types and extensions /// /// - Parameter parserResult: Result of parsing source code. /// - Parameter serial: Whether to process results serially instead of concurrently /// - Returns: Final types and extensions of unknown types. public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult, serial: Bool = false) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { let composed = ParserResultsComposed(parserResult: parserResult) let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in composed.resolveType(typeName: typeName, containingType: containingType) } let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in composed.resolveType(typeName: typeName, containingType: containingType, method: method) } let processType = { (type: Type) in type.variables.forEach { resolveVariableTypes($0, of: type, resolve: resolveType) } type.methods.forEach { resolveMethodTypes($0, of: type, resolve: methodResolveType) } type.subscripts.forEach { resolveSubscriptTypes($0, of: type, resolve: resolveType) } if let enumeration = type as? Enum { resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) } if let composition = type as? ProtocolComposition { resolveProtocolCompositionTypes(composition, resolve: resolveType) } if let sourceryProtocol = type as? SourceryProtocol { resolveAssociatedTypes(sourceryProtocol, resolve: resolveType) } } let processFunction = { (function: SourceryMethod) in resolveMethodTypes(function, of: nil, resolve: methodResolveType) } if serial { composed.types.forEach(processType) composed.functions.forEach(processFunction) } else { composed.types.parallelPerform(processType) composed.functions.parallelPerform(processFunction) } updateTypeRelationships(types: composed.types) return ( types: composed.types.sorted { $0.globalName < $1.globalName }, functions: composed.functions.sorted { $0.name < $1.name }, typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) ) } typealias TypeResolver = (TypeName, Type?) -> Type? typealias MethodArgumentTypeResolver = (TypeName, Type?, Method) -> Type? private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { variable.type = resolve(variable.typeName, type) /// The actual `definedInType` is assigned in `uniqueTypes` but we still /// need to resolve the type to correctly parse typealiases /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 if let definedInTypeName = variable.definedInTypeName { _ = resolve(definedInTypeName, type) } } private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { `subscript`.parameters.forEach { (parameter) in parameter.type = resolve(parameter.typeName, type) } `subscript`.returnType = resolve(`subscript`.returnTypeName, type) if let definedInTypeName = `subscript`.definedInTypeName { _ = resolve(definedInTypeName, type) } } private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: MethodArgumentTypeResolver) { method.parameters.forEach { parameter in parameter.type = resolve(parameter.typeName, type, method) } /// The actual `definedInType` is assigned in `uniqueTypes` but we still /// need to resolve the type to correctly parse typealiases /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 var definedInType: Type? if let definedInTypeName = method.definedInTypeName { definedInType = resolve(definedInTypeName, type, method) } guard !method.returnTypeName.isVoid else { return } if method.isInitializer || method.isFailableInitializer { method.returnType = definedInType if let type = method.actualDefinedInTypeName { if method.isFailableInitializer { method.returnTypeName = TypeName( name: type.name, isOptional: true, isImplicitlyUnwrappedOptional: false, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if method.isInitializer { method.returnTypeName = type } } } else { method.returnType = resolve(method.returnTypeName, type, method) } } private static func resolveEnumTypes(_ enumeration: Enum, types: [String: Type], resolve: TypeResolver) { enumeration.cases.forEach { enumCase in enumCase.associatedValues.forEach { associatedValue in associatedValue.type = resolve(associatedValue.typeName, enumeration) } } guard enumeration.hasRawType else { return } if let rawValueVariable = enumeration.variables.first(where: { $0.name == "rawValue" && !$0.isStatic }) { enumeration.rawTypeName = rawValueVariable.actualTypeName enumeration.rawType = rawValueVariable.type } else if let rawTypeName = enumeration.inheritedTypes.first { // enums with no cases or enums with cases that contain associated values can't have raw type guard !enumeration.cases.isEmpty, !enumeration.hasAssociatedValues else { return enumeration.rawTypeName = nil } if let rawTypeCandidate = types[rawTypeName] { if !((rawTypeCandidate is SourceryProtocol) || (rawTypeCandidate is ProtocolComposition)) { enumeration.rawTypeName = TypeName(rawTypeName) enumeration.rawType = rawTypeCandidate } } else { enumeration.rawTypeName = TypeName(rawTypeName) } } } private static func resolveProtocolCompositionTypes(_ protocolComposition: ProtocolComposition, resolve: TypeResolver) { let composedTypes = protocolComposition.composedTypeNames.compactMap { typeName in resolve(typeName, protocolComposition) } protocolComposition.composedTypes = composedTypes } private static func resolveAssociatedTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) { sourceryProtocol.associatedTypes.forEach { (_, value) in guard let typeName = value.typeName, let type = resolve(typeName, sourceryProtocol) else { return } value.type = type } sourceryProtocol.genericRequirements.forEach { requirment in if let knownAssociatedType = sourceryProtocol.associatedTypes[requirment.leftType.name] { requirment.leftType = knownAssociatedType } requirment.rightType.type = resolve(requirment.rightType.typeName, sourceryProtocol) } } private static func updateTypeRelationships(types: [Type]) { var typesByName = [String: Type]() types.forEach { typesByName[$0.globalName] = $0 } var processed = [String: Bool]() types.forEach { type in if let type = type as? Class, let supertype = type.inheritedTypes.first.flatMap({ typesByName[$0] }) as? Class { type.supertype = supertype } processed[type.globalName] = true updateTypeRelationship(for: type, typesByName: typesByName, processed: &processed) } } internal static func findBaseType(for type: Type, name: String, typesByName: [String: Type]) -> Type? { // special case to check if the type is based on one of the recognized types // and the superclass has a generic constraint in `name` part of the `TypeName` var name = name if name.contains("<") && name.contains(">") { let parts = name.split(separator: "<") name = String(parts.first!) } if let baseType = typesByName[name] { return baseType } if let module = type.module, let baseType = typesByName["\\(module).\\(name)"] { return baseType } for importModule in type.imports { if let baseType = typesByName["\\(importModule).\\(name)"] { return baseType } } guard name.contains("&") else { return nil } // this can happen for a type which consists of mutliple types composed together (i.e. (A & B)) let nameComponents = name.components(separatedBy: "&").map { $0.trimmingCharacters(in: .whitespaces) } let types: [Type] = nameComponents.compactMap { typesByName[$0] } let typeNames = types.map { TypeName(name: $0.name) } return ProtocolComposition(name: name, inheritedTypes: types.map { $0.globalName }, composedTypeNames: typeNames, composedTypes: types) } private static func updateTypeRelationship(for type: Type, typesByName: [String: Type], processed: inout [String: Bool]) { type.based.keys.forEach { name in guard let baseType = findBaseType(for: type, name: name, typesByName: typesByName) else { return } let globalName = baseType.globalName if processed[globalName] != true { processed[globalName] = true updateTypeRelationship(for: baseType, typesByName: typesByName, processed: &processed) } copyTypeRelationships(from: baseType, to: type) if let composedType = baseType as? ProtocolComposition { let implements = composedType.composedTypes?.filter({ $0 is SourceryProtocol }) implements?.forEach { updateInheritsAndImplements(from: $0, to: type) } if implements?.count == composedType.composedTypes?.count || composedType.composedTypes == nil || composedType.composedTypes?.isEmpty == true { type.implements[globalName] = baseType } } else { updateInheritsAndImplements(from: baseType, to: type) } type.basedTypes[globalName] = baseType } } private static func updateInheritsAndImplements(from baseType: Type, to type: Type) { if baseType is Class { type.inherits[baseType.name] = baseType } else if let `protocol` = baseType as? SourceryProtocol { type.implements[baseType.globalName] = baseType if let extendingProtocol = type as? SourceryProtocol { `protocol`.associatedTypes.forEach { if extendingProtocol.associatedTypes[$0.key] == nil { extendingProtocol.associatedTypes[$0.key] = $0.value } } } } } private static func copyTypeRelationships(from baseType: Type, to type: Type) { baseType.based.keys.forEach { type.based[$0] = $0 } baseType.basedTypes.forEach { type.basedTypes[$0.key] = $0.value } baseType.inherits.forEach { type.inherits[$0.key] = $0.value } baseType.implements.forEach { type.implements[$0.key] = $0.value } } } """), .init(name: "Definition.swift", content: """ import Foundation /// Describes that the object is defined in a context of some `Type` public protocol Definition: AnyObject { /// Reference to type name where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc var definedInTypeName: TypeName? { get } /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown var definedInType: Type? { get } // sourcery: skipJSExport /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` var actualDefinedInTypeName: TypeName? { get } } """), .init(name: "Dictionary.swift", content: """ import Foundation /// Describes dictionary type #if canImport(ObjectiveC) @objcMembers #endif public final class DictionaryType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Dictionary value type name public var valueTypeName: TypeName // sourcery: skipEquality, skipDescription /// Dictionary value type, if known public var valueType: Type? /// Dictionary key type name public var keyTypeName: TypeName // sourcery: skipEquality, skipDescription /// Dictionary key type, if known public var keyType: Type? /// :nodoc: public init(name: String, valueTypeName: TypeName, valueType: Type? = nil, keyTypeName: TypeName, keyType: Type? = nil) { self.name = name self.valueTypeName = valueTypeName self.valueType = valueType self.keyTypeName = keyTypeName self.keyType = keyType } /// Returns dictionary as generic type public var asGeneric: GenericType { GenericType(name: "Dictionary", typeParameters: [ .init(typeName: keyTypeName), .init(typeName: valueTypeName) ]) } public var asSource: String { "[\\(keyTypeName.asSource): \\(valueTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("valueTypeName = \\(String(describing: self.valueTypeName)), ") string.append("keyTypeName = \\(String(describing: self.keyTypeName)), ") string.append("asGeneric = \\(String(describing: self.asGeneric)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? DictionaryType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "valueTypeName").trackDifference(actual: self.valueTypeName, expected: castObject.valueTypeName)) results.append(contentsOf: DiffableResult(identifier: "keyTypeName").trackDifference(actual: self.keyTypeName, expected: castObject.keyTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.valueTypeName) hasher.combine(self.keyTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? DictionaryType else { return false } if self.name != rhs.name { return false } if self.valueTypeName != rhs.valueTypeName { return false } if self.keyTypeName != rhs.keyTypeName { return false } return true } // sourcery:inline:DictionaryType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { withVaList(["valueTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.valueTypeName = valueTypeName self.valueType = aDecoder.decode(forKey: "valueType") guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { withVaList(["keyTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.keyTypeName = keyTypeName self.keyType = aDecoder.decode(forKey: "keyType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.valueTypeName, forKey: "valueTypeName") aCoder.encode(self.valueType, forKey: "valueType") aCoder.encode(self.keyTypeName, forKey: "keyTypeName") aCoder.encode(self.keyType, forKey: "keyType") } // sourcery:end } """), .init(name: "Diffable.swift", content: """ // // Diffable.swift // Sourcery // // Created by Krzysztof Zabłocki on 22/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation public protocol Diffable { /// Returns `DiffableResult` for the given objects. /// /// - Parameter object: Object to diff against. /// - Returns: Diffable results. func diffAgainst(_ object: Any?) -> DiffableResult } /// :nodoc: extension NSRange: Diffable { /// :nodoc: public static func == (lhs: NSRange, rhs: NSRange) -> Bool { return NSEqualRanges(lhs, rhs) } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let rhs = object as? NSRange else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "location").trackDifference(actual: self.location, expected: rhs.location)) results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: rhs.length)) return results } } #if canImport(ObjectiveC) @objcMembers #endif public class DiffableResult: NSObject, AutoEquatable { // sourcery: skipEquality private var results: [String] internal var identifier: String? init(results: [String] = [], identifier: String? = nil) { self.results = results self.identifier = identifier } func append(_ element: String) { results.append(element) } func append(contentsOf contents: DiffableResult) { if !contents.isEmpty { results.append(contents.description) } } var isEmpty: Bool { return results.isEmpty } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.identifier) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? DiffableResult else { return false } if self.identifier != rhs.identifier { return false } return true } public override var description: String { guard !results.isEmpty else { return "" } var description = "\\(identifier.flatMap { "\\($0) " } ?? "")" description.append(results.joined(separator: "\\n")) return description } } public extension DiffableResult { #if swift(>=4.1) #else /// :nodoc: @discardableResult func trackDifference(actual: T, expected: T) -> DiffableResult { if actual != expected { let result = DiffableResult(results: [""]) append(contentsOf: result) } return self } #endif /// :nodoc: @discardableResult func trackDifference(actual: T?, expected: T?) -> DiffableResult { if actual != expected { let expected = expected.map({ "\\($0)" }) ?? "nil" let actual = actual.map({ "\\($0)" }) ?? "nil" let result = DiffableResult(results: [""]) append(contentsOf: result) } return self } /// :nodoc: @discardableResult func trackDifference(actual: T, expected: T) -> DiffableResult where T: Diffable { let diffResult = actual.diffAgainst(expected) append(contentsOf: diffResult) return self } /// :nodoc: @discardableResult func trackDifference(actual: [T], expected: [T]) -> DiffableResult where T: Diffable { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { diffResult.append("Different count, expected: \\(expected.count), received: \\(actual.count)") return self } for (idx, item) in actual.enumerated() { let diff = DiffableResult() diff.trackDifference(actual: item, expected: expected[idx]) if !diff.isEmpty { let string = "idx \\(idx): \\(diff)" diffResult.append(string) } } return self } /// :nodoc: @discardableResult func trackDifference(actual: [T], expected: [T]) -> DiffableResult { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { diffResult.append("Different count, expected: \\(expected.count), received: \\(actual.count)") return self } for (idx, item) in actual.enumerated() where item != expected[idx] { let string = "idx \\(idx): " diffResult.append(string) } return self } /// :nodoc: @discardableResult func trackDifference(actual: [K: T], expected: [K: T]) -> DiffableResult where T: Diffable { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { append("Different count, expected: \\(expected.count), received: \\(actual.count)") if expected.count > actual.count { let missingKeys = Array(expected.keys.filter { actual[$0] == nil }.map { String(describing: $0) }) diffResult.append("Missing keys: \\(missingKeys.joined(separator: ", "))") } return self } for (key, actualElement) in actual { guard let expectedElement = expected[key] else { diffResult.append("Missing key \\"\\(key)\\"") continue } let diff = DiffableResult() diff.trackDifference(actual: actualElement, expected: expectedElement) if !diff.isEmpty { let string = "key \\"\\(key)\\": \\(diff)" diffResult.append(string) } } return self } // MARK: - NSObject diffing /// :nodoc: @discardableResult func trackDifference(actual: [K: T], expected: [K: T]) -> DiffableResult { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { append("Different count, expected: \\(expected.count), received: \\(actual.count)") if expected.count > actual.count { let missingKeys = Array(expected.keys.filter { actual[$0] == nil }.map { String(describing: $0) }) diffResult.append("Missing keys: \\(missingKeys.joined(separator: ", "))") } return self } for (key, actualElement) in actual { guard let expectedElement = expected[key] else { diffResult.append("Missing key \\"\\(key)\\"") continue } if !actualElement.isEqual(expectedElement) { diffResult.append("key \\"\\(key)\\": ") } } return self } } """), .init(name: "Documentation.swift", content: """ import Foundation public typealias Documentation = [String] /// Describes a declaration with documentation, i.e. type, method, variable, enum case public protocol Documented { var documentation: Documentation { get } } """), .init(name: "Extensions.swift", content: """ import Foundation public extension StringProtocol { /// Trimms leading and trailing whitespaces and newlines var trimmed: String { self.trimmingCharacters(in: .whitespacesAndNewlines) } } public extension String { /// Returns nil if string is empty var nilIfEmpty: String? { if isEmpty { return nil } return self } /// Returns nil if string is empty or contains `_` character var nilIfNotValidParameterName: String? { if isEmpty { return nil } if self == "_" { return nil } return self } /// :nodoc: /// - Parameter substring: Instance of a substring /// - Returns: Returns number of times a substring appears in self func countInstances(of substring: String) -> Int { guard !substring.isEmpty else { return 0 } var count = 0 var searchRange: Range? while let foundRange = range(of: substring, options: [], range: searchRange) { count += 1 searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) } return count } /// :nodoc: /// Removes leading and trailing whitespace from str. Returns false if str was not altered. @discardableResult mutating func strip() -> Bool { let strippedString = stripped() guard strippedString != self else { return false } self = strippedString return true } /// :nodoc: /// Returns a copy of str with leading and trailing whitespace removed. func stripped() -> String { return String(self.trimmingCharacters(in: .whitespaces)) } /// :nodoc: @discardableResult mutating func trimPrefix(_ prefix: String) -> Bool { guard hasPrefix(prefix) else { return false } self = String(self.suffix(self.count - prefix.count)) return true } /// :nodoc: func trimmingPrefix(_ prefix: String) -> String { guard hasPrefix(prefix) else { return self } return String(self.suffix(self.count - prefix.count)) } /// :nodoc: @discardableResult mutating func trimSuffix(_ suffix: String) -> Bool { guard hasSuffix(suffix) else { return false } self = String(self.prefix(self.count - suffix.count)) return true } /// :nodoc: func trimmingSuffix(_ suffix: String) -> String { guard hasSuffix(suffix) else { return self } return String(self.prefix(self.count - suffix.count)) } /// :nodoc: func dropFirstAndLast(_ n: Int = 1) -> String { return drop(first: n, last: n) } /// :nodoc: func drop(first: Int, last: Int) -> String { return String(self.dropFirst(first).dropLast(last)) } /// :nodoc: /// Wraps brackets if needed to make a valid type name func bracketsBalancing() -> String { if hasPrefix("(") && hasSuffix(")") { let unwrapped = dropFirstAndLast() return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self } else { let wrapped = "(\\(self))" return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self } } /// :nodoc: /// Returns true if given string can represent a valid tuple type name func isValidTupleName() -> Bool { guard hasPrefix("(") && hasSuffix(")") else { return false } let trimmedBracketsName = dropFirstAndLast() return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 } /// :nodoc: func isValidArrayName() -> Bool { if hasPrefix("Array<") { return true } if hasPrefix("[") && hasSuffix("]") { return dropFirstAndLast().colonSeparated().count == 1 } return false } /// :nodoc: func isValidDictionaryName() -> Bool { if hasPrefix("Dictionary<") { return true } if hasPrefix("[") && contains(":") && hasSuffix("]") { return dropFirstAndLast().colonSeparated().count == 2 } return false } /// :nodoc: func isValidClosureName() -> Bool { return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 } /// :nodoc: /// Returns true if all opening brackets are balanced with closed brackets. func isBracketsBalanced() -> Bool { var bracketsCount: Int = 0 for char in self { if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } if bracketsCount < 0 { return false } } return bracketsCount == 0 } /// :nodoc: /// Returns components separated with a comma respecting nested types func commaSeparated() -> [String] { return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) } /// :nodoc: /// Returns components separated with colon respecting nested types func colonSeparated() -> [String] { return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) } /// :nodoc: /// Returns components separated with semicolon respecting nested contexts func semicolonSeparated() -> [String] { return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) } /// :nodoc: func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) } /// :nodoc: func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { var boundingCharactersCount: Int = 0 var quotesCount: Int = 0 var item = "" var items = [String]() var i = self.startIndex while i < self.endIndex { var offset = 1 defer { i = self.index(i, offsetBy: offset) } var currentlyScannedEnd: Index = self.endIndex if let endIndex = self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) { currentlyScannedEnd = endIndex } let currentlyScanned: String = String(self[i..` if !((self[i] == ">") as Bool && (item.last == "-") as Bool) { boundingCharactersCount = max(0, boundingCharactersCount - 1) } offset = closeString.count } if (self[i] == "\\"") as Bool { quotesCount += 1 } let currentIsDelimiter = (currentlyScanned == delimiter) as Bool let boundingCountIsZero = (boundingCharactersCount == 0) as Bool let hasEvenQuotes = (quotesCount % 2 == 0) as Bool if currentIsDelimiter && boundingCountIsZero && hasEvenQuotes { items.append(item) item = "" i = self.index(i, offsetBy: delimiter.count - 1) } else { let endIndex: Index = self.index(i, offsetBy: offset) item += self[i.. DiffableResult { let results = DiffableResult() guard let castObject = object as? FileParserResult else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.path) hasher.combine(self.module) hasher.combine(self.types) hasher.combine(self.functions) hasher.combine(self.typealiases) hasher.combine(self.inlineRanges) hasher.combine(self.inlineIndentations) hasher.combine(self.modifiedDate) hasher.combine(self.sourceryVersion) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? FileParserResult else { return false } if self.path != rhs.path { return false } if self.module != rhs.module { return false } if self.types != rhs.types { return false } if self.functions != rhs.functions { return false } if self.typealiases != rhs.typealiases { return false } if self.inlineRanges != rhs.inlineRanges { return false } if self.inlineIndentations != rhs.inlineIndentations { return false } if self.modifiedDate != rhs.modifiedDate { return false } if self.sourceryVersion != rhs.sourceryVersion { return false } return true } // sourcery:inline:FileParserResult.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.path = aDecoder.decode(forKey: "path") self.module = aDecoder.decode(forKey: "module") guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { withVaList(["functions"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.functions = functions guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { withVaList(["inlineRanges"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inlineRanges = inlineRanges guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { withVaList(["inlineIndentations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inlineIndentations = inlineIndentations guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { withVaList(["modifiedDate"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiedDate = modifiedDate guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { withVaList(["sourceryVersion"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.sourceryVersion = sourceryVersion } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.path, forKey: "path") aCoder.encode(self.module, forKey: "module") aCoder.encode(self.types, forKey: "types") aCoder.encode(self.functions, forKey: "functions") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.inlineRanges, forKey: "inlineRanges") aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") aCoder.encode(self.modifiedDate, forKey: "modifiedDate") aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") } // sourcery:end } """), .init(name: "Generic.swift", content: """ import Foundation /// Descibes Swift generic type #if canImport(ObjectiveC) @objcMembers #endif public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { /// The name of the base type, i.e. `Array` for `Array` public var name: String /// This generic type parameters public let typeParameters: [GenericTypeParameter] /// :nodoc: public init(name: String, typeParameters: [GenericTypeParameter] = []) { self.name = name self.typeParameters = typeParameters } public var asSource: String { let arguments = typeParameters .map({ $0.typeName.asSource }) .joined(separator: ", ") return "\\(name)<\\(arguments)>" } public override var description: String { asSource } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericType else { return false } if self.name != rhs.name { return false } if self.typeParameters != rhs.typeParameters { return false } return true } // sourcery:inline:GenericType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { withVaList(["typeParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeParameters = typeParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeParameters, forKey: "typeParameters") } // sourcery:end } """), .init(name: "Import.swift", content: """ import Foundation /// Defines import type #if canImport(ObjectiveC) @objcMembers #endif public class Import: NSObject, SourceryModelWithoutDescription, Diffable { /// Import kind, e.g. class, struct in `import class Module.ClassName` public var kind: String? /// Import path public var path: String /// :nodoc: public init(path: String, kind: String? = nil) { self.path = path self.kind = kind } /// Full import value e.g. `import struct Module.StructName` public override var description: String { if let kind = kind { return "\\(kind) \\(path)" } return path } /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` public var moduleName: String { if kind != nil { if let idx = path.lastIndex(of: ".") { return String(path[.. DiffableResult { let results = DiffableResult() guard let castObject = object as? Import else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.kind) hasher.combine(self.path) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Import else { return false } if self.kind != rhs.kind { return false } if self.path != rhs.path { return false } return true } // sourcery:inline:Import.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.kind = aDecoder.decode(forKey: "kind") guard let path: String = aDecoder.decode(forKey: "path") else { withVaList(["path"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.path = path } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.kind, forKey: "kind") aCoder.encode(self.path, forKey: "path") } // sourcery:end } """), .init(name: "Log.swift", content: """ //import Darwin import Foundation /// :nodoc: public enum Log { public struct Configuration { let isDryRun: Bool let isQuiet: Bool let isVerboseLoggingEnabled: Bool let isLogBenchmarkEnabled: Bool let shouldLogAST: Bool public init(isDryRun: Bool, isQuiet: Bool, isVerboseLoggingEnabled: Bool, isLogBenchmarkEnabled: Bool, shouldLogAST: Bool) { self.isDryRun = isDryRun self.isQuiet = isQuiet self.isVerboseLoggingEnabled = isVerboseLoggingEnabled self.isLogBenchmarkEnabled = isLogBenchmarkEnabled self.shouldLogAST = shouldLogAST } } public static func setup(using configuration: Configuration) { Log.stackMessages = configuration.isDryRun switch (configuration.isQuiet, configuration.isVerboseLoggingEnabled) { case (true, _): Log.level = .errors case (false, let isVerbose): Log.level = isVerbose ? .verbose : .info } Log.logBenchmarks = (configuration.isVerboseLoggingEnabled || configuration.isLogBenchmarkEnabled) && !configuration.isQuiet Log.logAST = (configuration.shouldLogAST) && !configuration.isQuiet } public enum Level: Int { case errors case warnings case info case verbose } public static var level: Level = .warnings public static var logBenchmarks: Bool = false public static var logAST: Bool = false public static var stackMessages: Bool = false public private(set) static var messagesStack = [String]() public static func error(_ message: Any) { log(level: .errors, "error: \\(message)") // to return error when running swift templates which is done in a different process if ProcessInfo.processInfo.processName != "Sourcery" { fputs("\\(message)", stderr) } } public static func warning(_ message: Any) { log(level: .warnings, "warning: \\(message)") } public static func astWarning(_ message: Any) { guard logAST else { return } log(level: .warnings, "ast warning: \\(message)") } public static func astError(_ message: Any) { guard logAST else { return } log(level: .errors, "ast error: \\(message)") } public static func verbose(_ message: Any) { log(level: .verbose, message) } public static func info(_ message: Any) { log(level: .info, message) } public static func benchmark(_ message: Any) { guard logBenchmarks else { return } if stackMessages { messagesStack.append("\\(message)") } else { print(message) } } private static func log(level logLevel: Level, _ message: Any) { guard logLevel.rawValue <= Log.level.rawValue else { return } if stackMessages { messagesStack.append("\\(message)") } else { print(message) } } public static func output(_ message: String) { print(message) } } extension String: Error {} """), .init(name: "Modifier.swift", content: """ import Foundation public typealias SourceryModifier = Modifier /// modifier can be thing like `private`, `class`, `nonmutating` /// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` #if canImport(ObjectiveC) @objcMembers #endif public class Modifier: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { /// The declaration modifier name. public let name: String /// The modifier detail, if any. public let detail: String? public init(name: String, detail: String? = nil) { self.name = name self.detail = detail } public var asSource: String { if let detail = detail { return "\\(name)(\\(detail))" } else { return name } } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Modifier else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.detail) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Modifier else { return false } if self.name != rhs.name { return false } if self.detail != rhs.detail { return false } return true } // sourcery:inline:Modifier.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.detail = aDecoder.decode(forKey: "detail") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.detail, forKey: "detail") } // sourcery:end } """), .init(name: "ParserResultsComposed.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation internal struct ParserResultsComposed { private(set) var typeMap = [String: Type]() private(set) var modules = [String: [String: Type]]() private(set) var types = [Type]() let parsedTypes: [Type] let functions: [SourceryMethod] let resolvedTypealiases: [String: Typealias] let associatedTypes: [String: AssociatedType] let unresolvedTypealiases: [String: Typealias] init(parserResult: FileParserResult) { // TODO: This logic should really be more complicated // For any resolution we need to be looking at accessLevel and module boundaries // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not self.functions = parserResult.functions let aliases = Self.typealiases(parserResult) resolvedTypealiases = aliases.resolved unresolvedTypealiases = aliases.unresolved associatedTypes = Self.extractAssociatedTypes(parserResult) parsedTypes = parserResult.types var moduleAndTypeNameCollisions: Set = [] for type in parsedTypes where !type.isExtension && type.parent == nil { if let module = type.module, type.localName == module { moduleAndTypeNameCollisions.insert(module) } } // set definedInType for all methods and variables parsedTypes .forEach { type in type.variables.forEach { $0.definedInType = type } type.methods.forEach { $0.definedInType = type } type.subscripts.forEach { $0.definedInType = type } } // map all known types to their names for type in parsedTypes where !type.isExtension && type.parent == nil { let name = type.name // If a type name has the `.` prefix, and the type `.` is undefined, we can safely remove the `.` prefix if let module = type.module, name.hasPrefix(module), name.dropFirst(module.count).hasPrefix("."), !moduleAndTypeNameCollisions.contains(module) { type.localName.removeFirst(module.count + 1) } } for type in parsedTypes where !type.isExtension { typeMap[type.globalName] = type if let module = type.module { var typesByModules = modules[module, default: [:]] typesByModules[type.name] = type modules[module] = typesByModules } } /// Resolve typealiases let typealiases = Array(unresolvedTypealiases.values) typealiases.forEach { alias in alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) } /// Map associated types associatedTypes.forEach { if let globalName = $0.value.type?.globalName, let type = typeMap[globalName] { typeMap[$0.key] = type } else { typeMap[$0.key] = $0.value.type } } types = unifyTypes() } mutating private func resolveExtensionOfNestedType(_ type: Type) { var components = type.localName.components(separatedBy: ".") let rootName: String if type.parent != nil, let module = type.module { rootName = module } else { rootName = components.removeFirst() } if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { type.localName = baseType.localName type.module = baseType.module type.parent = baseType.parent } else { for _import in type.imports { let parentKey = "\\(rootName).\\(components.joined(separator: "."))" let parentKeyFull = "\\(_import.moduleName).\\(parentKey)" if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { type.localName = baseType.localName type.module = baseType.module type.parent = baseType.parent return } } } // Parent extensions should always be processed before `type`, as this affects the globalName of `type`. for parent in type.parentTypes where parent.isExtension && parent.localName.contains(".") { let oldName = parent.globalName resolveExtensionOfNestedType(parent) if oldName != parent.globalName { rewriteChildren(of: parent) } } } // if it had contained types, they might have been fully defined and so their name has to be noted in uniques private mutating func rewriteChildren(of type: Type) { // child is never an extension so no need to check for child in type.containedTypes { typeMap[child.globalName] = child rewriteChildren(of: child) } } private mutating func unifyTypes() -> [Type] { /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed parsedTypes .filter { $0.isExtension } .forEach { (type: Type) in let oldName = type.globalName if type.localName.contains(".") { resolveExtensionOfNestedType(type) } else if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name { var moduleName: String = "" if let module = type.module { moduleName = "\\(module)." } type.localName = resolved.replacingOccurrences(of: moduleName, with: "") } // nothing left to do guard oldName != type.globalName else { return } rewriteChildren(of: type) } // extend all types with their extensions parsedTypes.forEach { type in let inheritedTypes: [[String]] = type.inheritedTypes.compactMap { inheritedName in if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name { return [resolvedGlobalName] } if let baseType = Composer.findBaseType(for: type, name: inheritedName, typesByName: typeMap) { if let composed = baseType as? ProtocolComposition, let composedTypes = composed.composedTypes { // ignore inheritedTypes when it is a `ProtocolComposition` and composedType is a protocol var combinedTypes = composedTypes.map { $0.globalName } combinedTypes.append(baseType.globalName) return combinedTypes } } return [inheritedName] } type.inheritedTypes = inheritedTypes.flatMap { $0 } let uniqueType: Type? if let mappedType = typeMap[type.globalName] { // this check will only fail on an extension? uniqueType = mappedType } else if let composedNameType = typeFromComposedName(type.name, modules: modules) { // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules uniqueType = composedNameType } else { uniqueType = inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] } } guard let current = uniqueType else { assert(type.isExtension, "Type \\(type.globalName) should be extension") // for unknown types we still store their extensions but mark them as unknown type.isUnknownExtension = true if let existingType = typeMap[type.globalName] { existingType.extend(type) typeMap[type.globalName] = existingType } else { typeMap[type.globalName] = type } let inheritanceClause = type.inheritedTypes.isEmpty ? "" : ": \\(type.inheritedTypes.joined(separator: ", "))" Log.astWarning("Found \\"extension \\(type.name)\\(inheritanceClause)\\" of type for which there is no original type declaration information.") return } if current == type { return } current.extend(type) typeMap[current.globalName] = current } let values = typeMap.values var processed = Set(minimumCapacity: values.count) return typeMap.values.filter({ let name = $0.globalName let wasProcessed = processed.contains(name) processed.insert(name) return !wasProcessed }) } // extract associated types from all types and add them to types private static func extractAssociatedTypes(_ parserResult: FileParserResult) -> [String: AssociatedType] { parserResult.types .compactMap { $0 as? SourceryProtocol } .map { $0.associatedTypes } .flatMap { $0 }.reduce(into: [:]) { $0[$1.key] = $1.value } } /// returns typealiases map to their full names, with `resolved` removing intermediate /// typealises and `unresolved` including typealiases that reference other typealiases. private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { var typealiasesByNames = [String: Typealias]() parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } parserResult.types.forEach { type in type.typealiases.forEach({ (_, alias) in // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on // maybe just handle non extension case here and extension aliases after resolving them? typealiasesByNames[alias.name] = alias }) } let unresolved = typealiasesByNames // ! if a typealias leads to another typealias, follow through and replace with final type typealiasesByNames.forEach { _, alias in var aliasNamesToReplace = [alias.name] var finalAlias = alias while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { aliasNamesToReplace.append(targetAlias.name) finalAlias = targetAlias } // ! replace all keys aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } } return (resolved: typealiasesByNames, unresolved: unresolved) } /// Resolves type identifier for name func resolveGlobalName( for type: String, containingType: Type? = nil, unique: [String: Type]? = nil, modules: [String: [String: Type]], typealiases: [String: Typealias], associatedTypes: [String: AssociatedType] ) -> (name: String, typealias: Typealias?)? { // if the type exists for this name and isn't an extension just return it's name // if it's extension we need to check if there aren't other options TODO: verify if let realType = unique?[type], realType.isExtension == false { return (name: realType.globalName, typealias: nil) } if let alias = typealiases[type] { return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) } if let associatedType = associatedTypes[type], let actualType = associatedType.type { let typeName = associatedType.typeName ?? TypeName(name: actualType.name) return (name: actualType.globalName, typealias: Typealias(aliasName: type, typeName: typeName)) } if let containingType = containingType { if type == "Self" { return (name: containingType.globalName, typealias: nil) } var currentContainer: Type? = containingType while currentContainer != nil, let parentName = currentContainer?.globalName { /// TODO: no parent for sure? /// manually walk the containment tree if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) { return name } currentContainer = currentContainer?.parent } // if let name = resolveGlobalName(for: "\\(containingType.globalName).\\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { // return name // } // last check it's via module // if let module = containingType.module, let name = resolveGlobalName(for: "\\(module).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { // return name // } } // TODO: is this needed? if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { return (name: inferred, typealias: nil) } return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } } private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { func fullName(for module: String) -> String { "\\(module).\\(typeIdentifier)" } func type(for module: String) -> Type? { return modules[module]?[typeIdentifier] } func ambiguousErrorMessage(from types: [Type]) -> String? { Log.astWarning("Ambiguous type \\(typeIdentifier), found \\(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") return nil } let explicitModulesAtDeclarationSite: [String] = [ containedInType?.module.map { [$0] } ?? [], // main module for this typename containedInType?.imports.map { $0.moduleName } ?? [] // imported modules ] .flatMap { $0 } let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity /// First checking explicit modules available at declaration site (so source module + all imported ones) /// If there is no ambigiuity there we can assume that module will be resolved by the compiler /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail let moduleSetsToCheck: [[String]] = [ explicitModulesAtDeclarationSite, Array(remainingModules) ] for modules in moduleSetsToCheck { let possibleTypes = modules .compactMap { type(for: $0) } if possibleTypes.count > 1 { return ambiguousErrorMessage(from: possibleTypes) } if let type = possibleTypes.first { return type.globalName } } // as last result for unknown types / extensions // try extracting type from unique array if let module = containedInType?.module { return uniqueTypes[fullName(for: module)]?.globalName } return nil } func typeFromComposedName(_ name: String, modules: [String: [String: Type]]) -> Type? { guard name.contains(".") else { return nil } let nameComponents = name.components(separatedBy: ".") let moduleName = nameComponents[0] let typeName = nameComponents.suffix(from: 1).joined(separator: ".") return modules[moduleName]?[typeName] } func resolveType(typeName: TypeName, containingType: Type?, method: Method? = nil) -> Type? { let resolveTypeWithName = { (typeName: TypeName) -> Type? in return self.resolveType(typeName: typeName, containingType: containingType) } let unique = typeMap if let name = typeName.actualTypeName { let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName return unique[resolvedIdentifier] } let retrievedName = actualTypeName(for: typeName, containingType: containingType) let lookupName = retrievedName ?? typeName if let tuple = lookupName.tuple { var needsUpdate = false tuple.elements.forEach { tupleElement in tupleElement.type = resolveTypeWithName(tupleElement.typeName) if tupleElement.typeName.actualTypeName != nil { needsUpdate = true } } if needsUpdate || retrievedName != nil { let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) tupleCopy.elements.forEach { $0.typeName = $0.actualTypeName ?? $0.typeName $0.typeName.actualTypeName = nil } tupleCopy.name = tupleCopy.elements.asTypeName typeName.tuple = tupleCopy // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: tupleCopy.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: tupleCopy, array: lookupName.array, dictionary: lookupName.dictionary, closure: lookupName.closure, set: lookupName.set, generic: lookupName.generic ) } return nil } else if let array = lookupName.array { array.elementType = resolveTypeWithName(array.elementTypeName) if array.elementTypeName.actualTypeName != nil || retrievedName != nil || array.elementType != nil { let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName array.elementTypeName.actualTypeName = nil array.name = array.asSource typeName.array = array // TODO: really don't like this old behaviour typeName.generic = array.asGeneric // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: array.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: array, dictionary: lookupName.dictionary, closure: lookupName.closure, set: lookupName.set, generic: typeName.generic ) } } else if let dictionary = lookupName.dictionary { dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour dictionary.name = dictionary.asSource typeName.dictionary = dictionary // TODO: really don't like this old behaviour typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: dictionary.asSource, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, dictionary: dictionary, closure: lookupName.closure, set: lookupName.set, generic: dictionary.asGeneric ) } } else if let closure = lookupName.closure { var needsUpdate = false closure.returnType = resolveTypeWithName(closure.returnTypeName) closure.parameters.forEach { parameter in parameter.type = resolveTypeWithName(parameter.typeName) if parameter.typeName.actualTypeName != nil { needsUpdate = true } } if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { typeName.closure = closure // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: closure.asSource, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, dictionary: lookupName.dictionary, closure: closure, set: lookupName.set, generic: lookupName.generic ) } return nil } else if let generic = lookupName.generic { var needsUpdate = false generic.typeParameters.forEach { parameter in // Detect if the generic type is local to the method if let method { for genericParameter in method.genericParameters where parameter.typeName.name == genericParameter.name { return } } parameter.type = resolveTypeWithName(parameter.typeName) if parameter.typeName.actualTypeName != nil { needsUpdate = true } } if needsUpdate || retrievedName != nil { let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) generic.typeParameters.forEach { $0.typeName = $0.typeName.actualTypeName ?? $0.typeName $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour } typeName.generic = generic // TODO: really don't like this old behaviour typeName.array = lookupName.array // TODO: really don't like this old behaviour typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") typeName.actualTypeName = TypeName(name: "\\(generic.name)<\\(params)>", isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, // TODO: asArray dictionary: lookupName.dictionary, // TODO: asDictionary closure: lookupName.closure, set: lookupName.set, generic: generic ) } } if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { typeName.actualTypeName = aliasedName } let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false || (method != nil && method?.genericRequirements.isEmpty == false) if hasGenericRequirements { // we should consider if we are looking up return type of a method with generic constraints // where `typeName` passed would include `... where ...` suffix let typeNameForLookup = typeName.name.split(separator: " ").first! let genericRequirements: [GenericRequirement] if let requirements = containingType?.genericRequirements, !requirements.isEmpty { genericRequirements = requirements } else { genericRequirements = method?.genericRequirements ?? [] } let relevantRequirements = genericRequirements.filter { // matched type against a generic requirement name // thus type should be replaced with a protocol composition $0.leftType.name == typeNameForLookup } if relevantRequirements.count > 1 { // compose protocols into `ProtocolComposition` and generate TypeName var implements: [String: Type] = [:] relevantRequirements.forEach { implements[$0.rightType.typeName.name] = $0.rightType.type } let composedProtocols = ProtocolComposition( inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, isGeneric: true, composedTypes: relevantRequirements.compactMap { $0.rightType.type }, implements: implements ) typeName.actualTypeName = TypeName(name: "(\\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) return composedProtocols } else if let protocolRequirement = relevantRequirements.first { // create TypeName off a single generic's protocol requirement typeName.actualTypeName = TypeName(name: "(\\(protocolRequirement.rightType.typeName))") return protocolRequirement.rightType.type } } // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias // i.e. // enum Module { // typealias ID = MyView // } // class MyView { // class ID: String {} // } // // let variable: Module.ID.ID // should be resolved as MyView.ID type let finalLookup = typeName.actualTypeName ?? typeName var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName if let type = unique[resolvedIdentifier] { return type } for alias in resolvedTypealiases { /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) } } // should we cache resolved typenames? if unique[resolvedIdentifier] == nil { // peek into typealiases, if any of them contain the same typeName // this is done after the initial attempt in order to prioritise local (recognized) types first // before even trying to substitute the requested type with any typealias for alias in resolvedTypealiases { /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, /// ignoring namespacing if resolvedIdentifier == alias.value.aliasName { resolvedIdentifier = alias.value.typeName.name typeName.actualTypeName = alias.value.typeName break } } } if let associatedType = associatedTypes[resolvedIdentifier] { return associatedType.type } return unique[resolvedIdentifier] ?? unique[typeName.name] } private func actualTypeName(for typeName: TypeName, containingType: Type? = nil) -> TypeName? { let unique = typeMap let typealiases = resolvedTypealiases let associatedTypes = associatedTypes var unwrapped = typeName.unwrappedTypeName if let generic = typeName.generic { unwrapped = generic.name } else if let type = associatedTypes[unwrapped] { unwrapped = type.name } guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) else { return nil } /// TODO: verify let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } generic?.name = aliased.name let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } dictionary?.name = aliased.name let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } array?.name = aliased.name let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } set?.name = aliased.name return TypeName(name: aliased.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify array: aliased.typealias?.typeName.array ?? array, dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, closure: aliased.typealias?.typeName.closure ?? typeName.closure, set: aliased.typealias?.typeName.set ?? set, generic: aliased.typealias?.typeName.generic ?? generic ) } } """), .init(name: "PhantomProtocols.swift", content: """ // // Created by Krzysztof Zablocki on 23/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation /// Phantom protocol for diffing protocol AutoDiffable {} /// Phantom protocol for equality protocol AutoEquatable {} /// Phantom protocol for equality protocol AutoDescription {} /// Phantom protocol for NSCoding protocol AutoCoding {} protocol AutoJSExport {} /// Phantom protocol for NSCoding, Equatable and Diffable protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} """), .init(name: "Protocol.swift", content: """ // // Protocol.swift // Sourcery // // Created by Krzysztof Zablocki on 09/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation #if canImport(ObjectiveC) /// :nodoc: public typealias SourceryProtocol = Protocol /// Describes Swift protocol @objcMembers public final class Protocol: Type { // sourcery: skipJSExport public class var kind: String { return "protocol" } /// Returns "protocol" public override var kind: String { Self.kind } /// list of all declared associated types with their names as keys public var associatedTypes: [String: AssociatedType] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } // sourcery: skipCoding /// list of generic requirements public override var genericRequirements: [GenericRequirement] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], associatedTypes: [String: AssociatedType] = [:], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], implements: [String: Type] = [:], kind: String = Protocol.kind) { self.associatedTypes = associatedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("associatedTypes = \\(String(describing: self.associatedTypes)), ") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Protocol else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.associatedTypes) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Protocol else { return false } if self.associatedTypes != rhs.associatedTypes { return false } return super.isEqual(rhs) } // sourcery:inline:Protocol.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { withVaList(["associatedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedTypes = associatedTypes super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.associatedTypes, forKey: "associatedTypes") } // sourcery:end } #endif """), .init(name: "ProtocolComposition.swift", content: """ // Created by eric_horacek on 2/12/20. // Copyright © 2020 Airbnb Inc. All rights reserved. import Foundation /// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). #if canImport(ObjectiveC) @objcMembers #endif public final class ProtocolComposition: Type { // sourcery: skipJSExport public class var kind: String { return "protocolComposition" } /// Returns "protocolComposition" public override var kind: String { Self.kind } /// The names of the types composed to form this composition public let composedTypeNames: [TypeName] // sourcery: skipEquality, skipDescription /// The types composed to form this composition, if known public var composedTypes: [Type]? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], annotations: [String: NSObject] = [:], isGeneric: Bool = false, composedTypeNames: [TypeName] = [], composedTypes: [Type]? = nil, implements: [String: Type] = [:], kind: String = ProtocolComposition.kind) { self.composedTypeNames = composedTypeNames self.composedTypes = composedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, annotations: annotations, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " string += "kind = \\(String(describing: self.kind)), " string += "composedTypeNames = \\(String(describing: self.composedTypeNames))" return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ProtocolComposition else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.composedTypeNames) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ProtocolComposition else { return false } if self.composedTypeNames != rhs.composedTypeNames { return false } return super.isEqual(rhs) } // sourcery:inline:ProtocolComposition.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { withVaList(["composedTypeNames"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.composedTypeNames = composedTypeNames self.composedTypes = aDecoder.decode(forKey: "composedTypes") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") aCoder.encode(self.composedTypes, forKey: "composedTypes") } // sourcery:end } """), .init(name: "Set.swift", content: """ import Foundation /// Describes set type #if canImport(ObjectiveC) @objcMembers #endif public final class SetType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Array element type name public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription /// Array element type, if known public var elementType: Type? /// :nodoc: public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name self.elementTypeName = elementTypeName self.elementType = elementType } /// Returns array as generic type public var asGeneric: GenericType { GenericType(name: "Set", typeParameters: [ .init(typeName: elementTypeName) ]) } public var asSource: String { "[\\(elementTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") string.append("asGeneric = \\(String(describing: self.asGeneric)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? SetType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? SetType else { return false } if self.name != rhs.name { return false } if self.elementTypeName != rhs.elementTypeName { return false } return true } // sourcery:inline:SetType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elementTypeName = elementTypeName self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elementTypeName, forKey: "elementTypeName") aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } """), .init(name: "Struct.swift", content: """ // // Struct.swift // Sourcery // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation // sourcery: skipDescription /// Describes Swift struct #if canImport(ObjectiveC) @objcMembers #endif public final class Struct: Type { // sourcery: skipJSExport public class var kind: String { return "struct" } /// Returns "struct" public override var kind: String { Self.kind } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Struct.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " string += "kind = \\(String(describing: self.kind))" return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Struct else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Struct else { return false } return super.isEqual(rhs) } // sourcery:inline:Struct.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } """), .init(name: "TemplateContext.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation /// :nodoc: // sourcery: skipCoding #if canImport(ObjectiveC) @objcMembers #endif public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { // sourcery: skipJSExport public let parserResult: FileParserResult? public let functions: [SourceryMethod] public let types: Types public let argument: [String: NSObject] // sourcery: skipDescription public var type: [String: Type] { return types.typesByName } public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { self.parserResult = parserResult self.types = types self.functions = functions self.argument = arguments } /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { withVaList(["parserResult"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) } fatalError() } guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { withVaList(["argument"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() } // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types let fileParserResultCopy: FileParserResult? = nil // fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult let composed = Composer.uniqueTypesAndFunctions(parserResult, serial: false) self.types = .init(types: composed.types, typealiases: composed.typealiases) self.functions = composed.functions self.parserResult = fileParserResultCopy self.argument = argument } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parserResult, forKey: "parserResult") aCoder.encode(self.argument, forKey: "argument") } public var stencilContext: [String: Any] { return [ "types": types, "functions": functions, "type": types.typesByName, "argument": argument ] } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("parserResult = \\(String(describing: self.parserResult)), ") string.append("functions = \\(String(describing: self.functions)), ") string.append("types = \\(String(describing: self.types)), ") string.append("argument = \\(String(describing: self.argument)), ") string.append("stencilContext = \\(String(describing: self.stencilContext))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TemplateContext else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parserResult) hasher.combine(self.functions) hasher.combine(self.types) hasher.combine(self.argument) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TemplateContext else { return false } if self.parserResult != rhs.parserResult { return false } if self.functions != rhs.functions { return false } if self.types != rhs.types { return false } if self.argument != rhs.argument { return false } return true } // sourcery: skipDescription, skipEquality public var jsContext: [String: Any] { return [ "types": [ "all": types.all, "protocols": types.protocols, "classes": types.classes, "structs": types.structs, "enums": types.enums, "extensions": types.extensions, "based": types.based, "inheriting": types.inheriting, "implementing": types.implementing, "protocolCompositions": types.protocolCompositions, "typealiases": types.typealiases ] as [String : Any], "functions": functions, "type": types.typesByName, "argument": argument ] } } extension ProcessInfo { /// :nodoc: public var context: TemplateContext! { return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext } } """), .init(name: "Typealias.swift", content: """ import Foundation /// :nodoc: #if canImport(ObjectiveC) @objcMembers #endif public final class Typealias: NSObject, Typed, SourceryModel, Diffable { // New typealias name public let aliasName: String // Target name public let typeName: TypeName // sourcery: skipEquality, skipDescription public var type: Type? /// module in which this typealias was declared public var module: String? /// Imports that existed in the file that contained this typealias declaration public var imports: [Import] = [] /// typealias annotations public var annotations: Annotations = [:] /// typealias documentation public var documentation: Documentation = [] // sourcery: skipEquality, skipDescription public var parent: Type? { didSet { parentName = parent?.name } } /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String var parentName: String? public var name: String { if let parentName = parent?.name { return "\\(module != nil ? "\\(module!)." : "")\\(parentName).\\(aliasName)" } else { return "\\(module != nil ? "\\(module!)." : "")\\(aliasName)" } } public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil, annotations: [String: NSObject] = [:], documentation: [String] = []) { self.aliasName = aliasName self.typeName = typeName self.accessLevel = accessLevel.rawValue self.parent = parent self.parentName = parent?.name self.module = module self.annotations = annotations self.documentation = documentation } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("aliasName = \\(String(describing: self.aliasName)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("module = \\(String(describing: self.module)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("parentName = \\(String(describing: self.parentName)), ") string.append("name = \\(String(describing: self.name)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Typealias else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.aliasName) hasher.combine(self.typeName) hasher.combine(self.module) hasher.combine(self.accessLevel) hasher.combine(self.parentName) hasher.combine(self.annotations) hasher.combine(self.documentation) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Typealias else { return false } if self.aliasName != rhs.aliasName { return false } if self.typeName != rhs.typeName { return false } if self.module != rhs.module { return false } if self.accessLevel != rhs.accessLevel { return false } if self.parentName != rhs.parentName { return false } if self.documentation != rhs.documentation { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:Typealias.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { withVaList(["aliasName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.aliasName = aliasName guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.parent = aDecoder.decode(forKey: "parent") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.parentName = aDecoder.decode(forKey: "parentName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.aliasName, forKey: "aliasName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.parentName, forKey: "parentName") } // sourcery:end } """), .init(name: "Typed.swift", content: """ import Foundation /// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value public protocol Typed { // sourcery: skipEquality, skipDescription /// Type, if known var type: Type? { get } // sourcery: skipEquality, skipDescription /// Type name var typeName: TypeName { get } // sourcery: skipEquality, skipDescription /// Whether type is optional var isOptional: Bool { get } // sourcery: skipEquality, skipDescription /// Whether type is implicitly unwrapped optional var isImplicitlyUnwrappedOptional: Bool { get } // sourcery: skipEquality, skipDescription /// Type name without attributes and optional type information var unwrappedTypeName: String { get } } """), .init(name: "AssociatedType.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Describes Swift AssociatedType @objcMembers public final class AssociatedType: NSObject, SourceryModel { /// Associated type name public let name: String /// Associated type type constraint name, if specified public let typeName: TypeName? // sourcery: skipEquality, skipDescription /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. public var type: Type? /// :nodoc: public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedType else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:AssociatedType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.typeName = aDecoder.decode(forKey: "typeName") self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif """), .init(name: "AssociatedValue.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Defines enum case associated value @objcMembers public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable { /// Associated value local name. /// This is a name to be used to construct enum case value public let localName: String? /// Associated value external name. /// This is a name to be used to access value in value-bindig public let externalName: String? /// Associated value type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Associated value type, if known public var type: Type? /// Associated value default value public let defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.localName = localName self.externalName = externalName self.typeName = typeName self.type = type self.defaultValue = defaultValue self.annotations = annotations } convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("localName = \\(String(describing: self.localName)), ") string.append("externalName = \\(String(describing: self.externalName)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedValue else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.localName) hasher.combine(self.externalName) hasher.combine(self.typeName) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedValue else { return false } if self.localName != rhs.localName { return false } if self.externalName != rhs.externalName { return false } if self.typeName != rhs.typeName { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:AssociatedValue.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.localName = aDecoder.decode(forKey: "localName") self.externalName = aDecoder.decode(forKey: "externalName") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.externalName, forKey: "externalName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } #endif """), .init(name: "Closure.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Describes closure type @objcMembers public final class ClosureType: NSObject, SourceryModel, Diffable { /// Type name used in declaration with stripped whitespaces and new lines public let name: String /// List of closure parameters public let parameters: [ClosureParameter] /// Return value type name public let returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// async keyword public let asyncKeyword: String? /// Whether closure throws public let `throws`: Bool /// throws or rethrows keyword public let throwsOrRethrowsKeyword: String? /// Type of thrown error if specified public let throwsTypeName: TypeName? /// :nodoc: public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil, throwsTypeName: TypeName? = nil) { self.name = name self.parameters = parameters self.returnTypeName = returnTypeName self.returnType = returnType self.asyncKeyword = asyncKeyword self.isAsync = asyncKeyword != nil self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword self.`throws` = throwsOrRethrowsKeyword != nil && !(throwsTypeName?.isNever ?? false) self.throwsTypeName = throwsTypeName } public var asSource: String { "\\(parameters.asSource)\\(asyncKeyword != nil ? " \\(asyncKeyword!)" : "")\\(throwsOrRethrowsKeyword != nil ? " \\(throwsOrRethrowsKeyword!)" : "") -> \\(returnTypeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("parameters = \\(String(describing: self.parameters)), ") string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("asyncKeyword = \\(String(describing: self.asyncKeyword)), ") string.append("`throws` = \\(String(describing: self.`throws`)), ") string.append("throwsOrRethrowsKeyword = \\(String(describing: self.throwsOrRethrowsKeyword)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ClosureType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.asyncKeyword) hasher.combine(self.`throws`) hasher.combine(self.throwsOrRethrowsKeyword) hasher.combine(self.throwsTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureType else { return false } if self.name != rhs.name { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.asyncKeyword != rhs.asyncKeyword { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } return true } // sourcery:inline:ClosureType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") } // sourcery:end } #endif """), .init(name: "ClosureParameter.swift", content: """ #if canImport(ObjectiveC) import Foundation // sourcery: skipDiffing @objcMembers public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated { /// Parameter external name public var argumentLabel: String? /// Parameter internal name public let name: String? /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter if the argument has a variadic type or not public let isVariadic: Bool /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let typeInfo = "\\(`inout` ? "inout " : "")\\(typeName.asSource)\\(isVariadic ? "..." : "")" if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { return typeInfo } let typeSuffix = ": \\(typeInfo)" guard argumentLabel != name else { return name ?? "" + typeSuffix } let labels = [argumentLabel ?? "_", name?.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("`inout` = \\(String(describing: self.`inout`)), ") string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:ClosureParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.type = aDecoder.decode(forKey: "type") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } extension Array where Element == ClosureParameter { public var asSource: String { "(\\(map { $0.asSource }.joined(separator: ", ")))" } } #endif """), .init(name: "Enum.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Defines Swift enum @objcMembers public final class Enum: Type { // sourcery: skipJSExport public class var kind: String { return "enum" } // sourcery: skipDescription /// Returns "enum" public override var kind: String { Self.kind } /// Enum cases public var cases: [EnumCase] /** Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. */ public var rawTypeName: TypeName? { didSet { if let rawTypeName = rawTypeName { hasRawType = true if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { inheritedTypes.remove(at: index) } if based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } else { hasRawType = false } } } // sourcery: skipDescription, skipEquality /// :nodoc: public private(set) var hasRawType: Bool // sourcery: skipDescription, skipEquality /// Enum raw value type, if known public var rawType: Type? // sourcery: skipEquality, skipDescription, skipCoding /// Names of types or protocols this type inherits from, including unknown (not scanned) types public override var based: [String: String] { didSet { if let rawTypeName = rawTypeName, based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } } /// Whether enum contains any associated values public var hasAssociatedValues: Bool { return cases.contains(where: { $0.hasAssociatedValue }) } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, inheritedTypes: [String] = [], rawTypeName: TypeName? = nil, cases: [EnumCase] = [], variables: [Variable] = [], methods: [Method] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false) { self.cases = cases self.rawTypeName = rawTypeName self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind) if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) { self.inheritedTypes.remove(at: index) } } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("cases = \\(String(describing: self.cases)), ") string.append("rawTypeName = \\(String(describing: self.rawTypeName)), ") string.append("hasAssociatedValues = \\(String(describing: self.hasAssociatedValues))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Enum else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.cases) hasher.combine(self.rawTypeName) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Enum else { return false } if self.cases != rhs.cases { return false } if self.rawTypeName != rhs.rawTypeName { return false } return super.isEqual(rhs) } // sourcery:inline:Enum.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { withVaList(["cases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.cases = cases self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") self.hasRawType = aDecoder.decode(forKey: "hasRawType") self.rawType = aDecoder.decode(forKey: "rawType") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.cases, forKey: "cases") aCoder.encode(self.rawTypeName, forKey: "rawTypeName") aCoder.encode(self.hasRawType, forKey: "hasRawType") aCoder.encode(self.rawType, forKey: "rawType") } // sourcery:end } #endif """), .init(name: "EnumCase.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Defines enum case @objcMembers public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable { /// Enum case name public let name: String /// Enum case raw value, if any public let rawValue: String? /// Enum case associated values public let associatedValues: [AssociatedValue] /// Enum case annotations public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Whether enum case is indirect public let indirect: Bool /// Whether enum case has associated value public var hasAssociatedValue: Bool { return !associatedValues.isEmpty } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { self.name = name self.rawValue = rawValue self.associatedValues = associatedValues self.annotations = annotations self.documentation = documentation self.indirect = indirect } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("rawValue = \\(String(describing: self.rawValue)), ") string.append("associatedValues = \\(String(describing: self.associatedValues)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("indirect = \\(String(describing: self.indirect)), ") string.append("hasAssociatedValue = \\(String(describing: self.hasAssociatedValue))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? EnumCase else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.rawValue) hasher.combine(self.associatedValues) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.indirect) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? EnumCase else { return false } if self.name != rhs.name { return false } if self.rawValue != rhs.rawValue { return false } if self.associatedValues != rhs.associatedValues { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.indirect != rhs.indirect { return false } return true } // sourcery:inline:EnumCase.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.rawValue = aDecoder.decode(forKey: "rawValue") guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { withVaList(["associatedValues"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedValues = associatedValues guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.indirect = aDecoder.decode(forKey: "indirect") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.rawValue, forKey: "rawValue") aCoder.encode(self.associatedValues, forKey: "associatedValues") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.indirect, forKey: "indirect") } // sourcery:end } #endif """), .init(name: "GenericParameter.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Descibes Swift generic parameter @objcMembers public final class GenericParameter: NSObject, SourceryModel, Diffable { /// Generic parameter name public var name: String /// Generic parameter inherited type public var inheritedTypeName: TypeName? /// :nodoc: public init(name: String, inheritedTypeName: TypeName? = nil) { self.name = name self.inheritedTypeName = inheritedTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("inheritedTypeName = \\(String(describing: self.inheritedTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.inheritedTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericParameter else { return false } if self.name != rhs.name { return false } if self.inheritedTypeName != rhs.inheritedTypeName { return false } return true } // sourcery:inline:GenericParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") } // sourcery:end } #endif """), .init(name: "GenericRequirement.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Descibes Swift generic requirement @objcMembers public class GenericRequirement: NSObject, SourceryModel, Diffable { public enum Relationship: String { case equals case conformsTo var syntax: String { switch self { case .equals: return "==" case .conformsTo: return ":" } } } public var leftType: AssociatedType public let rightType: GenericTypeParameter /// relationship name public let relationship: String /// Syntax e.g. `==` or `:` public let relationshipSyntax: String public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { self.leftType = leftType self.rightType = rightType self.relationship = relationship.rawValue self.relationshipSyntax = relationship.syntax } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("leftType = \\(String(describing: self.leftType)), ") string.append("rightType = \\(String(describing: self.rightType)), ") string.append("relationship = \\(String(describing: self.relationship)), ") string.append("relationshipSyntax = \\(String(describing: self.relationshipSyntax))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericRequirement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.leftType) hasher.combine(self.rightType) hasher.combine(self.relationship) hasher.combine(self.relationshipSyntax) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericRequirement else { return false } if self.leftType != rhs.leftType { return false } if self.rightType != rhs.rightType { return false } if self.relationship != rhs.relationship { return false } if self.relationshipSyntax != rhs.relationshipSyntax { return false } return true } // sourcery:inline:GenericRequirement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { withVaList(["leftType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.leftType = leftType guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { withVaList(["rightType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rightType = rightType guard let relationship: String = aDecoder.decode(forKey: "relationship") else { withVaList(["relationship"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationship = relationship guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { withVaList(["relationshipSyntax"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationshipSyntax = relationshipSyntax } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.leftType, forKey: "leftType") aCoder.encode(self.rightType, forKey: "rightType") aCoder.encode(self.relationship, forKey: "relationship") aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") } // sourcery:end } #endif """), .init(name: "GenericTypeParameter.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Descibes Swift generic type parameter @objcMembers public final class GenericTypeParameter: NSObject, SourceryModel, Diffable { /// Generic parameter type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Generic parameter type, if known public var type: Type? /// :nodoc: public init(typeName: TypeName, type: Type? = nil) { self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("typeName = \\(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericTypeParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericTypeParameter else { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:GenericTypeParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif """), .init(name: "Method.swift", content: """ #if canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryMethod = Method /// Describes method @objc(SwiftMethod) @objcMembers public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { /// Full method name, including generic constraints, i.e. `foo(bar: T)` public let name: String /// Method name including arguments names, i.e. `foo(bar:)` public var selectorName: String // sourcery: skipEquality, skipDescription /// Method name without arguments names and parentheses, i.e. `foo` public var shortName: String { return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name } // sourcery: skipEquality, skipDescription /// Method name without arguments names, parentheses and generic types, i.e. `foo` (can be used to generate code for method call) public var callName: String { return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName // sourcery: skipEquality, skipDescription /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional || isFailableInitializer } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// Whether method is distributed public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// Whether method throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Return if the throwsType is generic public var isThrowsTypeGeneric: Bool { return genericParameters.contains { $0.name == throwsTypeName?.name } } /// Whether method rethrows public let `rethrows`: Bool /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Whether method is a static method public let isStatic: Bool /// Whether method is a class method public let isClass: Bool // sourcery: skipEquality, skipDescription /// Whether method is an initializer public var isInitializer: Bool { return selectorName.hasPrefix("init(") || selectorName == "init" } // sourcery: skipEquality, skipDescription /// Whether method is an deinitializer public var isDeinitializer: Bool { return selectorName == "deinit" } /// Whether method is a failable initializer public let isFailableInitializer: Bool // sourcery: skipEquality, skipDescription /// Whether method is a convenience initializer public var isConvenienceInitializer: Bool { modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is required public var isRequired: Bool { modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is mutating public var isMutating: Bool { modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is generic public var isGeneric: Bool { shortName.hasSuffix(">") } // sourcery: skipEquality, skipDescription /// Whether method is optional (in an Objective-C protocol) public var isOptional: Bool { modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is nonisolated (this modifier only applies to actor methods) public var isNonisolated: Bool { modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is dynamic public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// list of generic requirements public var genericRequirements: [GenericRequirement] /// List of generic parameters /// /// - Example: /// /// ```swift /// func method(foo: GenericParameter) /// ^ ~ a generic parameter /// ``` public var genericParameters: [GenericParameter] /// :nodoc: public init(name: String, selectorName: String? = nil, parameters: [MethodParameter] = [], returnTypeName: TypeName = TypeName(name: "Void"), isAsync: Bool = false, throws: Bool = false, throwsTypeName: TypeName? = nil, rethrows: Bool = false, accessLevel: AccessLevel = .internal, isStatic: Bool = false, isClass: Bool = false, isFailableInitializer: Bool = false, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil, genericRequirements: [GenericRequirement] = [], genericParameters: [GenericParameter] = []) { self.name = name self.selectorName = selectorName ?? name self.parameters = parameters self.returnTypeName = returnTypeName self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.rethrows = `rethrows` self.accessLevel = accessLevel.rawValue self.isStatic = isStatic self.isClass = isClass self.isFailableInitializer = isFailableInitializer self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName self.genericRequirements = genericRequirements self.genericParameters = genericParameters } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("selectorName = \\(String(describing: self.selectorName)), ") string.append("parameters = \\(String(describing: self.parameters)), ") string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("`throws` = \\(String(describing: self.`throws`)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("`rethrows` = \\(String(describing: self.`rethrows`)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("isStatic = \\(String(describing: self.isStatic)), ") string.append("isClass = \\(String(describing: self.isClass)), ") string.append("isFailableInitializer = \\(String(describing: self.isFailableInitializer)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers)), ") string.append("genericRequirements = \\(String(describing: self.genericRequirements)), ") string.append("genericParameters = \\(String(describing: self.genericParameters))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Method else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.selectorName) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.`rethrows`) hasher.combine(self.accessLevel) hasher.combine(self.isStatic) hasher.combine(self.isClass) hasher.combine(self.isFailableInitializer) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.genericRequirements) hasher.combine(self.genericParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Method else { return false } if self.name != rhs.name { return false } if self.selectorName != rhs.selectorName { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.isDistributed != rhs.isDistributed { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.`rethrows` != rhs.`rethrows` { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isStatic != rhs.isStatic { return false } if self.isClass != rhs.isClass { return false } if self.isFailableInitializer != rhs.isFailableInitializer { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.genericParameters != rhs.genericParameters { return false } return true } // sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { withVaList(["selectorName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.selectorName = selectorName guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isStatic = aDecoder.decode(forKey: "isStatic") self.isClass = aDecoder.decode(forKey: "isClass") self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.selectorName, forKey: "selectorName") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.`rethrows`, forKey: "`rethrows`") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.isClass, forKey: "isClass") aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.genericParameters, forKey: "genericParameters") } // sourcery:end } #endif """), .init(name: "MethodParameter.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Describes method parameter @objcMembers public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable { /// Parameter external name public var argumentLabel: String? // Note: although method parameter can have no name, this property is not optional, // this is so to maintain compatibility with existing templates. /// Parameter internal name public let name: String /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool /// Is this variadic parameter? public let isVariadic: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// Method parameter index in the argument list public var index: Int /// :nodoc: public init(argumentLabel: String?, name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } /// :nodoc: public init(name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = name self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let values: String = defaultValue.map { " = \\($0)" } ?? "" let variadicity: String = isVariadic ? "..." : "" let inoutness: String = `inout` ? "inout " : "" let typeSuffix = ": \\(inoutness)\\(typeName.asSource)\\(values)\\(variadicity)" guard argumentLabel != name else { return name + typeSuffix } let labels = [argumentLabel ?? "_", name.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("`inout` = \\(String(describing: self.`inout`)), ") string.append("isVariadic = \\(String(describing: self.isVariadic)), ") string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("asSource = \\(String(describing: self.asSource)), ") string.append("index = \\(String(describing: self.index))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? MethodParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "index").trackDifference(actual: self.index, expected: castObject.index)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? MethodParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:MethodParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations self.index = aDecoder.decode(forKey: "index") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.index, forKey: "index") } // sourcery:end } extension Array where Element == MethodParameter { public var asSource: String { "(\\(map { $0.asSource }.joined(separator: ", ")))" } } #endif """), .init(name: "Subscript.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Describes subscript @objcMembers public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable { /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public var writeAccess: String /// Whether subscript is async public let isAsync: Bool /// Whether subscript throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] /// list of generic parameters public let genericParameters: [GenericParameter] /// list of generic requirements public let genericRequirements: [GenericRequirement] /// Whether subscript is generic or not public var isGeneric: Bool { return genericParameters.isEmpty == false } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? public init(parameters: [MethodParameter] = [], returnTypeName: TypeName, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, genericParameters: [GenericParameter] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.parameters = parameters self.returnTypeName = returnTypeName self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.genericParameters = genericParameters self.genericRequirements = genericRequirements self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("parameters = \\(String(describing: self.parameters)), ") string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") string.append("isFinal = \\(String(describing: self.isFinal)), ") string.append("readAccess = \\(String(describing: self.readAccess)), ") string.append("writeAccess = \\(String(describing: self.writeAccess)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("`throws` = \\(String(describing: self.throws)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("isMutable = \\(String(describing: self.isMutable)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName)), ") string.append("genericParameters = \\(String(describing: self.genericParameters)), ") string.append("genericRequirements = \\(String(describing: self.genericRequirements)), ") string.append("isGeneric = \\(String(describing: self.isGeneric)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Subscript else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.isAsync) hasher.combine(self.throws) hasher.combine(self.throwsTypeName) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.genericParameters) hasher.combine(self.genericRequirements) hasher.combine(self.attributes) hasher.combine(self.modifiers) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Subscript else { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.isAsync != rhs.isAsync { return false } if self.throws != rhs.throws { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.genericParameters != rhs.genericParameters { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } return true } // sourcery:inline:Subscript.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericParameters, forKey: "genericParameters") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end } #endif """), .init(name: "Tuple.swift", content: """ #if canImport(ObjectiveC) import Foundation /// Describes tuple type @objcMembers public final class TupleType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Tuple elements public var elements: [TupleElement] /// :nodoc: public init(name: String, elements: [TupleElement]) { self.name = name self.elements = elements } /// :nodoc: public init(elements: [TupleElement]) { self.name = elements.asSource self.elements = elements } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("elements = \\(String(describing: self.elements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleType else { return false } if self.name != rhs.name { return false } if self.elements != rhs.elements { return false } return true } // sourcery:inline:TupleType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { withVaList(["elements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elements = elements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elements, forKey: "elements") } // sourcery:end } /// Describes tuple type element @objcMembers public final class TupleElement: NSObject, SourceryModel, Typed, Diffable { /// Tuple element name public let name: String? /// Tuple element type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Tuple element type, if known public var type: Type? /// :nodoc: public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } public var asSource: String { // swiftlint:disable:next force_unwrapping "\\(name != nil ? "\\(name!): " : "")\\(typeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleElement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleElement else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:TupleElement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } extension Array where Element == TupleElement { public var asSource: String { "(\\(map { $0.asSource }.joined(separator: ", ")))" } public var asTypeName: String { "(\\(map { $0.typeName.asSource }.joined(separator: ", ")))" } } #endif """), .init(name: "Type.swift", content: """ // // Created by Krzysztof Zablocki on 11/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// :nodoc: public typealias AttributeList = [String: [Attribute]] /// Defines Swift type @objcMembers public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable { /// :nodoc: public var module: String? /// Imports that existed in the file that contained this type declaration public var imports: [Import] = [] // sourcery: skipEquality /// Imports existed in all files containing this type and all its super classes/protocols public var allImports: [Import] { return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) } private func gatherAllImports() -> [Import] { var allImports: [Import] = Array(self.imports) self.basedTypes.values.forEach { (basedType) in allImports.append(contentsOf: basedType.imports) } return allImports } // All local typealiases /// :nodoc: public var typealiases: [String: Typealias] { didSet { typealiases.values.forEach { $0.parent = self } } } // sourcery: skipJSExport /// Whether declaration is an extension of some type public var isExtension: Bool // sourcery: forceEquality /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` public var kind: String { isExtension ? "extension" : _kind } // sourcery: skipJSExport /// Kind of a backing store for `self.kind` private var _kind: String /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` public var name: String { guard let parentName = parent?.name else { return localName } return "\\(parentName).\\(localName)" } // sourcery: skipCoding /// Whether the type has been resolved as unknown extension public var isUnknownExtension: Bool = false // sourcery: skipDescription /// Global type name including module name, unless it's an extension of unknown type public var globalName: String { guard let module = module, !isUnknownExtension else { return name } return "\\(module).\\(name)" } /// Whether type is generic public var isGeneric: Bool /// Type name in its own scope. public var localName: String // sourcery: skipEquality, skipDescription /// Variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var variables: [Variable] { unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) } /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var rawVariables: [Variable] // sourcery: skipEquality, skipDescription /// All variables defined for this type, including variables defined in extensions, /// in superclasses (for classes only) and protocols public var allVariables: [Variable] { return flattenAll({ return $0.variables }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) }) } private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName } // sourcery: skipEquality, skipDescription /// Methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var methods: [Method] { unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) } /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var rawMethods: [Method] // sourcery: skipEquality, skipDescription /// All methods defined for this type, including methods defined in extensions, /// in superclasses (for classes only) and protocols public var allMethods: [Method] { return flattenAll({ $0.methods }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) }) } private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName } // sourcery: skipEquality, skipDescription /// Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var subscripts: [Subscript] { unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) } /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var rawSubscripts: [Subscript] // sourcery: skipEquality, skipDescription /// All subscripts defined for this type, including subscripts defined in extensions, /// in superclasses (for classes only) and protocols public var allSubscripts: [Subscript] { return flattenAll({ $0.subscripts }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) }) } private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess } // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the body of this type in its declaration file if available. public var bodyBytesRange: BytesRange? // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the whole declaration of this type in its declaration file if available. public var completeDeclarationRange: BytesRange? private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { let all = NSMutableOrderedSet() let allObjects = extraction(self) /// The order of importance for properties is: /// Base class /// Inheritance /// Protocol conformance /// Extension var extensions = [T]() var baseObjects = [T]() allObjects.forEach { if isExtension($0) { extensions.append($0) } else { baseObjects.append($0) } } all.addObjects(from: baseObjects) func filteredExtraction(_ target: Type) -> [T] { // swiftlint:disable:next force_cast let all = all.array as! [T] let extracted = extraction(target).filter({ filter(all, $0) }) return extracted } inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } // swiftlint:disable:next force_cast let array = all.array as! [T] all.addObjects(from: extensions.filter({ filter(array, $0) })) return all.array.compactMap { $0 as? T } } private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { let all = NSMutableOrderedSet() for nextItem in extraction(self) { // swiftlint:disable:next force_cast if !all.contains(where: { filter($0 as! T, nextItem) }) { all.add(nextItem) } } return all.array.compactMap { $0 as? T } } /// All initializers defined in this type public var initializers: [Method] { return methods.filter { $0.isInitializer } } /// All annotations for this type public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Static variables defined in this type public var staticVariables: [Variable] { return variables.filter { $0.isStatic } } /// Static methods defined in this type public var staticMethods: [Method] { return methods.filter { $0.isStatic } } /// Class methods defined in this type public var classMethods: [Method] { return methods.filter { $0.isClass } } /// Instance variables defined in this type public var instanceVariables: [Variable] { return variables.filter { !$0.isStatic } } /// Instance methods defined in this type public var instanceMethods: [Method] { return methods.filter { !$0.isStatic && !$0.isClass } } /// Computed instance variables defined in this type public var computedVariables: [Variable] { return variables.filter { $0.isComputed && !$0.isStatic } } /// Stored instance variables defined in this type public var storedVariables: [Variable] { return variables.filter { !$0.isComputed && !$0.isStatic } } /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition public var inheritedTypes: [String] { didSet { based.removeAll() inheritedTypes.forEach { name in self.based[name] = name } } } // sourcery: skipEquality, skipDescription /// Names of types or protocols this type inherits from, including unknown (not scanned) types public var based = [String: String]() // sourcery: skipEquality, skipDescription /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined public var basedTypes = [String: Type]() /// Types this type inherits from public var inherits = [String: Type]() // sourcery: skipEquality, skipDescription /// Protocols this type implements. Does not contain classes in case where composition (`&`) is used in the declaration public var implements: [String: Type] = [:] /// Contained types public var containedTypes: [Type] { didSet { containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } } } // sourcery: skipEquality, skipDescription /// Contained types groupd by their names public private(set) var containedType: [String: Type] = [:] /// Name of parent type (for contained types only) public private(set) var parentName: String? // sourcery: skipEquality, skipDescription /// Parent type, if known (for contained types only) public var parent: Type? { didSet { parentName = parent?.name } } // sourcery: skipJSExport /// :nodoc: public var parentTypes: AnyIterator { var next: Type? = self return AnyIterator { next = next?.parent return next } } // sourcery: skipEquality, skipDescription /// Superclass type, if known (only for classes) public var supertype: Type? /// Type attributes, i.e. `@objc` public var attributes: AttributeList /// Type modifiers, i.e. `private`, `final` public var modifiers: [SourceryModifier] /// Path to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var path: String? { didSet { if let path = path { fileName = (path as NSString).lastPathComponent } } } /// Directory to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var directory: String? { get { return (path as? NSString)?.deletingLastPathComponent } } /// list of generic requirements public var genericRequirements: [GenericRequirement] { didSet { isGeneric = isGeneric || !genericRequirements.isEmpty } } /// File name where the type was defined public var fileName: String? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = "unknown") { self.localName = name self.accessLevel = accessLevel.rawValue self.isExtension = isExtension self.rawVariables = variables self.rawMethods = methods self.rawSubscripts = subscripts self.inheritedTypes = inheritedTypes self.containedTypes = containedTypes self.typealiases = [:] self.parent = parent self.parentName = parent?.name self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.isGeneric = isGeneric self.genericRequirements = genericRequirements self.implements = implements self._kind = kind super.init() containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } inheritedTypes.forEach { name in self.based[name] = name } typealiases.forEach({ $0.parent = self self.typealiases[$0.aliasName] = $0 }) } /// :nodoc: public func extend(_ type: Type) { type.annotations.forEach { self.annotations[$0.key] = $0.value } type.inherits.forEach { self.inherits[$0.key] = $0.value } type.implements.forEach { self.implements[$0.key] = $0.value } self.inheritedTypes += type.inheritedTypes self.containedTypes += type.containedTypes self.rawVariables += type.rawVariables self.rawMethods += type.rawMethods self.rawSubscripts += type.rawSubscripts } /// :nodoc: // sourcery: skipJSExport override public var description: String { let type: Type.Type = Swift.type(of: self) var string = "\\(type): " string.append("module = \\(String(describing: self.module)), ") string.append("imports = \\(String(describing: self.imports)), ") string.append("allImports = \\(String(describing: self.allImports)), ") string.append("typealiases = \\(String(describing: self.typealiases)), ") string.append("isExtension = \\(String(describing: self.isExtension)), ") string.append("kind = \\(String(describing: self.kind)), ") string.append("_kind = \\(String(describing: self._kind)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("name = \\(String(describing: self.name)), ") string.append("isUnknownExtension = \\(String(describing: self.isUnknownExtension)), ") string.append("isGeneric = \\(String(describing: self.isGeneric)), ") string.append("localName = \\(String(describing: self.localName)), ") string.append("rawVariables = \\(String(describing: self.rawVariables)), ") string.append("rawMethods = \\(String(describing: self.rawMethods)), ") string.append("rawSubscripts = \\(String(describing: self.rawSubscripts)), ") string.append("initializers = \\(String(describing: self.initializers)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("staticVariables = \\(String(describing: self.staticVariables)), ") string.append("staticMethods = \\(String(describing: self.staticMethods)), ") string.append("classMethods = \\(String(describing: self.classMethods)), ") string.append("instanceVariables = \\(String(describing: self.instanceVariables)), ") string.append("instanceMethods = \\(String(describing: self.instanceMethods)), ") string.append("computedVariables = \\(String(describing: self.computedVariables)), ") string.append("storedVariables = \\(String(describing: self.storedVariables)), ") string.append("inheritedTypes = \\(String(describing: self.inheritedTypes)), ") string.append("inherits = \\(String(describing: self.inherits)), ") string.append("containedTypes = \\(String(describing: self.containedTypes)), ") string.append("parentName = \\(String(describing: self.parentName)), ") string.append("parentTypes = \\(String(describing: self.parentTypes)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers)), ") string.append("fileName = \\(String(describing: self.fileName)), ") string.append("genericRequirements = \\(String(describing: self.genericRequirements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Type else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.module) hasher.combine(self.imports) hasher.combine(self.typealiases) hasher.combine(self.isExtension) hasher.combine(self.accessLevel) hasher.combine(self.isUnknownExtension) hasher.combine(self.isGeneric) hasher.combine(self.localName) hasher.combine(self.rawVariables) hasher.combine(self.rawMethods) hasher.combine(self.rawSubscripts) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.inheritedTypes) hasher.combine(self.inherits) hasher.combine(self.containedTypes) hasher.combine(self.parentName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.fileName) hasher.combine(self.genericRequirements) hasher.combine(kind) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Type else { return false } if self.module != rhs.module { return false } if self.imports != rhs.imports { return false } if self.typealiases != rhs.typealiases { return false } if self.isExtension != rhs.isExtension { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isUnknownExtension != rhs.isUnknownExtension { return false } if self.isGeneric != rhs.isGeneric { return false } if self.localName != rhs.localName { return false } if self.rawVariables != rhs.rawVariables { return false } if self.rawMethods != rhs.rawMethods { return false } if self.rawSubscripts != rhs.rawSubscripts { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.inheritedTypes != rhs.inheritedTypes { return false } if self.inherits != rhs.inherits { return false } if self.containedTypes != rhs.containedTypes { return false } if self.parentName != rhs.parentName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.fileName != rhs.fileName { return false } if self.kind != rhs.kind { return false } if self.genericRequirements != rhs.genericRequirements { return false } return true } // sourcery:inline:Type.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases self.isExtension = aDecoder.decode(forKey: "isExtension") guard let _kind: String = aDecoder.decode(forKey: "_kind") else { withVaList(["_kind"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._kind = _kind guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isGeneric = aDecoder.decode(forKey: "isGeneric") guard let localName: String = aDecoder.decode(forKey: "localName") else { withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.localName = localName guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { withVaList(["rawVariables"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawVariables = rawVariables guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { withVaList(["rawMethods"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawMethods = rawMethods guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { withVaList(["rawSubscripts"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawSubscripts = rawSubscripts self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { withVaList(["inheritedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inheritedTypes = inheritedTypes guard let based: [String: String] = aDecoder.decode(forKey: "based") else { withVaList(["based"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.based = based guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { withVaList(["basedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.basedTypes = basedTypes guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { withVaList(["inherits"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inherits = inherits guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { withVaList(["implements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.implements = implements guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { withVaList(["containedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedTypes = containedTypes guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { withVaList(["containedType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedType = containedType self.parentName = aDecoder.decode(forKey: "parentName") self.parent = aDecoder.decode(forKey: "parent") self.supertype = aDecoder.decode(forKey: "supertype") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.path = aDecoder.decode(forKey: "path") guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements self.fileName = aDecoder.decode(forKey: "fileName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.isExtension, forKey: "isExtension") aCoder.encode(self._kind, forKey: "_kind") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isGeneric, forKey: "isGeneric") aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.rawVariables, forKey: "rawVariables") aCoder.encode(self.rawMethods, forKey: "rawMethods") aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") aCoder.encode(self.based, forKey: "based") aCoder.encode(self.basedTypes, forKey: "basedTypes") aCoder.encode(self.inherits, forKey: "inherits") aCoder.encode(self.implements, forKey: "implements") aCoder.encode(self.containedTypes, forKey: "containedTypes") aCoder.encode(self.containedType, forKey: "containedType") aCoder.encode(self.parentName, forKey: "parentName") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.supertype, forKey: "supertype") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.path, forKey: "path") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end } extension Type { // sourcery: skipDescription, skipJSExport /// :nodoc: var isClass: Bool { let isNotClass = self is Struct || self is Enum || self is Protocol return !isNotClass && !isExtension } } /// Extends type so that inner types can be accessed via KVC e.g. Parent.Inner.Children extension Type { /// :nodoc: override public func value(forUndefinedKey key: String) -> Any? { if let innerType = containedTypes.lazy.filter({ $0.localName == key }).first { return innerType } return super.value(forUndefinedKey: key) } } #endif """), .init(name: "TypeName.swift", content: """ // // Created by Krzysztof Zabłocki on 25/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) @objcMembers public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable { /// :nodoc: public init(name: String, actualTypeName: TypeName? = nil, unwrappedTypeName: String? = nil, attributes: AttributeList = [:], isOptional: Bool = false, isImplicitlyUnwrappedOptional: Bool = false, tuple: TupleType? = nil, array: ArrayType? = nil, dictionary: DictionaryType? = nil, closure: ClosureType? = nil, set: SetType? = nil, generic: GenericType? = nil, isProtocolComposition: Bool = false) { let optionalSuffix: String // TODO: TBR let hasPrefix: Bool = name.hasPrefix("Optional<") as Bool let containsName: Bool = name.contains(" where ") as Bool if !hasPrefix && !containsName { if isOptional { optionalSuffix = "?" } else if isImplicitlyUnwrappedOptional { optionalSuffix = "!" } else { optionalSuffix = "" } } else { optionalSuffix = "" } self.name = name + optionalSuffix self.actualTypeName = actualTypeName self.unwrappedTypeName = unwrappedTypeName ?? name self.tuple = tuple self.array = array self.dictionary = dictionary self.closure = closure self.generic = generic self.isOptional = isOptional || isImplicitlyUnwrappedOptional self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional self.isProtocolComposition = isProtocolComposition self.set = set self.attributes = attributes self.modifiers = [] super.init() } /// Type name used in declaration public var name: String /// The generics of this TypeName public var generic: GenericType? /// Whether this TypeName is generic public var isGeneric: Bool { actualTypeName?.generic != nil || generic != nil } /// Whether this TypeName is protocol composition public var isProtocolComposition: Bool // sourcery: skipEquality /// Actual type name if given type name is a typealias public var actualTypeName: TypeName? /// Type name attributes, i.e. `@escaping` public var attributes: AttributeList /// Modifiers, i.e. `escaping` public var modifiers: [SourceryModifier] // sourcery: skipEquality /// Whether type is optional public let isOptional: Bool // sourcery: skipEquality /// Whether type is implicitly unwrapped optional public let isImplicitlyUnwrappedOptional: Bool // sourcery: skipEquality /// Type name without attributes and optional type information public var unwrappedTypeName: String // sourcery: skipEquality /// Whether type is void (`Void` or `()`) public var isVoid: Bool { return name == "Void" || name == "()" || unwrappedTypeName == "Void" } /// Whether type is a tuple public var isTuple: Bool { actualTypeName?.tuple != nil || tuple != nil } /// Tuple type data public var tuple: TupleType? /// Whether type is an array public var isArray: Bool { actualTypeName?.array != nil || array != nil } /// Array type data public var array: ArrayType? /// Whether type is a dictionary public var isDictionary: Bool { actualTypeName?.dictionary != nil || dictionary != nil } /// Dictionary type data public var dictionary: DictionaryType? /// Whether type is a closure public var isClosure: Bool { actualTypeName?.closure != nil || closure != nil } /// Closure type data public var closure: ClosureType? /// Whether type is a Set public var isSet: Bool { actualTypeName?.set != nil || set != nil } /// Set type data public var set: SetType? /// Whether type is `Never` public var isNever: Bool { return name == "Never" } /// Prints typename as it would appear on definition public var asSource: String { // TODO: TBR special treatment let specialTreatment: Bool = isOptional && name.hasPrefix("Optional<") let attributeValues: [Attribute] = attributes.flatMap { $0.value } let attributeValuesUnsorted: [String] = attributeValues.map { $0.asSource } var attributes: [String] = attributeValuesUnsorted.sorted() attributes.append(contentsOf: modifiers.map({ $0.asSource })) attributes.append(contentsOf: [specialTreatment ? name : unwrappedTypeName]) var description = attributes.joined(separator: " ") // if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name // description.append(dictionary.asSource) // } else if let _ = self.array { // description.append(array.asSource) // } else if let _ = self.generic { // let arguments = generic.typeParameters // .map({ $0.typeName.asSource }) // .joined(separator: ", ") // description.append("<\\(arguments)>") // } if !specialTreatment { if isImplicitlyUnwrappedOptional { description.append("!") } else if isOptional { description.append("?") } } return description } public override var description: String { var description: [String] = attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() description.append(contentsOf: modifiers.map({ $0.asSource })) description.append(contentsOf: [name]) return description.joined(separator: " ") } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TypeName else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) return results } public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.generic) hasher.combine(self.isProtocolComposition) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.tuple) hasher.combine(self.array) hasher.combine(self.dictionary) hasher.combine(self.closure) hasher.combine(self.set) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TypeName else { return false } if self.name != rhs.name { return false } if self.generic != rhs.generic { return false } if self.isProtocolComposition != rhs.isProtocolComposition { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.tuple != rhs.tuple { return false } if self.array != rhs.array { return false } if self.dictionary != rhs.dictionary { return false } if self.closure != rhs.closure { return false } if self.set != rhs.set { return false } return true } // sourcery:inline:TypeName.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.generic = aDecoder.decode(forKey: "generic") self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.isOptional = aDecoder.decode(forKey: "isOptional") self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { withVaList(["unwrappedTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.unwrappedTypeName = unwrappedTypeName self.tuple = aDecoder.decode(forKey: "tuple") self.array = aDecoder.decode(forKey: "array") self.dictionary = aDecoder.decode(forKey: "dictionary") self.closure = aDecoder.decode(forKey: "closure") self.set = aDecoder.decode(forKey: "set") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.generic, forKey: "generic") aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") aCoder.encode(self.actualTypeName, forKey: "actualTypeName") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.isOptional, forKey: "isOptional") aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") aCoder.encode(self.tuple, forKey: "tuple") aCoder.encode(self.array, forKey: "array") aCoder.encode(self.dictionary, forKey: "dictionary") aCoder.encode(self.closure, forKey: "closure") aCoder.encode(self.set, forKey: "set") } // sourcery:end // sourcery: skipEquality, skipDescription /// :nodoc: public override var debugDescription: String { return name } public convenience init(_ description: String) { self.init(name: description, actualTypeName: nil) } } extension TypeName { public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { if let description = description { Log.astWarning("Unknown type, please add type attribution to \\(description)") } else { Log.astWarning("Unknown type, please add type attribution") } return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) } } #endif """), .init(name: "Types.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation // sourcery: skipJSExport /// Collection of scanned types for accessing in templates @objcMembers public final class Types: NSObject, SourceryModel, Diffable { /// :nodoc: public let types: [Type] /// All known typealiases public let typealiases: [Typealias] /// :nodoc: public init(types: [Type], typealiases: [Typealias] = []) { self.types = types self.typealiases = typealiases } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("types = \\(String(describing: self.types)), ") string.append("typealiases = \\(String(describing: self.typealiases))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Types else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.types) hasher.combine(self.typealiases) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Types else { return false } if self.types != rhs.types { return false } if self.typealiases != rhs.typealiases { return false } return true } // sourcery:inline:Types.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.types, forKey: "types") aCoder.encode(self.typealiases, forKey: "typealiases") } // sourcery:end // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesByName: [String: Type] = { var typesByName = [String: Type]() self.types.forEach { typesByName[$0.globalName] = $0 } return typesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesaliasesByName: [String: Typealias] = { var typesaliasesByName = [String: Typealias]() self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } return typesaliasesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// All known types, excluding protocols or protocol compositions. public lazy internal(set) var all: [Type] = { return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocols public lazy internal(set) var protocols: [Protocol] = { return self.types.compactMap { $0 as? Protocol } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocol compositions public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { return self.types.compactMap { $0 as? ProtocolComposition } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known classes public lazy internal(set) var classes: [Class] = { return self.all.compactMap { $0 as? Class } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known structs public lazy internal(set) var structs: [Struct] = { return self.all.compactMap { $0 as? Struct } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known enums public lazy internal(set) var enums: [Enum] = { return self.all.compactMap { $0 as? Enum } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known extensions public lazy internal(set) var extensions: [Type] = { return self.all.compactMap { $0.isExtension ? $0 : nil } }() // sourcery: skipDescription, skipEquality, skipCoding /// Types based on any other type, grouped by its name, even if they are not known. /// `types.based.MyType` returns list of types based on `MyType` public lazy internal(set) var based: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.based.keys) } ) }() // sourcery: skipDescription, skipEquality, skipCoding /// Classes inheriting from any known class, grouped by its name. /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` public lazy internal(set) var inheriting: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.inherits.keys) }, validate: { type in guard type is Class else { throw "\\(type.name) is not a class and should be used with `implementing` or `based`" } }) }() // sourcery: skipDescription, skipEquality, skipCoding /// Types implementing known protocol, grouped by its name. /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` public lazy internal(set) var implementing: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.implements.keys) }, validate: { type in guard type is Protocol else { throw "\\(type.name) is a class and should be used with `inheriting` or `based`" } }) }() } #endif """), .init(name: "TypesCollection.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// :nodoc: @objcMembers public class TypesCollection: NSObject, AutoJSExport { // sourcery:begin: skipJSExport let all: [Type] let types: [String: [Type]] let validate: ((Type) throws -> Void)? // sourcery:end init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { self.all = types var content = [String: [Type]]() self.all.forEach { type in collection(type).forEach { name in var list = content[name] ?? [Type]() list.append(type) content[name] = list } } self.types = content self.validate = validate } public func types(forKey key: String) throws -> [Type] { // In some configurations, the types are keyed by "ModuleName.TypeName" var longKey: String? if let validate = validate { guard let type = all.first(where: { $0.name == key }) else { throw "Unknown type \\(key), should be used with `based`" } try validate(type) if let module = type.module { longKey = [module, type.name].joined(separator: ".") } } // If we find the types directly, return them if let types = types[key] { return types } // if we find a types for the longKey, return them if let longKey = longKey, let types = types[longKey] { return types } return [] } /// :nodoc: override public func value(forKey key: String) -> Any? { do { return try types(forKey: key) } catch { Log.error(error) return nil } } /// :nodoc: public subscript(_ key: String) -> [Type] { do { return try types(forKey: key) } catch { Log.error(error) return [] } } override public func responds(to aSelector: Selector!) -> Bool { return true } } #endif """), .init(name: "Variable.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryVariable = Variable /// Defines variable @objcMembers public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable { /// Variable name public let name: String /// Variable type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Variable type, if known, i.e. if the type is declared in the scanned sources. /// For explanation, see public var type: Type? /// Whether variable is computed and not stored public let isComputed: Bool /// Whether variable is async public let isAsync: Bool /// Whether variable throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is static public let isStatic: Bool /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public let writeAccess: String /// composed access level /// sourcery: skipJSExport public var accessLevel: (read: AccessLevel, write: AccessLevel) { (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) } /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Variable default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` public var attributes: AttributeList /// Modifiers, i.e. `private` public var modifiers: [SourceryModifier] /// Whether variable is final or not public var isFinal: Bool { return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } /// Whether variable is lazy or not public var isLazy: Bool { return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } } /// Whether variable is dynamic or not public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Reference to type name where the variable is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public internal(set) var definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// :nodoc: public init(name: String = "", typeName: TypeName, type: Type? = nil, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isComputed: Bool = false, isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, isStatic: Bool = false, defaultValue: String? = nil, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.name = name self.typeName = typeName self.type = type self.isComputed = isComputed self.isAsync = isAsync self.`throws` = `throws` self.throwsTypeName = throwsTypeName self.isStatic = isStatic self.defaultValue = defaultValue self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("isComputed = \\(String(describing: self.isComputed)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("`throws` = \\(String(describing: self.`throws`)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("isStatic = \\(String(describing: self.isStatic)), ") string.append("readAccess = \\(String(describing: self.readAccess)), ") string.append("writeAccess = \\(String(describing: self.writeAccess)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("isMutable = \\(String(describing: self.isMutable)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers)), ") string.append("isFinal = \\(String(describing: self.isFinal)), ") string.append("isLazy = \\(String(describing: self.isLazy)), ") string.append("isDynamic = \\(String(describing: self.isDynamic)), ") string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Variable else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "type").trackDifference(actual: self.type, expected: castObject.type)) results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.isComputed) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.isStatic) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.defaultValue) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.definedInTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Variable else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.isComputed != rhs.isComputed { return false } if self.isAsync != rhs.isAsync { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.isStatic != rhs.isStatic { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } return true } // sourcery:inline:Variable.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.isComputed = aDecoder.decode(forKey: "isComputed") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.isStatic = aDecoder.decode(forKey: "isStatic") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isComputed, forKey: "isComputed") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") } // sourcery:end } #endif """), .init(name: "AutoHashable.generated.swift", content: """ // Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable all // MARK: - AutoHashable for classes, protocols, structs // MARK: - AutoHashable for Enums """), .init(name: "Coding.generated.swift", content: """ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace trailing_newline import Foundation extension NSCoder { @nonobjc func decode(forKey: String) -> String? { return self.maybeDecode(forKey: forKey) as String? } @nonobjc func decode(forKey: String) -> TypeName? { return self.maybeDecode(forKey: forKey) as TypeName? } @nonobjc func decode(forKey: String) -> AccessLevel? { return self.maybeDecode(forKey: forKey) as AccessLevel? } @nonobjc func decode(forKey: String) -> Bool { return self.decodeBool(forKey: forKey) } @nonobjc func decode(forKey: String) -> Int { return self.decodeInteger(forKey: forKey) } func decode(forKey: String) -> E? { return maybeDecode(forKey: forKey) as E? } fileprivate func maybeDecode(forKey: String) -> E? { guard let object = self.decodeObject(forKey: forKey) else { return nil } return object as? E } } extension ArrayType: NSCoding {} extension AssociatedType: NSCoding {} extension AssociatedValue: NSCoding {} extension Attribute: NSCoding {} extension BytesRange: NSCoding {} extension ClosureParameter: NSCoding {} extension ClosureType: NSCoding {} extension DictionaryType: NSCoding {} extension EnumCase: NSCoding {} extension FileParserResult: NSCoding {} extension GenericParameter: NSCoding {} extension GenericRequirement: NSCoding {} extension GenericType: NSCoding {} extension GenericTypeParameter: NSCoding {} extension Import: NSCoding {} extension Method: NSCoding {} extension MethodParameter: NSCoding {} extension Modifier: NSCoding {} extension SetType: NSCoding {} extension Subscript: NSCoding {} extension TupleElement: NSCoding {} extension TupleType: NSCoding {} extension Type: NSCoding {} extension TypeName: NSCoding {} extension Typealias: NSCoding {} extension Types: NSCoding {} extension Variable: NSCoding {} """), .init(name: "JSExport.generated.swift", content: """ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace trailing_newline #if canImport(JavaScriptCore) import JavaScriptCore @objc protocol ActorAutoJSExport: JSExport { var kind: String { get } var isFinal: Bool { get } var isDistributed: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Actor: ActorAutoJSExport {} @objc protocol ArrayTypeAutoJSExport: JSExport { var name: String { get } var elementTypeName: TypeName { get } var elementType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension ArrayType: ArrayTypeAutoJSExport {} @objc protocol AssociatedTypeAutoJSExport: JSExport { var name: String { get } var typeName: TypeName? { get } var type: Type? { get } } extension AssociatedType: AssociatedTypeAutoJSExport {} @objc protocol AssociatedValueAutoJSExport: JSExport { var localName: String? { get } var externalName: String? { get } var typeName: TypeName { get } var type: Type? { get } var defaultValue: String? { get } var annotations: Annotations { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension AssociatedValue: AssociatedValueAutoJSExport {} @objc protocol AttributeAutoJSExport: JSExport { var name: String { get } var arguments: [String: NSObject] { get } var asSource: String { get } var description: String { get } } extension Attribute: AttributeAutoJSExport {} @objc protocol BytesRangeAutoJSExport: JSExport { var offset: Int64 { get } var length: Int64 { get } } extension BytesRange: BytesRangeAutoJSExport {} @objc protocol ClassAutoJSExport: JSExport { var kind: String { get } var isFinal: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Class: ClassAutoJSExport {} @objc protocol ClosureParameterAutoJSExport: JSExport { var argumentLabel: String? { get } var name: String? { get } var typeName: TypeName { get } var `inout`: Bool { get } var type: Type? { get } var isVariadic: Bool { get } var typeAttributes: AttributeList { get } var defaultValue: String? { get } var annotations: Annotations { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension ClosureParameter: ClosureParameterAutoJSExport {} @objc protocol ClosureTypeAutoJSExport: JSExport { var name: String { get } var parameters: [ClosureParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isAsync: Bool { get } var asyncKeyword: String? { get } var `throws`: Bool { get } var throwsOrRethrowsKeyword: String? { get } var throwsTypeName: TypeName? { get } var asSource: String { get } } extension ClosureType: ClosureTypeAutoJSExport {} @objc protocol DictionaryTypeAutoJSExport: JSExport { var name: String { get } var valueTypeName: TypeName { get } var valueType: Type? { get } var keyTypeName: TypeName { get } var keyType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension DictionaryType: DictionaryTypeAutoJSExport {} @objc protocol EnumAutoJSExport: JSExport { var kind: String { get } var cases: [EnumCase] { get } var rawTypeName: TypeName? { get } var hasRawType: Bool { get } var rawType: Type? { get } var based: [String: String] { get } var hasAssociatedValues: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Enum: EnumAutoJSExport {} @objc protocol EnumCaseAutoJSExport: JSExport { var name: String { get } var rawValue: String? { get } var associatedValues: [AssociatedValue] { get } var annotations: Annotations { get } var documentation: Documentation { get } var indirect: Bool { get } var hasAssociatedValue: Bool { get } } extension EnumCase: EnumCaseAutoJSExport {} @objc protocol GenericParameterAutoJSExport: JSExport { var name: String { get } var inheritedTypeName: TypeName? { get } } extension GenericParameter: GenericParameterAutoJSExport {} @objc protocol GenericRequirementAutoJSExport: JSExport { var leftType: AssociatedType { get } var rightType: GenericTypeParameter { get } var relationship: String { get } var relationshipSyntax: String { get } } extension GenericRequirement: GenericRequirementAutoJSExport {} @objc protocol GenericTypeAutoJSExport: JSExport { var name: String { get } var typeParameters: [GenericTypeParameter] { get } var asSource: String { get } var description: String { get } } extension GenericType: GenericTypeAutoJSExport {} @objc protocol GenericTypeParameterAutoJSExport: JSExport { var typeName: TypeName { get } var type: Type? { get } } extension GenericTypeParameter: GenericTypeParameterAutoJSExport {} @objc protocol ImportAutoJSExport: JSExport { var kind: String? { get } var path: String { get } var description: String { get } var moduleName: String { get } } extension Import: ImportAutoJSExport {} @objc protocol MethodAutoJSExport: JSExport { var name: String { get } var selectorName: String { get } var shortName: String { get } var callName: String { get } var parameters: [MethodParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var isThrowsTypeGeneric: Bool { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isAsync: Bool { get } var isDistributed: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var `rethrows`: Bool { get } var accessLevel: String { get } var isStatic: Bool { get } var isClass: Bool { get } var isInitializer: Bool { get } var isDeinitializer: Bool { get } var isFailableInitializer: Bool { get } var isConvenienceInitializer: Bool { get } var isRequired: Bool { get } var isFinal: Bool { get } var isMutating: Bool { get } var isGeneric: Bool { get } var isOptional: Bool { get } var isNonisolated: Bool { get } var isDynamic: Bool { get } var annotations: Annotations { get } var documentation: Documentation { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var genericParameters: [GenericParameter] { get } } extension Method: MethodAutoJSExport {} @objc protocol MethodParameterAutoJSExport: JSExport { var argumentLabel: String? { get } var name: String { get } var typeName: TypeName { get } var `inout`: Bool { get } var isVariadic: Bool { get } var type: Type? { get } var typeAttributes: AttributeList { get } var defaultValue: String? { get } var annotations: Annotations { get } var index: Int { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension MethodParameter: MethodParameterAutoJSExport {} @objc protocol ModifierAutoJSExport: JSExport { var name: String { get } var detail: String? { get } var asSource: String { get } } extension Modifier: ModifierAutoJSExport {} @objc protocol ProtocolAutoJSExport: JSExport { var kind: String { get } var associatedTypes: [String: AssociatedType] { get } var genericRequirements: [GenericRequirement] { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var fileName: String? { get } } extension Protocol: ProtocolAutoJSExport {} @objc protocol ProtocolCompositionAutoJSExport: JSExport { var kind: String { get } var composedTypeNames: [TypeName] { get } var composedTypes: [Type]? { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension ProtocolComposition: ProtocolCompositionAutoJSExport {} @objc protocol SetTypeAutoJSExport: JSExport { var name: String { get } var elementTypeName: TypeName { get } var elementType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension SetType: SetTypeAutoJSExport {} @objc protocol StructAutoJSExport: JSExport { var kind: String { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Struct: StructAutoJSExport {} @objc protocol SubscriptAutoJSExport: JSExport { var parameters: [MethodParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isFinal: Bool { get } var readAccess: String { get } var writeAccess: String { get } var isAsync: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var isMutable: Bool { get } var annotations: Annotations { get } var documentation: Documentation { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericParameters: [GenericParameter] { get } var genericRequirements: [GenericRequirement] { get } var isGeneric: Bool { get } } extension Subscript: SubscriptAutoJSExport {} @objc protocol TemplateContextAutoJSExport: JSExport { var functions: [SourceryMethod] { get } var types: Types { get } var argument: [String: NSObject] { get } var type: [String: Type] { get } var stencilContext: [String: Any] { get } var jsContext: [String: Any] { get } } extension TemplateContext: TemplateContextAutoJSExport {} @objc protocol TupleElementAutoJSExport: JSExport { var name: String? { get } var typeName: TypeName { get } var type: Type? { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension TupleElement: TupleElementAutoJSExport {} @objc protocol TupleTypeAutoJSExport: JSExport { var name: String { get } var elements: [TupleElement] { get } } extension TupleType: TupleTypeAutoJSExport {} @objc protocol TypeAutoJSExport: JSExport { var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var kind: String { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Type: TypeAutoJSExport {} @objc protocol TypeNameAutoJSExport: JSExport { var name: String { get } var generic: GenericType? { get } var isGeneric: Bool { get } var isProtocolComposition: Bool { get } var actualTypeName: TypeName? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } var isVoid: Bool { get } var isTuple: Bool { get } var tuple: TupleType? { get } var isArray: Bool { get } var array: ArrayType? { get } var isDictionary: Bool { get } var dictionary: DictionaryType? { get } var isClosure: Bool { get } var closure: ClosureType? { get } var isSet: Bool { get } var set: SetType? { get } var isNever: Bool { get } var asSource: String { get } var description: String { get } var debugDescription: String { get } } extension TypeName: TypeNameAutoJSExport {} @objc protocol TypealiasAutoJSExport: JSExport { var aliasName: String { get } var typeName: TypeName { get } var type: Type? { get } var module: String? { get } var imports: [Import] { get } var annotations: Annotations { get } var documentation: Documentation { get } var parent: Type? { get } var accessLevel: String { get } var parentName: String? { get } var name: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension Typealias: TypealiasAutoJSExport {} @objc protocol TypesCollectionAutoJSExport: JSExport { } extension TypesCollection: TypesCollectionAutoJSExport {} @objc protocol VariableAutoJSExport: JSExport { var name: String { get } var typeName: TypeName { get } var type: Type? { get } var isComputed: Bool { get } var isAsync: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var isStatic: Bool { get } var readAccess: String { get } var writeAccess: String { get } var isMutable: Bool { get } var defaultValue: String? { get } var annotations: Annotations { get } var documentation: Documentation { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var isFinal: Bool { get } var isLazy: Bool { get } var isDynamic: Bool { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension Variable: VariableAutoJSExport {} #endif """), .init(name: "Typed.generated.swift", content: """ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace extension AssociatedValue { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension ClosureParameter { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension MethodParameter { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension TupleElement { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension Typealias { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension Variable { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } """), ] #endif ================================================ FILE: SourcerySwift/Sources/SourceryRuntime_Linux.content.generated.swift ================================================ #if !canImport(ObjectiveC) let sourceryRuntimeFiles: [FolderSynchronizer.File] = [ .init(name: "AccessLevel.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation /// :nodoc: public enum AccessLevel: String { case `package` = "package" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" case `public` = "public" case `open` = "open" case none = "" } """), .init(name: "Actor.swift", content: """ import Foundation // sourcery: skipDescription /// Descibes Swift actor #if canImport(ObjectiveC) @objc(SwiftActor) @objcMembers #endif public final class Actor: Type { // sourcery: skipJSExport public class var kind: String { return "actor" } /// Returns "actor" public override var kind: String { Self.kind } /// Whether type is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Whether method is distributed method public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Actor.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("isFinal = \\(String(describing: self.isFinal)), ") string.append("isDistributed = \\(String(describing: self.isDistributed))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Actor else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Actor else { return false } return super.isEqual(rhs) } // sourcery:inline:Actor.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } """), .init(name: "Annotations.swift", content: """ import Foundation public typealias Annotations = [String: NSObject] /// Describes annotated declaration, i.e. type, method, variable, enum case public protocol Annotated { /** All annotations of declaration stored by their name. Value can be `bool`, `String`, float `NSNumber` or array of those types if you use several annotations with the same name. **Example:** ``` //sourcery: booleanAnnotation //sourcery: stringAnnotation = "value" //sourcery: numericAnnotation = 0.5 [ "booleanAnnotation": true, "stringAnnotation": "value", "numericAnnotation": 0.5 ] ``` */ var annotations: Annotations { get } } """), .init(name: "Array+Parallel.swift", content: """ // // Created by Krzysztof Zablocki on 06/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation public extension Array { func parallelFlatMap(transform: (Element) -> [T]) -> [T] { return parallelMap(transform: transform).flatMap { $0 } } func parallelCompactMap(transform: (Element) -> T?) -> [T] { return parallelMap(transform: transform).compactMap { $0 } } func parallelMap(transform: (Element) -> T) -> [T] { var result = ContiguousArray(repeating: nil, count: count) return result.withUnsafeMutableBufferPointer { buffer in nonisolated(unsafe) let buffer = buffer DispatchQueue.concurrentPerform(iterations: buffer.count) { idx in buffer[idx] = transform(self[idx]) } return buffer.map { $0! } } } func parallelPerform(_ work: (Element) -> Void) { DispatchQueue.concurrentPerform(iterations: count) { idx in work(self[idx]) } } } """), .init(name: "Array.swift", content: """ import Foundation /// Describes array type #if canImport(ObjectiveC) @objcMembers #endif public final class ArrayType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Array element type name public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription /// Array element type, if known public var elementType: Type? /// :nodoc: public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name self.elementTypeName = elementTypeName self.elementType = elementType } /// Returns array as generic type public var asGeneric: GenericType { GenericType(name: "Array", typeParameters: [ .init(typeName: elementTypeName, type: elementType) ]) } public var asSource: String { "[\\(elementTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") string.append("asGeneric = \\(String(describing: self.asGeneric)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ArrayType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ArrayType else { return false } if self.name != rhs.name { return false } if self.elementTypeName != rhs.elementTypeName { return false } return true } // sourcery:inline:ArrayType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elementTypeName = elementTypeName self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elementTypeName, forKey: "elementTypeName") aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } """), .init(name: "Attribute.swift", content: """ import Foundation /// Describes Swift attribute #if canImport(ObjectiveC) @objcMembers #endif public class Attribute: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { /// Attribute name public let name: String /// Attribute arguments public let arguments: [String: NSObject] // sourcery: skipJSExport let _description: String // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, arguments: [String: NSObject] = [:], description: String? = nil) { self.name = name self.arguments = arguments let argumentDescription = arguments.map { "\\($0.key): \\($0.value is String ? "\\"" : "")\\($0.value)\\($0.value is String ? "\\"" : "")" }.joined(separator: ", ") self._description = description ?? "@\\(name)\\(!argumentDescription.isEmpty ? "(" : "")\\(argumentDescription)\\(!argumentDescription.isEmpty ? ")" : "")" } /// TODO: unify `asSource` / `description`? public var asSource: String { description } /// Attribute description that can be used in a template. public override var description: String { _description } /// :nodoc: public enum Identifier: String { case convenience case required case available case discardableResult case GKInspectable = "gkinspectable" case objc case objcMembers case nonobjc case NSApplicationMain case NSCopying case NSManaged case UIApplicationMain case IBOutlet = "iboutlet" case IBInspectable = "ibinspectable" case IBDesignable = "ibdesignable" case autoclosure case convention case mutating case nonisolated case isolated case escaping case final case open case lazy case `package` = "package" case `public` = "public" case `internal` = "internal" case `private` = "private" case `fileprivate` = "fileprivate" case publicSetter = "setter_access.public" case internalSetter = "setter_access.internal" case privateSetter = "setter_access.private" case fileprivateSetter = "setter_access.fileprivate" case optional case dynamic public init?(identifier: String) { let identifier = identifier.trimmingPrefix("source.decl.attribute.") if identifier == "objc.name" { self.init(rawValue: "objc") } else { self.init(rawValue: identifier) } } public static func from(string: String) -> Identifier? { switch string { case "GKInspectable": return Identifier.GKInspectable case "objc": return .objc case "IBOutlet": return .IBOutlet case "IBInspectable": return .IBInspectable case "IBDesignable": return .IBDesignable default: return Identifier(rawValue: string) } } public var name: String { switch self { case .GKInspectable: return "GKInspectable" case .objc: return "objc" case .IBOutlet: return "IBOutlet" case .IBInspectable: return "IBInspectable" case .IBDesignable: return "IBDesignable" case .fileprivateSetter: return "fileprivate" case .privateSetter: return "private" case .internalSetter: return "internal" case .publicSetter: return "public" default: return rawValue } } public var description: String { return hasAtPrefix ? "@\\(name)" : name } public var hasAtPrefix: Bool { switch self { case .available, .discardableResult, .GKInspectable, .objc, .objcMembers, .nonobjc, .NSApplicationMain, .NSCopying, .NSManaged, .UIApplicationMain, .IBOutlet, .IBInspectable, .IBDesignable, .autoclosure, .convention, .escaping: return true default: return false } } } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Attribute else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "arguments").trackDifference(actual: self.arguments, expected: castObject.arguments)) results.append(contentsOf: DiffableResult(identifier: "_description").trackDifference(actual: self._description, expected: castObject._description)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.arguments) hasher.combine(self._description) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Attribute else { return false } if self.name != rhs.name { return false } if self.arguments != rhs.arguments { return false } if self._description != rhs._description { return false } return true } // sourcery:inline:Attribute.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let arguments: [String: NSObject] = aDecoder.decode(forKey: "arguments") else { withVaList(["arguments"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.arguments = arguments guard let _description: String = aDecoder.decode(forKey: "_description") else { withVaList(["_description"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._description = _description } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.arguments, forKey: "arguments") aCoder.encode(self._description, forKey: "_description") } // sourcery:end } """), .init(name: "BytesRange.swift", content: """ // // Created by Sébastien Duperron on 03/01/2018. // Copyright © 2018 Pixle. All rights reserved. // import Foundation /// :nodoc: #if canImport(ObjectiveC) @objcMembers #endif public final class BytesRange: NSObject, SourceryModel, Diffable { public let offset: Int64 public let length: Int64 public init(offset: Int64, length: Int64) { self.offset = offset self.length = length } public convenience init(range: (offset: Int64, length: Int64)) { self.init(offset: range.offset, length: range.length) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string += "offset = \\(String(describing: self.offset)), " string += "length = \\(String(describing: self.length))" return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? BytesRange else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "offset").trackDifference(actual: self.offset, expected: castObject.offset)) results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: castObject.length)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.offset) hasher.combine(self.length) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? BytesRange else { return false } if self.offset != rhs.offset { return false } if self.length != rhs.length { return false } return true } // sourcery:inline:BytesRange.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.offset = aDecoder.decodeInt64(forKey: "offset") self.length = aDecoder.decodeInt64(forKey: "length") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.offset, forKey: "offset") aCoder.encode(self.length, forKey: "length") } // sourcery:end } """), .init(name: "Class.swift", content: """ import Foundation // sourcery: skipDescription /// Descibes Swift class #if canImport(ObjectiveC) @objc(SwiftClass) @objcMembers #endif public final class Class: Type { // sourcery: skipJSExport public class var kind: String { return "class" } /// Returns "class" public override var kind: String { Self.kind } /// Whether type is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Class.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("isFinal = \\(String(describing: self.isFinal))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Class else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Class else { return false } return super.isEqual(rhs) } // sourcery:inline:Class.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } """), .init(name: "Composer.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation private func currentTimestamp() -> TimeInterval { return Date().timeIntervalSince1970 } /// Responsible for composing results of `FileParser`. public enum Composer { /// Performs final processing of discovered types: /// - extends types with their corresponding extensions; /// - replaces typealiases with actual types /// - finds actual types for variables and enums raw values /// - filters out any private types and extensions /// /// - Parameter parserResult: Result of parsing source code. /// - Parameter serial: Whether to process results serially instead of concurrently /// - Returns: Final types and extensions of unknown types. public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult, serial: Bool = false) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { let composed = ParserResultsComposed(parserResult: parserResult) let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in composed.resolveType(typeName: typeName, containingType: containingType) } let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in composed.resolveType(typeName: typeName, containingType: containingType, method: method) } let processType = { (type: Type) in type.variables.forEach { resolveVariableTypes($0, of: type, resolve: resolveType) } type.methods.forEach { resolveMethodTypes($0, of: type, resolve: methodResolveType) } type.subscripts.forEach { resolveSubscriptTypes($0, of: type, resolve: resolveType) } if let enumeration = type as? Enum { resolveEnumTypes(enumeration, types: composed.typeMap, resolve: resolveType) } if let composition = type as? ProtocolComposition { resolveProtocolCompositionTypes(composition, resolve: resolveType) } if let sourceryProtocol = type as? SourceryProtocol { resolveAssociatedTypes(sourceryProtocol, resolve: resolveType) } } let processFunction = { (function: SourceryMethod) in resolveMethodTypes(function, of: nil, resolve: methodResolveType) } if serial { composed.types.forEach(processType) composed.functions.forEach(processFunction) } else { composed.types.parallelPerform(processType) composed.functions.parallelPerform(processFunction) } updateTypeRelationships(types: composed.types) return ( types: composed.types.sorted { $0.globalName < $1.globalName }, functions: composed.functions.sorted { $0.name < $1.name }, typealiases: composed.unresolvedTypealiases.values.sorted(by: { $0.name < $1.name }) ) } typealias TypeResolver = (TypeName, Type?) -> Type? typealias MethodArgumentTypeResolver = (TypeName, Type?, Method) -> Type? private static func resolveVariableTypes(_ variable: Variable, of type: Type, resolve: TypeResolver) { variable.type = resolve(variable.typeName, type) /// The actual `definedInType` is assigned in `uniqueTypes` but we still /// need to resolve the type to correctly parse typealiases /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 if let definedInTypeName = variable.definedInTypeName { _ = resolve(definedInTypeName, type) } } private static func resolveSubscriptTypes(_ subscript: Subscript, of type: Type, resolve: TypeResolver) { `subscript`.parameters.forEach { (parameter) in parameter.type = resolve(parameter.typeName, type) } `subscript`.returnType = resolve(`subscript`.returnTypeName, type) if let definedInTypeName = `subscript`.definedInTypeName { _ = resolve(definedInTypeName, type) } } private static func resolveMethodTypes(_ method: SourceryMethod, of type: Type?, resolve: MethodArgumentTypeResolver) { method.parameters.forEach { parameter in parameter.type = resolve(parameter.typeName, type, method) } /// The actual `definedInType` is assigned in `uniqueTypes` but we still /// need to resolve the type to correctly parse typealiases /// @see https://github.com/krzysztofzablocki/Sourcery/pull/374 var definedInType: Type? if let definedInTypeName = method.definedInTypeName { definedInType = resolve(definedInTypeName, type, method) } guard !method.returnTypeName.isVoid else { return } if method.isInitializer || method.isFailableInitializer { method.returnType = definedInType if let type = method.actualDefinedInTypeName { if method.isFailableInitializer { method.returnTypeName = TypeName( name: type.name, isOptional: true, isImplicitlyUnwrappedOptional: false, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic, isProtocolComposition: type.isProtocolComposition ) } else if method.isInitializer { method.returnTypeName = type } } } else { method.returnType = resolve(method.returnTypeName, type, method) } } private static func resolveEnumTypes(_ enumeration: Enum, types: [String: Type], resolve: TypeResolver) { enumeration.cases.forEach { enumCase in enumCase.associatedValues.forEach { associatedValue in associatedValue.type = resolve(associatedValue.typeName, enumeration) } } guard enumeration.hasRawType else { return } if let rawValueVariable = enumeration.variables.first(where: { $0.name == "rawValue" && !$0.isStatic }) { enumeration.rawTypeName = rawValueVariable.actualTypeName enumeration.rawType = rawValueVariable.type } else if let rawTypeName = enumeration.inheritedTypes.first { // enums with no cases or enums with cases that contain associated values can't have raw type guard !enumeration.cases.isEmpty, !enumeration.hasAssociatedValues else { return enumeration.rawTypeName = nil } if let rawTypeCandidate = types[rawTypeName] { if !((rawTypeCandidate is SourceryProtocol) || (rawTypeCandidate is ProtocolComposition)) { enumeration.rawTypeName = TypeName(rawTypeName) enumeration.rawType = rawTypeCandidate } } else { enumeration.rawTypeName = TypeName(rawTypeName) } } } private static func resolveProtocolCompositionTypes(_ protocolComposition: ProtocolComposition, resolve: TypeResolver) { let composedTypes = protocolComposition.composedTypeNames.compactMap { typeName in resolve(typeName, protocolComposition) } protocolComposition.composedTypes = composedTypes } private static func resolveAssociatedTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) { sourceryProtocol.associatedTypes.forEach { (_, value) in guard let typeName = value.typeName, let type = resolve(typeName, sourceryProtocol) else { return } value.type = type } sourceryProtocol.genericRequirements.forEach { requirment in if let knownAssociatedType = sourceryProtocol.associatedTypes[requirment.leftType.name] { requirment.leftType = knownAssociatedType } requirment.rightType.type = resolve(requirment.rightType.typeName, sourceryProtocol) } } private static func updateTypeRelationships(types: [Type]) { var typesByName = [String: Type]() types.forEach { typesByName[$0.globalName] = $0 } var processed = [String: Bool]() types.forEach { type in if let type = type as? Class, let supertype = type.inheritedTypes.first.flatMap({ typesByName[$0] }) as? Class { type.supertype = supertype } processed[type.globalName] = true updateTypeRelationship(for: type, typesByName: typesByName, processed: &processed) } } internal static func findBaseType(for type: Type, name: String, typesByName: [String: Type]) -> Type? { // special case to check if the type is based on one of the recognized types // and the superclass has a generic constraint in `name` part of the `TypeName` var name = name if name.contains("<") && name.contains(">") { let parts = name.split(separator: "<") name = String(parts.first!) } if let baseType = typesByName[name] { return baseType } if let module = type.module, let baseType = typesByName["\\(module).\\(name)"] { return baseType } for importModule in type.imports { if let baseType = typesByName["\\(importModule).\\(name)"] { return baseType } } guard name.contains("&") else { return nil } // this can happen for a type which consists of mutliple types composed together (i.e. (A & B)) let nameComponents = name.components(separatedBy: "&").map { $0.trimmingCharacters(in: .whitespaces) } let types: [Type] = nameComponents.compactMap { typesByName[$0] } let typeNames = types.map { TypeName(name: $0.name) } return ProtocolComposition(name: name, inheritedTypes: types.map { $0.globalName }, composedTypeNames: typeNames, composedTypes: types) } private static func updateTypeRelationship(for type: Type, typesByName: [String: Type], processed: inout [String: Bool]) { type.based.keys.forEach { name in guard let baseType = findBaseType(for: type, name: name, typesByName: typesByName) else { return } let globalName = baseType.globalName if processed[globalName] != true { processed[globalName] = true updateTypeRelationship(for: baseType, typesByName: typesByName, processed: &processed) } copyTypeRelationships(from: baseType, to: type) if let composedType = baseType as? ProtocolComposition { let implements = composedType.composedTypes?.filter({ $0 is SourceryProtocol }) implements?.forEach { updateInheritsAndImplements(from: $0, to: type) } if implements?.count == composedType.composedTypes?.count || composedType.composedTypes == nil || composedType.composedTypes?.isEmpty == true { type.implements[globalName] = baseType } } else { updateInheritsAndImplements(from: baseType, to: type) } type.basedTypes[globalName] = baseType } } private static func updateInheritsAndImplements(from baseType: Type, to type: Type) { if baseType is Class { type.inherits[baseType.name] = baseType } else if let `protocol` = baseType as? SourceryProtocol { type.implements[baseType.globalName] = baseType if let extendingProtocol = type as? SourceryProtocol { `protocol`.associatedTypes.forEach { if extendingProtocol.associatedTypes[$0.key] == nil { extendingProtocol.associatedTypes[$0.key] = $0.value } } } } } private static func copyTypeRelationships(from baseType: Type, to type: Type) { baseType.based.keys.forEach { type.based[$0] = $0 } baseType.basedTypes.forEach { type.basedTypes[$0.key] = $0.value } baseType.inherits.forEach { type.inherits[$0.key] = $0.value } baseType.implements.forEach { type.implements[$0.key] = $0.value } } } """), .init(name: "Definition.swift", content: """ import Foundation /// Describes that the object is defined in a context of some `Type` public protocol Definition: AnyObject { /// Reference to type name where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc var definedInTypeName: TypeName? { get } /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown var definedInType: Type? { get } // sourcery: skipJSExport /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` var actualDefinedInTypeName: TypeName? { get } } """), .init(name: "Dictionary.swift", content: """ import Foundation /// Describes dictionary type #if canImport(ObjectiveC) @objcMembers #endif public final class DictionaryType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Dictionary value type name public var valueTypeName: TypeName // sourcery: skipEquality, skipDescription /// Dictionary value type, if known public var valueType: Type? /// Dictionary key type name public var keyTypeName: TypeName // sourcery: skipEquality, skipDescription /// Dictionary key type, if known public var keyType: Type? /// :nodoc: public init(name: String, valueTypeName: TypeName, valueType: Type? = nil, keyTypeName: TypeName, keyType: Type? = nil) { self.name = name self.valueTypeName = valueTypeName self.valueType = valueType self.keyTypeName = keyTypeName self.keyType = keyType } /// Returns dictionary as generic type public var asGeneric: GenericType { GenericType(name: "Dictionary", typeParameters: [ .init(typeName: keyTypeName), .init(typeName: valueTypeName) ]) } public var asSource: String { "[\\(keyTypeName.asSource): \\(valueTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("valueTypeName = \\(String(describing: self.valueTypeName)), ") string.append("keyTypeName = \\(String(describing: self.keyTypeName)), ") string.append("asGeneric = \\(String(describing: self.asGeneric)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? DictionaryType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "valueTypeName").trackDifference(actual: self.valueTypeName, expected: castObject.valueTypeName)) results.append(contentsOf: DiffableResult(identifier: "keyTypeName").trackDifference(actual: self.keyTypeName, expected: castObject.keyTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.valueTypeName) hasher.combine(self.keyTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? DictionaryType else { return false } if self.name != rhs.name { return false } if self.valueTypeName != rhs.valueTypeName { return false } if self.keyTypeName != rhs.keyTypeName { return false } return true } // sourcery:inline:DictionaryType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let valueTypeName: TypeName = aDecoder.decode(forKey: "valueTypeName") else { withVaList(["valueTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.valueTypeName = valueTypeName self.valueType = aDecoder.decode(forKey: "valueType") guard let keyTypeName: TypeName = aDecoder.decode(forKey: "keyTypeName") else { withVaList(["keyTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.keyTypeName = keyTypeName self.keyType = aDecoder.decode(forKey: "keyType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.valueTypeName, forKey: "valueTypeName") aCoder.encode(self.valueType, forKey: "valueType") aCoder.encode(self.keyTypeName, forKey: "keyTypeName") aCoder.encode(self.keyType, forKey: "keyType") } // sourcery:end } """), .init(name: "Diffable.swift", content: """ // // Diffable.swift // Sourcery // // Created by Krzysztof Zabłocki on 22/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation public protocol Diffable { /// Returns `DiffableResult` for the given objects. /// /// - Parameter object: Object to diff against. /// - Returns: Diffable results. func diffAgainst(_ object: Any?) -> DiffableResult } /// :nodoc: extension NSRange: Diffable { /// :nodoc: public static func == (lhs: NSRange, rhs: NSRange) -> Bool { return NSEqualRanges(lhs, rhs) } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let rhs = object as? NSRange else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "location").trackDifference(actual: self.location, expected: rhs.location)) results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: rhs.length)) return results } } #if canImport(ObjectiveC) @objcMembers #endif public class DiffableResult: NSObject, AutoEquatable { // sourcery: skipEquality private var results: [String] internal var identifier: String? init(results: [String] = [], identifier: String? = nil) { self.results = results self.identifier = identifier } func append(_ element: String) { results.append(element) } func append(contentsOf contents: DiffableResult) { if !contents.isEmpty { results.append(contents.description) } } var isEmpty: Bool { return results.isEmpty } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.identifier) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? DiffableResult else { return false } if self.identifier != rhs.identifier { return false } return true } public override var description: String { guard !results.isEmpty else { return "" } var description = "\\(identifier.flatMap { "\\($0) " } ?? "")" description.append(results.joined(separator: "\\n")) return description } } public extension DiffableResult { #if swift(>=4.1) #else /// :nodoc: @discardableResult func trackDifference(actual: T, expected: T) -> DiffableResult { if actual != expected { let result = DiffableResult(results: [""]) append(contentsOf: result) } return self } #endif /// :nodoc: @discardableResult func trackDifference(actual: T?, expected: T?) -> DiffableResult { if actual != expected { let expected = expected.map({ "\\($0)" }) ?? "nil" let actual = actual.map({ "\\($0)" }) ?? "nil" let result = DiffableResult(results: [""]) append(contentsOf: result) } return self } /// :nodoc: @discardableResult func trackDifference(actual: T, expected: T) -> DiffableResult where T: Diffable { let diffResult = actual.diffAgainst(expected) append(contentsOf: diffResult) return self } /// :nodoc: @discardableResult func trackDifference(actual: [T], expected: [T]) -> DiffableResult where T: Diffable { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { diffResult.append("Different count, expected: \\(expected.count), received: \\(actual.count)") return self } for (idx, item) in actual.enumerated() { let diff = DiffableResult() diff.trackDifference(actual: item, expected: expected[idx]) if !diff.isEmpty { let string = "idx \\(idx): \\(diff)" diffResult.append(string) } } return self } /// :nodoc: @discardableResult func trackDifference(actual: [T], expected: [T]) -> DiffableResult { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { diffResult.append("Different count, expected: \\(expected.count), received: \\(actual.count)") return self } for (idx, item) in actual.enumerated() where item != expected[idx] { let string = "idx \\(idx): " diffResult.append(string) } return self } /// :nodoc: @discardableResult func trackDifference(actual: [K: T], expected: [K: T]) -> DiffableResult where T: Diffable { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { append("Different count, expected: \\(expected.count), received: \\(actual.count)") if expected.count > actual.count { let missingKeys = Array(expected.keys.filter { actual[$0] == nil }.map { String(describing: $0) }) diffResult.append("Missing keys: \\(missingKeys.joined(separator: ", "))") } return self } for (key, actualElement) in actual { guard let expectedElement = expected[key] else { diffResult.append("Missing key \\"\\(key)\\"") continue } let diff = DiffableResult() diff.trackDifference(actual: actualElement, expected: expectedElement) if !diff.isEmpty { let string = "key \\"\\(key)\\": \\(diff)" diffResult.append(string) } } return self } // MARK: - NSObject diffing /// :nodoc: @discardableResult func trackDifference(actual: [K: T], expected: [K: T]) -> DiffableResult { let diffResult = DiffableResult() defer { append(contentsOf: diffResult) } guard actual.count == expected.count else { append("Different count, expected: \\(expected.count), received: \\(actual.count)") if expected.count > actual.count { let missingKeys = Array(expected.keys.filter { actual[$0] == nil }.map { String(describing: $0) }) diffResult.append("Missing keys: \\(missingKeys.joined(separator: ", "))") } return self } for (key, actualElement) in actual { guard let expectedElement = expected[key] else { diffResult.append("Missing key \\"\\(key)\\"") continue } if !actualElement.isEqual(expectedElement) { diffResult.append("key \\"\\(key)\\": ") } } return self } } """), .init(name: "Documentation.swift", content: """ import Foundation public typealias Documentation = [String] /// Describes a declaration with documentation, i.e. type, method, variable, enum case public protocol Documented { var documentation: Documentation { get } } """), .init(name: "Extensions.swift", content: """ import Foundation public extension StringProtocol { /// Trimms leading and trailing whitespaces and newlines var trimmed: String { self.trimmingCharacters(in: .whitespacesAndNewlines) } } public extension String { /// Returns nil if string is empty var nilIfEmpty: String? { if isEmpty { return nil } return self } /// Returns nil if string is empty or contains `_` character var nilIfNotValidParameterName: String? { if isEmpty { return nil } if self == "_" { return nil } return self } /// :nodoc: /// - Parameter substring: Instance of a substring /// - Returns: Returns number of times a substring appears in self func countInstances(of substring: String) -> Int { guard !substring.isEmpty else { return 0 } var count = 0 var searchRange: Range? while let foundRange = range(of: substring, options: [], range: searchRange) { count += 1 searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex)) } return count } /// :nodoc: /// Removes leading and trailing whitespace from str. Returns false if str was not altered. @discardableResult mutating func strip() -> Bool { let strippedString = stripped() guard strippedString != self else { return false } self = strippedString return true } /// :nodoc: /// Returns a copy of str with leading and trailing whitespace removed. func stripped() -> String { return String(self.trimmingCharacters(in: .whitespaces)) } /// :nodoc: @discardableResult mutating func trimPrefix(_ prefix: String) -> Bool { guard hasPrefix(prefix) else { return false } self = String(self.suffix(self.count - prefix.count)) return true } /// :nodoc: func trimmingPrefix(_ prefix: String) -> String { guard hasPrefix(prefix) else { return self } return String(self.suffix(self.count - prefix.count)) } /// :nodoc: @discardableResult mutating func trimSuffix(_ suffix: String) -> Bool { guard hasSuffix(suffix) else { return false } self = String(self.prefix(self.count - suffix.count)) return true } /// :nodoc: func trimmingSuffix(_ suffix: String) -> String { guard hasSuffix(suffix) else { return self } return String(self.prefix(self.count - suffix.count)) } /// :nodoc: func dropFirstAndLast(_ n: Int = 1) -> String { return drop(first: n, last: n) } /// :nodoc: func drop(first: Int, last: Int) -> String { return String(self.dropFirst(first).dropLast(last)) } /// :nodoc: /// Wraps brackets if needed to make a valid type name func bracketsBalancing() -> String { if hasPrefix("(") && hasSuffix(")") { let unwrapped = dropFirstAndLast() return unwrapped.commaSeparated().count == 1 ? unwrapped.bracketsBalancing() : self } else { let wrapped = "(\\(self))" return wrapped.isValidTupleName() || !isBracketsBalanced() ? wrapped : self } } /// :nodoc: /// Returns true if given string can represent a valid tuple type name func isValidTupleName() -> Bool { guard hasPrefix("(") && hasSuffix(")") else { return false } let trimmedBracketsName = dropFirstAndLast() return trimmedBracketsName.isBracketsBalanced() && trimmedBracketsName.commaSeparated().count > 1 } /// :nodoc: func isValidArrayName() -> Bool { if hasPrefix("Array<") { return true } if hasPrefix("[") && hasSuffix("]") { return dropFirstAndLast().colonSeparated().count == 1 } return false } /// :nodoc: func isValidDictionaryName() -> Bool { if hasPrefix("Dictionary<") { return true } if hasPrefix("[") && contains(":") && hasSuffix("]") { return dropFirstAndLast().colonSeparated().count == 2 } return false } /// :nodoc: func isValidClosureName() -> Bool { return components(separatedBy: "->", excludingDelimiterBetween: (["(", "<"], [")", ">"])).count > 1 } /// :nodoc: /// Returns true if all opening brackets are balanced with closed brackets. func isBracketsBalanced() -> Bool { var bracketsCount: Int = 0 for char in self { if char == "(" { bracketsCount += 1 } else if char == ")" { bracketsCount -= 1 } if bracketsCount < 0 { return false } } return bracketsCount == 0 } /// :nodoc: /// Returns components separated with a comma respecting nested types func commaSeparated() -> [String] { return components(separatedBy: ",", excludingDelimiterBetween: ("<[({", "})]>")) } /// :nodoc: /// Returns components separated with colon respecting nested types func colonSeparated() -> [String] { return components(separatedBy: ":", excludingDelimiterBetween: ("<[({", "})]>")) } /// :nodoc: /// Returns components separated with semicolon respecting nested contexts func semicolonSeparated() -> [String] { return components(separatedBy: ";", excludingDelimiterBetween: ("{", "}")) } /// :nodoc: func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: String, close: String)) -> [String] { return self.components(separatedBy: delimiter, excludingDelimiterBetween: (between.open.map { String($0) }, between.close.map { String($0) })) } /// :nodoc: func components(separatedBy delimiter: String, excludingDelimiterBetween between: (open: [String], close: [String])) -> [String] { var boundingCharactersCount: Int = 0 var quotesCount: Int = 0 var item = "" var items = [String]() var i = self.startIndex while i < self.endIndex { var offset = 1 defer { i = self.index(i, offsetBy: offset) } var currentlyScannedEnd: Index = self.endIndex if let endIndex = self.index(i, offsetBy: delimiter.count, limitedBy: self.endIndex) { currentlyScannedEnd = endIndex } let currentlyScanned: String = String(self[i..` if !((self[i] == ">") as Bool && (item.last == "-") as Bool) { boundingCharactersCount = max(0, boundingCharactersCount - 1) } offset = closeString.count } if (self[i] == "\\"") as Bool { quotesCount += 1 } let currentIsDelimiter = (currentlyScanned == delimiter) as Bool let boundingCountIsZero = (boundingCharactersCount == 0) as Bool let hasEvenQuotes = (quotesCount % 2 == 0) as Bool if currentIsDelimiter && boundingCountIsZero && hasEvenQuotes { items.append(item) item = "" i = self.index(i, offsetBy: delimiter.count - 1) } else { let endIndex: Index = self.index(i, offsetBy: offset) item += self[i.. DiffableResult { let results = DiffableResult() guard let castObject = object as? FileParserResult else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "inlineRanges").trackDifference(actual: self.inlineRanges, expected: castObject.inlineRanges)) results.append(contentsOf: DiffableResult(identifier: "inlineIndentations").trackDifference(actual: self.inlineIndentations, expected: castObject.inlineIndentations)) results.append(contentsOf: DiffableResult(identifier: "modifiedDate").trackDifference(actual: self.modifiedDate, expected: castObject.modifiedDate)) results.append(contentsOf: DiffableResult(identifier: "sourceryVersion").trackDifference(actual: self.sourceryVersion, expected: castObject.sourceryVersion)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.path) hasher.combine(self.module) hasher.combine(self.types) hasher.combine(self.functions) hasher.combine(self.typealiases) hasher.combine(self.inlineRanges) hasher.combine(self.inlineIndentations) hasher.combine(self.modifiedDate) hasher.combine(self.sourceryVersion) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? FileParserResult else { return false } if self.path != rhs.path { return false } if self.module != rhs.module { return false } if self.types != rhs.types { return false } if self.functions != rhs.functions { return false } if self.typealiases != rhs.typealiases { return false } if self.inlineRanges != rhs.inlineRanges { return false } if self.inlineIndentations != rhs.inlineIndentations { return false } if self.modifiedDate != rhs.modifiedDate { return false } if self.sourceryVersion != rhs.sourceryVersion { return false } return true } // sourcery:inline:FileParserResult.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.path = aDecoder.decode(forKey: "path") self.module = aDecoder.decode(forKey: "module") guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let functions: [SourceryMethod] = aDecoder.decode(forKey: "functions") else { withVaList(["functions"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.functions = functions guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases guard let inlineRanges: [String: NSRange] = aDecoder.decode(forKey: "inlineRanges") else { withVaList(["inlineRanges"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inlineRanges = inlineRanges guard let inlineIndentations: [String: String] = aDecoder.decode(forKey: "inlineIndentations") else { withVaList(["inlineIndentations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inlineIndentations = inlineIndentations guard let modifiedDate: Date = aDecoder.decode(forKey: "modifiedDate") else { withVaList(["modifiedDate"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiedDate = modifiedDate guard let sourceryVersion: String = aDecoder.decode(forKey: "sourceryVersion") else { withVaList(["sourceryVersion"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.sourceryVersion = sourceryVersion } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.path, forKey: "path") aCoder.encode(self.module, forKey: "module") aCoder.encode(self.types, forKey: "types") aCoder.encode(self.functions, forKey: "functions") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.inlineRanges, forKey: "inlineRanges") aCoder.encode(self.inlineIndentations, forKey: "inlineIndentations") aCoder.encode(self.modifiedDate, forKey: "modifiedDate") aCoder.encode(self.sourceryVersion, forKey: "sourceryVersion") } // sourcery:end } """), .init(name: "Generic.swift", content: """ import Foundation /// Descibes Swift generic type #if canImport(ObjectiveC) @objcMembers #endif public final class GenericType: NSObject, SourceryModelWithoutDescription, Diffable { /// The name of the base type, i.e. `Array` for `Array` public var name: String /// This generic type parameters public let typeParameters: [GenericTypeParameter] /// :nodoc: public init(name: String, typeParameters: [GenericTypeParameter] = []) { self.name = name self.typeParameters = typeParameters } public var asSource: String { let arguments = typeParameters .map({ $0.typeName.asSource }) .joined(separator: ", ") return "\\(name)<\\(arguments)>" } public override var description: String { asSource } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeParameters").trackDifference(actual: self.typeParameters, expected: castObject.typeParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericType else { return false } if self.name != rhs.name { return false } if self.typeParameters != rhs.typeParameters { return false } return true } // sourcery:inline:GenericType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeParameters: [GenericTypeParameter] = aDecoder.decode(forKey: "typeParameters") else { withVaList(["typeParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeParameters = typeParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeParameters, forKey: "typeParameters") } // sourcery:end } """), .init(name: "Import.swift", content: """ import Foundation /// Defines import type #if canImport(ObjectiveC) @objcMembers #endif public class Import: NSObject, SourceryModelWithoutDescription, Diffable { /// Import kind, e.g. class, struct in `import class Module.ClassName` public var kind: String? /// Import path public var path: String /// :nodoc: public init(path: String, kind: String? = nil) { self.path = path self.kind = kind } /// Full import value e.g. `import struct Module.StructName` public override var description: String { if let kind = kind { return "\\(kind) \\(path)" } return path } /// Returns module name from a import, e.g. if you had `import struct Module.Submodule.Struct` it will return `Module.Submodule` public var moduleName: String { if kind != nil { if let idx = path.lastIndex(of: ".") { return String(path[.. DiffableResult { let results = DiffableResult() guard let castObject = object as? Import else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "kind").trackDifference(actual: self.kind, expected: castObject.kind)) results.append(contentsOf: DiffableResult(identifier: "path").trackDifference(actual: self.path, expected: castObject.path)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.kind) hasher.combine(self.path) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Import else { return false } if self.kind != rhs.kind { return false } if self.path != rhs.path { return false } return true } // sourcery:inline:Import.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.kind = aDecoder.decode(forKey: "kind") guard let path: String = aDecoder.decode(forKey: "path") else { withVaList(["path"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.path = path } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.kind, forKey: "kind") aCoder.encode(self.path, forKey: "path") } // sourcery:end } """), .init(name: "Log.swift", content: """ //import Darwin import Foundation /// :nodoc: public enum Log { public struct Configuration { let isDryRun: Bool let isQuiet: Bool let isVerboseLoggingEnabled: Bool let isLogBenchmarkEnabled: Bool let shouldLogAST: Bool public init(isDryRun: Bool, isQuiet: Bool, isVerboseLoggingEnabled: Bool, isLogBenchmarkEnabled: Bool, shouldLogAST: Bool) { self.isDryRun = isDryRun self.isQuiet = isQuiet self.isVerboseLoggingEnabled = isVerboseLoggingEnabled self.isLogBenchmarkEnabled = isLogBenchmarkEnabled self.shouldLogAST = shouldLogAST } } public static func setup(using configuration: Configuration) { Log.stackMessages = configuration.isDryRun switch (configuration.isQuiet, configuration.isVerboseLoggingEnabled) { case (true, _): Log.level = .errors case (false, let isVerbose): Log.level = isVerbose ? .verbose : .info } Log.logBenchmarks = (configuration.isVerboseLoggingEnabled || configuration.isLogBenchmarkEnabled) && !configuration.isQuiet Log.logAST = (configuration.shouldLogAST) && !configuration.isQuiet } public enum Level: Int { case errors case warnings case info case verbose } public static var level: Level = .warnings public static var logBenchmarks: Bool = false public static var logAST: Bool = false public static var stackMessages: Bool = false public private(set) static var messagesStack = [String]() public static func error(_ message: Any) { log(level: .errors, "error: \\(message)") // to return error when running swift templates which is done in a different process if ProcessInfo.processInfo.processName != "Sourcery" { fputs("\\(message)", stderr) } } public static func warning(_ message: Any) { log(level: .warnings, "warning: \\(message)") } public static func astWarning(_ message: Any) { guard logAST else { return } log(level: .warnings, "ast warning: \\(message)") } public static func astError(_ message: Any) { guard logAST else { return } log(level: .errors, "ast error: \\(message)") } public static func verbose(_ message: Any) { log(level: .verbose, message) } public static func info(_ message: Any) { log(level: .info, message) } public static func benchmark(_ message: Any) { guard logBenchmarks else { return } if stackMessages { messagesStack.append("\\(message)") } else { print(message) } } private static func log(level logLevel: Level, _ message: Any) { guard logLevel.rawValue <= Log.level.rawValue else { return } if stackMessages { messagesStack.append("\\(message)") } else { print(message) } } public static func output(_ message: String) { print(message) } } extension String: Error {} """), .init(name: "Modifier.swift", content: """ import Foundation public typealias SourceryModifier = Modifier /// modifier can be thing like `private`, `class`, `nonmutating` /// if a declaration has modifier like `private(set)` it's name will be `private` and detail will be `set` #if canImport(ObjectiveC) @objcMembers #endif public class Modifier: NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable { /// The declaration modifier name. public let name: String /// The modifier detail, if any. public let detail: String? public init(name: String, detail: String? = nil) { self.name = name self.detail = detail } public var asSource: String { if let detail = detail { return "\\(name)(\\(detail))" } else { return name } } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Modifier else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "detail").trackDifference(actual: self.detail, expected: castObject.detail)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.detail) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Modifier else { return false } if self.name != rhs.name { return false } if self.detail != rhs.detail { return false } return true } // sourcery:inline:Modifier.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.detail = aDecoder.decode(forKey: "detail") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.detail, forKey: "detail") } // sourcery:end } """), .init(name: "ParserResultsComposed.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation internal struct ParserResultsComposed { private(set) var typeMap = [String: Type]() private(set) var modules = [String: [String: Type]]() private(set) var types = [Type]() let parsedTypes: [Type] let functions: [SourceryMethod] let resolvedTypealiases: [String: Typealias] let associatedTypes: [String: AssociatedType] let unresolvedTypealiases: [String: Typealias] init(parserResult: FileParserResult) { // TODO: This logic should really be more complicated // For any resolution we need to be looking at accessLevel and module boundaries // e.g. there might be a typealias `private typealias Something = MyType` in one module and same name in another with public modifier, one could be accessed and the other could not self.functions = parserResult.functions let aliases = Self.typealiases(parserResult) resolvedTypealiases = aliases.resolved unresolvedTypealiases = aliases.unresolved associatedTypes = Self.extractAssociatedTypes(parserResult) parsedTypes = parserResult.types var moduleAndTypeNameCollisions: Set = [] for type in parsedTypes where !type.isExtension && type.parent == nil { if let module = type.module, type.localName == module { moduleAndTypeNameCollisions.insert(module) } } // set definedInType for all methods and variables parsedTypes .forEach { type in type.variables.forEach { $0.definedInType = type } type.methods.forEach { $0.definedInType = type } type.subscripts.forEach { $0.definedInType = type } } // map all known types to their names for type in parsedTypes where !type.isExtension && type.parent == nil { let name = type.name // If a type name has the `.` prefix, and the type `.` is undefined, we can safely remove the `.` prefix if let module = type.module, name.hasPrefix(module), name.dropFirst(module.count).hasPrefix("."), !moduleAndTypeNameCollisions.contains(module) { type.localName.removeFirst(module.count + 1) } } for type in parsedTypes where !type.isExtension { typeMap[type.globalName] = type if let module = type.module { var typesByModules = modules[module, default: [:]] typesByModules[type.name] = type modules[module] = typesByModules } } /// Resolve typealiases let typealiases = Array(unresolvedTypealiases.values) typealiases.forEach { alias in alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent) } /// Map associated types associatedTypes.forEach { if let globalName = $0.value.type?.globalName, let type = typeMap[globalName] { typeMap[$0.key] = type } else { typeMap[$0.key] = $0.value.type } } types = unifyTypes() } mutating private func resolveExtensionOfNestedType(_ type: Type) { var components = type.localName.components(separatedBy: ".") let rootName: String if type.parent != nil, let module = type.module { rootName = module } else { rootName = components.removeFirst() } if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] { type.localName = baseType.localName type.module = baseType.module type.parent = baseType.parent } else { for _import in type.imports { let parentKey = "\\(rootName).\\(components.joined(separator: "."))" let parentKeyFull = "\\(_import.moduleName).\\(parentKey)" if let moduleTypes = modules[_import.moduleName], let baseType = moduleTypes[parentKey] ?? moduleTypes[parentKeyFull] { type.localName = baseType.localName type.module = baseType.module type.parent = baseType.parent return } } } // Parent extensions should always be processed before `type`, as this affects the globalName of `type`. for parent in type.parentTypes where parent.isExtension && parent.localName.contains(".") { let oldName = parent.globalName resolveExtensionOfNestedType(parent) if oldName != parent.globalName { rewriteChildren(of: parent) } } } // if it had contained types, they might have been fully defined and so their name has to be noted in uniques private mutating func rewriteChildren(of type: Type) { // child is never an extension so no need to check for child in type.containedTypes { typeMap[child.globalName] = child rewriteChildren(of: child) } } private mutating func unifyTypes() -> [Type] { /// Resolve actual names of extensions, as they could have been done on typealias and note updated child names in uniques if needed parsedTypes .filter { $0.isExtension } .forEach { (type: Type) in let oldName = type.globalName if type.localName.contains(".") { resolveExtensionOfNestedType(type) } else if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name { var moduleName: String = "" if let module = type.module { moduleName = "\\(module)." } type.localName = resolved.replacingOccurrences(of: moduleName, with: "") } // nothing left to do guard oldName != type.globalName else { return } rewriteChildren(of: type) } // extend all types with their extensions parsedTypes.forEach { type in let inheritedTypes: [[String]] = type.inheritedTypes.compactMap { inheritedName in if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name { return [resolvedGlobalName] } if let baseType = Composer.findBaseType(for: type, name: inheritedName, typesByName: typeMap) { if let composed = baseType as? ProtocolComposition, let composedTypes = composed.composedTypes { // ignore inheritedTypes when it is a `ProtocolComposition` and composedType is a protocol var combinedTypes = composedTypes.map { $0.globalName } combinedTypes.append(baseType.globalName) return combinedTypes } } return [inheritedName] } type.inheritedTypes = inheritedTypes.flatMap { $0 } let uniqueType: Type? if let mappedType = typeMap[type.globalName] { // this check will only fail on an extension? uniqueType = mappedType } else if let composedNameType = typeFromComposedName(type.name, modules: modules) { // this can happen for an extension on unknown type, this case should probably be handled by the inferTypeNameFromModules uniqueType = composedNameType } else { uniqueType = inferTypeNameFromModules(from: type.localName, containedInType: type.parent, uniqueTypes: typeMap, modules: modules).flatMap { typeMap[$0] } } guard let current = uniqueType else { assert(type.isExtension, "Type \\(type.globalName) should be extension") // for unknown types we still store their extensions but mark them as unknown type.isUnknownExtension = true if let existingType = typeMap[type.globalName] { existingType.extend(type) typeMap[type.globalName] = existingType } else { typeMap[type.globalName] = type } let inheritanceClause = type.inheritedTypes.isEmpty ? "" : ": \\(type.inheritedTypes.joined(separator: ", "))" Log.astWarning("Found \\"extension \\(type.name)\\(inheritanceClause)\\" of type for which there is no original type declaration information.") return } if current == type { return } current.extend(type) typeMap[current.globalName] = current } let values = typeMap.values var processed = Set(minimumCapacity: values.count) return typeMap.values.filter({ let name = $0.globalName let wasProcessed = processed.contains(name) processed.insert(name) return !wasProcessed }) } // extract associated types from all types and add them to types private static func extractAssociatedTypes(_ parserResult: FileParserResult) -> [String: AssociatedType] { parserResult.types .compactMap { $0 as? SourceryProtocol } .map { $0.associatedTypes } .flatMap { $0 }.reduce(into: [:]) { $0[$1.key] = $1.value } } /// returns typealiases map to their full names, with `resolved` removing intermediate /// typealises and `unresolved` including typealiases that reference other typealiases. private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) { var typealiasesByNames = [String: Typealias]() parserResult.typealiases.forEach { typealiasesByNames[$0.name] = $0 } parserResult.types.forEach { type in type.typealiases.forEach({ (_, alias) in // TODO: should I deal with the fact that alias.name depends on type name but typenames might be updated later on // maybe just handle non extension case here and extension aliases after resolving them? typealiasesByNames[alias.name] = alias }) } let unresolved = typealiasesByNames // ! if a typealias leads to another typealias, follow through and replace with final type typealiasesByNames.forEach { _, alias in var aliasNamesToReplace = [alias.name] var finalAlias = alias while let targetAlias = typealiasesByNames[finalAlias.typeName.name] { aliasNamesToReplace.append(targetAlias.name) finalAlias = targetAlias } // ! replace all keys aliasNamesToReplace.forEach { typealiasesByNames[$0] = finalAlias } } return (resolved: typealiasesByNames, unresolved: unresolved) } /// Resolves type identifier for name func resolveGlobalName( for type: String, containingType: Type? = nil, unique: [String: Type]? = nil, modules: [String: [String: Type]], typealiases: [String: Typealias], associatedTypes: [String: AssociatedType] ) -> (name: String, typealias: Typealias?)? { // if the type exists for this name and isn't an extension just return it's name // if it's extension we need to check if there aren't other options TODO: verify if let realType = unique?[type], realType.isExtension == false { return (name: realType.globalName, typealias: nil) } if let alias = typealiases[type] { return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias) } if let associatedType = associatedTypes[type], let actualType = associatedType.type { let typeName = associatedType.typeName ?? TypeName(name: actualType.name) return (name: actualType.globalName, typealias: Typealias(aliasName: type, typeName: typeName)) } if let containingType = containingType { if type == "Self" { return (name: containingType.globalName, typealias: nil) } var currentContainer: Type? = containingType while currentContainer != nil, let parentName = currentContainer?.globalName { /// TODO: no parent for sure? /// manually walk the containment tree if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) { return name } currentContainer = currentContainer?.parent } // if let name = resolveGlobalName(for: "\\(containingType.globalName).\\(type)", containingType: containingType.parent, unique: unique, modules: modules, typealiases: typealiases) { // return name // } // last check it's via module // if let module = containingType.module, let name = resolveGlobalName(for: "\\(module).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) { // return name // } } // TODO: is this needed? if let inferred = inferTypeNameFromModules(from: type, containedInType: containingType, uniqueTypes: unique ?? [:], modules: modules) { return (name: inferred, typealias: nil) } return typeFromComposedName(type, modules: modules).map { (name: $0.globalName, typealias: nil) } } private func inferTypeNameFromModules(from typeIdentifier: String, containedInType: Type?, uniqueTypes: [String: Type], modules: [String: [String: Type]]) -> String? { func fullName(for module: String) -> String { "\\(module).\\(typeIdentifier)" } func type(for module: String) -> Type? { return modules[module]?[typeIdentifier] } func ambiguousErrorMessage(from types: [Type]) -> String? { Log.astWarning("Ambiguous type \\(typeIdentifier), found \\(types.map { $0.globalName }.joined(separator: ", ")). Specify module name at declaration site to disambiguate.") return nil } let explicitModulesAtDeclarationSite: [String] = [ containedInType?.module.map { [$0] } ?? [], // main module for this typename containedInType?.imports.map { $0.moduleName } ?? [] // imported modules ] .flatMap { $0 } let remainingModules = Set(modules.keys).subtracting(explicitModulesAtDeclarationSite) /// We need to check whether we can find type in one of the modules but we need to be careful to avoid amibiguity /// First checking explicit modules available at declaration site (so source module + all imported ones) /// If there is no ambigiuity there we can assume that module will be resolved by the compiler /// If that's not the case we look after remaining modules in the application and if the typename has no ambigiuity we use that /// But if there is more than 1 typename duplication across modules we have no way to resolve what is the compiler going to use so we fail let moduleSetsToCheck: [[String]] = [ explicitModulesAtDeclarationSite, Array(remainingModules) ] for modules in moduleSetsToCheck { let possibleTypes = modules .compactMap { type(for: $0) } if possibleTypes.count > 1 { return ambiguousErrorMessage(from: possibleTypes) } if let type = possibleTypes.first { return type.globalName } } // as last result for unknown types / extensions // try extracting type from unique array if let module = containedInType?.module { return uniqueTypes[fullName(for: module)]?.globalName } return nil } func typeFromComposedName(_ name: String, modules: [String: [String: Type]]) -> Type? { guard name.contains(".") else { return nil } let nameComponents = name.components(separatedBy: ".") let moduleName = nameComponents[0] let typeName = nameComponents.suffix(from: 1).joined(separator: ".") return modules[moduleName]?[typeName] } func resolveType(typeName: TypeName, containingType: Type?, method: Method? = nil) -> Type? { let resolveTypeWithName = { (typeName: TypeName) -> Type? in return self.resolveType(typeName: typeName, containingType: containingType) } let unique = typeMap if let name = typeName.actualTypeName { let resolvedIdentifier = name.generic?.name ?? name.unwrappedTypeName return unique[resolvedIdentifier] } let retrievedName = actualTypeName(for: typeName, containingType: containingType) let lookupName = retrievedName ?? typeName if let tuple = lookupName.tuple { var needsUpdate = false tuple.elements.forEach { tupleElement in tupleElement.type = resolveTypeWithName(tupleElement.typeName) if tupleElement.typeName.actualTypeName != nil { needsUpdate = true } } if needsUpdate || retrievedName != nil { let tupleCopy = TupleType(name: tuple.name, elements: tuple.elements) tupleCopy.elements.forEach { $0.typeName = $0.actualTypeName ?? $0.typeName $0.typeName.actualTypeName = nil } tupleCopy.name = tupleCopy.elements.asTypeName typeName.tuple = tupleCopy // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: tupleCopy.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: tupleCopy, array: lookupName.array, dictionary: lookupName.dictionary, closure: lookupName.closure, set: lookupName.set, generic: lookupName.generic ) } return nil } else if let array = lookupName.array { array.elementType = resolveTypeWithName(array.elementTypeName) if array.elementTypeName.actualTypeName != nil || retrievedName != nil || array.elementType != nil { let array = ArrayType(name: array.name, elementTypeName: array.elementTypeName, elementType: array.elementType) array.elementTypeName = array.elementTypeName.actualTypeName ?? array.elementTypeName array.elementTypeName.actualTypeName = nil array.name = array.asSource typeName.array = array // TODO: really don't like this old behaviour typeName.generic = array.asGeneric // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: array.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: array, dictionary: lookupName.dictionary, closure: lookupName.closure, set: lookupName.set, generic: typeName.generic ) } } else if let dictionary = lookupName.dictionary { dictionary.keyType = resolveTypeWithName(dictionary.keyTypeName) dictionary.valueType = resolveTypeWithName(dictionary.valueTypeName) if dictionary.keyTypeName.actualTypeName != nil || dictionary.valueTypeName.actualTypeName != nil || retrievedName != nil { let dictionary = DictionaryType(name: dictionary.name, valueTypeName: dictionary.valueTypeName, valueType: dictionary.valueType, keyTypeName: dictionary.keyTypeName, keyType: dictionary.keyType) dictionary.keyTypeName = dictionary.keyTypeName.actualTypeName ?? dictionary.keyTypeName dictionary.keyTypeName.actualTypeName = nil // TODO: really don't like this old behaviour dictionary.valueTypeName = dictionary.valueTypeName.actualTypeName ?? dictionary.valueTypeName dictionary.valueTypeName.actualTypeName = nil // TODO: really don't like this old behaviour dictionary.name = dictionary.asSource typeName.dictionary = dictionary // TODO: really don't like this old behaviour typeName.generic = dictionary.asGeneric // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: dictionary.asSource, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, dictionary: dictionary, closure: lookupName.closure, set: lookupName.set, generic: dictionary.asGeneric ) } } else if let closure = lookupName.closure { var needsUpdate = false closure.returnType = resolveTypeWithName(closure.returnTypeName) closure.parameters.forEach { parameter in parameter.type = resolveTypeWithName(parameter.typeName) if parameter.typeName.actualTypeName != nil { needsUpdate = true } } if closure.returnTypeName.actualTypeName != nil || needsUpdate || retrievedName != nil { typeName.closure = closure // TODO: really don't like this old behaviour typeName.actualTypeName = TypeName(name: closure.asSource, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, dictionary: lookupName.dictionary, closure: closure, set: lookupName.set, generic: lookupName.generic ) } return nil } else if let generic = lookupName.generic { var needsUpdate = false generic.typeParameters.forEach { parameter in // Detect if the generic type is local to the method if let method { for genericParameter in method.genericParameters where parameter.typeName.name == genericParameter.name { return } } parameter.type = resolveTypeWithName(parameter.typeName) if parameter.typeName.actualTypeName != nil { needsUpdate = true } } if needsUpdate || retrievedName != nil { let generic = GenericType(name: generic.name, typeParameters: generic.typeParameters) generic.typeParameters.forEach { $0.typeName = $0.typeName.actualTypeName ?? $0.typeName $0.typeName.actualTypeName = nil // TODO: really don't like this old behaviour } typeName.generic = generic // TODO: really don't like this old behaviour typeName.array = lookupName.array // TODO: really don't like this old behaviour typeName.dictionary = lookupName.dictionary // TODO: really don't like this old behaviour let params = generic.typeParameters.map { $0.typeName.asSource }.joined(separator: ", ") typeName.actualTypeName = TypeName(name: "\\(generic.name)<\\(params)>", isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: lookupName.tuple, array: lookupName.array, // TODO: asArray dictionary: lookupName.dictionary, // TODO: asDictionary closure: lookupName.closure, set: lookupName.set, generic: generic ) } } if let aliasedName = (typeName.actualTypeName ?? retrievedName), aliasedName.unwrappedTypeName != typeName.unwrappedTypeName { typeName.actualTypeName = aliasedName } let hasGenericRequirements = containingType?.genericRequirements.isEmpty == false || (method != nil && method?.genericRequirements.isEmpty == false) if hasGenericRequirements { // we should consider if we are looking up return type of a method with generic constraints // where `typeName` passed would include `... where ...` suffix let typeNameForLookup = typeName.name.split(separator: " ").first! let genericRequirements: [GenericRequirement] if let requirements = containingType?.genericRequirements, !requirements.isEmpty { genericRequirements = requirements } else { genericRequirements = method?.genericRequirements ?? [] } let relevantRequirements = genericRequirements.filter { // matched type against a generic requirement name // thus type should be replaced with a protocol composition $0.leftType.name == typeNameForLookup } if relevantRequirements.count > 1 { // compose protocols into `ProtocolComposition` and generate TypeName var implements: [String: Type] = [:] relevantRequirements.forEach { implements[$0.rightType.typeName.name] = $0.rightType.type } let composedProtocols = ProtocolComposition( inheritedTypes: relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }, isGeneric: true, composedTypes: relevantRequirements.compactMap { $0.rightType.type }, implements: implements ) typeName.actualTypeName = TypeName(name: "(\\(relevantRequirements.map { $0.rightType.typeName.unwrappedTypeName }.joined(separator: " & ")))", isProtocolComposition: true) return composedProtocols } else if let protocolRequirement = relevantRequirements.first { // create TypeName off a single generic's protocol requirement typeName.actualTypeName = TypeName(name: "(\\(protocolRequirement.rightType.typeName))") return protocolRequirement.rightType.type } } // try to peek into typealias, maybe part of the typeName is a composed identifier from a type and typealias // i.e. // enum Module { // typealias ID = MyView // } // class MyView { // class ID: String {} // } // // let variable: Module.ID.ID // should be resolved as MyView.ID type let finalLookup = typeName.actualTypeName ?? typeName var resolvedIdentifier = finalLookup.generic?.name ?? finalLookup.unwrappedTypeName if let type = unique[resolvedIdentifier] { return type } for alias in resolvedTypealiases { /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested if resolvedIdentifier.contains(alias.value.name), let range = resolvedIdentifier.range(of: alias.value.name) { resolvedIdentifier = resolvedIdentifier.replacingCharacters(in: range, with: alias.value.typeName.name) } } // should we cache resolved typenames? if unique[resolvedIdentifier] == nil { // peek into typealiases, if any of them contain the same typeName // this is done after the initial attempt in order to prioritise local (recognized) types first // before even trying to substitute the requested type with any typealias for alias in resolvedTypealiases { /// iteratively replace all typealiases from the resolvedIdentifier to get to the actual type name requested, /// ignoring namespacing if resolvedIdentifier == alias.value.aliasName { resolvedIdentifier = alias.value.typeName.name typeName.actualTypeName = alias.value.typeName break } } } if let associatedType = associatedTypes[resolvedIdentifier] { return associatedType.type } return unique[resolvedIdentifier] ?? unique[typeName.name] } private func actualTypeName(for typeName: TypeName, containingType: Type? = nil) -> TypeName? { let unique = typeMap let typealiases = resolvedTypealiases let associatedTypes = associatedTypes var unwrapped = typeName.unwrappedTypeName if let generic = typeName.generic { unwrapped = generic.name } else if let type = associatedTypes[unwrapped] { unwrapped = type.name } guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) else { return nil } /// TODO: verify let generic = typeName.generic.map { GenericType(name: $0.name, typeParameters: $0.typeParameters) } generic?.name = aliased.name let dictionary = typeName.dictionary.map { DictionaryType(name: $0.name, valueTypeName: $0.valueTypeName, valueType: $0.valueType, keyTypeName: $0.keyTypeName, keyType: $0.keyType) } dictionary?.name = aliased.name let array = typeName.array.map { ArrayType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } array?.name = aliased.name let set = typeName.set.map { SetType(name: $0.name, elementTypeName: $0.elementTypeName, elementType: $0.elementType) } set?.name = aliased.name return TypeName(name: aliased.name, isOptional: typeName.isOptional, isImplicitlyUnwrappedOptional: typeName.isImplicitlyUnwrappedOptional, tuple: aliased.typealias?.typeName.tuple ?? typeName.tuple, // TODO: verify array: aliased.typealias?.typeName.array ?? array, dictionary: aliased.typealias?.typeName.dictionary ?? dictionary, closure: aliased.typealias?.typeName.closure ?? typeName.closure, set: aliased.typealias?.typeName.set ?? set, generic: aliased.typealias?.typeName.generic ?? generic ) } } """), .init(name: "PhantomProtocols.swift", content: """ // // Created by Krzysztof Zablocki on 23/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation /// Phantom protocol for diffing protocol AutoDiffable {} /// Phantom protocol for equality protocol AutoEquatable {} /// Phantom protocol for equality protocol AutoDescription {} /// Phantom protocol for NSCoding protocol AutoCoding {} protocol AutoJSExport {} /// Phantom protocol for NSCoding, Equatable and Diffable protocol SourceryModelWithoutDescription: AutoDiffable, AutoEquatable, AutoCoding, AutoJSExport {} protocol SourceryModel: SourceryModelWithoutDescription, AutoDescription {} """), .init(name: "Protocol.swift", content: """ // // Protocol.swift // Sourcery // // Created by Krzysztof Zablocki on 09/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation #if canImport(ObjectiveC) /// :nodoc: public typealias SourceryProtocol = Protocol /// Describes Swift protocol @objcMembers public final class Protocol: Type { // sourcery: skipJSExport public class var kind: String { return "protocol" } /// Returns "protocol" public override var kind: String { Self.kind } /// list of all declared associated types with their names as keys public var associatedTypes: [String: AssociatedType] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } // sourcery: skipCoding /// list of generic requirements public override var genericRequirements: [GenericRequirement] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], associatedTypes: [String: AssociatedType] = [:], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], implements: [String: Type] = [:], kind: String = Protocol.kind) { self.associatedTypes = associatedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("associatedTypes = \\(String(describing: self.associatedTypes)), ") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Protocol else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.associatedTypes) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Protocol else { return false } if self.associatedTypes != rhs.associatedTypes { return false } return super.isEqual(rhs) } // sourcery:inline:Protocol.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { withVaList(["associatedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedTypes = associatedTypes super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.associatedTypes, forKey: "associatedTypes") } // sourcery:end } #endif """), .init(name: "ProtocolComposition.swift", content: """ // Created by eric_horacek on 2/12/20. // Copyright © 2020 Airbnb Inc. All rights reserved. import Foundation /// Describes a Swift [protocol composition](https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454). #if canImport(ObjectiveC) @objcMembers #endif public final class ProtocolComposition: Type { // sourcery: skipJSExport public class var kind: String { return "protocolComposition" } /// Returns "protocolComposition" public override var kind: String { Self.kind } /// The names of the types composed to form this composition public let composedTypeNames: [TypeName] // sourcery: skipEquality, skipDescription /// The types composed to form this composition, if known public var composedTypes: [Type]? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], annotations: [String: NSObject] = [:], isGeneric: Bool = false, composedTypeNames: [TypeName] = [], composedTypes: [Type]? = nil, implements: [String: Type] = [:], kind: String = ProtocolComposition.kind) { self.composedTypeNames = composedTypeNames self.composedTypes = composedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, annotations: annotations, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " string += "kind = \\(String(describing: self.kind)), " string += "composedTypeNames = \\(String(describing: self.composedTypeNames))" return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ProtocolComposition else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "composedTypeNames").trackDifference(actual: self.composedTypeNames, expected: castObject.composedTypeNames)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.composedTypeNames) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ProtocolComposition else { return false } if self.composedTypeNames != rhs.composedTypeNames { return false } return super.isEqual(rhs) } // sourcery:inline:ProtocolComposition.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let composedTypeNames: [TypeName] = aDecoder.decode(forKey: "composedTypeNames") else { withVaList(["composedTypeNames"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.composedTypeNames = composedTypeNames self.composedTypes = aDecoder.decode(forKey: "composedTypes") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.composedTypeNames, forKey: "composedTypeNames") aCoder.encode(self.composedTypes, forKey: "composedTypes") } // sourcery:end } """), .init(name: "Set.swift", content: """ import Foundation /// Describes set type #if canImport(ObjectiveC) @objcMembers #endif public final class SetType: NSObject, SourceryModel, Diffable { /// Type name used in declaration public var name: String /// Array element type name public var elementTypeName: TypeName // sourcery: skipEquality, skipDescription /// Array element type, if known public var elementType: Type? /// :nodoc: public init(name: String, elementTypeName: TypeName, elementType: Type? = nil) { self.name = name self.elementTypeName = elementTypeName self.elementType = elementType } /// Returns array as generic type public var asGeneric: GenericType { GenericType(name: "Set", typeParameters: [ .init(typeName: elementTypeName) ]) } public var asSource: String { "[\\(elementTypeName.asSource)]" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("elementTypeName = \\(String(describing: self.elementTypeName)), ") string.append("asGeneric = \\(String(describing: self.asGeneric)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? SetType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elementTypeName").trackDifference(actual: self.elementTypeName, expected: castObject.elementTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elementTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? SetType else { return false } if self.name != rhs.name { return false } if self.elementTypeName != rhs.elementTypeName { return false } return true } // sourcery:inline:SetType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elementTypeName: TypeName = aDecoder.decode(forKey: "elementTypeName") else { withVaList(["elementTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elementTypeName = elementTypeName self.elementType = aDecoder.decode(forKey: "elementType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elementTypeName, forKey: "elementTypeName") aCoder.encode(self.elementType, forKey: "elementType") } // sourcery:end } """), .init(name: "Struct.swift", content: """ // // Struct.swift // Sourcery // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation // sourcery: skipDescription /// Describes Swift struct #if canImport(ObjectiveC) @objcMembers #endif public final class Struct: Type { // sourcery: skipJSExport public class var kind: String { return "struct" } /// Returns "struct" public override var kind: String { Self.kind } /// :nodoc: public override init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = Struct.kind) { super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string += ", " string += "kind = \\(String(describing: self.kind))" return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Struct else { results.append("Incorrect type ") return results } results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Struct else { return false } return super.isEqual(rhs) } // sourcery:inline:Struct.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) } // sourcery:end } """), .init(name: "TemplateContext.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation /// :nodoc: // sourcery: skipCoding #if canImport(ObjectiveC) @objcMembers #endif public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable { // sourcery: skipJSExport public let parserResult: FileParserResult? public let functions: [SourceryMethod] public let types: Types public let argument: [String: NSObject] // sourcery: skipDescription public var type: [String: Type] { return types.typesByName } public init(parserResult: FileParserResult?, types: Types, functions: [SourceryMethod], arguments: [String: NSObject]) { self.parserResult = parserResult self.types = types self.functions = functions self.argument = arguments } /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parserResult: FileParserResult = aDecoder.decode(forKey: "parserResult") else { withVaList(["parserResult"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found. FileParserResults are required for template context that needs persisting.", arguments: arguments) } fatalError() } guard let argument: [String: NSObject] = aDecoder.decode(forKey: "argument") else { withVaList(["argument"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() } // if we want to support multiple cycles of encode / decode we need deep copy because composer changes reference types let fileParserResultCopy: FileParserResult? = nil // fileParserResultCopy = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: parserResult)) as? FileParserResult let composed = Composer.uniqueTypesAndFunctions(parserResult, serial: false) self.types = .init(types: composed.types, typealiases: composed.typealiases) self.functions = composed.functions self.parserResult = fileParserResultCopy self.argument = argument } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parserResult, forKey: "parserResult") aCoder.encode(self.argument, forKey: "argument") } public var stencilContext: [String: Any] { return [ "types": types, "functions": functions, "type": types.typesByName, "argument": argument ] } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("parserResult = \\(String(describing: self.parserResult)), ") string.append("functions = \\(String(describing: self.functions)), ") string.append("types = \\(String(describing: self.types)), ") string.append("argument = \\(String(describing: self.argument)), ") string.append("stencilContext = \\(String(describing: self.stencilContext))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TemplateContext else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parserResult").trackDifference(actual: self.parserResult, expected: castObject.parserResult)) results.append(contentsOf: DiffableResult(identifier: "functions").trackDifference(actual: self.functions, expected: castObject.functions)) results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "argument").trackDifference(actual: self.argument, expected: castObject.argument)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parserResult) hasher.combine(self.functions) hasher.combine(self.types) hasher.combine(self.argument) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TemplateContext else { return false } if self.parserResult != rhs.parserResult { return false } if self.functions != rhs.functions { return false } if self.types != rhs.types { return false } if self.argument != rhs.argument { return false } return true } // sourcery: skipDescription, skipEquality public var jsContext: [String: Any] { return [ "types": [ "all": types.all, "protocols": types.protocols, "classes": types.classes, "structs": types.structs, "enums": types.enums, "extensions": types.extensions, "based": types.based, "inheriting": types.inheriting, "implementing": types.implementing, "protocolCompositions": types.protocolCompositions, "typealiases": types.typealiases ] as [String : Any], "functions": functions, "type": types.typesByName, "argument": argument ] } } extension ProcessInfo { /// :nodoc: public var context: TemplateContext! { return NSKeyedUnarchiver.unarchiveObject(withFile: arguments[1]) as? TemplateContext } } """), .init(name: "Typealias.swift", content: """ import Foundation /// :nodoc: #if canImport(ObjectiveC) @objcMembers #endif public final class Typealias: NSObject, Typed, SourceryModel, Diffable { // New typealias name public let aliasName: String // Target name public let typeName: TypeName // sourcery: skipEquality, skipDescription public var type: Type? /// module in which this typealias was declared public var module: String? /// Imports that existed in the file that contained this typealias declaration public var imports: [Import] = [] /// typealias annotations public var annotations: Annotations = [:] /// typealias documentation public var documentation: Documentation = [] // sourcery: skipEquality, skipDescription public var parent: Type? { didSet { parentName = parent?.name } } /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String var parentName: String? public var name: String { if let parentName = parent?.name { return "\\(module != nil ? "\\(module!)." : "")\\(parentName).\\(aliasName)" } else { return "\\(module != nil ? "\\(module!)." : "")\\(aliasName)" } } public init(aliasName: String = "", typeName: TypeName, accessLevel: AccessLevel = .internal, parent: Type? = nil, module: String? = nil, annotations: [String: NSObject] = [:], documentation: [String] = []) { self.aliasName = aliasName self.typeName = typeName self.accessLevel = accessLevel.rawValue self.parent = parent self.parentName = parent?.name self.module = module self.annotations = annotations self.documentation = documentation } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("aliasName = \\(String(describing: self.aliasName)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("module = \\(String(describing: self.module)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("parentName = \\(String(describing: self.parentName)), ") string.append("name = \\(String(describing: self.name)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Typealias else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "aliasName").trackDifference(actual: self.aliasName, expected: castObject.aliasName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.aliasName) hasher.combine(self.typeName) hasher.combine(self.module) hasher.combine(self.accessLevel) hasher.combine(self.parentName) hasher.combine(self.annotations) hasher.combine(self.documentation) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Typealias else { return false } if self.aliasName != rhs.aliasName { return false } if self.typeName != rhs.typeName { return false } if self.module != rhs.module { return false } if self.accessLevel != rhs.accessLevel { return false } if self.parentName != rhs.parentName { return false } if self.documentation != rhs.documentation { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:Typealias.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let aliasName: String = aDecoder.decode(forKey: "aliasName") else { withVaList(["aliasName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.aliasName = aliasName guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.parent = aDecoder.decode(forKey: "parent") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.parentName = aDecoder.decode(forKey: "parentName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.aliasName, forKey: "aliasName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.parentName, forKey: "parentName") } // sourcery:end } """), .init(name: "Typed.swift", content: """ import Foundation /// Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value public protocol Typed { // sourcery: skipEquality, skipDescription /// Type, if known var type: Type? { get } // sourcery: skipEquality, skipDescription /// Type name var typeName: TypeName { get } // sourcery: skipEquality, skipDescription /// Whether type is optional var isOptional: Bool { get } // sourcery: skipEquality, skipDescription /// Whether type is implicitly unwrapped optional var isImplicitlyUnwrappedOptional: Bool { get } // sourcery: skipEquality, skipDescription /// Type name without attributes and optional type information var unwrappedTypeName: String { get } } """), .init(name: "AssociatedType_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Describes Swift AssociatedType public final class AssociatedType: NSObject, SourceryModel, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "typeName": return typeName case "type": return type default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Associated type name public let name: String /// Associated type type constraint name, if specified public let typeName: TypeName? // sourcery: skipEquality, skipDescription /// Associated type constrained type, if known, i.e. if the type is declared in the scanned sources. public var type: Type? /// :nodoc: public init(name: String, typeName: TypeName? = nil, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedType else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:AssociatedType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.typeName = aDecoder.decode(forKey: "typeName") self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif """), .init(name: "AssociatedValue_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Defines enum case associated value public final class AssociatedValue: NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "externalName": return externalName case "localName": return localName case "typeName": return typeName case "type": return type case "defaultValue": return defaultValue case "annotations": return annotations case "isArray": return isArray case "isClosure": return isClosure case "isDictionary": return isDictionary case "isTuple": return isTuple case "isOptional": return isOptional case "isImplicitlyUnwrappedOptional": return isImplicitlyUnwrappedOptional case "isGeneric": return typeName.isGeneric default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Associated value local name. /// This is a name to be used to construct enum case value public let localName: String? /// Associated value external name. /// This is a name to be used to access value in value-bindig public let externalName: String? /// Associated value type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Associated value type, if known public var type: Type? /// Associated value default value public let defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(localName: String?, externalName: String?, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.localName = localName self.externalName = externalName self.typeName = typeName self.type = type self.defaultValue = defaultValue self.annotations = annotations } convenience init(name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:]) { self.init(localName: name, externalName: name, typeName: typeName, type: type, defaultValue: defaultValue, annotations: annotations) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("localName = \\(String(describing: self.localName)), ") string.append("externalName = \\(String(describing: self.externalName)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? AssociatedValue else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "externalName").trackDifference(actual: self.externalName, expected: castObject.externalName)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.localName) hasher.combine(self.externalName) hasher.combine(self.typeName) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? AssociatedValue else { return false } if self.localName != rhs.localName { return false } if self.externalName != rhs.externalName { return false } if self.typeName != rhs.typeName { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:AssociatedValue.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.localName = aDecoder.decode(forKey: "localName") self.externalName = aDecoder.decode(forKey: "externalName") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.externalName, forKey: "externalName") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } #endif """), .init(name: "ClosureParameter_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation // sourcery: skipDiffing public final class ClosureParameter: NSObject, SourceryModel, Typed, Annotated, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "argumentLabel": return argumentLabel case "name": return name case "typeName": return typeName case "inout": return `inout` case "type": return type case "isVariadic": return isVariadic case "defaultValue": return defaultValue default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Parameter external name public var argumentLabel: String? /// Parameter internal name public let name: String? /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter if the argument has a variadic type or not public let isVariadic: Bool /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// :nodoc: public init(argumentLabel: String? = nil, name: String? = nil, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let typeInfo = "\\(`inout` ? "inout " : "")\\(typeName.asSource)\\(isVariadic ? "..." : "")" if argumentLabel?.nilIfNotValidParameterName == nil, name?.nilIfNotValidParameterName == nil { return typeInfo } let typeSuffix = ": \\(typeInfo)" guard argumentLabel != name else { return name ?? "" + typeSuffix } let labels = [argumentLabel ?? "_", name?.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("`inout` = \\(String(describing: self.`inout`)), ") string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:ClosureParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.type = aDecoder.decode(forKey: "type") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") } // sourcery:end } extension Array where Element == ClosureParameter { public var asSource: String { "(\\(map { $0.asSource }.joined(separator: ", ")))" } } #endif """), .init(name: "Closure_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Describes closure type public final class ClosureType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "parameters": return parameters case "returnTypeName": return returnTypeName case "actualReturnTypeName": return actualReturnTypeName case "returnType": return returnType case "isOptionalReturnType": return isOptionalReturnType case "isImplicitlyUnwrappedOptionalReturnType": return isImplicitlyUnwrappedOptionalReturnType case "unwrappedReturnTypeName": return unwrappedReturnTypeName case "isAsync": return isAsync case "asyncKeyword": return asyncKeyword case "throws": return `throws` case "throwsOrRethrowsKeyword": return throwsOrRethrowsKeyword case "throwsTypeName": return throwsTypeName default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Type name used in declaration with stripped whitespaces and new lines public let name: String /// List of closure parameters public let parameters: [ClosureParameter] /// Return value type name public let returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// async keyword public let asyncKeyword: String? /// Whether closure throws public let `throws`: Bool /// throws or rethrows keyword public let throwsOrRethrowsKeyword: String? /// Type of thrown error if specified public let throwsTypeName: TypeName? /// :nodoc: public init(name: String, parameters: [ClosureParameter], returnTypeName: TypeName, returnType: Type? = nil, asyncKeyword: String? = nil, throwsOrRethrowsKeyword: String? = nil, throwsTypeName: TypeName? = nil) { self.name = name self.parameters = parameters self.returnTypeName = returnTypeName self.returnType = returnType self.asyncKeyword = asyncKeyword self.isAsync = asyncKeyword != nil self.throwsOrRethrowsKeyword = throwsOrRethrowsKeyword self.`throws` = throwsOrRethrowsKeyword != nil && !(throwsTypeName?.isNever ?? false) self.throwsTypeName = throwsTypeName } public var asSource: String { "\\(parameters.asSource)\\(asyncKeyword != nil ? " \\(asyncKeyword!)" : "")\\(throwsOrRethrowsKeyword != nil ? " \\(throwsOrRethrowsKeyword!)\\(throwsTypeName != nil ? "(\\(throwsTypeName!.asSource))" : "")" : "") -> \\(returnTypeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("parameters = \\(String(describing: self.parameters)), ") string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("asyncKeyword = \\(String(describing: self.asyncKeyword)), ") string.append("`throws` = \\(String(describing: self.`throws`)), ") string.append("throwsOrRethrowsKeyword = \\(String(describing: self.throwsOrRethrowsKeyword)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? ClosureType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "asyncKeyword").trackDifference(actual: self.asyncKeyword, expected: castObject.asyncKeyword)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsOrRethrowsKeyword").trackDifference(actual: self.throwsOrRethrowsKeyword, expected: castObject.throwsOrRethrowsKeyword)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.asyncKeyword) hasher.combine(self.`throws`) hasher.combine(self.throwsOrRethrowsKeyword) hasher.combine(self.throwsTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? ClosureType else { return false } if self.name != rhs.name { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.asyncKeyword != rhs.asyncKeyword { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsOrRethrowsKeyword != rhs.throwsOrRethrowsKeyword { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } return true } // sourcery:inline:ClosureType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let parameters: [ClosureParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.asyncKeyword = aDecoder.decode(forKey: "asyncKeyword") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsOrRethrowsKeyword = aDecoder.decode(forKey: "throwsOrRethrowsKeyword") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.asyncKeyword, forKey: "asyncKeyword") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsOrRethrowsKeyword, forKey: "throwsOrRethrowsKeyword") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") } // sourcery:end } #endif """), .init(name: "DynamicMemberLookup_Linux.swift", content: """ // // Stencil // Copyright © 2022 Stencil // MIT Licence // #if !canImport(ObjectiveC) #if canImport(Stencil) import Stencil #else // This is not supposed to work at all, since in Stencil there is a protocol conformance check against `DynamicMemberLookup`, // and, of course, a substitute with the "same name" but in `Sourcery` will never satisfy that check. // Here, we are just mimicking `Stencil.DynamicMemberLookup` to showcase what is happening within the `Sourcery` during runtime. /// Marker protocol so we can know which types support `@dynamicMemberLookup`. Add this to your own types that support /// lookup by String. public protocol DynamicMemberLookup { /// Get a value for a given `String` key subscript(dynamicMember member: String) -> Any? { get } } public extension DynamicMemberLookup where Self: RawRepresentable { /// Get a value for a given `String` key subscript(dynamicMember member: String) -> Any? { switch member { case "rawValue": return rawValue default: return nil } } } #endif public protocol SourceryDynamicMemberLookup: DynamicMemberLookup {} #endif """), .init(name: "EnumCase_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Defines enum case public final class EnumCase: NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "hasAssociatedValue": return hasAssociatedValue case "associatedValues": return associatedValues case "indirect": return indirect case "annotations": return annotations case "rawValue": return rawValue default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Enum case name public let name: String /// Enum case raw value, if any public let rawValue: String? /// Enum case associated values public let associatedValues: [AssociatedValue] /// Enum case annotations public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Whether enum case is indirect public let indirect: Bool /// Whether enum case has associated value public var hasAssociatedValue: Bool { return !associatedValues.isEmpty } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(name: String, rawValue: String? = nil, associatedValues: [AssociatedValue] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], indirect: Bool = false) { self.name = name self.rawValue = rawValue self.associatedValues = associatedValues self.annotations = annotations self.documentation = documentation self.indirect = indirect } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("rawValue = \\(String(describing: self.rawValue)), ") string.append("associatedValues = \\(String(describing: self.associatedValues)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("indirect = \\(String(describing: self.indirect)), ") string.append("hasAssociatedValue = \\(String(describing: self.hasAssociatedValue))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? EnumCase else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "rawValue").trackDifference(actual: self.rawValue, expected: castObject.rawValue)) results.append(contentsOf: DiffableResult(identifier: "associatedValues").trackDifference(actual: self.associatedValues, expected: castObject.associatedValues)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "indirect").trackDifference(actual: self.indirect, expected: castObject.indirect)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.rawValue) hasher.combine(self.associatedValues) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.indirect) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? EnumCase else { return false } if self.name != rhs.name { return false } if self.rawValue != rhs.rawValue { return false } if self.associatedValues != rhs.associatedValues { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.indirect != rhs.indirect { return false } return true } // sourcery:inline:EnumCase.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.rawValue = aDecoder.decode(forKey: "rawValue") guard let associatedValues: [AssociatedValue] = aDecoder.decode(forKey: "associatedValues") else { withVaList(["associatedValues"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedValues = associatedValues guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.indirect = aDecoder.decode(forKey: "indirect") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.rawValue, forKey: "rawValue") aCoder.encode(self.associatedValues, forKey: "associatedValues") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.indirect, forKey: "indirect") } // sourcery:end } #endif """), .init(name: "Enum_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Defines Swift enum public final class Enum: Type { public override subscript(dynamicMember member: String) -> Any? { switch member { case "cases": return cases case "hasAssociatedValues": return hasAssociatedValues default: return super[dynamicMember: member] } } // sourcery: skipJSExport public class var kind: String { return "enum" } // sourcery: skipDescription /// Returns "enum" public override var kind: String { Self.kind } /// Enum cases public var cases: [EnumCase] /** Enum raw value type name, if any. This type is removed from enum's `based` and `inherited` types collections. - important: Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. So if your enum does not have raw value but implements protocols you'll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types. */ public var rawTypeName: TypeName? { didSet { if let rawTypeName = rawTypeName { hasRawType = true if let index = inheritedTypes.firstIndex(of: rawTypeName.name) { inheritedTypes.remove(at: index) } if based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } else { hasRawType = false } } } // sourcery: skipDescription, skipEquality /// :nodoc: public private(set) var hasRawType: Bool // sourcery: skipDescription, skipEquality /// Enum raw value type, if known public var rawType: Type? // sourcery: skipEquality, skipDescription, skipCoding /// Names of types or protocols this type inherits from, including unknown (not scanned) types public override var based: [String: String] { didSet { if let rawTypeName = rawTypeName, based[rawTypeName.name] != nil { based[rawTypeName.name] = nil } } } /// Whether enum contains any associated values public var hasAssociatedValues: Bool { return cases.contains(where: { $0.hasAssociatedValue }) } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, inheritedTypes: [String] = [], rawTypeName: TypeName? = nil, cases: [EnumCase] = [], variables: [Variable] = [], methods: [Method] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false) { self.cases = cases self.rawTypeName = rawTypeName self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind) if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) { self.inheritedTypes.remove(at: index) } } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("cases = \\(String(describing: self.cases)), ") string.append("rawTypeName = \\(String(describing: self.rawTypeName)), ") string.append("hasAssociatedValues = \\(String(describing: self.hasAssociatedValues))") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Enum else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "cases").trackDifference(actual: self.cases, expected: castObject.cases)) results.append(contentsOf: DiffableResult(identifier: "rawTypeName").trackDifference(actual: self.rawTypeName, expected: castObject.rawTypeName)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.cases) hasher.combine(self.rawTypeName) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Enum else { return false } if self.cases != rhs.cases { return false } if self.rawTypeName != rhs.rawTypeName { return false } return super.isEqual(rhs) } // sourcery:inline:Enum.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let cases: [EnumCase] = aDecoder.decode(forKey: "cases") else { withVaList(["cases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.cases = cases self.rawTypeName = aDecoder.decode(forKey: "rawTypeName") self.hasRawType = aDecoder.decode(forKey: "hasRawType") self.rawType = aDecoder.decode(forKey: "rawType") super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.cases, forKey: "cases") aCoder.encode(self.rawTypeName, forKey: "rawTypeName") aCoder.encode(self.hasRawType, forKey: "hasRawType") aCoder.encode(self.rawType, forKey: "rawType") } // sourcery:end } #endif """), .init(name: "GenericParameter_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Descibes Swift generic parameter public final class GenericParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "inheritedTypeName": return inheritedTypeName default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Generic parameter name public var name: String /// Generic parameter inherited type public var inheritedTypeName: TypeName? /// :nodoc: public init(name: String, inheritedTypeName: TypeName? = nil) { self.name = name self.inheritedTypeName = inheritedTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("inheritedTypeName = \\(String(describing: self.inheritedTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypeName").trackDifference(actual: self.inheritedTypeName, expected: castObject.inheritedTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.inheritedTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericParameter else { return false } if self.name != rhs.name { return false } if self.inheritedTypeName != rhs.inheritedTypeName { return false } return true } // sourcery:inline:GenericParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.inheritedTypeName = aDecoder.decode(forKey: "inheritedTypeName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.inheritedTypeName, forKey: "inheritedTypeName") } // sourcery:end } #endif """), .init(name: "GenericRequirement_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Descibes Swift generic requirement public class GenericRequirement: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "leftType": return leftType case "rightType": return rightType case "relationship": return relationship case "relationshipSyntax": return relationshipSyntax default: fatalError("unable to lookup: \\(member) in \\(self)") } } public enum Relationship: String { case equals case conformsTo var syntax: String { switch self { case .equals: return "==" case .conformsTo: return ":" } } } public var leftType: AssociatedType public let rightType: GenericTypeParameter /// relationship name public let relationship: String /// Syntax e.g. `==` or `:` public let relationshipSyntax: String public init(leftType: AssociatedType, rightType: GenericTypeParameter, relationship: Relationship) { self.leftType = leftType self.rightType = rightType self.relationship = relationship.rawValue self.relationshipSyntax = relationship.syntax } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("leftType = \\(String(describing: self.leftType)), ") string.append("rightType = \\(String(describing: self.rightType)), ") string.append("relationship = \\(String(describing: self.relationship)), ") string.append("relationshipSyntax = \\(String(describing: self.relationshipSyntax))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericRequirement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "leftType").trackDifference(actual: self.leftType, expected: castObject.leftType)) results.append(contentsOf: DiffableResult(identifier: "rightType").trackDifference(actual: self.rightType, expected: castObject.rightType)) results.append(contentsOf: DiffableResult(identifier: "relationship").trackDifference(actual: self.relationship, expected: castObject.relationship)) results.append(contentsOf: DiffableResult(identifier: "relationshipSyntax").trackDifference(actual: self.relationshipSyntax, expected: castObject.relationshipSyntax)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.leftType) hasher.combine(self.rightType) hasher.combine(self.relationship) hasher.combine(self.relationshipSyntax) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericRequirement else { return false } if self.leftType != rhs.leftType { return false } if self.rightType != rhs.rightType { return false } if self.relationship != rhs.relationship { return false } if self.relationshipSyntax != rhs.relationshipSyntax { return false } return true } // sourcery:inline:GenericRequirement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let leftType: AssociatedType = aDecoder.decode(forKey: "leftType") else { withVaList(["leftType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.leftType = leftType guard let rightType: GenericTypeParameter = aDecoder.decode(forKey: "rightType") else { withVaList(["rightType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rightType = rightType guard let relationship: String = aDecoder.decode(forKey: "relationship") else { withVaList(["relationship"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationship = relationship guard let relationshipSyntax: String = aDecoder.decode(forKey: "relationshipSyntax") else { withVaList(["relationshipSyntax"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.relationshipSyntax = relationshipSyntax } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.leftType, forKey: "leftType") aCoder.encode(self.rightType, forKey: "rightType") aCoder.encode(self.relationship, forKey: "relationship") aCoder.encode(self.relationshipSyntax, forKey: "relationshipSyntax") } // sourcery:end } #endif """), .init(name: "GenericTypeParameter_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Descibes Swift generic type parameter public final class GenericTypeParameter: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "typeName": return typeName case "type": return type default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Generic parameter type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Generic parameter type, if known public var type: Type? /// :nodoc: public init(typeName: TypeName, type: Type? = nil) { self.typeName = typeName self.type = type } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("typeName = \\(String(describing: self.typeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? GenericTypeParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? GenericTypeParameter else { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:GenericTypeParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } #endif """), .init(name: "MethodParameter_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Describes method parameter public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "argumentLabel": return argumentLabel case "name": return name case "typeName": return typeName case "isClosure": return isClosure case "typeAttributes": return typeAttributes case "isVariadic": return isVariadic case "asSource": return asSource case "index": return index case "isOptional": return isOptional default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Parameter external name public var argumentLabel: String? // Note: although method parameter can have no name, this property is not optional, // this is so to maintain compatibility with existing templates. /// Parameter internal name public let name: String /// Parameter type name public let typeName: TypeName /// Parameter flag whether it's inout or not public let `inout`: Bool /// Is this variadic parameter? public let isVariadic: Bool // sourcery: skipEquality, skipDescription /// Parameter type, if known public var type: Type? /// Parameter type attributes, i.e. `@escaping` public var typeAttributes: AttributeList { return typeName.attributes } /// Method parameter default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] /// Method parameter index in the argument list public var index: Int /// :nodoc: public init(argumentLabel: String?, name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = argumentLabel self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } /// :nodoc: public init(name: String = "", index: Int, typeName: TypeName, type: Type? = nil, defaultValue: String? = nil, annotations: [String: NSObject] = [:], isInout: Bool = false, isVariadic: Bool = false) { self.typeName = typeName self.argumentLabel = name self.name = name self.index = index self.type = type self.defaultValue = defaultValue self.annotations = annotations self.`inout` = isInout self.isVariadic = isVariadic } public var asSource: String { let values: String = defaultValue.map { " = \\($0)" } ?? "" let variadicity: String = isVariadic ? "..." : "" let inoutness: String = `inout` ? "inout " : "" let typeSuffix = ": \\(inoutness)\\(typeName.asSource)\\(values)\\(variadicity)" guard argumentLabel != name else { return name + typeSuffix } let labels = [argumentLabel ?? "_", name.nilIfEmpty] .compactMap { $0 } .joined(separator: " ") return (labels.nilIfEmpty ?? "_") + typeSuffix } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("argumentLabel = \\(String(describing: self.argumentLabel)), ") string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("`inout` = \\(String(describing: self.`inout`)), ") string.append("isVariadic = \\(String(describing: self.isVariadic)), ") string.append("typeAttributes = \\(String(describing: self.typeAttributes)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("asSource = \\(String(describing: self.asSource)), ") string.append("index = \\(String(describing: self.index))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? MethodParameter else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "argumentLabel").trackDifference(actual: self.argumentLabel, expected: castObject.argumentLabel)) results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "`inout`").trackDifference(actual: self.`inout`, expected: castObject.`inout`)) results.append(contentsOf: DiffableResult(identifier: "isVariadic").trackDifference(actual: self.isVariadic, expected: castObject.isVariadic)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "index").trackDifference(actual: self.index, expected: castObject.index)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.argumentLabel) hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.`inout`) hasher.combine(self.isVariadic) hasher.combine(self.defaultValue) hasher.combine(self.annotations) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? MethodParameter else { return false } if self.argumentLabel != rhs.argumentLabel { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.`inout` != rhs.`inout` { return false } if self.isVariadic != rhs.isVariadic { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } return true } // sourcery:inline:MethodParameter.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.argumentLabel = aDecoder.decode(forKey: "argumentLabel") guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.`inout` = aDecoder.decode(forKey: "`inout`") self.isVariadic = aDecoder.decode(forKey: "isVariadic") self.type = aDecoder.decode(forKey: "type") self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations self.index = aDecoder.decode(forKey: "index") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.argumentLabel, forKey: "argumentLabel") aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.`inout`, forKey: "`inout`") aCoder.encode(self.isVariadic, forKey: "isVariadic") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.index, forKey: "index") } // sourcery:end } extension Array where Element == MethodParameter { public var asSource: String { "(\\(map { $0.asSource }.joined(separator: ", ")))" } } #endif """), .init(name: "Method_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryMethod = Method /// Describes method public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "definedInType": return definedInType case "shortName": return shortName case "name": return name case "selectorName": return selectorName case "callName": return callName case "parameters": return parameters case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isInitializer": return isInitializer case "accessLevel": return accessLevel case "isStatic": return isStatic case "returnTypeName": return returnTypeName case "isAsync": return isAsync case "attributes": return attributes case "isOptionalReturnType": return isOptionalReturnType case "actualReturnTypeName": return actualReturnTypeName case "isThrowsTypeGeneric": return isThrowsTypeGeneric case "isDynamic": return isDynamic case "genericRequirements": return genericRequirements default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Full method name, including generic constraints, i.e. `foo(bar: T)` public let name: String /// Method name including arguments names, i.e. `foo(bar:)` public var selectorName: String // sourcery: skipEquality, skipDescription /// Method name without arguments names and parentheses, i.e. `foo` public var shortName: String { return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name } // sourcery: skipEquality, skipDescription /// Method name without arguments names, parentheses and generic types, i.e. `foo` (can be used to generate code for method call) public var callName: String { return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName // sourcery: skipEquality, skipDescription /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Return if the throwsType is generic public var isThrowsTypeGeneric: Bool { return genericParameters.contains { $0.name == throwsTypeName?.name } } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional || isFailableInitializer } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// Whether method is distributed public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// Whether method throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether method rethrows public let `rethrows`: Bool /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Whether method is a static method public let isStatic: Bool /// Whether method is a class method public let isClass: Bool // sourcery: skipEquality, skipDescription /// Whether method is an initializer public var isInitializer: Bool { return selectorName.hasPrefix("init(") || selectorName == "init" } // sourcery: skipEquality, skipDescription /// Whether method is an deinitializer public var isDeinitializer: Bool { return selectorName == "deinit" } /// Whether method is a failable initializer public let isFailableInitializer: Bool // sourcery: skipEquality, skipDescription /// Whether method is a convenience initializer public var isConvenienceInitializer: Bool { modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is required public var isRequired: Bool { modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is mutating public var isMutating: Bool { modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is generic public var isGeneric: Bool { shortName.hasSuffix(">") } // sourcery: skipEquality, skipDescription /// Whether method is optional (in an Objective-C protocol) public var isOptional: Bool { modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is nonisolated (this modifier only applies to actor methods) public var isNonisolated: Bool { modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is dynamic public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// list of generic requirements public var genericRequirements: [GenericRequirement] /// List of generic parameters /// /// - Example: /// /// ```swift /// func method(foo: GenericParameter) /// ^ ~ a generic parameter /// ``` public var genericParameters: [GenericParameter] /// :nodoc: public init(name: String, selectorName: String? = nil, parameters: [MethodParameter] = [], returnTypeName: TypeName = TypeName(name: "Void"), isAsync: Bool = false, throws: Bool = false, throwsTypeName: TypeName? = nil, rethrows: Bool = false, accessLevel: AccessLevel = .internal, isStatic: Bool = false, isClass: Bool = false, isFailableInitializer: Bool = false, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil, genericRequirements: [GenericRequirement] = [], genericParameters: [GenericParameter] = []) { self.name = name self.selectorName = selectorName ?? name self.parameters = parameters self.returnTypeName = returnTypeName self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.rethrows = `rethrows` self.accessLevel = accessLevel.rawValue self.isStatic = isStatic self.isClass = isClass self.isFailableInitializer = isFailableInitializer self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName self.genericRequirements = genericRequirements self.genericParameters = genericParameters } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("selectorName = \\(String(describing: self.selectorName)), ") string.append("parameters = \\(String(describing: self.parameters)), ") string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("`throws` = \\(String(describing: self.`throws`)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("`rethrows` = \\(String(describing: self.`rethrows`)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("isStatic = \\(String(describing: self.isStatic)), ") string.append("isClass = \\(String(describing: self.isClass)), ") string.append("isFailableInitializer = \\(String(describing: self.isFailableInitializer)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers)), ") string.append("genericRequirements = \\(String(describing: self.genericRequirements)), ") string.append("genericParameters = \\(String(describing: self.genericParameters))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Method else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.selectorName) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.`rethrows`) hasher.combine(self.accessLevel) hasher.combine(self.isStatic) hasher.combine(self.isClass) hasher.combine(self.isFailableInitializer) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.genericRequirements) hasher.combine(self.genericParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Method else { return false } if self.name != rhs.name { return false } if self.selectorName != rhs.selectorName { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.isDistributed != rhs.isDistributed { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.`rethrows` != rhs.`rethrows` { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isStatic != rhs.isStatic { return false } if self.isClass != rhs.isClass { return false } if self.isFailableInitializer != rhs.isFailableInitializer { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.genericParameters != rhs.genericParameters { return false } return true } // sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else { withVaList(["selectorName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.selectorName = selectorName guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isStatic = aDecoder.decode(forKey: "isStatic") self.isClass = aDecoder.decode(forKey: "isClass") self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.selectorName, forKey: "selectorName") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.`rethrows`, forKey: "`rethrows`") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.isClass, forKey: "isClass") aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.genericParameters, forKey: "genericParameters") } // sourcery:end } #endif """), .init(name: "NSException_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation public class NSException { static func raise(_ name: String, format: String, arguments: CVaListPointer) { fatalError ("\\(name) exception: \\(NSString(format: format, arguments: arguments))") } static func raise(_ name: String) { fatalError("\\(name) exception") } } public extension NSExceptionName { static var parseErrorException = "parseErrorException" } #endif """), .init(name: "Protocol_Linux.swift", content: """ // // Protocol.swift // Sourcery // // Created by Krzysztof Zablocki on 09/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import Foundation #if !canImport(ObjectiveC) /// :nodoc: public typealias SourceryProtocol = Protocol /// Describes Swift protocol public final class Protocol: Type { public override subscript(dynamicMember member: String) -> Any? { switch member { case "associatedTypes": return associatedTypes default: return super[dynamicMember: member] } } // sourcery: skipJSExport public class var kind: String { return "protocol" } /// Returns "protocol" public override var kind: String { Self.kind } /// list of all declared associated types with their names as keys public var associatedTypes: [String: AssociatedType] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } // sourcery: skipCoding /// list of generic requirements public override var genericRequirements: [GenericRequirement] { didSet { isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty } } /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], associatedTypes: [String: AssociatedType] = [:], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], implements: [String: Type] = [:], kind: String = Protocol.kind) { self.associatedTypes = associatedTypes super.init( name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, subscripts: subscripts, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, genericRequirements: genericRequirements, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty, implements: implements, kind: kind ) } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = super.description string.append(", ") string.append("kind = \\(String(describing: self.kind)), ") string.append("associatedTypes = \\(String(describing: self.associatedTypes)), ") return string } override public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Protocol else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes)) results.append(contentsOf: super.diffAgainst(castObject)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.associatedTypes) hasher.combine(super.hash) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Protocol else { return false } if self.associatedTypes != rhs.associatedTypes { return false } return super.isEqual(rhs) } // sourcery:inline:Protocol.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else { withVaList(["associatedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.associatedTypes = associatedTypes super.init(coder: aDecoder) } /// :nodoc: override public func encode(with aCoder: NSCoder) { super.encode(with: aCoder) aCoder.encode(self.associatedTypes, forKey: "associatedTypes") } // sourcery:end } #endif """), .init(name: "Subscript_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Describes subscript public final class Subscript: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "parameters": return parameters case "returnTypeName": return returnTypeName case "actualReturnTypeName": return actualReturnTypeName case "returnType": return returnType case "isOptionalReturnType": return isOptionalReturnType case "isImplicitlyUnwrappedOptionalReturnType": return isImplicitlyUnwrappedOptionalReturnType case "unwrappedReturnTypeName": return unwrappedReturnTypeName case "isFinal": return isFinal case "readAccess": return readAccess case "writeAccess": return writeAccess case "isAsync": return isAsync case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isMutable": return isMutable case "annotations": return annotations case "documentation": return documentation case "definedInTypeName": return definedInTypeName case "actualDefinedInTypeName": return actualDefinedInTypeName case "attributes": return attributes case "modifiers": return modifiers case "genericParameters": return genericParameters case "genericRequirements": return genericRequirements case "isGeneric": return isGeneric default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == "final" } } /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public var writeAccess: String /// Whether subscript is async public let isAsync: Bool /// Whether subscript throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] /// list of generic parameters public let genericParameters: [GenericParameter] /// list of generic requirements public let genericRequirements: [GenericRequirement] /// Whether subscript is generic or not public var isGeneric: Bool { return genericParameters.isEmpty == false } // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// :nodoc: public init(parameters: [MethodParameter] = [], returnTypeName: TypeName, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, genericParameters: [GenericParameter] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.parameters = parameters self.returnTypeName = returnTypeName self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.genericParameters = genericParameters self.genericRequirements = genericRequirements self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("parameters = \\(String(describing: self.parameters)), ") string.append("returnTypeName = \\(String(describing: self.returnTypeName)), ") string.append("actualReturnTypeName = \\(String(describing: self.actualReturnTypeName)), ") string.append("isFinal = \\(String(describing: self.isFinal)), ") string.append("readAccess = \\(String(describing: self.readAccess)), ") string.append("writeAccess = \\(String(describing: self.writeAccess)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("`throws` = \\(String(describing: self.throws)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("isMutable = \\(String(describing: self.isMutable)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName)), ") string.append("genericParameters = \\(String(describing: self.genericParameters)), ") string.append("genericRequirements = \\(String(describing: self.genericRequirements)), ") string.append("isGeneric = \\(String(describing: self.isGeneric)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Subscript else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.throws, expected: castObject.throws)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.isAsync) hasher.combine(self.throws) hasher.combine(self.throwsTypeName) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.genericParameters) hasher.combine(self.genericRequirements) hasher.combine(self.attributes) hasher.combine(self.modifiers) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Subscript else { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.isAsync != rhs.isAsync { return false } if self.throws != rhs.throws { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.genericParameters != rhs.genericParameters { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } return true } // sourcery:inline:Subscript.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else { withVaList(["parameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.parameters = parameters guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericParameters, forKey: "genericParameters") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") } // sourcery:end } #endif """), .init(name: "Tuple_Linux.swift", content: """ #if !canImport(ObjectiveC) import Foundation /// Describes tuple type public final class TupleType: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "elements": return elements default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Type name used in declaration public var name: String /// Tuple elements public var elements: [TupleElement] /// :nodoc: public init(name: String, elements: [TupleElement]) { self.name = name self.elements = elements } /// :nodoc: public init(elements: [TupleElement]) { self.name = elements.asSource self.elements = elements } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("elements = \\(String(describing: self.elements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleType else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "elements").trackDifference(actual: self.elements, expected: castObject.elements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.elements) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleType else { return false } if self.name != rhs.name { return false } if self.elements != rhs.elements { return false } return true } // sourcery:inline:TupleType.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let elements: [TupleElement] = aDecoder.decode(forKey: "elements") else { withVaList(["elements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.elements = elements } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.elements, forKey: "elements") } // sourcery:end } /// Describes tuple type element public final class TupleElement: NSObject, SourceryModel, Typed, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "name": return name case "typeName": return typeName case "type": return type default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Tuple element name public let name: String? /// Tuple element type name public var typeName: TypeName // sourcery: skipEquality, skipDescription /// Tuple element type, if known public var type: Type? /// :nodoc: public init(name: String? = nil, typeName: TypeName, type: Type? = nil) { self.name = name self.typeName = typeName self.type = type } public var asSource: String { // swiftlint:disable:next force_unwrapping "\\(name != nil ? "\\(name!): " : "")\\(typeName.asSource)" } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("asSource = \\(String(describing: self.asSource))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TupleElement else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TupleElement else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } return true } // sourcery:inline:TupleElement.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.name = aDecoder.decode(forKey: "name") guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") } // sourcery:end } extension Array where Element == TupleElement { public var asSource: String { "(\\(map { $0.asSource }.joined(separator: ", ")))" } public var asTypeName: String { "(\\(map { $0.typeName.asSource }.joined(separator: ", ")))" } } #endif """), .init(name: "TypeName_Linux.swift", content: """ // // Created by Krzysztof Zabłocki on 25/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// Describes name of the type used in typed declaration (variable, method parameter or return value etc.) public final class TypeName: NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "array": return array case "closure": return closure case "dictionary": return dictionary case "generic": return generic case "set": return set case "tuple": return tuple case "name": return name case "actualTypeName": return actualTypeName case "isOptional": return isOptional case "unwrappedTypeName": return unwrappedTypeName case "isProtocolComposition": return isProtocolComposition case "isVoid": return isVoid case "isArray": return isArray case "isClosure": return isClosure case "isDictionary": return isDictionary case "isGeneric": return isGeneric case "isSet": return isSet default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// :nodoc: public init(name: String, actualTypeName: TypeName? = nil, unwrappedTypeName: String? = nil, attributes: AttributeList = [:], isOptional: Bool = false, isImplicitlyUnwrappedOptional: Bool = false, tuple: TupleType? = nil, array: ArrayType? = nil, dictionary: DictionaryType? = nil, closure: ClosureType? = nil, set: SetType? = nil, generic: GenericType? = nil, isProtocolComposition: Bool = false) { let optionalSuffix: String // TODO: TBR if !name.hasPrefix("Optional<") && !name.contains(" where ") { if isOptional { optionalSuffix = "?" } else if isImplicitlyUnwrappedOptional { optionalSuffix = "!" } else { optionalSuffix = "" } } else { optionalSuffix = "" } self.name = name + optionalSuffix self.actualTypeName = actualTypeName self.unwrappedTypeName = unwrappedTypeName ?? name self.tuple = tuple self.array = array self.dictionary = dictionary self.closure = closure self.generic = generic self.isOptional = isOptional || isImplicitlyUnwrappedOptional self.isImplicitlyUnwrappedOptional = isImplicitlyUnwrappedOptional self.isProtocolComposition = isProtocolComposition self.set = set self.attributes = attributes self.modifiers = [] super.init() } /// Type name used in declaration public var name: String /// The generics of this TypeName public var generic: GenericType? /// Whether this TypeName is generic public var isGeneric: Bool { actualTypeName?.generic != nil || generic != nil } /// Whether this TypeName is protocol composition public var isProtocolComposition: Bool // sourcery: skipEquality /// Actual type name if given type name is a typealias public var actualTypeName: TypeName? /// Type name attributes, i.e. `@escaping` public var attributes: AttributeList /// Modifiers, i.e. `escaping` public var modifiers: [SourceryModifier] // sourcery: skipEquality /// Whether type is optional public let isOptional: Bool // sourcery: skipEquality /// Whether type is implicitly unwrapped optional public let isImplicitlyUnwrappedOptional: Bool // sourcery: skipEquality /// Type name without attributes and optional type information public var unwrappedTypeName: String // sourcery: skipEquality /// Whether type is void (`Void` or `()`) public var isVoid: Bool { return name == "Void" || name == "()" || unwrappedTypeName == "Void" } /// Whether type is a tuple public var isTuple: Bool { actualTypeName?.tuple != nil || tuple != nil } /// Tuple type data public var tuple: TupleType? /// Whether type is an array public var isArray: Bool { actualTypeName?.array != nil || array != nil } /// Array type data public var array: ArrayType? /// Whether type is a dictionary public var isDictionary: Bool { actualTypeName?.dictionary != nil || dictionary != nil } /// Dictionary type data public var dictionary: DictionaryType? /// Whether type is a closure public var isClosure: Bool { actualTypeName?.closure != nil || closure != nil } /// Closure type data public var closure: ClosureType? /// Whether type is a Set public var isSet: Bool { actualTypeName?.set != nil || set != nil } /// Set type data public var set: SetType? /// Whether type is `Never` public var isNever: Bool { return name == "Never" } /// Prints typename as it would appear on definition public var asSource: String { // TODO: TBR special treatment let specialTreatment = isOptional && name.hasPrefix("Optional<") var description = ( attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + modifiers.map({ $0.asSource }) + [specialTreatment ? name : unwrappedTypeName] ).joined(separator: " ") if let _ = self.dictionary { // array and dictionary cases are covered by the unwrapped type name // description.append(dictionary.asSource) } else if let _ = self.array { // description.append(array.asSource) } else if let _ = self.generic { // let arguments = generic.typeParameters // .map({ $0.typeName.asSource }) // .joined(separator: ", ") // description.append("<\\(arguments)>") } if !specialTreatment { if isImplicitlyUnwrappedOptional { description.append("!") } else if isOptional { description.append("?") } } return description } public override var description: String { ( attributes.flatMap({ $0.value }).map({ $0.asSource }).sorted() + modifiers.map({ $0.asSource }) + [name] ).joined(separator: " ") } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? TypeName else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "generic").trackDifference(actual: self.generic, expected: castObject.generic)) results.append(contentsOf: DiffableResult(identifier: "isProtocolComposition").trackDifference(actual: self.isProtocolComposition, expected: castObject.isProtocolComposition)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "tuple").trackDifference(actual: self.tuple, expected: castObject.tuple)) results.append(contentsOf: DiffableResult(identifier: "array").trackDifference(actual: self.array, expected: castObject.array)) results.append(contentsOf: DiffableResult(identifier: "dictionary").trackDifference(actual: self.dictionary, expected: castObject.dictionary)) results.append(contentsOf: DiffableResult(identifier: "closure").trackDifference(actual: self.closure, expected: castObject.closure)) results.append(contentsOf: DiffableResult(identifier: "set").trackDifference(actual: self.set, expected: castObject.set)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.generic) hasher.combine(self.isProtocolComposition) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.tuple) hasher.combine(self.array) hasher.combine(self.dictionary) hasher.combine(self.closure) hasher.combine(self.set) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? TypeName else { return false } if self.name != rhs.name { return false } if self.generic != rhs.generic { return false } if self.isProtocolComposition != rhs.isProtocolComposition { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.tuple != rhs.tuple { return false } if self.array != rhs.array { return false } if self.dictionary != rhs.dictionary { return false } if self.closure != rhs.closure { return false } if self.set != rhs.set { return false } return true } // sourcery:inline:TypeName.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name self.generic = aDecoder.decode(forKey: "generic") self.isProtocolComposition = aDecoder.decode(forKey: "isProtocolComposition") self.actualTypeName = aDecoder.decode(forKey: "actualTypeName") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.isOptional = aDecoder.decode(forKey: "isOptional") self.isImplicitlyUnwrappedOptional = aDecoder.decode(forKey: "isImplicitlyUnwrappedOptional") guard let unwrappedTypeName: String = aDecoder.decode(forKey: "unwrappedTypeName") else { withVaList(["unwrappedTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.unwrappedTypeName = unwrappedTypeName self.tuple = aDecoder.decode(forKey: "tuple") self.array = aDecoder.decode(forKey: "array") self.dictionary = aDecoder.decode(forKey: "dictionary") self.closure = aDecoder.decode(forKey: "closure") self.set = aDecoder.decode(forKey: "set") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.generic, forKey: "generic") aCoder.encode(self.isProtocolComposition, forKey: "isProtocolComposition") aCoder.encode(self.actualTypeName, forKey: "actualTypeName") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.isOptional, forKey: "isOptional") aCoder.encode(self.isImplicitlyUnwrappedOptional, forKey: "isImplicitlyUnwrappedOptional") aCoder.encode(self.unwrappedTypeName, forKey: "unwrappedTypeName") aCoder.encode(self.tuple, forKey: "tuple") aCoder.encode(self.array, forKey: "array") aCoder.encode(self.dictionary, forKey: "dictionary") aCoder.encode(self.closure, forKey: "closure") aCoder.encode(self.set, forKey: "set") } // sourcery:end // sourcery: skipEquality, skipDescription /// :nodoc: public override var debugDescription: String { return name } public convenience init(_ description: String) { self.init(name: description, actualTypeName: nil) } } extension TypeName { public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName { if let description = description { Log.astWarning("Unknown type, please add type attribution to \\(description)") } else { Log.astWarning("Unknown type, please add type attribution") } return TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable", attributes: attributes) } } #endif """), .init(name: "Type_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 11/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias AttributeList = [String: [Attribute]] /// Defines Swift type public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "implements": return implements case "name": return name case "kind": return kind case "based": return based case "supertype": return supertype case "accessLevel": return accessLevel case "storedVariables": return storedVariables case "variables": return variables case "allVariables": return allVariables case "allMethods": return allMethods case "annotations": return annotations case "methods": return methods case "containedType": return containedType case "computedVariables": return computedVariables case "inherits": return inherits case "inheritedTypes": return inheritedTypes case "subscripts": return subscripts case "rawSubscripts": return rawSubscripts case "allSubscripts": return allSubscripts case "genericRequirements": return genericRequirements default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// :nodoc: public var module: String? /// Imports that existed in the file that contained this type declaration public var imports: [Import] = [] // sourcery: skipEquality /// Imports existed in all files containing this type and all its super classes/protocols public var allImports: [Import] { return self.unique({ $0.gatherAllImports() }, filter: { $0 == $1 }) } private func gatherAllImports() -> [Import] { var allImports: [Import] = Array(self.imports) self.basedTypes.values.forEach { (basedType) in allImports.append(contentsOf: basedType.imports) } return allImports } // All local typealiases /// :nodoc: public var typealiases: [String: Typealias] { didSet { typealiases.values.forEach { $0.parent = self } } } // sourcery: skipJSExport /// Whether declaration is an extension of some type public var isExtension: Bool // sourcery: forceEquality /// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension` public var kind: String { isExtension ? "extension" : _kind } // sourcery: skipJSExport /// Kind of a backing store for `self.kind` private var _kind: String /// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Type name in global scope. For inner types includes the name of its containing type, i.e. `Type.Inner` public var name: String { guard let parentName = parent?.name else { return localName } return "\\(parentName).\\(localName)" } // sourcery: skipCoding /// Whether the type has been resolved as unknown extension public var isUnknownExtension: Bool = false // sourcery: skipDescription /// Global type name including module name, unless it's an extension of unknown type public var globalName: String { guard let module = module, !isUnknownExtension else { return name } return "\\(module).\\(name)" } /// Whether type is generic public var isGeneric: Bool /// Type name in its own scope. public var localName: String // sourcery: skipEquality, skipDescription /// Variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var variables: [Variable] { unique({ $0.rawVariables }, filter: Self.uniqueVariableFilter) } /// Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, /// but not including variables inherited from superclasses (for classes only) and protocols public var rawVariables: [Variable] // sourcery: skipEquality, skipDescription /// All variables defined for this type, including variables defined in extensions, /// in superclasses (for classes only) and protocols public var allVariables: [Variable] { return flattenAll({ return $0.variables }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueVariableFilter($0, rhs: extracted) }) }) } private static func uniqueVariableFilter(_ lhs: Variable, rhs: Variable) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.typeName == rhs.typeName } // sourcery: skipEquality, skipDescription /// Methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var methods: [Method] { unique({ $0.rawMethods }, filter: Self.uniqueMethodFilter) } /// Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, /// but not including methods inherited from superclasses (for classes only) and protocols public var rawMethods: [Method] // sourcery: skipEquality, skipDescription /// All methods defined for this type, including methods defined in extensions, /// in superclasses (for classes only) and protocols public var allMethods: [Method] { return flattenAll({ $0.methods }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueMethodFilter($0, rhs: extracted) }) }) } private static func uniqueMethodFilter(_ lhs: Method, rhs: Method) -> Bool { return lhs.name == rhs.name && lhs.isStatic == rhs.isStatic && lhs.isClass == rhs.isClass && lhs.actualReturnTypeName == rhs.actualReturnTypeName } // sourcery: skipEquality, skipDescription /// Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var subscripts: [Subscript] { unique({ $0.rawSubscripts }, filter: Self.uniqueSubscriptFilter) } /// Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, /// but not including subscripts inherited from superclasses (for classes only) and protocols public var rawSubscripts: [Subscript] // sourcery: skipEquality, skipDescription /// All subscripts defined for this type, including subscripts defined in extensions, /// in superclasses (for classes only) and protocols public var allSubscripts: [Subscript] { return flattenAll({ $0.subscripts }, isExtension: { $0.definedInType?.isExtension == true }, filter: { all, extracted in !all.contains(where: { Self.uniqueSubscriptFilter($0, rhs: extracted) }) }) } private static func uniqueSubscriptFilter(_ lhs: Subscript, rhs: Subscript) -> Bool { return lhs.parameters == rhs.parameters && lhs.returnTypeName == rhs.returnTypeName && lhs.readAccess == rhs.readAccess && lhs.writeAccess == rhs.writeAccess } // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the body of this type in its declaration file if available. public var bodyBytesRange: BytesRange? // sourcery: skipEquality, skipDescription, skipJSExport /// Bytes position of the whole declaration of this type in its declaration file if available. public var completeDeclarationRange: BytesRange? private func flattenAll(_ extraction: @escaping (Type) -> [T], isExtension: (T) -> Bool, filter: ([T], T) -> Bool) -> [T] { let all = NSMutableOrderedSet() let allObjects = extraction(self) /// The order of importance for properties is: /// Base class /// Inheritance /// Protocol conformance /// Extension var extensions = [T]() var baseObjects = [T]() allObjects.forEach { if isExtension($0) { extensions.append($0) } else { baseObjects.append($0) } } all.addObjects(from: baseObjects) func filteredExtraction(_ target: Type) -> [T] { // swiftlint:disable:next force_cast let all = all.array as! [T] let extracted = extraction(target).filter({ filter(all, $0) }) return extracted } inherits.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } implements.values.sorted(by: { $0.name < $1.name }).forEach { all.addObjects(from: filteredExtraction($0)) } // swiftlint:disable:next force_cast let array = all.array as! [T] all.addObjects(from: extensions.filter({ filter(array, $0) })) return all.array.compactMap { $0 as? T } } private func unique(_ extraction: @escaping (Type) -> [T], filter: (T, T) -> Bool) -> [T] { let all = NSMutableOrderedSet() for nextItem in extraction(self) { // swiftlint:disable:next force_cast if !all.contains(where: { filter($0 as! T, nextItem) }) { all.add(nextItem) } } return all.array.compactMap { $0 as? T } } /// All initializers defined in this type public var initializers: [Method] { return methods.filter { $0.isInitializer } } /// All annotations for this type public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Static variables defined in this type public var staticVariables: [Variable] { return variables.filter { $0.isStatic } } /// Static methods defined in this type public var staticMethods: [Method] { return methods.filter { $0.isStatic } } /// Class methods defined in this type public var classMethods: [Method] { return methods.filter { $0.isClass } } /// Instance variables defined in this type public var instanceVariables: [Variable] { return variables.filter { !$0.isStatic } } /// Instance methods defined in this type public var instanceMethods: [Method] { return methods.filter { !$0.isStatic && !$0.isClass } } /// Computed instance variables defined in this type public var computedVariables: [Variable] { return variables.filter { $0.isComputed && !$0.isStatic } } /// Stored instance variables defined in this type public var storedVariables: [Variable] { return variables.filter { !$0.isComputed && !$0.isStatic } } /// Names of types this type inherits from (for classes only) and protocols it implements, in order of definition public var inheritedTypes: [String] { didSet { based.removeAll() inheritedTypes.forEach { name in self.based[name] = name } } } // sourcery: skipEquality, skipDescription /// Names of types or protocols this type inherits from, including unknown (not scanned) types public var based = [String: String]() // sourcery: skipEquality, skipDescription /// Types this type inherits from or implements, including unknown (not scanned) types with extensions defined public var basedTypes = [String: Type]() /// Types this type inherits from public var inherits = [String: Type]() // sourcery: skipEquality, skipDescription /// Protocols this type implements. Does not contain classes in case where composition (`&`) is used in the declaration public var implements = [String: Type]() /// Contained types public var containedTypes: [Type] { didSet { containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } } } // sourcery: skipEquality, skipDescription /// Contained types groupd by their names public private(set) var containedType: [String: Type] = [:] /// Name of parent type (for contained types only) public private(set) var parentName: String? // sourcery: skipEquality, skipDescription /// Parent type, if known (for contained types only) public var parent: Type? { didSet { parentName = parent?.name } } // sourcery: skipJSExport /// :nodoc: public var parentTypes: AnyIterator { var next: Type? = self return AnyIterator { next = next?.parent return next } } // sourcery: skipEquality, skipDescription /// Superclass type, if known (only for classes) public var supertype: Type? /// Type attributes, i.e. `@objc` public var attributes: AttributeList /// Type modifiers, i.e. `private`, `final` public var modifiers: [SourceryModifier] /// Path to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var path: String? { didSet { if let path = path { fileName = (path as NSString).lastPathComponent } } } /// Directory to file where the type is defined // sourcery: skipDescription, skipEquality, skipJSExport public var directory: String? { get { return (path as? NSString)?.deletingLastPathComponent } } /// list of generic requirements public var genericRequirements: [GenericRequirement] { didSet { isGeneric = isGeneric || !genericRequirements.isEmpty } } /// File name where the type was defined public var fileName: String? /// :nodoc: public init(name: String = "", parent: Type? = nil, accessLevel: AccessLevel = .internal, isExtension: Bool = false, variables: [Variable] = [], methods: [Method] = [], subscripts: [Subscript] = [], inheritedTypes: [String] = [], containedTypes: [Type] = [], typealiases: [Typealias] = [], genericRequirements: [GenericRequirement] = [], attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], isGeneric: Bool = false, implements: [String: Type] = [:], kind: String = "unknown") { self.localName = name self.accessLevel = accessLevel.rawValue self.isExtension = isExtension self.rawVariables = variables self.rawMethods = methods self.rawSubscripts = subscripts self.inheritedTypes = inheritedTypes self.containedTypes = containedTypes self.typealiases = [:] self.parent = parent self.parentName = parent?.name self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.isGeneric = isGeneric self.genericRequirements = genericRequirements self.implements = implements self._kind = kind super.init() containedTypes.forEach { containedType[$0.localName] = $0 $0.parent = self } inheritedTypes.forEach { name in self.based[name] = name } typealiases.forEach({ $0.parent = self self.typealiases[$0.aliasName] = $0 }) } /// :nodoc: public func extend(_ type: Type) { type.annotations.forEach { self.annotations[$0.key] = $0.value } type.inherits.forEach { self.inherits[$0.key] = $0.value } type.implements.forEach { self.implements[$0.key] = $0.value } self.inheritedTypes += type.inheritedTypes self.containedTypes += type.containedTypes self.rawVariables += type.rawVariables self.rawMethods += type.rawMethods self.rawSubscripts += type.rawSubscripts } /// :nodoc: // sourcery: skipJSExport override public var description: String { let type: Type.Type = Swift.type(of: self) var string = "\\(type): " string.append("module = \\(String(describing: self.module)), ") string.append("imports = \\(String(describing: self.imports)), ") string.append("allImports = \\(String(describing: self.allImports)), ") string.append("typealiases = \\(String(describing: self.typealiases)), ") string.append("isExtension = \\(String(describing: self.isExtension)), ") string.append("kind = \\(String(describing: self.kind)), ") string.append("_kind = \\(String(describing: self._kind)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("name = \\(String(describing: self.name)), ") string.append("isUnknownExtension = \\(String(describing: self.isUnknownExtension)), ") string.append("isGeneric = \\(String(describing: self.isGeneric)), ") string.append("localName = \\(String(describing: self.localName)), ") string.append("rawVariables = \\(String(describing: self.rawVariables)), ") string.append("rawMethods = \\(String(describing: self.rawMethods)), ") string.append("rawSubscripts = \\(String(describing: self.rawSubscripts)), ") string.append("initializers = \\(String(describing: self.initializers)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("staticVariables = \\(String(describing: self.staticVariables)), ") string.append("staticMethods = \\(String(describing: self.staticMethods)), ") string.append("classMethods = \\(String(describing: self.classMethods)), ") string.append("instanceVariables = \\(String(describing: self.instanceVariables)), ") string.append("instanceMethods = \\(String(describing: self.instanceMethods)), ") string.append("computedVariables = \\(String(describing: self.computedVariables)), ") string.append("storedVariables = \\(String(describing: self.storedVariables)), ") string.append("inheritedTypes = \\(String(describing: self.inheritedTypes)), ") string.append("inherits = \\(String(describing: self.inherits)), ") string.append("containedTypes = \\(String(describing: self.containedTypes)), ") string.append("parentName = \\(String(describing: self.parentName)), ") string.append("parentTypes = \\(String(describing: self.parentTypes)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers)), ") string.append("fileName = \\(String(describing: self.fileName)), ") string.append("genericRequirements = \\(String(describing: self.genericRequirements))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Type else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "module").trackDifference(actual: self.module, expected: castObject.module)) results.append(contentsOf: DiffableResult(identifier: "imports").trackDifference(actual: self.imports, expected: castObject.imports)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) results.append(contentsOf: DiffableResult(identifier: "isExtension").trackDifference(actual: self.isExtension, expected: castObject.isExtension)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isUnknownExtension").trackDifference(actual: self.isUnknownExtension, expected: castObject.isUnknownExtension)) results.append(contentsOf: DiffableResult(identifier: "isGeneric").trackDifference(actual: self.isGeneric, expected: castObject.isGeneric)) results.append(contentsOf: DiffableResult(identifier: "localName").trackDifference(actual: self.localName, expected: castObject.localName)) results.append(contentsOf: DiffableResult(identifier: "rawVariables").trackDifference(actual: self.rawVariables, expected: castObject.rawVariables)) results.append(contentsOf: DiffableResult(identifier: "rawMethods").trackDifference(actual: self.rawMethods, expected: castObject.rawMethods)) results.append(contentsOf: DiffableResult(identifier: "rawSubscripts").trackDifference(actual: self.rawSubscripts, expected: castObject.rawSubscripts)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "inheritedTypes").trackDifference(actual: self.inheritedTypes, expected: castObject.inheritedTypes)) results.append(contentsOf: DiffableResult(identifier: "inherits").trackDifference(actual: self.inherits, expected: castObject.inherits)) results.append(contentsOf: DiffableResult(identifier: "containedTypes").trackDifference(actual: self.containedTypes, expected: castObject.containedTypes)) results.append(contentsOf: DiffableResult(identifier: "parentName").trackDifference(actual: self.parentName, expected: castObject.parentName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "fileName").trackDifference(actual: self.fileName, expected: castObject.fileName)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.module) hasher.combine(self.imports) hasher.combine(self.typealiases) hasher.combine(self.isExtension) hasher.combine(self.accessLevel) hasher.combine(self.isUnknownExtension) hasher.combine(self.isGeneric) hasher.combine(self.localName) hasher.combine(self.rawVariables) hasher.combine(self.rawMethods) hasher.combine(self.rawSubscripts) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.inheritedTypes) hasher.combine(self.inherits) hasher.combine(self.containedTypes) hasher.combine(self.parentName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.fileName) hasher.combine(self.genericRequirements) hasher.combine(kind) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Type else { return false } if self.module != rhs.module { return false } if self.imports != rhs.imports { return false } if self.typealiases != rhs.typealiases { return false } if self.isExtension != rhs.isExtension { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isUnknownExtension != rhs.isUnknownExtension { return false } if self.isGeneric != rhs.isGeneric { return false } if self.localName != rhs.localName { return false } if self.rawVariables != rhs.rawVariables { return false } if self.rawMethods != rhs.rawMethods { return false } if self.rawSubscripts != rhs.rawSubscripts { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.inheritedTypes != rhs.inheritedTypes { return false } if self.inherits != rhs.inherits { return false } if self.containedTypes != rhs.containedTypes { return false } if self.parentName != rhs.parentName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.fileName != rhs.fileName { return false } if self.kind != rhs.kind { return false } if self.genericRequirements != rhs.genericRequirements { return false } return true } // sourcery:inline:Type.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { self.module = aDecoder.decode(forKey: "module") guard let imports: [Import] = aDecoder.decode(forKey: "imports") else { withVaList(["imports"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.imports = imports guard let typealiases: [String: Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases self.isExtension = aDecoder.decode(forKey: "isExtension") guard let _kind: String = aDecoder.decode(forKey: "_kind") else { withVaList(["_kind"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self._kind = _kind guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel self.isGeneric = aDecoder.decode(forKey: "isGeneric") guard let localName: String = aDecoder.decode(forKey: "localName") else { withVaList(["localName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.localName = localName guard let rawVariables: [Variable] = aDecoder.decode(forKey: "rawVariables") else { withVaList(["rawVariables"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawVariables = rawVariables guard let rawMethods: [Method] = aDecoder.decode(forKey: "rawMethods") else { withVaList(["rawMethods"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawMethods = rawMethods guard let rawSubscripts: [Subscript] = aDecoder.decode(forKey: "rawSubscripts") else { withVaList(["rawSubscripts"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.rawSubscripts = rawSubscripts self.bodyBytesRange = aDecoder.decode(forKey: "bodyBytesRange") self.completeDeclarationRange = aDecoder.decode(forKey: "completeDeclarationRange") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let inheritedTypes: [String] = aDecoder.decode(forKey: "inheritedTypes") else { withVaList(["inheritedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inheritedTypes = inheritedTypes guard let based: [String: String] = aDecoder.decode(forKey: "based") else { withVaList(["based"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.based = based guard let basedTypes: [String: Type] = aDecoder.decode(forKey: "basedTypes") else { withVaList(["basedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.basedTypes = basedTypes guard let inherits: [String: Type] = aDecoder.decode(forKey: "inherits") else { withVaList(["inherits"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.inherits = inherits guard let implements: [String: Type] = aDecoder.decode(forKey: "implements") else { withVaList(["implements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.implements = implements guard let containedTypes: [Type] = aDecoder.decode(forKey: "containedTypes") else { withVaList(["containedTypes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedTypes = containedTypes guard let containedType: [String: Type] = aDecoder.decode(forKey: "containedType") else { withVaList(["containedType"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.containedType = containedType self.parentName = aDecoder.decode(forKey: "parentName") self.parent = aDecoder.decode(forKey: "parent") self.supertype = aDecoder.decode(forKey: "supertype") guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.path = aDecoder.decode(forKey: "path") guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else { withVaList(["genericRequirements"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericRequirements = genericRequirements self.fileName = aDecoder.decode(forKey: "fileName") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.module, forKey: "module") aCoder.encode(self.imports, forKey: "imports") aCoder.encode(self.typealiases, forKey: "typealiases") aCoder.encode(self.isExtension, forKey: "isExtension") aCoder.encode(self._kind, forKey: "_kind") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isGeneric, forKey: "isGeneric") aCoder.encode(self.localName, forKey: "localName") aCoder.encode(self.rawVariables, forKey: "rawVariables") aCoder.encode(self.rawMethods, forKey: "rawMethods") aCoder.encode(self.rawSubscripts, forKey: "rawSubscripts") aCoder.encode(self.bodyBytesRange, forKey: "bodyBytesRange") aCoder.encode(self.completeDeclarationRange, forKey: "completeDeclarationRange") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.inheritedTypes, forKey: "inheritedTypes") aCoder.encode(self.based, forKey: "based") aCoder.encode(self.basedTypes, forKey: "basedTypes") aCoder.encode(self.inherits, forKey: "inherits") aCoder.encode(self.implements, forKey: "implements") aCoder.encode(self.containedTypes, forKey: "containedTypes") aCoder.encode(self.containedType, forKey: "containedType") aCoder.encode(self.parentName, forKey: "parentName") aCoder.encode(self.parent, forKey: "parent") aCoder.encode(self.supertype, forKey: "supertype") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.path, forKey: "path") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.fileName, forKey: "fileName") } // sourcery:end } extension Type { // sourcery: skipDescription, skipJSExport /// :nodoc: var isClass: Bool { let isNotClass = self is Struct || self is Enum || self is Protocol return !isNotClass && !isExtension } } #endif """), .init(name: "TypesCollection_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// :nodoc: public class TypesCollection: NSObject, AutoJSExport, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { return try? types(forKey: member) } // sourcery:begin: skipJSExport let all: [Type] let types: [String: [Type]] let validate: ((Type) throws -> Void)? // sourcery:end init(types: [Type], collection: (Type) -> [String], validate: ((Type) throws -> Void)? = nil) { self.all = types var content = [String: [Type]]() self.all.forEach { type in collection(type).forEach { name in var list = content[name] ?? [Type]() list.append(type) content[name] = list } } self.types = content self.validate = validate } public func types(forKey key: String) throws -> [Type] { // In some configurations, the types are keyed by "ModuleName.TypeName" var longKey: String? if let validate = validate { guard let type = all.first(where: { $0.name == key }) else { throw "Unknown type \\(key), should be used with `based`" } try validate(type) if let module = type.module { longKey = [module, type.name].joined(separator: ".") } } // If we find the types directly, return them if let types = types[key] { return types } // if we find a types for the longKey, return them if let longKey = longKey, let types = types[longKey] { return types } return [] } /// :nodoc: public func value(forKey key: String) -> Any? { do { return try types(forKey: key) } catch { Log.error(error) return nil } } /// :nodoc: public subscript(_ key: String) -> [Type] { do { return try types(forKey: key) } catch { Log.error(error) return [] } } } #endif """), .init(name: "Types_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation // sourcery: skipJSExport /// Collection of scanned types for accessing in templates public final class Types: NSObject, SourceryModel, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "types": return types case "enums": return enums case "all": return all case "protocols": return protocols case "classes": return classes case "structs": return structs case "extensions": return extensions case "implementing": return implementing case "inheriting": return inheriting case "based": return based default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// :nodoc: public let types: [Type] /// All known typealiases public let typealiases: [Typealias] /// :nodoc: public init(types: [Type], typealiases: [Typealias] = []) { self.types = types self.typealiases = typealiases } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("types = \\(String(describing: self.types)), ") string.append("typealiases = \\(String(describing: self.typealiases))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Types else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "types").trackDifference(actual: self.types, expected: castObject.types)) results.append(contentsOf: DiffableResult(identifier: "typealiases").trackDifference(actual: self.typealiases, expected: castObject.typealiases)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.types) hasher.combine(self.typealiases) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Types else { return false } if self.types != rhs.types { return false } if self.typealiases != rhs.typealiases { return false } return true } // sourcery:inline:Types.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let types: [Type] = aDecoder.decode(forKey: "types") else { withVaList(["types"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.types = types guard let typealiases: [Typealias] = aDecoder.decode(forKey: "typealiases") else { withVaList(["typealiases"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typealiases = typealiases } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.types, forKey: "types") aCoder.encode(self.typealiases, forKey: "typealiases") } // sourcery:end // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesByName: [String: Type] = { var typesByName = [String: Type]() self.types.forEach { typesByName[$0.globalName] = $0 } return typesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// :nodoc: public lazy internal(set) var typesaliasesByName: [String: Typealias] = { var typesaliasesByName = [String: Typealias]() self.typealiases.forEach { typesaliasesByName[$0.name] = $0 } return typesaliasesByName }() // sourcery: skipDescription, skipEquality, skipCoding /// All known types, excluding protocols or protocol compositions. public lazy internal(set) var all: [Type] = { return self.types.filter { !($0 is Protocol || $0 is ProtocolComposition) } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocols public lazy internal(set) var protocols: [Protocol] = { return self.types.compactMap { $0 as? Protocol } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known protocol compositions public lazy internal(set) var protocolCompositions: [ProtocolComposition] = { return self.types.compactMap { $0 as? ProtocolComposition } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known classes public lazy internal(set) var classes: [Class] = { return self.all.compactMap { $0 as? Class } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known structs public lazy internal(set) var structs: [Struct] = { return self.all.compactMap { $0 as? Struct } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known enums public lazy internal(set) var enums: [Enum] = { return self.all.compactMap { $0 as? Enum } }() // sourcery: skipDescription, skipEquality, skipCoding /// All known extensions public lazy internal(set) var extensions: [Type] = { return self.all.compactMap { $0.isExtension ? $0 : nil } }() // sourcery: skipDescription, skipEquality, skipCoding /// Types based on any other type, grouped by its name, even if they are not known. /// `types.based.MyType` returns list of types based on `MyType` public lazy internal(set) var based: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.based.keys) } ) }() // sourcery: skipDescription, skipEquality, skipCoding /// Classes inheriting from any known class, grouped by its name. /// `types.inheriting.MyClass` returns list of types inheriting from `MyClass` public lazy internal(set) var inheriting: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.inherits.keys) }, validate: { type in guard type is Class else { throw "\\(type.name) is not a class and should be used with `implementing` or `based`" } }) }() // sourcery: skipDescription, skipEquality, skipCoding /// Types implementing known protocol, grouped by its name. /// `types.implementing.MyProtocol` returns list of types implementing `MyProtocol` public lazy internal(set) var implementing: TypesCollection = { TypesCollection( types: self.types, collection: { Array($0.implements.keys) }, validate: { type in guard type is Protocol else { throw "\\(type.name) is a class and should be used with `inheriting` or `based`" } }) }() } #endif """), .init(name: "Variable_Linux.swift", content: """ // // Created by Krzysztof Zablocki on 13/09/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryVariable = Variable /// Defines variable public final class Variable: NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "readAccess": return readAccess case "annotations": return annotations case "isOptional": return isOptional case "name": return name case "typeName": return typeName case "type": return type case "definedInType": return definedInType case "isStatic": return isStatic case "isAsync": return isAsync case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isArray": return isArray case "isDictionary": return isDictionary case "isDynamic": return isDynamic default: fatalError("unable to lookup: \\(member) in \\(self)") } } /// Variable name public let name: String /// Variable type name public let typeName: TypeName // sourcery: skipEquality, skipDescription /// Variable type, if known, i.e. if the type is declared in the scanned sources. /// For explanation, see public var type: Type? /// Whether variable is computed and not stored public let isComputed: Bool /// Whether variable is async public let isAsync: Bool /// Whether variable throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether variable is static public let isStatic: Bool /// Variable read access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let readAccess: String /// Variable write access, i.e. `internal`, `private`, `fileprivate`, `public`, `open`. /// For immutable variables this value is empty string public let writeAccess: String /// composed access level /// sourcery: skipJSExport public var accessLevel: (read: AccessLevel, write: AccessLevel) { (read: AccessLevel(rawValue: readAccess) ?? .none, AccessLevel(rawValue: writeAccess) ?? .none) } /// Whether variable is mutable or not public var isMutable: Bool { return writeAccess != AccessLevel.none.rawValue } /// Variable default value expression public var defaultValue: String? /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public var annotations: Annotations = [:] public var documentation: Documentation = [] /// Variable attributes, i.e. `@IBOutlet`, `@IBInspectable` public var attributes: AttributeList /// Modifiers, i.e. `private` public var modifiers: [SourceryModifier] /// Whether variable is final or not public var isFinal: Bool { return modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } /// Whether variable is lazy or not public var isLazy: Bool { return modifiers.contains { $0.name == Attribute.Identifier.lazy.rawValue } } /// Whether variable is dynamic or not public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Reference to type name where the variable is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public internal(set) var definedInTypeName: TypeName? /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// :nodoc: public init(name: String = "", typeName: TypeName, type: Type? = nil, accessLevel: (read: AccessLevel, write: AccessLevel) = (.internal, .internal), isComputed: Bool = false, isAsync: Bool = false, `throws`: Bool = false, throwsTypeName: TypeName? = nil, isStatic: Bool = false, defaultValue: String? = nil, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil) { self.name = name self.typeName = typeName self.type = type self.isComputed = isComputed self.isAsync = isAsync self.`throws` = `throws` self.throwsTypeName = throwsTypeName self.isStatic = isStatic self.defaultValue = defaultValue self.readAccess = accessLevel.read.rawValue self.writeAccess = accessLevel.write.rawValue self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\\(Swift.type(of: self)): " string.append("name = \\(String(describing: self.name)), ") string.append("typeName = \\(String(describing: self.typeName)), ") string.append("isComputed = \\(String(describing: self.isComputed)), ") string.append("isAsync = \\(String(describing: self.isAsync)), ") string.append("`throws` = \\(String(describing: self.`throws`)), ") string.append("throwsTypeName = \\(String(describing: self.throwsTypeName)), ") string.append("isStatic = \\(String(describing: self.isStatic)), ") string.append("readAccess = \\(String(describing: self.readAccess)), ") string.append("writeAccess = \\(String(describing: self.writeAccess)), ") string.append("accessLevel = \\(String(describing: self.accessLevel)), ") string.append("isMutable = \\(String(describing: self.isMutable)), ") string.append("defaultValue = \\(String(describing: self.defaultValue)), ") string.append("annotations = \\(String(describing: self.annotations)), ") string.append("documentation = \\(String(describing: self.documentation)), ") string.append("attributes = \\(String(describing: self.attributes)), ") string.append("modifiers = \\(String(describing: self.modifiers)), ") string.append("isFinal = \\(String(describing: self.isFinal)), ") string.append("isLazy = \\(String(describing: self.isLazy)), ") string.append("isDynamic = \\(String(describing: self.isDynamic)), ") string.append("definedInTypeName = \\(String(describing: self.definedInTypeName)), ") string.append("actualDefinedInTypeName = \\(String(describing: self.actualDefinedInTypeName))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Variable else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "typeName").trackDifference(actual: self.typeName, expected: castObject.typeName)) results.append(contentsOf: DiffableResult(identifier: "isComputed").trackDifference(actual: self.isComputed, expected: castObject.isComputed)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "readAccess").trackDifference(actual: self.readAccess, expected: castObject.readAccess)) results.append(contentsOf: DiffableResult(identifier: "writeAccess").trackDifference(actual: self.writeAccess, expected: castObject.writeAccess)) results.append(contentsOf: DiffableResult(identifier: "defaultValue").trackDifference(actual: self.defaultValue, expected: castObject.defaultValue)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.typeName) hasher.combine(self.isComputed) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.isStatic) hasher.combine(self.readAccess) hasher.combine(self.writeAccess) hasher.combine(self.defaultValue) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.definedInTypeName) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Variable else { return false } if self.name != rhs.name { return false } if self.typeName != rhs.typeName { return false } if self.isComputed != rhs.isComputed { return false } if self.isAsync != rhs.isAsync { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.isStatic != rhs.isStatic { return false } if self.readAccess != rhs.readAccess { return false } if self.writeAccess != rhs.writeAccess { return false } if self.defaultValue != rhs.defaultValue { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } return true } // sourcery:inline:Variable.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { guard let name: String = aDecoder.decode(forKey: "name") else { withVaList(["name"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.name = name guard let typeName: TypeName = aDecoder.decode(forKey: "typeName") else { withVaList(["typeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.typeName = typeName self.type = aDecoder.decode(forKey: "type") self.isComputed = aDecoder.decode(forKey: "isComputed") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.isStatic = aDecoder.decode(forKey: "isStatic") guard let readAccess: String = aDecoder.decode(forKey: "readAccess") else { withVaList(["readAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.readAccess = readAccess guard let writeAccess: String = aDecoder.decode(forKey: "writeAccess") else { withVaList(["writeAccess"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.writeAccess = writeAccess self.defaultValue = aDecoder.decode(forKey: "defaultValue") guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else { withVaList(["annotations"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.annotations = annotations guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else { withVaList(["attributes"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.attributes = attributes guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else { withVaList(["modifiers"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.modifiers = modifiers self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.typeName, forKey: "typeName") aCoder.encode(self.type, forKey: "type") aCoder.encode(self.isComputed, forKey: "isComputed") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.readAccess, forKey: "readAccess") aCoder.encode(self.writeAccess, forKey: "writeAccess") aCoder.encode(self.defaultValue, forKey: "defaultValue") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") } // sourcery:end } #endif """), .init(name: "AutoHashable.generated.swift", content: """ // Generated using Sourcery 1.3.1 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable all // MARK: - AutoHashable for classes, protocols, structs // MARK: - AutoHashable for Enums """), .init(name: "Coding.generated.swift", content: """ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace trailing_newline import Foundation extension NSCoder { @nonobjc func decode(forKey: String) -> String? { return self.maybeDecode(forKey: forKey) as String? } @nonobjc func decode(forKey: String) -> TypeName? { return self.maybeDecode(forKey: forKey) as TypeName? } @nonobjc func decode(forKey: String) -> AccessLevel? { return self.maybeDecode(forKey: forKey) as AccessLevel? } @nonobjc func decode(forKey: String) -> Bool { return self.decodeBool(forKey: forKey) } @nonobjc func decode(forKey: String) -> Int { return self.decodeInteger(forKey: forKey) } func decode(forKey: String) -> E? { return maybeDecode(forKey: forKey) as E? } fileprivate func maybeDecode(forKey: String) -> E? { guard let object = self.decodeObject(forKey: forKey) else { return nil } return object as? E } } extension ArrayType: NSCoding {} extension AssociatedType: NSCoding {} extension AssociatedValue: NSCoding {} extension Attribute: NSCoding {} extension BytesRange: NSCoding {} extension ClosureParameter: NSCoding {} extension ClosureType: NSCoding {} extension DictionaryType: NSCoding {} extension EnumCase: NSCoding {} extension FileParserResult: NSCoding {} extension GenericParameter: NSCoding {} extension GenericRequirement: NSCoding {} extension GenericType: NSCoding {} extension GenericTypeParameter: NSCoding {} extension Import: NSCoding {} extension Method: NSCoding {} extension MethodParameter: NSCoding {} extension Modifier: NSCoding {} extension SetType: NSCoding {} extension Subscript: NSCoding {} extension TupleElement: NSCoding {} extension TupleType: NSCoding {} extension Type: NSCoding {} extension TypeName: NSCoding {} extension Typealias: NSCoding {} extension Types: NSCoding {} extension Variable: NSCoding {} """), .init(name: "JSExport.generated.swift", content: """ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace trailing_newline #if canImport(JavaScriptCore) import JavaScriptCore @objc protocol ActorAutoJSExport: JSExport { var kind: String { get } var isFinal: Bool { get } var isDistributed: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Actor: ActorAutoJSExport {} @objc protocol ArrayTypeAutoJSExport: JSExport { var name: String { get } var elementTypeName: TypeName { get } var elementType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension ArrayType: ArrayTypeAutoJSExport {} @objc protocol AssociatedTypeAutoJSExport: JSExport { var name: String { get } var typeName: TypeName? { get } var type: Type? { get } } extension AssociatedType: AssociatedTypeAutoJSExport {} @objc protocol AssociatedValueAutoJSExport: JSExport { var localName: String? { get } var externalName: String? { get } var typeName: TypeName { get } var type: Type? { get } var defaultValue: String? { get } var annotations: Annotations { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension AssociatedValue: AssociatedValueAutoJSExport {} @objc protocol AttributeAutoJSExport: JSExport { var name: String { get } var arguments: [String: NSObject] { get } var asSource: String { get } var description: String { get } } extension Attribute: AttributeAutoJSExport {} @objc protocol BytesRangeAutoJSExport: JSExport { var offset: Int64 { get } var length: Int64 { get } } extension BytesRange: BytesRangeAutoJSExport {} @objc protocol ClassAutoJSExport: JSExport { var kind: String { get } var isFinal: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Class: ClassAutoJSExport {} @objc protocol ClosureParameterAutoJSExport: JSExport { var argumentLabel: String? { get } var name: String? { get } var typeName: TypeName { get } var `inout`: Bool { get } var type: Type? { get } var isVariadic: Bool { get } var typeAttributes: AttributeList { get } var defaultValue: String? { get } var annotations: Annotations { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension ClosureParameter: ClosureParameterAutoJSExport {} @objc protocol ClosureTypeAutoJSExport: JSExport { var name: String { get } var parameters: [ClosureParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isAsync: Bool { get } var asyncKeyword: String? { get } var `throws`: Bool { get } var throwsOrRethrowsKeyword: String? { get } var throwsTypeName: TypeName? { get } var asSource: String { get } } extension ClosureType: ClosureTypeAutoJSExport {} @objc protocol DictionaryTypeAutoJSExport: JSExport { var name: String { get } var valueTypeName: TypeName { get } var valueType: Type? { get } var keyTypeName: TypeName { get } var keyType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension DictionaryType: DictionaryTypeAutoJSExport {} @objc protocol EnumAutoJSExport: JSExport { var kind: String { get } var cases: [EnumCase] { get } var rawTypeName: TypeName? { get } var hasRawType: Bool { get } var rawType: Type? { get } var based: [String: String] { get } var hasAssociatedValues: Bool { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Enum: EnumAutoJSExport {} @objc protocol EnumCaseAutoJSExport: JSExport { var name: String { get } var rawValue: String? { get } var associatedValues: [AssociatedValue] { get } var annotations: Annotations { get } var documentation: Documentation { get } var indirect: Bool { get } var hasAssociatedValue: Bool { get } } extension EnumCase: EnumCaseAutoJSExport {} @objc protocol GenericParameterAutoJSExport: JSExport { var name: String { get } var inheritedTypeName: TypeName? { get } } extension GenericParameter: GenericParameterAutoJSExport {} @objc protocol GenericRequirementAutoJSExport: JSExport { var leftType: AssociatedType { get } var rightType: GenericTypeParameter { get } var relationship: String { get } var relationshipSyntax: String { get } } extension GenericRequirement: GenericRequirementAutoJSExport {} @objc protocol GenericTypeAutoJSExport: JSExport { var name: String { get } var typeParameters: [GenericTypeParameter] { get } var asSource: String { get } var description: String { get } } extension GenericType: GenericTypeAutoJSExport {} @objc protocol GenericTypeParameterAutoJSExport: JSExport { var typeName: TypeName { get } var type: Type? { get } } extension GenericTypeParameter: GenericTypeParameterAutoJSExport {} @objc protocol ImportAutoJSExport: JSExport { var kind: String? { get } var path: String { get } var description: String { get } var moduleName: String { get } } extension Import: ImportAutoJSExport {} @objc protocol MethodAutoJSExport: JSExport { var name: String { get } var selectorName: String { get } var shortName: String { get } var callName: String { get } var parameters: [MethodParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var isThrowsTypeGeneric: Bool { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isAsync: Bool { get } var isDistributed: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var `rethrows`: Bool { get } var accessLevel: String { get } var isStatic: Bool { get } var isClass: Bool { get } var isInitializer: Bool { get } var isDeinitializer: Bool { get } var isFailableInitializer: Bool { get } var isConvenienceInitializer: Bool { get } var isRequired: Bool { get } var isFinal: Bool { get } var isMutating: Bool { get } var isGeneric: Bool { get } var isOptional: Bool { get } var isNonisolated: Bool { get } var isDynamic: Bool { get } var annotations: Annotations { get } var documentation: Documentation { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var genericParameters: [GenericParameter] { get } } extension Method: MethodAutoJSExport {} @objc protocol MethodParameterAutoJSExport: JSExport { var argumentLabel: String? { get } var name: String { get } var typeName: TypeName { get } var `inout`: Bool { get } var isVariadic: Bool { get } var type: Type? { get } var typeAttributes: AttributeList { get } var defaultValue: String? { get } var annotations: Annotations { get } var index: Int { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension MethodParameter: MethodParameterAutoJSExport {} @objc protocol ModifierAutoJSExport: JSExport { var name: String { get } var detail: String? { get } var asSource: String { get } } extension Modifier: ModifierAutoJSExport {} @objc protocol ProtocolAutoJSExport: JSExport { var kind: String { get } var associatedTypes: [String: AssociatedType] { get } var genericRequirements: [GenericRequirement] { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var fileName: String? { get } } extension Protocol: ProtocolAutoJSExport {} @objc protocol ProtocolCompositionAutoJSExport: JSExport { var kind: String { get } var composedTypeNames: [TypeName] { get } var composedTypes: [Type]? { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension ProtocolComposition: ProtocolCompositionAutoJSExport {} @objc protocol SetTypeAutoJSExport: JSExport { var name: String { get } var elementTypeName: TypeName { get } var elementType: Type? { get } var asGeneric: GenericType { get } var asSource: String { get } } extension SetType: SetTypeAutoJSExport {} @objc protocol StructAutoJSExport: JSExport { var kind: String { get } var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Struct: StructAutoJSExport {} @objc protocol SubscriptAutoJSExport: JSExport { var parameters: [MethodParameter] { get } var returnTypeName: TypeName { get } var actualReturnTypeName: TypeName { get } var returnType: Type? { get } var isOptionalReturnType: Bool { get } var isImplicitlyUnwrappedOptionalReturnType: Bool { get } var unwrappedReturnTypeName: String { get } var isFinal: Bool { get } var readAccess: String { get } var writeAccess: String { get } var isAsync: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var isMutable: Bool { get } var annotations: Annotations { get } var documentation: Documentation { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericParameters: [GenericParameter] { get } var genericRequirements: [GenericRequirement] { get } var isGeneric: Bool { get } } extension Subscript: SubscriptAutoJSExport {} @objc protocol TemplateContextAutoJSExport: JSExport { var functions: [SourceryMethod] { get } var types: Types { get } var argument: [String: NSObject] { get } var type: [String: Type] { get } var stencilContext: [String: Any] { get } var jsContext: [String: Any] { get } } extension TemplateContext: TemplateContextAutoJSExport {} @objc protocol TupleElementAutoJSExport: JSExport { var name: String? { get } var typeName: TypeName { get } var type: Type? { get } var asSource: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension TupleElement: TupleElementAutoJSExport {} @objc protocol TupleTypeAutoJSExport: JSExport { var name: String { get } var elements: [TupleElement] { get } } extension TupleType: TupleTypeAutoJSExport {} @objc protocol TypeAutoJSExport: JSExport { var module: String? { get } var imports: [Import] { get } var allImports: [Import] { get } var typealiases: [String: Typealias] { get } var kind: String { get } var accessLevel: String { get } var name: String { get } var isUnknownExtension: Bool { get } var globalName: String { get } var isGeneric: Bool { get } var localName: String { get } var variables: [Variable] { get } var rawVariables: [Variable] { get } var allVariables: [Variable] { get } var methods: [Method] { get } var rawMethods: [Method] { get } var allMethods: [Method] { get } var subscripts: [Subscript] { get } var rawSubscripts: [Subscript] { get } var allSubscripts: [Subscript] { get } var initializers: [Method] { get } var annotations: Annotations { get } var documentation: Documentation { get } var staticVariables: [Variable] { get } var staticMethods: [Method] { get } var classMethods: [Method] { get } var instanceVariables: [Variable] { get } var instanceMethods: [Method] { get } var computedVariables: [Variable] { get } var storedVariables: [Variable] { get } var inheritedTypes: [String] { get } var based: [String: String] { get } var basedTypes: [String: Type] { get } var inherits: [String: Type] { get } var implements: [String: Type] { get } var containedTypes: [Type] { get } var containedType: [String: Type] { get } var parentName: String? { get } var parent: Type? { get } var supertype: Type? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var genericRequirements: [GenericRequirement] { get } var fileName: String? { get } } extension Type: TypeAutoJSExport {} @objc protocol TypeNameAutoJSExport: JSExport { var name: String { get } var generic: GenericType? { get } var isGeneric: Bool { get } var isProtocolComposition: Bool { get } var actualTypeName: TypeName? { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } var isVoid: Bool { get } var isTuple: Bool { get } var tuple: TupleType? { get } var isArray: Bool { get } var array: ArrayType? { get } var isDictionary: Bool { get } var dictionary: DictionaryType? { get } var isClosure: Bool { get } var closure: ClosureType? { get } var isSet: Bool { get } var set: SetType? { get } var isNever: Bool { get } var asSource: String { get } var description: String { get } var debugDescription: String { get } } extension TypeName: TypeNameAutoJSExport {} @objc protocol TypealiasAutoJSExport: JSExport { var aliasName: String { get } var typeName: TypeName { get } var type: Type? { get } var module: String? { get } var imports: [Import] { get } var annotations: Annotations { get } var documentation: Documentation { get } var parent: Type? { get } var accessLevel: String { get } var parentName: String? { get } var name: String { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension Typealias: TypealiasAutoJSExport {} @objc protocol TypesCollectionAutoJSExport: JSExport { } extension TypesCollection: TypesCollectionAutoJSExport {} @objc protocol VariableAutoJSExport: JSExport { var name: String { get } var typeName: TypeName { get } var type: Type? { get } var isComputed: Bool { get } var isAsync: Bool { get } var `throws`: Bool { get } var throwsTypeName: TypeName? { get } var isStatic: Bool { get } var readAccess: String { get } var writeAccess: String { get } var isMutable: Bool { get } var defaultValue: String? { get } var annotations: Annotations { get } var documentation: Documentation { get } var attributes: AttributeList { get } var modifiers: [SourceryModifier] { get } var isFinal: Bool { get } var isLazy: Bool { get } var isDynamic: Bool { get } var definedInTypeName: TypeName? { get } var actualDefinedInTypeName: TypeName? { get } var definedInType: Type? { get } var isOptional: Bool { get } var isImplicitlyUnwrappedOptional: Bool { get } var unwrappedTypeName: String { get } } extension Variable: VariableAutoJSExport {} #endif """), .init(name: "Typed.generated.swift", content: """ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable vertical_whitespace extension AssociatedValue { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension ClosureParameter { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension MethodParameter { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension TupleElement { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension Typealias { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } extension Variable { /// Whether type is optional. Shorthand for `typeName.isOptional` public var isOptional: Bool { return typeName.isOptional } /// Whether type is implicitly unwrapped optional. Shorthand for `typeName.isImplicitlyUnwrappedOptional` public var isImplicitlyUnwrappedOptional: Bool { return typeName.isImplicitlyUnwrappedOptional } /// Type name without attributes and optional type information. Shorthand for `typeName.unwrappedTypeName` public var unwrappedTypeName: String { return typeName.unwrappedTypeName } /// Actual type name if declaration uses typealias, otherwise just a `typeName`. Shorthand for `typeName.actualTypeName` public var actualTypeName: TypeName? { return typeName.actualTypeName ?? typeName } /// Whether type is a tuple. Shorthand for `typeName.isTuple` public var isTuple: Bool { return typeName.isTuple } /// Whether type is a closure. Shorthand for `typeName.isClosure` public var isClosure: Bool { return typeName.isClosure } /// Whether type is an array. Shorthand for `typeName.isArray` public var isArray: Bool { return typeName.isArray } /// Whether type is a set. Shorthand for `typeName.isSet` public var isSet: Bool { return typeName.isSet } /// Whether type is a dictionary. Shorthand for `typeName.isDictionary` public var isDictionary: Bool { return typeName.isDictionary } } """), ] #endif ================================================ FILE: SourcerySwift/Sources/SwiftTemplate.swift ================================================ // // SwiftTemplate.swift // Sourcery // // Created by Krunoslav Zaher on 12/30/16. // Copyright © 2016 Pixle. All rights reserved. // import Foundation import PathKit import SourceryRuntime import SourceryUtils private enum Delimiters { static let open = "<%" static let close = "%>" } private struct ProcessResult { let output: String let error: String let exitCode: Int32 } open class SwiftTemplate { public let sourcePath: Path let buildPath: Path? let cachePath: Path? let mainFileCodeRaw: String let version: String? let includedFiles: [Path] private enum RenderError: Error { case binaryMissing } private lazy var buildDir: Path = { var pathComponent = "SwiftTemplate" pathComponent.append("/\(UUID().uuidString)") pathComponent.append((version.map { "/\($0)" } ?? "")) if let buildPath { return (buildPath + pathComponent).absolute() } guard let tempDirURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(pathComponent) else { fatalError("Unable to get temporary path") } return Path(tempDirURL.path) }() public init(path: Path, cachePath: Path? = nil, version: String? = nil, buildPath: Path? = nil) throws { self.sourcePath = path self.buildPath = buildPath self.cachePath = cachePath self.version = version (self.mainFileCodeRaw, self.includedFiles) = try SwiftTemplate.parse(sourcePath: path) } private enum Command { case includeFile(Path) case output(String) case controlFlow(String) case outputEncoded(String) } static func parse(sourcePath: Path) throws -> (String, [Path]) { let commands = try SwiftTemplate.parseCommands(in: sourcePath) let startParsing = currentTimestamp() var includedFiles: [Path] = [] var outputFile = [String]() var hasContents = false for command in commands { switch command { case let .includeFile(path): includedFiles.append(path) case let .output(code): outputFile.append("sourceryBuffer.append(\"\\(" + code + ")\");") hasContents = true case let .controlFlow(code): outputFile.append("\(code)") hasContents = true case let .outputEncoded(code): if !code.isEmpty { outputFile.append(("sourceryBuffer.append(\"") + code.stringEncoded + "\");") hasContents = true } } } if hasContents { outputFile.insert("var sourceryBuffer = \"\";", at: 0) } outputFile.append("print(\"\\(sourceryBuffer)\", terminator: \"\");") let contents = outputFile.joined(separator: "\n") let code = """ import Foundation import SourceryRuntime let context = ProcessInfo.processInfo.context! let types = context.types let functions = context.functions let type = context.types.typesByName let argument = context.argument \(contents) """ Log.benchmark("\tRaw processing time for \(sourcePath.lastComponent) took: \(currentTimestamp() - startParsing)") return (code, includedFiles) } private static func parseCommands(in sourcePath: Path, includeStack: [Path] = []) throws -> [Command] { let startProcessing = currentTimestamp() let templateContent = try "<%%>" + sourcePath.read() let components = templateContent.components(separatedBy: Delimiters.open) var processedComponents = [String]() var commands = [Command]() let currentLineNumber = { // the following +1 is to transform a line count (starting from 0) to a line number (starting from 1) return processedComponents.joined(separator: "").numberOfLineSeparators + 1 } for component in components.suffix(from: 1) { guard let endIndex = component.range(of: Delimiters.close) else { throw "\(sourcePath):\(currentLineNumber()) Error while parsing template. Unmatched <%" } var code = String(component[.. Path? { let regex = try? NSRegularExpression(pattern: "\(command)\\(\"([^\"]*)\"\\)", options: []) let match = regex?.firstMatch(in: code, options: [], range: code.bridge().entireRange) guard let includedFile = match.map({ code.bridge().substring(with: $0.range(at: 1)) }) else { return nil } let includePath = Path(components: [sourcePath.parent().string, includedFile]) // The template extension may be omitted, so try to read again by adding it if a template was not found if !includePath.exists, includePath.extension != "\(defaultExtension)" { return Path(includePath.string + ".\(defaultExtension)") } else { return includePath } } if code.trimPrefix("-") { if let includePath = parseInclude(command: "includeFile", defaultExtension: "swift") { commands.append(.includeFile(includePath)) } else if let includePath = parseInclude(command: "include", defaultExtension: "swifttemplate") { // Check for include cycles to prevent stack overflow and show a more user friendly error if includeStack.contains(includePath) { throw "\(sourcePath):\(currentLineNumber()) Error: Include cycle detected for \(includePath). Check your include statements so that templates do not include each other." } let includedCommands = try SwiftTemplate.parseCommands(in: includePath, includeStack: includeStack + [includePath]) commands.append(contentsOf: includedCommands) } else { throw "\(sourcePath):\(currentLineNumber()) Error while parsing template. Invalid include tag format '\(code)'" } } else if code.trimPrefix("=") { commands.append(.output(code)) } else { if !code.hasPrefix("#") && !code.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { commands.append(.controlFlow(code)) } } if !encodedPart.isEmpty { commands.append(.outputEncoded(encodedPart)) } processedComponents.append(component) } Log.benchmark("\tRaw command processing for \(sourcePath.lastComponent) took: \(currentTimestamp() - startProcessing)") return commands } public func render(_ context: Any) throws -> String { do { return try render(context: context) } catch is RenderError { return try render(context: context) } } private func render(context: Any) throws -> String { var destinationBinaryPath: Path var originalBinaryPath = buildDir + Path(".build/release/SwiftTemplate") if let cachePath = cachePath, let hash = executableCacheKey, let hashPath = hash.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics) { destinationBinaryPath = cachePath + hashPath if destinationBinaryPath.exists { Log.benchmark("Reusing built SwiftTemplate binary for SwiftTemplate with cache key: \(hash)...") } else { Log.benchmark("Building new SwiftTemplate binary for SwiftTemplate...") try build() // attempt to create cache dir try? cachePath.mkdir() // attempt to move to the created `cacheDir` try? originalBinaryPath.copy(destinationBinaryPath) } // create a link to the compiled binary in a unique stable location if !buildDir.exists { try buildDir.mkpath() } originalBinaryPath = buildDir + hashPath destinationBinaryPath = destinationBinaryPath.isRelative ? destinationBinaryPath.absolute() : destinationBinaryPath try FileManager.default.createSymbolicLink(atPath: originalBinaryPath.string, withDestinationPath: destinationBinaryPath.string) } else { try build() } let serializedContextPath = buildDir + "context.bin" let data = try NSKeyedArchiver.archivedData(withRootObject: context, requiringSecureCoding: false) if !buildDir.exists { try buildDir.mkpath() } try serializedContextPath.write(data) Log.benchmark("Binary file location: \(originalBinaryPath.string)") if FileManager.default.fileExists(atPath: originalBinaryPath.string) { let result = try Process.runCommand(path: originalBinaryPath.string, arguments: [serializedContextPath.description]) if !result.error.isEmpty { throw "\(sourcePath): \(result.error)" } return result.output } throw RenderError.binaryMissing } private func build() throws { let startCompiling = currentTimestamp() let sourcesDir = buildDir + Path("Sources") let templateFilesDir = sourcesDir + Path("SwiftTemplate") let mainFile = templateFilesDir + Path("main.swift") let manifestFile = buildDir + Path("Package.swift") try sourcesDir.mkpath() try? templateFilesDir.delete() try templateFilesDir.mkpath() try copyRuntimePackage(to: sourcesDir) if !manifestFile.exists { try manifestFile.write(manifestCode) } try mainFile.write(mainFileCodeRaw) try includedFiles.forEach { includedFile in try includedFile.copy(templateFilesDir + Path(includedFile.lastComponent)) } #if os(macOS) let arguments = [ "xcrun", "--sdk", "macosx", "swift", "build", "-c", "release", "-Xswiftc", "-Onone", "-Xswiftc", "-suppress-warnings", "--disable-sandbox" ] #else let arguments = [ "swift", "build", "-c", "release", "-Xswiftc", "-Onone", "-Xswiftc", "-suppress-warnings", "--disable-sandbox" ] #endif let compilationResult = try Process.runCommand(path: "/usr/bin/env", arguments: arguments, currentDirectoryPath: buildDir) if compilationResult.exitCode != EXIT_SUCCESS { throw [compilationResult.output, compilationResult.error] .filter { !$0.isEmpty } .joined(separator: "\n") } Log.benchmark("\tRaw compilation of SwiftTemplate took: \(currentTimestamp() - startCompiling)") } #if os(macOS) private var manifestCode: String { return """ // swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "SwiftTemplate", platforms: [ .macOS(.v10_15) ], products: [ .executable(name: "SwiftTemplate", targets: ["SwiftTemplate"]) ], targets: [ .target(name: "SourceryRuntime"), .executableTarget(name: "SwiftTemplate", dependencies: ["SourceryRuntime"]) ] ) """ } #else private var manifestCode: String { return """ // swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "SwiftTemplate", products: [ .executable(name: "SwiftTemplate", targets: ["SwiftTemplate"]) ], targets: [ .target(name: "SourceryRuntime"), .executableTarget(name: "SwiftTemplate", dependencies: ["SourceryRuntime"]) ] ) """ } #endif /// Brief: /// - Executable cache key is calculated solely on the contents of the SwiftTemplate ephemeral package. /// Rationale: /// 1. cache key is used to find SwiftTemplate `executable` file from a previous compilation /// 2. `SwiftTemplate` contains types from `SourceryRuntime` and `main.swift` /// 3. `main.swift` in `SwiftTemplate` contains `only .swifttemplate file processing result` /// 4. Copied `includeFile` directives from the given `.swifttemplate` are also included into `SwiftTemplate` ephemeral package /// /// Due to this reason, the correct logic for calculating `executableCacheKey` is to only consider contents of `SwiftTemplate` ephemeral package, /// because `main.swift` is **the only file** which changes in `SwiftTemplate` ephemeral binary, and `includeFiles` are the only files that may /// be changed between executions of Sourcery. var executableCacheKey: String? { var contents = mainFileCodeRaw let files = includedFiles.map({ $0.absolute() }).sorted(by: { $0.string < $1.string }) for file in files { let hash = (try? file.read().sha256().base64EncodedString()) ?? "" contents += "\n// \(file.string)-\(hash)" } return contents.sha256() } private func copyRuntimePackage(to path: Path) throws { try FolderSynchronizer().sync(files: sourceryRuntimeFiles, to: path + Path("SourceryRuntime")) } } fileprivate extension SwiftTemplate { static var frameworksPath: Path { return Path(Bundle(for: SwiftTemplate.self).bundlePath + "/Versions/Current/Frameworks") } } // swiftlint:disable:next force_try private let newlines = try! NSRegularExpression(pattern: "\\n\\r|\\r\\n|\\r|\\n", options: []) private extension String { var numberOfLineSeparators: Int { return newlines.matches(in: self, options: [], range: NSRange(location: 0, length: self.count)).count } var stringEncoded: String { return self.unicodeScalars.map { x -> String in return x.escaped(asASCII: true) }.joined(separator: "") } } private extension Process { static func runCommand(path: String, arguments: [String], currentDirectoryPath: Path? = nil) throws -> ProcessResult { let task = Process() var environment = ProcessInfo.processInfo.environment // https://stackoverflow.com/questions/67595371/swift-package-calling-usr-bin-swift-errors-with-failed-to-open-macho-file-to if ProcessInfo.processInfo.environment.keys.contains("OS_ACTIVITY_DT_MODE") { environment = ProcessInfo.processInfo.environment environment["OS_ACTIVITY_DT_MODE"] = nil } task.launchPath = path task.environment = environment task.arguments = arguments if let currentDirectoryPath = currentDirectoryPath { if #available(OSX 10.13, *) { task.currentDirectoryURL = currentDirectoryPath.url } else { task.currentDirectoryPath = currentDirectoryPath.description } } let outputPipe = Pipe() let errorPipe = Pipe() task.standardOutput = outputPipe task.standardError = errorPipe let outHandle = outputPipe.fileHandleForReading let errorHandle = errorPipe.fileHandleForReading Log.verbose(path + " " + arguments.map { "\"\($0)\"" }.joined(separator: " ")) task.launch() let outputData = outHandle.readDataToEndOfFile() let errorData = errorHandle.readDataToEndOfFile() outHandle.closeFile() errorHandle.closeFile() task.waitUntilExit() let output = String(data: outputData, encoding: .utf8) ?? "" let error = String(data: errorData, encoding: .utf8) ?? "" return ProcessResult(output: output, error: error, exitCode: task.terminationStatus) } } extension String { func bridge() -> NSString { #if os(Linux) return NSString(string: self) #else return self as NSString #endif } } struct FolderSynchronizer { struct File { let name: String let content: String init(name: String, content: String) { assert(name.isEmpty == false) self.name = name self.content = content } } func sync(files: [File], to dir: Path) throws { if dir.exists { let synchronizedPaths = files.map { dir + Path($0.name) } try dir.children().forEach({ path in if synchronizedPaths.contains(path) { return } try path.delete() }) } else { try dir.mkpath() } try files.forEach { file in let filePath = dir + Path(file.name) try filePath.write(file.content) } } } ================================================ FILE: SourceryTests/ConfigurationSpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif class ConfigurationSpec: QuickSpec { // swiftlint:disable:next function_body_length override func spec() { let relativePath = Path("/some/path") describe("Configuration") { let serverUrlArg = "serverUrl" let serverUrl: String = "www.example.com" let sourcePath = "Sources" let env = ["SOURCE_PATH": sourcePath, serverUrlArg: serverUrl] context("given valid config file with env placeholders") { it("replaces the env placeholder") { do { let config = try Configuration( path: Stubs.configs + "valid.yml", relativePath: relativePath, env: env ) guard case let Source.sources(paths) = config.source, let path = paths.include.first else { fail("Config has no Source Paths") return } let configServerUrl = config.args[serverUrlArg] as? String expect(configServerUrl).to(equal(serverUrl)) expect(path).to(equal("/some/path/Sources")) } catch { expect("\(error)").to(equal("Invalid config file format. Expected dictionary.")) } } it("removes args entries with missing env variables") { do { let config = try Configuration(path: Stubs.configs + "valid.yml", relativePath: relativePath, env: env) let serverPort = config.args["serverPort"] as? String expect(serverPort).to(equal("")) } catch { expect("\(error)").to(equal("Invalid config file format. Expected dictionary.")) } } } context("given config file with multiple configurations") { it("resolves each configuration") { do { let configs = try Configurations.make( path: Stubs.configs + "multi.yml", relativePath: relativePath, env: env ) expect(configs.count).to(equal(2)) configs.enumerated().forEach { offset, config in guard case let Source.sources(paths) = config.source, let path = paths.include.first else { fail("Config has no Source Paths") return } let configServerUrl = config.args[serverUrlArg] as? String expect(configServerUrl).to(equal("\(serverUrl)/\(offset)")) expect(path).to(equal(Path("/some/path/Sources/\(offset)"))) } } catch { expect("\(error)").to(equal("Invalid config file format. Expected dictionary.")) } } } context("given config file with child configurations") { it("resolves each child configuration") { do { let configs = try Configurations.make( path: Stubs.configs + "parent.yml", relativePath: Stubs.configs, env: env ) expect(configs.count).to(equal(1)) guard case let Source.sources(paths) = configs[0].source, let path = paths.include.first else { fail("Config has no Source Paths") return } let configServerUrl = configs[0].args[serverUrlArg] as? String expect(configServerUrl).to(equal(serverUrl)) expect(path).to(equal(Stubs.configs + sourcePath)) } catch { expect("\(error)").to(equal("Invalid config file format. Expected dictionary.")) } } } context("given invalid config file") { func configError(_ config: [String: Any]) -> String { do { _ = try Configuration(dict: config, relativePath: relativePath) return "No error" } catch { return "\(error)" } } it("throws error on invalid file format") { do { _ = try Configuration( path: Stubs.configs + "invalid.yml", relativePath: relativePath, env: [:] ) fail("expected to throw error") } catch { expect("\(error)").to(equal("Invalid config file format. Expected dictionary.")) } } it("throws error on empty sources") { let config: [String: Any] = ["sources": [], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. No paths provided.")) } it("throws error on missing sources") { let config: [String: Any] = ["templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. 'sources', 'project' or 'package' key are missing.")) } it("throws error on invalid sources format") { let config: [String: Any] = ["sources": ["inc": ["."]], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. No paths provided. Expected list of strings or object with 'include' and optional 'exclude' keys.")) } it("throws error on missing sources include key") { let config: [String: Any] = ["sources": ["exclude": ["."]], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. No paths provided. Expected list of strings or object with 'include' and optional 'exclude' keys.")) } it("throws error on invalid sources include format") { let config: [String: Any] = ["sources": ["include": "."], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. No paths provided. Expected list of strings or object with 'include' and optional 'exclude' keys.")) } it("throws error on missing templates key") { let config: [String: Any] = ["sources": ["."], "output": "."] expect(configError(config)).to(equal("Invalid templates. 'templates' key is missing.")) } it("throws error on empty templates") { let config: [String: Any] = ["sources": ["."], "templates": [], "output": "."] expect(configError(config)).to(equal("Invalid templates. No paths provided.")) } it("throws error on missing template include key") { let config: [String: Any] = ["sources": ["."], "templates": ["exclude": ["."]], "output": "."] expect(configError(config)).to(equal("Invalid templates. No paths provided. Expected list of strings or object with 'include' and optional 'exclude' keys.")) } it("throws error on invalid template include format") { let config: [String: Any] = ["sources": ["."], "templates": ["include": "."], "output": "."] expect(configError(config)).to(equal("Invalid templates. No paths provided. Expected list of strings or object with 'include' and optional 'exclude' keys.")) } it("throws error on empty projects") { let config: [String: Any] = ["project": [], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. No projects provided.")) } it("throws error on missing project file") { let config: [String: Any] = ["project": ["root": "."], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. Project file path is not provided. Expected string.")) } it("throws error on missing target key") { let config: [String: Any] = ["project": ["file": ".", "root": "."], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. 'target' key is missing. Expected object or array of objects.")) } it("throws error on empty targets") { let config: [String: Any] = ["project": ["file": ".", "root": ".", "target": []], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. No targets provided.")) } it("throws error on missing target name key") { let config: [String: Any] = ["project": ["file": ".", "root": ".", "target": ["module": "module"]], "templates": ["."], "output": "."] expect(configError(config)).to(equal("Invalid sources. Target name is not provided. Expected string.")) } it("throws error on missing output key") { let config: [String: Any] = ["sources": ["."], "templates": ["."]] expect(configError(config)).to(equal("Invalid output. 'output' key is missing or is not a string or object.")) } it("throws error on invalid output format") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": ["."]] expect(configError(config)).to(equal("Invalid output. 'output' key is missing or is not a string or object.")) } it("throws error on invalid cacheBasePath format") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": ".", "cacheBasePath": ["."]] expect(configError(config)).to(equal("Invalid cacheBasePath. 'cacheBasePath' key is not a string.")) } } } describe("Source") { context("provided with sources paths") { it("include paths provided as an array") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": "."] let source = try? Configuration(dict: config, relativePath: relativePath).source let expected = Source.sources(Paths(include: [relativePath])) expect(source).to(equal(expected)) } it("include paths provided with `include` key") { let config: [String: Any] = ["sources": ["include": ["."]], "templates": ["."], "output": "."] let source = try? Configuration(dict: config, relativePath: relativePath).source let expected = Source.sources(Paths(include: [relativePath])) expect(source).to(equal(expected)) } it("exclude paths provided with the `exclude` key") { let config: [String: Any] = ["sources": ["include": ["."], "exclude": ["excludedPath"]], "templates": ["."], "output": "."] let source = try? Configuration(dict: config, relativePath: relativePath).source let expected = Source.sources(Paths(include: [relativePath], exclude: [relativePath + "excludedPath"])) expect(source).to(equal(expected)) } } } describe("Templates") { context("provided with templates paths") { it("include paths provided as an array") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": "."] let templates = try? Configuration(dict: config, relativePath: relativePath).templates let expected = Paths(include: [relativePath]) expect(templates).to(equal(expected)) } it("include paths provided with `include` key") { let config: [String: Any] = ["sources": ["."], "templates": ["include": ["."]], "output": "."] let templates = try? Configuration(dict: config, relativePath: relativePath).templates let expected = Paths(include: [relativePath]) expect(templates).to(equal(expected)) } it("exclude paths provided with the `exclude` key") { let config: [String: Any] = ["sources": ["."], "templates": ["include": ["."], "exclude": ["excludedPath"]], "output": "."] let templates = try? Configuration(dict: config, relativePath: relativePath).templates let expected = Paths(include: [relativePath], exclude: [relativePath + "excludedPath"]) expect(templates).to(equal(expected)) } } } describe("Cache Base Path") { context("provided with cacheBasePath") { it("has the correct cacheBasePath") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": ".", "cacheBasePath": "test-base-path"] let cacheBasePath = try? Configuration(dict: config, relativePath: relativePath).cacheBasePath let expected = Path("test-base-path", relativeTo: relativePath) expect(cacheBasePath).to(equal(expected)) } } } describe("Parse Documentation") { context("when parseDocumentation is true") { it("has the correct parseDocumentation") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": ".", "parseDocumentation": true] let parseDocumentation = try? Configuration(dict: config, relativePath: relativePath).parseDocumentation let expected = true expect(parseDocumentation).to(equal(expected)) } } context("when parseDocumentation is unset") { it("defaults to false") { let config: [String: Any] = ["sources": ["."], "templates": ["."], "output": "."] let parseDocumentation = try? Configuration(dict: config, relativePath: relativePath).parseDocumentation let expected = false expect(parseDocumentation).to(equal(expected)) } } } } } extension Source: Equatable { public static func == (lhs: Source, rhs: Source) -> Bool { switch (lhs, rhs) { case let (.projects(lProjects), .projects(rProjects)): return lProjects == rProjects case let (.sources(lPaths), .sources(rPaths)): return lPaths == rPaths default: return false } } } extension Project: Equatable { public static func == (lhs: Project, rhs: Project) -> Bool { return lhs.root == rhs.root } } extension Paths: Equatable { public static func == (lhs: Paths, rhs: Paths) -> Bool { return lhs.include == rhs.include && lhs.exclude == rhs.exclude && lhs.allPaths == rhs.allPaths } } ================================================ FILE: SourceryTests/Generating/JavaScriptTemplateSpecs.swift ================================================ #if !canImport(ObjectiveC) #else import Foundation import Quick import Nimble import PathKit #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime @testable import SourceryJS class JavaScriptTemplateTests: QuickSpec { override func spec() { describe("JavaScriptTemplate") { let outputDir: Path = { return Stubs.cleanTemporarySourceryDir() }() let output = Output(outputDir) it("generates correct output") { let templatePath = Stubs.jsTemplates + Path("Equality.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("provides protocol compositions") { let templatePath = Stubs.jsTemplates + Path("ProtocolCompositions.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("ProtocolCompositions.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) print("expected:\n\(expectedResult)\n\ngot:\n\(result)") expect(result).to(equal(expectedResult)) } it("provides protocol all typealiases") { let templatePath = Stubs.jsTemplates + Path("AllTypealiases.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("AllTypealiases.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) print("expected:\n\(expectedResult)\n\ngot:\n\(result)") expect(result).to(equal(expectedResult)) } it("provides typealias information") { let templatePath = Stubs.jsTemplates + Path("Typealiases.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Typealiases.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) print("expected:\n\(expectedResult)\n\ngot:\n\(result)") expect(result).to(equal(expectedResult)) } it("handles includes") { let templatePath = Stubs.jsTemplates + Path("Includes.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("handles includes from included files relatively") { let templatePath = Stubs.jsTemplates + Path("SubfolderIncludes.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("rethrows template parsing errors") { expect { expect(EJSTemplate.ejsPath).toNot(beNil()) try Generator.generate(nil, types: Types(types: []), functions: [], template: JavaScriptTemplate(templateString: "<% invalid %>", ejsPath: EJSTemplate.ejsPath!)) } .to(throwError(closure: { (error) in expect("\(error)").to(equal(": ReferenceError: ejs:1\n >> 1| <% invalid %>\n\nCan\'t find variable: invalid")) })) } it("rethrows template runtime errors") { expect { expect(EJSTemplate.ejsPath).toNot(beNil()) try Generator.generate(nil, types: Types(types: []), functions: [], template: JavaScriptTemplate(templateString: "<%_ for (type of types.implementing.Some) { -%><% } %>", ejsPath: EJSTemplate.ejsPath!)) } .to(throwError(closure: { (error) in expect("\(error)").to(equal(": Unknown type Some, should be used with `based`")) })) } it("throws unknown property exception") { expect { expect(EJSTemplate.ejsPath).toNot(beNil()) try Generator.generate(nil, types: Types(types: []), functions: [], template: JavaScriptTemplate(templateString: "<%_ for (type of types.implements.Some) { -%><% } %>", ejsPath: EJSTemplate.ejsPath!)) } .to(throwError(closure: { (error) in expect("\(error)").to(equal(": TypeError: ejs:1\n >> 1| <%_ for (type of types.implements.Some) { -%><% } %>\n\nUnknown property `implements`")) })) } it("handles free functions") { let templatePath = Stubs.jsTemplates + Path("Function.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Function.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } } } } #endif ================================================ FILE: SourceryTests/Generating/StencilTemplateSpec.swift ================================================ import Quick import Nimble import PathKit import SourceryStencil #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class StencilTemplateSpec: QuickSpec { // swiftlint:disable:next function_body_length override func spec() { describe("StencilTemplate") { func generate(_ template: String) -> String { let arrayAnnotations = Variable(name: "annotated1", typeName: TypeName(name: "MyClass")) arrayAnnotations.annotations = ["Foo": ["Hello", "beautiful", "World"] as NSArray] let singleAnnotation = Variable(name: "annotated2", typeName: TypeName(name: "MyClass")) singleAnnotation.annotations = ["Foo": "HelloWorld" as NSString] return (try? Generator.generate(nil, types: Types(types: [ Class(name: "MyClass", variables: [ Variable(name: "lowerFirstLetter", typeName: TypeName(name: "myClass")), Variable(name: "upperFirstLetter", typeName: TypeName(name: "MyClass")), arrayAnnotations, singleAnnotation ]) ]), functions: [], template: StencilTemplate(templateString: template))) ?? "" } describe("json") { context("given dictionary") { let context = TemplateContext( parserResult: nil, types: Types(types: []), functions: [], arguments: ["json": ["Version": 1] as NSDictionary] ) it("renders unpretty json") { let result = try? StencilTemplate(templateString: "{{ argument.json | json }}").render(context) expect(result).to(equal("{\"Version\":1}")) } it("renders pretty json") { let result = try? StencilTemplate(templateString: "{{ argument.json | json:true }}").render(context) expect(result).to(equal("{\n \"Version\" : 1\n}")) } } context("given array") { let context = TemplateContext( parserResult: nil, types: Types(types: []), functions: [], arguments: ["json": ["a", "b"] as NSArray] ) it("renders unpretty json") { let result = try? StencilTemplate(templateString: "{{ argument.json | json }}").render(context) expect(result).to(equal("[\"a\",\"b\"]")) } it("renders pretty json") { let result = try? StencilTemplate(templateString: "{{ argument.json | json:true }}").render(context) expect(result).to(equal("[\n \"a\",\n \"b\"\n]")) } } } describe("toArray") { #if canImport(ObjectiveC) context("given array") { it("doesnt modify the value") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | toArray }}{% endfor %}") expect(result).to(equal("[Hello, beautiful, World]")) } } #else context("given array") { it("doesnt modify the value") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | toArray }}{% endfor %}") expect(result).to(equal("[\"Hello\", \"beautiful\", \"World\"]")) } } #endif context("given something") { it("transforms it into array") { let result = generate("{% for key,value in type.MyClass.variables.3.annotations %}{{ value | toArray }}{% endfor %}") expect(result).to(equal("[HelloWorld]")) } } } describe("count") { context("given array") { it("counts it") { let result = generate("{{ type.MyClass.allVariables | count }}") expect(result).to(equal("4")) } } } describe("isEmpty") { context("given empty array") { it("returns true") { let result = generate("{{ type.MyClass.allMethods | isEmpty }}") expect(result).to(equal("true")) } } context("given non-empty array") { it("returns false") { let result = generate("{{ type.MyClass.allVariables | isEmpty }}") expect(result).to(equal("false")) } } } describe("sorted") { #if canImport(ObjectiveC) context("given array") { it("sorts it") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | sorted:\"description\" }}{% endfor %}") expect(result).to(equal("[beautiful, Hello, World]")) } } #else context("given array") { it("sorts it") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | sorted:\"description\" }}{% endfor %}") expect(result).to(equal("[\"beautiful\", \"Hello\", \"World\"]")) } } #endif } describe("sortedDescending") { context("given array") { #if canImport(ObjectiveC) it("sorts it descending") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | sortedDescending:\"description\" }}{% endfor %}") expect(result).to(equal("[World, Hello, beautiful]")) } #else it("sorts it descending") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | sortedDescending:\"description\" }}{% endfor %}") expect(result).to(equal("[\"World\", \"Hello\", \"beautiful\"]")) } #endif } } describe("reversed") { context("given array") { #if canImport(ObjectiveC) it("reverses it") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | reversed }}{% endfor %}") expect(result).to(equal("[World, beautiful, Hello]")) } #else it("reverses it") { let result = generate("{% for key,value in type.MyClass.variables.2.annotations %}{{ value | reversed }}{% endfor %}") expect(result).to(equal("[\"World\", \"beautiful\", \"Hello\"]")) } #endif } } context("given string") { it("generates upperFirstLetter") { expect( generate("{{\"helloWorld\" | upperFirstLetter }}")).to(equal("HelloWorld")) } it("generates lowerFirstLetter") { expect(generate("{{\"HelloWorld\" | lowerFirstLetter }}")).to(equal("helloWorld")) } it("generates uppercase") { expect(generate("{{ \"HelloWorld\" | uppercase }}")).to(equal("HELLOWORLD")) } it("generates lowercase") { expect(generate("{{ \"HelloWorld\" | lowercase }}")).to(equal("helloworld")) } it("generates capitalise") { expect(generate("{{ \"helloWorld\" | capitalise }}")).to(equal("Helloworld")) } it("generates deletingLastComponent") { expect(generate("{{ \"/Path/Class.swift\" | deletingLastComponent }}")).to(equal("/Path")) } it("checks for string in name") { expect(generate("{{ \"FooBar\" | contains:\"oo\" }}")).to(equal("true")) expect(generate("{{ \"FooBar\" | contains:\"xx\" }}")).to(equal("false")) expect(generate("{{ \"FooBar\" | !contains:\"oo\" }}")).to(equal("false")) expect(generate("{{ \"FooBar\" | !contains:\"xx\" }}")).to(equal("true")) } it("checks for string in prefix") { expect(generate("{{ \"FooBar\" | hasPrefix:\"Foo\" }}")).to(equal("true")) expect(generate("{{ \"FooBar\" | hasPrefix:\"Bar\" }}")).to(equal("false")) expect(generate("{{ \"FooBar\" | !hasPrefix:\"Foo\" }}")).to(equal("false")) expect(generate("{{ \"FooBar\" | !hasPrefix:\"Bar\" }}")).to(equal("true")) } it("checks for string in suffix") { expect(generate("{{ \"FooBar\" | hasSuffix:\"Bar\" }}")).to(equal("true")) expect(generate("{{ \"FooBar\" | hasSuffix:\"Foo\" }}")).to(equal("false")) expect(generate("{{ \"FooBar\" | !hasSuffix:\"Bar\" }}")).to(equal("false")) expect(generate("{{ \"FooBar\" | !hasSuffix:\"Foo\" }}")).to(equal("true")) } it("removes instances of a substring") { expect(generate("{{\"helloWorld\" | replace:\"he\",\"bo\" | replace:\"llo\",\"la\" }}")).to(equal("bolaWorld")) expect(generate("{{\"helloWorldhelloWorld\" | replace:\"hello\",\"hola\" }}")).to(equal("holaWorldholaWorld")) expect(generate("{{\"helloWorld\" | replace:\"hello\",\"\" }}")).to(equal("World")) expect(generate("{{\"helloWorld\" | replace:\"foo\",\"bar\" }}")).to(equal("helloWorld")) } } context("given TypeName") { it("generates upperFirstLetter") { expect(generate("{{ type.MyClass.variables.0.typeName }}")).to(equal("myClass")) } it("generates upperFirstLetter") { expect(generate("{{ type.MyClass.variables.0.typeName | upperFirstLetter }}")).to(equal("MyClass")) } it("generates lowerFirstLetter") { expect(generate("{{ type.MyClass.variables.1.typeName | lowerFirstLetter }}")).to(equal("myClass")) } it("generates uppercase") { expect(generate("{{ type.MyClass.variables.0.typeName | uppercase }}")).to(equal("MYCLASS")) } it("generates lowercase") { expect(generate("{{ type.MyClass.variables.1.typeName | lowercase }}")).to(equal("myclass")) } it("generates capitalise") { expect(generate("{{ type.MyClass.variables.1.typeName | capitalise }}")).to(equal("Myclass")) } it("checks for string in name") { expect(generate("{{ type.MyClass.variables.0.typeName | contains:\"my\" }}")).to(equal("true")) expect(generate("{{ type.MyClass.variables.0.typeName | contains:\"xx\" }}")).to(equal("false")) expect(generate("{{ type.MyClass.variables.0.typeName | !contains:\"my\" }}")).to(equal("false")) expect(generate("{{ type.MyClass.variables.0.typeName | !contains:\"xx\" }}")).to(equal("true")) } it("checks for string in prefix") { expect(generate("{{ type.MyClass.variables.0.typeName | hasPrefix:\"my\" }}")).to(equal("true")) expect(generate("{{ type.MyClass.variables.0.typeName | hasPrefix:\"My\" }}")).to(equal("false")) expect(generate("{{ type.MyClass.variables.0.typeName | !hasPrefix:\"my\" }}")).to(equal("false")) expect(generate("{{ type.MyClass.variables.0.typeName | !hasPrefix:\"My\" }}")).to(equal("true")) } it("checks for string in suffix") { expect(generate("{{ type.MyClass.variables.0.typeName | hasSuffix:\"Class\" }}")).to(equal("true")) expect(generate("{{ type.MyClass.variables.0.typeName | hasSuffix:\"class\" }}")).to(equal("false")) expect(generate("{{ type.MyClass.variables.0.typeName | !hasSuffix:\"Class\" }}")).to(equal("false")) expect(generate("{{ type.MyClass.variables.0.typeName | !hasSuffix:\"class\" }}")).to(equal("true")) } it("removes instances of a substring") { expect(generate("{{type.MyClass.variables.0.typeName | replace:\"my\",\"My\" | replace:\"Class\",\"Struct\" }}")).to(equal("MyStruct")) expect(generate("{{type.MyClass.variables.0.typeName | replace:\"s\",\"z\" }}")).to(equal("myClazz")) expect(generate("{{type.MyClass.variables.0.typeName | replace:\"my\",\"\" }}")).to(equal("Class")) expect(generate("{{type.MyClass.variables.0.typeName | replace:\"foo\",\"bar\" }}")).to(equal("myClass")) } } it("rethrows template parsing errors") { expect { try Generator.generate(nil, types: Types(types: []), functions: [], template: StencilTemplate(templateString: "{% tag %}")) } .to(throwError(closure: { (error) in expect("\(error)").to(equal(": Unknown template tag 'tag'")) })) } it("includes partial templates") { var outputDir = Path("/tmp") outputDir = Stubs.cleanTemporarySourceryDir() let templatePath = Stubs.templateDirectory + Path("Include.stencil") let expectedResult = "// Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery\n" + "// DO NOT EDIT\n" + "partial template content\n" expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: Output(outputDir), baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } } } } ================================================ FILE: SourceryTests/Generating/SwiftTemplateSpecs.swift ================================================ // // SwiftTemplateSpecs.swift // Sourcery // // Created by Krunoslav Zaher on 12/30/16. // Copyright © 2016 Pixle. All rights reserved. // import Foundation import Quick import Nimble import PathKit #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif import SourceryFramework @testable import SourceryRuntime @testable import SourcerySwift class SwiftTemplateTests: QuickSpec { // swiftlint:disable function_body_length override func spec() { describe("SwiftTemplate") { let outputDir: Path = { return Stubs.cleanTemporarySourceryDir() }() let output = Output(outputDir) let templatePath = Stubs.swiftTemplates + Path("Equality.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) #if canImport(ObjectiveC) it("creates persistable data") { func templateContextData(_ code: String) -> TemplateContext? { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return nil } let data = NSKeyedArchiver.archivedData(withRootObject: parserResult) let result = Composer.uniqueTypesAndFunctions(parserResult) return TemplateContext(parserResult: try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? FileParserResult, types: .init(types: result.types, typealiases: result.typealiases), functions: result.functions, arguments: [:]) } let maybeContext = templateContextData( """ public struct Periodization { public typealias Action = Identified public struct ActionType { public static let prototypes: [Action] = [] } } """ ) guard let context = maybeContext else { return fail() } let data = NSKeyedArchiver.archivedData(withRootObject: context) let unarchived = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? TemplateContext expect(context.types).to(equal(unarchived?.types)) } #endif it("generates correct output") { expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("throws an error showing the involved line for unmatched delimiter in the template") { let templatePath = Stubs.swiftTemplates + Path("InvalidTag.swifttemplate") expect { try SwiftTemplate(path: templatePath) } .to(throwError(closure: { (error) in expect("\(error)").to(equal("\(templatePath):2 Error while parsing template. Unmatched <%")) })) } it("handles includes") { let templatePath = Stubs.swiftTemplates + Path("Includes.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("handles file includes") { let templatePath = Stubs.swiftTemplates + Path("IncludeFile.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true) .processFiles( .sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError() ) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("handles includes without swifttemplate extension") { let templatePath = Stubs.swiftTemplates + Path("IncludesNoExtension.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("handles file includes without swift extension") { let templatePath = Stubs.swiftTemplates + Path("IncludeFileNoExtension.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("handles includes from included files relatively") { let templatePath = Stubs.swiftTemplates + Path("SubfolderIncludes.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("handles file includes from included files relatively") { let templatePath = Stubs.swiftTemplates + Path("SubfolderFileIncludes.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("throws an error when an include cycle is detected") { let templatePath = Stubs.swiftTemplates + Path("IncludeCycle.swifttemplate") let templateCycleDetectionLocationPath = Stubs.swiftTemplates + Path("includeCycle/Two.swifttemplate") let templateInvolvedInCyclePath = Stubs.swiftTemplates + Path("includeCycle/One.swifttemplate") expect { try SwiftTemplate(path: templatePath) } .to(throwError(closure: { (error) in expect("\(error)").to(equal("\(templateCycleDetectionLocationPath):1 Error: Include cycle detected for \(templateInvolvedInCyclePath). Check your include statements so that templates do not include each other.")) })) } it("throws an error when an include cycle involving the root template is detected") { let templatePath = Stubs.swiftTemplates + Path("SelfIncludeCycle.swifttemplate") expect { try SwiftTemplate(path: templatePath) } .to(throwError(closure: { (error) in expect("\(error)").to(equal("\(templatePath):1 Error: Include cycle detected for \(templatePath). Check your include statements so that templates do not include each other.")) })) } it("rethrows template parsing errors") { let templatePath = Stubs.swiftTemplates + Path("Invalid.swifttemplate") expect { try Generator.generate(.init(path: nil, module: nil, types: [], functions: []), types: Types(types: []), functions: [], template: SwiftTemplate(path: templatePath, version: "version")) } .to(throwError(closure: { (error) in let path = Path.cleanTemporaryDir(name: "build").parent() + "/version/Sources/SwiftTemplate/main.swift" expect("\(error)").to(contain("\(path):11:27: error: missing argument for parameter #1 in call")) expect("\(error)").to(contain("sourceryBuffer.append(\"\\( )\");")) })) } it("rethrows template runtime errors") { let templatePath = Stubs.swiftTemplates + Path("Runtime.swifttemplate") expect { try Generator.generate(.init(path: nil, module: nil, types: [], functions: []), types: Types(types: []), functions: [], template: SwiftTemplate(path: templatePath)) } .to(throwError(closure: { (error) in expect("\(error)").to(equal("\(templatePath): Unknown type Some, should be used with `based`")) })) } it("rethrows errors thrown in template") { let templatePath = Stubs.swiftTemplates + Path("Throws.swifttemplate") expect { try Generator.generate(.init(path: nil, module: nil, types: [], functions: []), types: Types(types: []), functions: [], template: SwiftTemplate(path: templatePath)) } .to(throwError(closure: { (error) in expect("\(error)").to(contain("\(templatePath): SwiftTemplate/main.swift:11: Fatal error: Template not implemented")) })) } context("with existing cache") { context("and missing build dir") { expect { try Sourcery(cacheDisabled: false).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) expect((try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8))).to(equal(expectedResult)) guard let buildDir = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("SwiftTemplate").map({ Path($0.path) }) else { fail("Could not create buildDir path") return } if buildDir.exists { do { try buildDir.delete() } catch { fail("Failed to delete \(buildDir)") } } it("generates the code") { expect { try Sourcery(cacheDisabled: false).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) expect((try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8))).to(equal(expectedResult)) expect { try Sourcery(cacheDisabled: false).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("generates the code asynchronously without throwing error") { let iterations = 2 let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true) as [String] let path = paths[0] let caches = Path(path) + Path("Sourcery") try? caches.delete() @Sendable func generateCode() async throws -> Int { expect { try Sourcery(cacheDisabled: false).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) return 1 } let semaphore = DispatchSemaphore(value: 0) Task { _ = try await withThrowingTaskGroup(of: Int.self) { taskGroup in for _ in 0 ..< iterations { taskGroup.addTask { try await generateCode() } } var counter = 0 for try await _ in taskGroup { counter += 1 } return counter } semaphore.signal() } semaphore.wait() } } } it("handles free functions") { let templatePath = Stubs.swiftTemplates + Path("Function.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Function.swift")).read(.utf8) expect { try Sourcery(cacheDisabled: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result).to(equal(expectedResult)) } it("should have different executableCacheKey based on includeFile modifications") { let templatePath = outputDir + "Template.swifttemplate" try templatePath.write(#"<%- includeFile("Utils.swift") -%>"#) let utilsPath = outputDir + "Utils.swift" try utilsPath.write(#"let foo = "bar""#) let template = try SwiftTemplate(path: templatePath, cachePath: nil, version: "1.0.0") let originalKey = template.executableCacheKey let keyBeforeModification = template.executableCacheKey try utilsPath.write(#"let foo = "baz""#) let keyAfterModification = template.executableCacheKey expect(originalKey).to(equal(keyBeforeModification)) expect(originalKey).toNot(equal(keyAfterModification)) } } describe("FolderSynchronizer") { let outputDir: Path = { return Stubs.cleanTemporarySourceryDir() }() let files: [FolderSynchronizer.File] = [.init(name: "file.swift", content: "Swift code")] it("adds its files to an empty folder") { expect { try FolderSynchronizer().sync(files: files, to: outputDir) } .toNot(throwError()) let newFile = outputDir + Path("file.swift") expect(newFile.exists).to(equal(true)) expect(try? newFile.read()).to(equal("Swift code")) } it("creates the target folder if it does not exist") { let synchronizedFolder = outputDir + Path("Folder") expect { try FolderSynchronizer().sync(files: files, to: synchronizedFolder) } .toNot(throwError()) expect(synchronizedFolder.exists).to(equal(true)) expect(synchronizedFolder.isDirectory).to(equal(true)) } it("deletes files not present in the synchronized files") { let existingFile = outputDir + Path("Existing.swift") expect { try existingFile.write("Discarded") } .toNot(throwError()) expect { try FolderSynchronizer().sync(files: files, to: outputDir) } .toNot(throwError()) expect(existingFile.exists).to(equal(false)) let newFile = outputDir + Path("file.swift") expect(newFile.exists).to(equal(true)) expect(try? newFile.read()).to(equal("Swift code")) } it("replaces the content of a file if a file with the same name already exists") { let existingFile = outputDir + Path("file.swift") expect { try existingFile.write("Discarded") } .toNot(throwError()) expect { try FolderSynchronizer().sync(files: files, to: outputDir) } .toNot(throwError()) expect(try? existingFile.read()).to(equal("Swift code")) } } } } ================================================ FILE: SourceryTests/GeneratorSpec.swift ================================================ import Quick import Nimble import SourceryStencil #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class GeneratorSpec: QuickSpec { // swiftlint:disable function_body_length override func spec() { describe("Generator") { var types: [Type] = [] var arguments: [String: NSObject] = [:] let beforeEachGenerate: () -> Void = { let fooType = Class(name: "Foo", variables: [Variable(name: "intValue", typeName: TypeName(name: "Int"))], inheritedTypes: ["NSObject", "Decodable", "AlternativeProtocol"]) let fooSubclassType = Class(name: "FooSubclass", inheritedTypes: ["Foo", "ProtocolBasedOnKnownProtocol"], annotations: ["foo": NSNumber(value: 2), "smth": ["bar": NSNumber(value: 2)] as NSObject]) let barType = Struct(name: "Bar", inheritedTypes: ["KnownProtocol", "Decodable"], annotations: ["bar": NSNumber(value: true)]) let complexType = Struct(name: "Complex", accessLevel: .public, isExtension: false, variables: []) let fooVar = Variable(name: "foo", typeName: TypeName(name: "Foo"), accessLevel: (read: .public, write: .private), isComputed: false, definedInTypeName: TypeName(name: "Complex")) fooVar.type = fooType let barVar = Variable(name: "bar", typeName: TypeName(name: "Bar"), accessLevel: (read: .public, write: .public), isComputed: false, definedInTypeName: TypeName(name: "Complex")) barVar.type = barType complexType.rawVariables = [ fooVar, barVar, Variable(name: "fooBar", typeName: TypeName(name: "Int", isOptional: true), isComputed: true, definedInTypeName: TypeName(name: "Complex")), Variable(name: "tuple", typeName: .buildTuple(.Int, TypeName(name: "Bar")), definedInTypeName: TypeName(name: "Complex")) ] complexType.rawMethods = [ Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))], accessLevel: .public, definedInTypeName: TypeName(name: "Complex")), Method(name: "foo2(some: Int)", selectorName: "foo2(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Float"))], isStatic: true, definedInTypeName: TypeName(name: "Complex")), Method(name: "foo3(some: Int)", selectorName: "foo3(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))], isClass: true, definedInTypeName: TypeName(name: "Complex")) ] let complexTypeExtension = Type(name: "Complex", isExtension: true, variables: []) complexTypeExtension.rawVariables = [ Variable(name: "fooBarFromExtension", typeName: TypeName(name: "Int"), isComputed: true, definedInTypeName: TypeName(name: "Complex")), Variable(name: "tupleFromExtension", typeName: .buildTuple(.Int, TypeName(name: "Bar")), isComputed: true, definedInTypeName: TypeName(name: "Complex")) ] complexTypeExtension.rawMethods = [ Method(name: "fooFromExtension(some: Int)", selectorName: "fooFromExtension(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))], definedInTypeName: TypeName(name: "Complex")), Method(name: "foo2FromExtension(some: Int)", selectorName: "foo2FromExtension(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Float"))], definedInTypeName: TypeName(name: "Complex")) ] let knownProtocol = Protocol(name: "KnownProtocol", variables: [ Variable(name: "protocolVariable", typeName: TypeName(name: "Int"), isComputed: true, definedInTypeName: TypeName(name: "KnownProtocol")) ], methods: [ Method(name: "foo(some: String)", selectorName: "foo(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "String"))], accessLevel: .public, definedInTypeName: TypeName(name: "KnownProtocol")) ]) let innerOptionsType = Type(name: "InnerOptions", accessLevel: .public, variables: [ Variable(name: "fooInnerOptions", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .public), isComputed: false, definedInTypeName: TypeName(name: "InnerOptions")) ]) innerOptionsType.variables.forEach { $0.definedInType = innerOptionsType } let optionsType = Enum(name: "Options", accessLevel: .public, inheritedTypes: ["KnownProtocol"], cases: [EnumCase(name: "optionA"), EnumCase(name: "optionB")], variables: [ Variable(name: "optionVar", typeName: TypeName(name: "String"), accessLevel: (read: .public, write: .public), isComputed: false, definedInTypeName: TypeName(name: "Options")) ], containedTypes: [innerOptionsType]) types = [ fooType, fooSubclassType, complexType, complexTypeExtension, barType, optionsType, Enum(name: "FooOptions", accessLevel: .public, inheritedTypes: ["Foo", "KnownProtocol"], rawTypeName: TypeName(name: "Foo"), cases: [EnumCase(name: "fooA"), EnumCase(name: "fooB")]), Type(name: "NSObject", accessLevel: .none, isExtension: true, inheritedTypes: ["KnownProtocol"]), Class(name: "ProjectClass", accessLevel: .open), Class(name: "ProjectFooSubclass", inheritedTypes: ["FooSubclass"]), knownProtocol, Protocol(name: "AlternativeProtocol"), Protocol(name: "ProtocolBasedOnKnownProtocol", inheritedTypes: ["KnownProtocol"]) ] arguments = ["some": "value" as NSString, "number": NSNumber(value: Float(4))] } func generate(_ template: String) -> String { beforeEachGenerate() let (uniqueTypes, _, _) = Composer.uniqueTypesAndFunctions(FileParserResult(path: nil, module: nil, types: types, functions: [], typealiases: [])) return (try? Generator.generate(nil, types: Types(types: uniqueTypes), functions: [], template: StencilTemplate(templateString: template), arguments: arguments)) ?? "" } it("generates types.all by skipping protocols") { expect(generate("Found {{ types.all.count }} types")).to(equal("Found 9 types")) } it("generates types.protocols") { expect(generate("Found {{ types.protocols.count }} protocols")).to(equal("Found 3 protocols")) } it("generates types.classes") { expect(generate("Found {{ types.classes.count }} classes, first: {{ types.classes.first.name }}, second: {{ types.classes.last.name }}")).to(equal("Found 4 classes, first: Foo, second: ProjectFooSubclass")) } it("generates types.structs") { expect(generate("Found {{ types.structs.count }} structs, first: {{ types.structs.first.name }}")).to(equal("Found 2 structs, first: Bar")) } it("generates types.enums") { expect(generate("Found {{ types.enums.count }} enums, first: {{ types.enums.first.name }}")).to(equal("Found 2 enums, first: FooOptions")) } it("generates types.extensions") { expect(generate("Found {{ types.extensions.count }} extensions, first: {{ types.extensions.first.name }}")).to(equal("Found 1 extensions, first: NSObject")) } it("feeds types.implementing specific protocol") { expect(generate("Found {{ types.implementing.KnownProtocol.count }} types")).to(equal("Found 8 types")) expect(generate("Found {{ types.implementing.Decodable.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("Found {{ types.implementing.Foo.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("Found {{ types.implementing.NSObject.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("Found {{ types.implementing.Bar.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("{{ types.all|implements:\"KnownProtocol\"|count }}")).to(equal("7")) } it("feeds types.inheriting specific class") { expect(generate("Found {{ types.inheriting.KnownProtocol.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("Found {{ types.inheriting.Decodable.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("Found {{ types.inheriting.Foo.count }} types")).to(equal("Found 2 types")) expect(generate("Found {{ types.inheriting.NSObject.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("Found {{ types.inheriting.Bar.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("{{ types.all|inherits:\"Foo\"|count }}")).to(equal("2")) } it("feeds types.based specific type or protocol") { expect(generate("Found {{ types.based.KnownProtocol.count }} types")).to(equal("Found 8 types")) expect(generate("Found {{ types.based.Decodable.count }} types")).to(equal("Found 4 types")) expect(generate("Found {{ types.based.Foo.count }} types")).to(equal("Found 2 types")) expect(generate("Found {{ types.based.NSObject.count }} types")).to(equal("Found 3 types")) expect(generate("Found {{ types.based.Bar.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("{{ types.all|based:\"Decodable\"|count }}")).to(equal("4")) } it("feeds types.extends specific type or protocol") { expect(generate("Found {{ types.based.KnownProtocol.count }} types")).to(equal("Found 8 types")) expect(generate("Found {{ types.based.Decodable.count }} types")).to(equal("Found 4 types")) expect(generate("Found {{ types.based.Foo.count }} types")).to(equal("Found 2 types")) expect(generate("Found {{ types.based.NSObject.count }} types")).to(equal("Found 3 types")) expect(generate("Found {{ types.based.Bar.count|default:\"0\" }} types")).to(equal("Found 0 types")) expect(generate("{{ types.all|based:\"Decodable\"|count }}")).to(equal("4")) } describe("accessing specific type via type.Typename") { it("can render accessLevel") { expect(generate("{{ type.Complex.accessLevel }}")).to(equal("public")) } it("can access supertype") { expect(generate("{{ type.FooSubclass.supertype.name }}")).to(equal("Foo")) } it("counts all variables including implements, inherits") { expect(generate("{{ type.ProjectFooSubclass.allVariables.count }}")).to(equal("2")) } it("can use annotations filter") { expect(generate("{% for type in types.all|annotated:\"bar\" %}{{ type.name }}{% endfor %}")).to(equal("Bar")) expect(generate("{% for type in types.all|annotated:\"foo = 2\" %}{{ type.name }}{% endfor %}")).to(equal("FooSubclass")) expect(generate("{% for type in types.all|annotated:\"smth.bar = 2\" %}{{ type.name }}{% endfor %}")).to(equal("FooSubclass")) expect(generate("{% for type in types.all where type.annotations.smth.bar == 2 %}{{ type.name }}{% endfor %}")).to(equal("FooSubclass")) } it("can use filter on variables") { expect(generate("{{ type.Complex.allVariables|computed|count }}")).to(equal("3")) expect(generate("{{ type.Complex.allVariables|stored|count }}")).to(equal("3")) expect(generate("{{ type.Complex.allVariables|instance|count }}")).to(equal("6")) expect(generate("{{ type.Complex.allVariables|static|count }}")).to(equal("0")) expect(generate("{{ type.Complex.allVariables|tuple|count }}")).to(equal("2")) expect(generate("{{ type.Complex.allVariables|optional|count }}")).to(equal("1")) expect(generate("{{ type.Complex.allVariables|implements:\"KnownProtocol\"|count }}")).to(equal("2")) expect(generate("{{ type.Complex.allVariables|based:\"Decodable\"|count }}")).to(equal("2")) expect(generate("{{ type.Complex.allVariables|inherits:\"NSObject\"|count }}")).to(equal("0")) } it("can use filter on methods") { expect(generate("{{ type.Complex.allMethods|instance|count }}")).to(equal("3")) expect(generate("{{ type.Complex.allMethods|class|count }}")).to(equal("1")) expect(generate("{{ type.Complex.allMethods|static|count }}")).to(equal("1")) expect(generate("{{ type.Complex.allMethods|initializer|count }}")).to(equal("0")) expect(generate("{{ type.Complex.allMethods|count }}")).to(equal("5")) } it("can use access level filter on types") { expect(generate("{{ types.all|public|count }}")).to(equal("3")) expect(generate("{{ types.all|open|count }}")).to(equal("1")) expect(generate("{{ types.all|!private|!fileprivate|!internal|count }}")).to(equal("4")) } it("can use access level filter on methods") { expect(generate("{{ type.Complex.methods|public|count }}")).to(equal("1")) expect(generate("{{ type.Complex.methods|private|count }}")).to(equal("0")) expect(generate("{{ type.Complex.methods|internal|count }}")).to(equal("4")) } it("can use access level filter on variables") { expect(generate("{{ type.Complex.variables|publicGet|count }}")).to(equal("2")) expect(generate("{{ type.Complex.variables|publicSet|count }}")).to(equal("1")) expect(generate("{{ type.Complex.variables|privateSet|count }}")).to(equal("1")) } it("can use definedInExtension filter on variables") { expect(generate("{{ type.Complex.variables|definedInExtension|count }}")).to(equal("2")) expect(generate("{{ type.Complex.variables|!definedInExtension|count }}")).to(equal("4")) } it("can use definedInExtension filter on methods") { expect(generate("{{ type.Complex.methods|definedInExtension|count }}")).to(equal("2")) expect(generate("{{ type.Complex.methods|!definedInExtension|count }}")).to(equal("3")) } context("given tuple variable") { it("can access tuple elements") { expect(generate("{% for var in type.Complex.allVariables|tuple %}{% for e in var.typeName.tuple.elements %}{{ e.typeName.name }},{% endfor %}{% endfor %}")).to(equal("Int,Bar,Int,Bar,")) } it("can access tuple element type metadata") { expect(generate("{% for var in type.Complex.allVariables|tuple %}{% for e in var.typeName.tuple.elements|implements:\"KnownProtocol\" %}{{ e.type.name }},{% endfor %}{% endfor %}")).to(equal("Bar,Bar,")) } } it("generates type.TypeName") { expect(generate("{{ type.Foo.name }} has {{ type.Foo.variables.first.name }} variable")).to(equal("Foo has intValue variable")) } it("generates contained types properly, type.ParentType.ContainedType properly") { expect(generate("{{ type.Options.containedType.InnerOptions.variables.count }} variables, first {{ type.Options.containedType.InnerOptions.variables.first.name }}")).to(equal("1 variables, first fooInnerOptions")) } it("generates enum properly") { expect(generate("{% for case in type.Options.cases %} {{ case.name }} {% endfor %}")).to(equal(" optionA optionB ")) } it("classifies computed properties properly") { expect(generate("{{ type.Complex.variables.count }}, {{ type.Complex.computedVariables.count }}, {{ type.Complex.storedVariables.count }}")).to(equal("6, 3, 3")) } it("can access variable type information") { expect(generate("{% for variable in type.Complex.variables %}{{ variable.type.name }}{% endfor %}")).to(equal("FooBar")) } #if canImport(ObjectiveC) it("can render variable isOptional") { expect(generate("{{ type.Complex.variables.first.isOptional }}")).to(equal("0")) } #else it("can render variable isOptional") { expect(generate("{{ type.Complex.variables.first.isOptional }}")).to(equal("false")) } #endif it("can render variable definedInType") { expect(generate("{% for type in types.all %}{% for variable in type.variables %}{{ variable.definedInType.name }} {% endfor %}{% endfor %}")).to(equal("Complex Complex Complex Complex Complex Complex Foo Options ")) } it("can render method definedInType") { expect(generate("{% for type in types.all %}{% for method in type.methods %}{{ method.definedInType.name }} {% endfor %}{% endfor %}")).to(equal("Complex Complex Complex Complex Complex ")) } it("generates proper response for type.inherits") { expect(generate("{% if type.Foo.inherits.ProjectClass %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.Foo.inherits.Decodable %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.Foo.inherits.KnownProtocol %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.Foo.inherits.AlternativeProtocol %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.inherits.Foo %} TRUE {% endif %}")).to(equal(" TRUE ")) } it("generates proper response for type.implements") { expect(generate("{% if type.Bar.implements.ProjectClass %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.Bar.implements.Decodable %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.Bar.implements.KnownProtocol %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.implements.KnownProtocol %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.implements.AlternativeProtocol %} TRUE {% endif %}")).to(equal(" TRUE ")) } it("generates proper response for type.based") { expect(generate("{% if type.Bar.based.ProjectClass %} TRUE {% endif %}")).toNot(equal(" TRUE ")) expect(generate("{% if type.Bar.based.Decodable %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.Bar.based.KnownProtocol %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.based.KnownProtocol %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.based.Foo %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.based.Decodable %} TRUE {% endif %}")).to(equal(" TRUE ")) expect(generate("{% if type.ProjectFooSubclass.based.AlternativeProtocol %} TRUE {% endif %}")).to(equal(" TRUE ")) } } context("given additional arguments") { it("can reflect them") { expect(generate("{{ argument.some }}")).to(equal("value")) } it("parses numbers correctly") { expect(generate("{% if argument.number > 2 %}TRUE{% endif %}")).to(equal("TRUE")) } } } } } ================================================ FILE: SourceryTests/Helpers/Builders.swift ================================================ import Foundation import SourceryRuntime extension TypeName { static func buildArray(of elementType: TypeName, useGenericName: Bool = false) -> TypeName { let name = useGenericName ? "Array<\(elementType.asSource)>": "[\(elementType.asSource)]" let array = ArrayType(name: name, elementTypeName: elementType) return TypeName(name: array.name, array: array, generic: array.asGeneric) } static func buildSet(of elementType: TypeName) -> TypeName { let name = "Set<\(elementType.asSource)>" let set = SetType(name: name, elementTypeName: elementType) return TypeName(name: set.name, set: set, generic: set.asGeneric) } static func buildDictionary(key keyTypeName: TypeName, value valueTypeName: TypeName, useGenericName: Bool = false) -> TypeName { let name = useGenericName ? "Dictionary<\(keyTypeName.asSource), \(valueTypeName.asSource)>": "[\(keyTypeName.asSource): \(valueTypeName.asSource)]" let dictionary = DictionaryType(name: name, valueTypeName: valueTypeName, keyTypeName: keyTypeName) return TypeName(name: dictionary.name, dictionary: dictionary, generic: dictionary.asGeneric) } static func buildTuple(_ elements: TupleElement...) -> TypeName { let name = "(\(elements.enumerated().map { "\($1.name == "\($0)" ? $1.typeName.asSource : $1.asSource)" }.joined(separator: ", ")))" let tuple = TupleType(name: name, elements: elements) return TypeName(name: tuple.name, tuple: tuple) } static func buildTuple(_ elements: TypeName...) -> TypeName { let name = "(\(elements.map { "\($0.asSource)" }.joined(separator: ", ")))" let tuple = TupleType(name: name, elements: elements.enumerated().map { TupleElement(name: "\($0)", typeName: $1) }) return TypeName(name: name, tuple: tuple) } static func buildClosure(_ returnTypeName: TypeName, attributes: AttributeList = [:]) -> TypeName { let closure = ClosureType(name: "() -> \(returnTypeName)", parameters: [], returnTypeName: returnTypeName) return TypeName(name: closure.name, attributes: attributes, closure: closure) } static func buildClosure(_ parameters: ClosureParameter..., returnTypeName: TypeName) -> TypeName { let closure = ClosureType(name: "\(parameters.asSource) -> \(returnTypeName)", parameters: parameters, returnTypeName: returnTypeName) return TypeName(name: closure.name, closure: closure) } static func buildClosure(_ parameters: TypeName..., returnTypeName: TypeName) -> TypeName { let parameters = parameters.map({ ClosureParameter(typeName: $0) }) let closure = ClosureType(name: "\(parameters.asSource) -> \(returnTypeName)", parameters: parameters, returnTypeName: returnTypeName) return TypeName(name: closure.name, closure: closure) } var asOptional: TypeName { let type = self return TypeName(name: type.name, isOptional: true, isImplicitlyUnwrappedOptional: type.isImplicitlyUnwrappedOptional, tuple: type.tuple, array: type.array, dictionary: type.dictionary, closure: type.closure, set: type.set, generic: type.generic ) } static var Void: TypeName { TypeName(name: "Void") } static var `Any`: TypeName { TypeName(name: "Any") } static var Int: TypeName { TypeName(name: "Int") } static var String: TypeName { TypeName(name: "String") } static var Float: TypeName { TypeName(name: "Float") } } ================================================ FILE: SourceryTests/Helpers/CustomMatchers.swift ================================================ // // Created by Krzysztof Zabłocki on 22/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime import Nimble import Quick /// A Nimble matcher that succeeds when the actual value is equal to the expected value. /// Values can support equal by supporting the Equatable protocol. /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(_ expectedValue: T?) -> Predicate where T: Diffable { return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg -> PredicateResult in var msg = msg let actualValue = try actualExpression.evaluate() let matches = actualValue == expectedValue && expectedValue != nil if expectedValue == nil || actualValue == nil { if expectedValue == nil { return PredicateResult( status: .fail, message: msg.appendedBeNilHint() ) } return PredicateResult( status: .fail, message: msg ) } if !matches, let actual = actualValue, let expected = expectedValue { let results = DiffableResult() results.trackDifference(actual: actual, expected: expected) prepare(&msg, results: results, actual: stringify(actualValue)) } return PredicateResult(status: PredicateStatus(bool: matches), message: msg) } } /// A Nimble matcher that succeeds when the actual collection is equal to the expected collection. /// Items must implement the Equatable protocol. public func equal(_ expectedValue: [T]?) -> Predicate<[T]> where T: Diffable { return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg -> PredicateResult in var msg = msg let actualValue = try actualExpression.evaluate() if expectedValue == nil || actualValue == nil { if expectedValue == nil { return PredicateResult( status: .fail, message: msg.appendedBeNilHint() ) } return PredicateResult( status: .fail, message: msg ) } // swiftlint:disable:next force_unwrapping let matches = expectedValue! == actualValue! if !matches, let actual = actualValue, let expected = expectedValue { let results = DiffableResult() results.trackDifference(actual: actual, expected: expected) prepare(&msg, results: results, actual: stringify(actualValue)) } return PredicateResult(status: PredicateStatus(bool: matches), message: msg) } } /// A Nimble matcher that succeeds when the actual value is equal to the expected value. /// Values can support equal by supporting the Equatable protocol. /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(_ expectedValue: [T: C]?) -> Predicate<[T: C]> where C: Diffable { return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg -> PredicateResult in var msg = msg let actualValue = try actualExpression.evaluate() if expectedValue == nil || actualValue == nil { if expectedValue == nil { return PredicateResult( status: .fail, message: msg.appendedBeNilHint() ) } return PredicateResult( status: .fail, message: msg ) } // swiftlint:disable:next force_unwrapping let matches = expectedValue! == actualValue! if !matches, let actual = actualValue, let expected = expectedValue { let results = DiffableResult() results.trackDifference(actual: actual, expected: expected) prepare(&msg, results: results, actual: stringify(actualValue)) } return PredicateResult(status: PredicateStatus(bool: matches), message: msg) } } private func prepare(_ message: inout ExpectationMessage, results: DiffableResult, actual: String) { if !results.isEmpty { message = .fail("\(results)") } } ================================================ FILE: SourceryTests/Helpers/Extensions.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime extension String { var withoutWhitespaces: String { return components(separatedBy: .whitespacesAndNewlines).joined(separator: "") } } extension Type { public func asUnknownException() -> Self { isUnknownExtension = true return self } } ================================================ FILE: SourceryTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: SourceryTests/Models/ActorSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class ActorSpec: QuickSpec { override func spec() { describe("Actor") { var sut: Type? beforeEach { sut = Actor(name: "Foo", variables: [], inheritedTypes: [], modifiers: [.init(name: "distributed")]) } afterEach { sut = nil } it("reports kind as actor") { expect(sut?.kind).to(equal("actor")) } it("reports is distributed as true") { expect((sut as? Actor)?.isDistributed).to(beTrue()) } } } } ================================================ FILE: SourceryTests/Models/ArrayTypeSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class ArrayTypeSpec: QuickSpec { override func spec() { describe("Array") { var sut: ArrayType? beforeEach { sut = ArrayType(name: "Foo", elementTypeName: TypeName(name: "Foo"), elementType: Type(name: "Bar")) } afterEach { sut = nil } it("preserves element type for generic") { expect(sut?.asGeneric.typeParameters.first?.type).toNot(beNil()) } } } } ================================================ FILE: SourceryTests/Models/ClassSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class ClassSpec: QuickSpec { override func spec() { describe("Class") { var sut: Type? beforeEach { sut = Class(name: "Foo", variables: [], inheritedTypes: []) } afterEach { sut = nil } it("reports kind as class") { expect(sut?.kind).to(equal("class")) } it("supports package access level") { expect(Class(name: "Foo", accessLevel: .package).accessLevel == AccessLevel.package.rawValue).to(beTrue()) expect(Class(name: "Foo", accessLevel: .internal).accessLevel == AccessLevel.package.rawValue).to(beFalse()) } } } } ================================================ FILE: SourceryTests/Models/DiffableSpec.swift ================================================ // // Created by Krzysztof Zabłocki on 23/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class DiffableSpec: QuickSpec { override func spec() { describe("DiffableResults") { var sut = DiffableResult() beforeEach { sut = DiffableResult() } describe("isEmpty") { context("given its empty") { it("returns true") { expect(sut.isEmpty).to(beTrue()) } } context("given its not empty") { it("returns false") { sut.append("Something") expect(sut.isEmpty).to(beFalse()) } } } it("appends element") { sut.append("Expected value") expect("\(sut)").to(equal("Expected value")) } it("ads newline separator between elements") { sut.append("Value 1") sut.append("Value 2") expect("\(sut)").to(equal("Value 1\nValue 2")) } it("processes identifier for all elements") { sut.identifier = "Prefixed" sut.append("Value 1") sut.append("Value 2") expect("\(sut)").to(equal("Prefixed Value 1\nValue 2")) } it("joins 2 diffable results") { sut.append("Value 1") sut.append(contentsOf: DiffableResult(results: ["Value 2"])) expect("\(sut)").to(equal("Value 1\nValue 2")) } describe("trackDifference") { context("given not diffable elements") { it("ads them if they aren't equal") { sut.trackDifference(actual: 3, expected: 5) expect("\(sut)").to(equal("")) } it("doesn't add them if they are equal") { sut.trackDifference(actual: 3, expected: 3) expect("\(sut)").to(equal("")) } } context("given diffable elements") { it("ads them if they aren't equal") { sut.trackDifference(actual: Type(name: "Foo"), expected: Type(name: "Bar")) expect("\(sut)").to(equal("localName ")) } it("doesn't add them if they are equal") { sut.trackDifference(actual: Type(name: "Foo"), expected: Type(name: "Foo")) expect("\(sut)").to(equal("")) } context("given arrays") { it("finds difference in count") { sut.trackDifference( actual: [Type(name: "Foo")], expected: [Type(name: "Foo"), Type(name: "Foo2")]) expect("\(sut)").to(equal("Different count, expected: 2, received: 1")) } it("finds difference at given idx") { sut.trackDifference( actual: [Type(name: "Foo"), Type(name: "Foo")], expected: [Type(name: "Foo"), Type(name: "Foo2")]) expect("\(sut)").to(equal("idx 1: localName ")) } it("finds difference at multiple idx") { sut.trackDifference( actual: [Type(name: "FooBar"), Type(name: "Foo")], expected: [Type(name: "Foo"), Type(name: "Foo2")]) expect("\(sut)").to(equal("idx 0: localName \nidx 1: localName ")) } } context("given dictionaries") { it("finds difference in count") { sut.trackDifference( actual: ["Key": Type(name: "Foo")], expected: ["Key": Type(name: "Foo"), "Something": Type(name: "Bar")]) expect("\(sut)").to(equal("Different count, expected: 2, received: 1\nMissing keys: Something")) } it("finds difference at given key count") { sut.trackDifference( actual: ["Key": Type(name: "Foo"), "Something": Type(name: "FooBar")], expected: ["Key": Type(name: "Foo"), "Something": Type(name: "Bar")]) expect("\(sut)").to(equal("key \"Something\": localName ")) } } } } } } } ================================================ FILE: SourceryTests/Models/EnumSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class EnumSpec: QuickSpec { override func spec() { describe("Enum") { var sut: Enum? let variable = Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: false, definedInTypeName: TypeName(name: "Foo")) beforeEach { sut = Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")]) } afterEach { sut = nil } it("reports kind as enum") { expect(sut?.kind).to(equal("enum")) } it("doesn't have associated values") { expect(sut?.hasAssociatedValues).to(beFalse()) } context("given associated values") { it("hasAssociatedValues") { let sut = Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA", associatedValues: [AssociatedValue(name: nil, typeName: TypeName(name: "Int"))]), EnumCase(name: "CaseB")]) expect(sut.hasAssociatedValues).to(beTrue()) } } describe("When testing equality") { #if canImport(ObjectiveC) context("given same items") { it("is equal") { expect(sut).to(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")]))) } } #endif context("given different items") { it("is not equal") { expect(sut).toNot(equal(Enum(name: "Bar", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")], variables: [variable]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .public, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: true, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [EnumCase(name: "CaseA"), EnumCase(name: "CaseB")]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseB")]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseB", associatedValues: [AssociatedValue(name: nil, typeName: TypeName(name: "Int"))])]))) expect(sut).toNot(equal(Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "CaseB")]))) } } } } } } ================================================ FILE: SourceryTests/Models/MethodSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class MethodSpec: QuickSpec { override func spec() { describe("Method") { var sut: SourceryMethod? beforeEach { sut = Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))], definedInTypeName: TypeName(name: "Bar")) } afterEach { sut = nil } it("reports short name properly") { expect(sut?.shortName).to(equal("foo")) } it("reports isDynamic properly") { expect(Method(name: "foo()", modifiers: [Modifier(name: "dynamic", detail: nil)]).isDynamic).to(beTrue()) expect(Method(name: "foo()", modifiers: [Modifier(name: "mutating", detail: nil)]).isDynamic).to(beFalse()) } it("reports definedInTypeName propertly") { expect(Method(name: "foo()", definedInTypeName: TypeName(name: "BarAlias", actualTypeName: TypeName(name: "Bar"))).definedInTypeName).to(equal(TypeName(name: "BarAlias"))) expect(Method(name: "foo()", definedInTypeName: TypeName(name: "Foo")).definedInTypeName).to(equal(TypeName(name: "Foo"))) } it("reports actualDefinedInTypeName propertly") { expect(Method(name: "foo()", definedInTypeName: TypeName(name: "BarAlias", actualTypeName: TypeName(name: "Bar"))).actualDefinedInTypeName).to(equal(TypeName(name: "Bar"))) } it("reports isDeinitializer properly") { expect(sut?.isDeinitializer).to(beFalse()) expect(Method(name: "deinitObjects() {}").isDeinitializer).to(beFalse()) expect(Method(name: "deinit").isDeinitializer).to(beTrue()) } it("reports isInitializer properly") { expect(sut?.isInitializer).to(beFalse()) expect(Method(name: "init()").isInitializer).to(beTrue()) } it("reports failable initializer return type as optional") { expect(Method(name: "init()", isFailableInitializer: true).isOptionalReturnType).to(beTrue()) } it("reports generic method") { expect(Method(name: "foo()").isGeneric).to(beTrue()) expect(Method(name: "foo()").isGeneric).to(beFalse()) } it("reports throws error generic type") { expect(Method(name: "foo() throws(E)", throws: true, throwsTypeName: TypeName("E"), genericRequirements: [], genericParameters: [GenericParameter(name: "E", inheritedTypeName: TypeName("Error"))]).isThrowsTypeGeneric).to(beTrue()) expect(Method(name: "foo() throws(E) where E: Error", throws: true, throwsTypeName: TypeName("E"), genericRequirements: [GenericRequirement(leftType: AssociatedType(name: "E", typeName: TypeName("E"), type: nil), rightType: GenericTypeParameter(typeName: TypeName("Error"), type: nil), relationship: .conformsTo)], genericParameters: [GenericParameter(name: "E")]).isThrowsTypeGeneric).to(beTrue()) expect(Method(name: "foo()").isThrowsTypeGeneric).to(beFalse()) } it("reports distributed method") { expect(Method(name: "foo()", modifiers: [.init(name: "distributed")]).isDistributed).to(beTrue()) } it("has correct access level") { expect(Method(name: "foo()", accessLevel: .package).accessLevel == AccessLevel.package.rawValue).to(beTrue()) expect(Method(name: "foo()", accessLevel: .open).accessLevel == AccessLevel.package.rawValue).to(beFalse()) } describe("When testing equality") { context("given same items") { it("is equal") { expect(sut).to(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))], definedInTypeName: TypeName(name: "Bar")))) } } context("given different items") { var mockMethodParameters: [MethodParameter]! beforeEach { mockMethodParameters = [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))] } it("is not equal") { expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: [MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int"))], definedInTypeName: TypeName(name: "Baz")))) expect(sut).toNot(equal(Method(name: "bar(some: Int)", selectorName: "bar(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), accessLevel: .internal, isStatic: false, isClass: false, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: [], returnTypeName: TypeName(name: "Void"), accessLevel: .internal, isStatic: false, isClass: false, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "String"), accessLevel: .internal, isStatic: false, isClass: false, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), throws: true, accessLevel: .internal, isStatic: false, isClass: false, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), accessLevel: .public, isStatic: false, isClass: false, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), accessLevel: .internal, isStatic: true, isClass: false, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), accessLevel: .internal, isStatic: false, isClass: true, isFailableInitializer: false, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), accessLevel: .internal, isStatic: false, isClass: false, isFailableInitializer: true, annotations: [:]))) expect(sut).toNot(equal(Method(name: "foo(some: Int)", selectorName: "foo(some:)", parameters: mockMethodParameters, returnTypeName: TypeName(name: "Void"), accessLevel: .internal, isStatic: false, isClass: false, isFailableInitializer: false, annotations: ["some": NSNumber(value: true)]))) } } } } describe("MethodParameter") { var sut: MethodParameter! context("given default initializer parameters") { beforeEach { sut = MethodParameter(index: 0, typeName: TypeName(name: "Int")) } it("has empty name") { expect(sut.name).to(equal("")) } it("has empty argumentLabel") { expect(sut.argumentLabel).to(equal("")) } it("has no type") { expect(sut.type).to(beNil()) } it("has not default value") { expect(sut.defaultValue).to(beNil()) } it("has no annotations") { expect(sut.annotations).to(equal([:])) } it("is not inout") { expect(sut.inout).to(beFalse()) } } context("given method parameter with attributes") { beforeEach { sut = MethodParameter(index: 0, typeName: TypeName(name: "ConversationApiResponse", attributes: ["escaping": [Attribute(name: "escaping")]])) } it("returns unwrapped type name") { expect(sut.unwrappedTypeName).to(equal("ConversationApiResponse")) } } context("when inout") { beforeEach { sut = MethodParameter(index: 0, typeName: TypeName(name: "Bar"), isInout: true) } it("is inout") { expect(sut.inout).to(beTrue()) } } describe("when testing equality") { beforeEach { sut = MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "Int")) } context("given same items") { it("is equal") { expect(sut).to(equal(MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "Int")))) } } context("given different items") { it("is not equal") { expect(sut).toNot(equal(MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "Int")))) expect(sut).toNot(equal(MethodParameter(argumentLabel: "bar", name: "foo", index: 0, typeName: TypeName(name: "Int")))) expect(sut).toNot(equal(MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "String")))) expect(sut).toNot(equal(MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "String"), isInout: true))) } } } } } } ================================================ FILE: SourceryTests/Models/ProtocolSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class ProtocolSpec: QuickSpec { override func spec() { describe("Protocol") { var sut: Type? beforeEach { sut = Protocol(name: "Foo", variables: [], inheritedTypes: []) } afterEach { sut = nil } it("reports kind as protocol") { expect(sut?.kind).to(equal("protocol")) } it("supports package access level") { expect(Protocol(name: "Foo", accessLevel: .package).accessLevel == AccessLevel.package.rawValue).to(beTrue()) expect(Protocol(name: "Foo", accessLevel: .internal).accessLevel == AccessLevel.package.rawValue).to(beFalse()) } } } } ================================================ FILE: SourceryTests/Models/StructSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class StructSpec: QuickSpec { override func spec() { describe("Struct") { var sut: Struct? beforeEach { sut = Struct(name: "Foo", variables: [], inheritedTypes: []) } afterEach { sut = nil } it("reports kind as struct") { expect(sut?.kind).to(equal("struct")) } } } } ================================================ FILE: SourceryTests/Models/TypeSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class TypeSpec: QuickSpec { override func spec() { describe("Type") { var sut: Type? let staticVariable = Variable(name: "staticVar", typeName: TypeName(name: "Int"), isStatic: true) let computedVariable = Variable(name: "variable", typeName: TypeName(name: "Int"), isComputed: true) let storedVariable = Variable(name: "otherVariable", typeName: TypeName(name: "Int"), isComputed: false) let supertypeVariable = Variable(name: "supertypeVariable", typeName: TypeName(name: "Int"), isComputed: true) let superTypeMethod = Method(name: "doSomething()", definedInTypeName: TypeName(name: "Protocol")) let secondMethod = Method(name: "doSomething()", returnTypeName: TypeName(name: "Int")) let overrideMethod = superTypeMethod let overrideVariable = supertypeVariable let initializer = Method(name: "init()", definedInTypeName: TypeName(name: "Foo")) let parentType = Type(name: "Parent") let protocolType = Type(name: "Protocol", variables: [Variable(name: "supertypeVariable", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none))], methods: [superTypeMethod]) let superType = Type(name: "Supertype", variables: [supertypeVariable], methods: [superTypeMethod], inheritedTypes: ["Protocol"]) superType.implements["Protocol"] = protocolType beforeEach { sut = Type(name: "Foo", parent: parentType, variables: [storedVariable, computedVariable, staticVariable, overrideVariable], methods: [initializer, overrideMethod, secondMethod], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]) sut?.supertype = superType } afterEach { sut = nil } it("being not an extension reports kind as unknown") { expect(sut?.kind).to(equal("unknown")) } it("being an extension reports kind as extension") { expect((Type(name: "Foo", isExtension: true)).kind).to(equal("extension")) } it("resolves name") { expect(sut?.name).to(equal("Parent.Foo")) } it("has local name") { expect(sut?.localName).to(equal("Foo")) } it("filters static variables") { expect(sut?.staticVariables).to(equal([staticVariable])) } it("filters computed variables") { expect(sut?.computedVariables).to(equal([computedVariable, overrideVariable])) } it("filters stored variables") { expect(sut?.storedVariables).to(equal([storedVariable])) } it("filters instance variables") { expect(sut?.instanceVariables).to(equal([storedVariable, computedVariable, overrideVariable])) } it("filters initializers") { expect(sut?.initializers).to(equal([initializer])) } it("flattens methods from supertype") { expect(sut?.allMethods).to(equal([initializer, overrideMethod, secondMethod])) } it("flattens variables from supertype") { expect(sut?.allVariables).to(equal([storedVariable, computedVariable, staticVariable, overrideVariable])) expect(superType.allVariables).to(equal([supertypeVariable])) } describe("isGeneric") { context("given generic type") { it("recognizes correctly for simple generic") { let sut = Type(name: "Foo", isGeneric: true) expect(sut.isGeneric).to(beTrue()) } } context("given non-generic type") { it("recognizes correctly for simple type") { let sut = Type(name: "Foo") expect(sut.isGeneric).to(beFalse()) } } } describe("when setting containedTypes") { it("sets their parent to self") { let type = Type(name: "Bar", isExtension: false) sut?.containedTypes = [type] expect(type.parent).to(beIdenticalTo(sut)) } } describe("when extending with Type extension") { it("adds variables if they are unique") { let extraVariable = Variable(name: "variable2", typeName: TypeName(name: "Int")) let type = Type(name: "Foo", isExtension: true, variables: [extraVariable]) sut?.extend(type) expect(sut?.variables).to(equal([storedVariable, computedVariable, staticVariable, overrideVariable, extraVariable])) } it("does not duplicate variables of same configuration") { let type = Type(name: "Foo", isExtension: true, variables: [storedVariable]) sut?.extend(type) expect(sut?.variables).to(equal([storedVariable, computedVariable, staticVariable, overrideVariable])) } it("does not duplicate variables with protocol extension") { let aExtension = Type(name: "Foo", isExtension: true, variables: [Variable(name: "variable", typeName: TypeName(name: "Int"), isComputed: true)]) let aProtocol = Protocol(name: "Foo", variables: [Variable(name: "variable", typeName: TypeName(name: "Int"))]) aProtocol.extend(aExtension) expect(aProtocol.variables).to(equal([Variable(name: "variable", typeName: TypeName(name: "Int"))])) } it("adds methods") { let extraMethod = Method(name: "foo()", definedInTypeName: TypeName(name: "Foo")) let type = Type(name: "Foo", isExtension: true, methods: [extraMethod]) sut?.extend(type) expect(sut?.methods).to(equal([initializer, overrideMethod, secondMethod, extraMethod])) } it("does not duplicate methods with protocol extension") { let aExtension = Type(name: "Foo", isExtension: true, methods: [Method(name: "foo()", definedInTypeName: TypeName(name: "Foo"))]) let aProtocol = Protocol(name: "Foo", methods: [Method(name: "foo()", definedInTypeName: TypeName(name: "Foo"))]) aProtocol.extend(aExtension) expect(aProtocol.methods).to(equal([Method(name: "foo()", definedInTypeName: TypeName(name: "Foo"))])) } it("adds annotations") { let expected: [String: NSObject] = ["something": NSNumber(value: 161), "ExtraAnnotation": "ExtraValue" as NSString] let type = Type(name: "Foo", isExtension: true, annotations: ["ExtraAnnotation": "ExtraValue" as NSString]) sut?.extend(type) guard let annotations = sut?.annotations else { return fail() } expect(annotations == expected).to(beTrue()) } it("adds inherited types") { let type = Type(name: "Foo", isExtension: true, inheritedTypes: ["Something", "New"]) sut?.extend(type) expect(sut?.inheritedTypes).to(equal(["NSObject", "Something", "New"])) expect(sut?.based).to(equal(["NSObject": "NSObject", "Something": "Something", "New": "New"])) } it("adds implemented types") { let type = Type(name: "Foo", isExtension: true) type.implements = ["New": Protocol(name: "New")] sut?.extend(type) expect(sut?.implements).to(equal(["New": Protocol(name: "New")])) } } describe("When accessing allImports property") { it("returns correct imports after removing duplicates for type with a super type") { let superType = Type(name: "Bar") let superTypeImports = [Import(path: "cModule"), Import(path: "aModule")] superType.imports = superTypeImports let type = Type(name: "Foo", inheritedTypes: [superType.name]) let typeImports = [Import(path: "aModule"), Import(path: "bModule")] type.imports = typeImports type.basedTypes[superType.name] = superType let expectedImports = [Import(path: "aModule"), Import(path: "bModule"), Import(path: "cModule")] expect(type.allImports.sorted { $0.path < $1.path }).to(equal(expectedImports)) } } describe("When testing equality") { context("given same items") { it("is equal") { expect(sut).to(equal(Type(name: "Foo", parent: parentType, accessLevel: .internal, isExtension: false, variables: [storedVariable, computedVariable, staticVariable, overrideVariable], methods: [initializer, overrideMethod, secondMethod], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) } } context("given different items") { it("is not equal") { expect(sut).toNot(equal(Type(name: "Bar", parent: parentType, accessLevel: .internal, isExtension: false, variables: [storedVariable, computedVariable], methods: [initializer], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) expect(sut).toNot(equal(Type(name: "Foo", parent: parentType, accessLevel: .public, isExtension: false, variables: [storedVariable, computedVariable], methods: [initializer], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) expect(sut).toNot(equal(Type(name: "Foo", parent: parentType, accessLevel: .internal, isExtension: true, variables: [storedVariable, computedVariable], methods: [initializer], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) expect(sut).toNot(equal(Type(name: "Foo", parent: parentType, accessLevel: .internal, isExtension: false, variables: [computedVariable], methods: [initializer], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) expect(sut).toNot(equal(Type(name: "Foo", parent: parentType, accessLevel: .internal, isExtension: false, variables: [storedVariable, computedVariable], methods: [initializer], inheritedTypes: [], annotations: ["something": NSNumber(value: 161)]))) expect(sut).toNot(equal(Type(name: "Foo", parent: nil, accessLevel: .internal, isExtension: false, variables: [storedVariable, computedVariable], methods: [initializer], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) expect(sut).toNot(equal(Type(name: "Foo", parent: parentType, accessLevel: .internal, isExtension: false, variables: [storedVariable, computedVariable], methods: [initializer], inheritedTypes: ["NSObject"], annotations: [:]))) expect(sut).toNot(equal(Type(name: "Foo", parent: parentType, accessLevel: .internal, isExtension: false, variables: [storedVariable, computedVariable], methods: [], inheritedTypes: ["NSObject"], annotations: ["something": NSNumber(value: 161)]))) } } } } } } ================================================ FILE: SourceryTests/Models/TypealiasSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class TypealiasSpec: QuickSpec { override func spec() { describe("Typealias") { var sut: Typealias? beforeEach { sut = Typealias(aliasName: "Foo", typeName: TypeName(name: "Bar")) } afterEach { sut = nil } context("give no parent type") { it("reports name correctly") { expect(sut?.name).to(equal("Foo")) } } context("given parent type") { it("reports name correctly") { sut?.parent = Type(name: "FooBar", parent: Type(name: "Parent")) expect(sut?.name).to(equal("Parent.FooBar.Foo")) } } describe("When testing equality") { context("given same items") { it("is equal") { expect(sut).to(equal(Typealias(aliasName: "Foo", typeName: TypeName(name: "Bar")))) } } context("given different items") { it("is not equal") { expect(sut).toNot(equal(Typealias(aliasName: "Foo", typeName: TypeName(name: "Foo")))) expect(sut).toNot(equal(Typealias(aliasName: "Bar", typeName: TypeName(name: "Bar")))) expect(sut).toNot(equal(Typealias(aliasName: "Bar", typeName: TypeName(name: "Bar"), parent: Type(name: "Parent")))) } } } } } } ================================================ FILE: SourceryTests/Models/TypedSpec.generated.swift ================================================ // Generated using Sourcery 2.2.6 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT import Quick import Nimble #if SWIFT_PACKAGE import SourceryLib #else import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime // swiftlint:disable function_body_length class TypedSpec: QuickSpec { override func spec() { describe("AssociatedValue") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect(AssociatedValue(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(AssociatedValue(typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(AssociatedValue(typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect(AssociatedValue(typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect(AssociatedValue(typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = AssociatedValue(typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = AssociatedValue(typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = AssociatedValue(typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = AssociatedValue(typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = AssociatedValue(typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = AssociatedValue(typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } describe("ClosureParameter") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect(ClosureParameter(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(ClosureParameter(typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(ClosureParameter(typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect(ClosureParameter(typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect(ClosureParameter(typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = ClosureParameter(typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = ClosureParameter(typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = ClosureParameter(typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = ClosureParameter(typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = ClosureParameter(typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = ClosureParameter(typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } describe("MethodParameter") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect(MethodParameter(index: 0, typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(MethodParameter(index: 0, typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(MethodParameter(index: 0, typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect(MethodParameter(index: 0, typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect(MethodParameter(index: 0, typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = MethodParameter(index: 0, typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = MethodParameter(index: 0, typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = MethodParameter(index: 0, typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = MethodParameter(index: 0, typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = MethodParameter(index: 0, typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = MethodParameter(index: 0, typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } describe("TupleElement") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect(TupleElement(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(TupleElement(typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(TupleElement(typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect(TupleElement(typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect(TupleElement(typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = TupleElement(typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = TupleElement(typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = TupleElement(typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = TupleElement(typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = TupleElement(typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = TupleElement(typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } describe("Typealias") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect(Typealias(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(Typealias(typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(Typealias(typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect(Typealias(typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect(Typealias(typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = Typealias(typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = Typealias(typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = Typealias(typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = Typealias(typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = Typealias(typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = Typealias(typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } describe("Variable") { func typeName(_ code: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } #if canImport(ObjectiveC) it("can report optional via KVC") { expect(Variable(typeName: typeName("Int?")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(Variable(typeName: typeName("Int!")).value(forKeyPath: "isOptional") as? Bool).to(equal(true)) expect(Variable(typeName: typeName("Int?")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(false)) expect(Variable(typeName: typeName("Int!")).value(forKeyPath: "isImplicitlyUnwrappedOptional") as? Bool).to(equal(true)) expect(Variable(typeName: typeName("Int?")).value(forKeyPath: "unwrappedTypeName") as? String).to(equal("Int")) } it("can report tuple type via KVC") { let sut = Variable(typeName: typeName("(Int, Int)")) expect(sut.value(forKeyPath: "isTuple") as? Bool).to(equal(true)) } it("can report closure type via KVC") { let sut = Variable(typeName: typeName("(Int) -> (Int)")) expect(sut.value(forKeyPath: "isClosure") as? Bool).to(equal(true)) } it("can report array type via KVC") { let sut = Variable(typeName: typeName("[Int]")) expect(sut.value(forKeyPath: "isArray") as? Bool).to(equal(true)) } it("can report set type via KVC") { let sut = Variable(typeName: typeName("Set")) expect(sut.value(forKeyPath: "isSet") as? Bool).to(equal(true)) } it("can report dictionary type via KVC") { let sut = Variable(typeName: typeName("[Int: Int]")) expect(sut.value(forKeyPath: "isDictionary") as? Bool).to(equal(true)) } it("can report actual type name via KVC") { let sut = Variable(typeName: typeName("Alias")) expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Alias"))) sut.typeName.actualTypeName = typeName("Int") expect(sut.value(forKeyPath: "actualTypeName") as? TypeName).to(equal(typeName("Int"))) } #endif } } } ================================================ FILE: SourceryTests/Models/VariableSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryRuntime class VariableSpec: QuickSpec { override func spec() { describe("Variable") { var sut: Variable? beforeEach { sut = Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: true, definedInTypeName: TypeName(name: "Foo")) } afterEach { sut = nil } it("has proper defined in type name") { expect(sut?.definedInTypeName).to(equal(TypeName(name: "Foo"))) } it("has proper read access") { expect(sut?.readAccess == AccessLevel.public.rawValue).to(beTrue()) expect(Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .package, write: .public), isComputed: true).readAccess == AccessLevel.package.rawValue).to(beTrue()) } it("has proper dynamic state") { expect(Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: true, modifiers: [Modifier(name: "dynamic")]).isDynamic).to(beTrue()) expect(Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: true, modifiers: [Modifier(name: "lazy")]).isDynamic).to(beFalse()) } it("has proper write access") { expect(sut?.writeAccess == AccessLevel.internal.rawValue).to(beTrue()) expect(Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .package), isComputed: true).writeAccess == AccessLevel.package.rawValue).to(beTrue()) } describe("When testing equality") { context("given same items") { it("is equal") { expect(sut).to(equal(Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: true, definedInTypeName: TypeName(name: "Foo")))) } } context("given different items") { it("is not equal") { expect(sut).toNot(equal(Variable(name: "other", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: true, definedInTypeName: TypeName(name: "Foo")))) expect(sut).toNot(equal(Variable(name: "variable", typeName: TypeName(name: "Float"), accessLevel: (read: .public, write: .internal), isComputed: true, definedInTypeName: TypeName(name: "Foo")))) expect(sut).toNot(equal(Variable(name: "other", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: true, definedInTypeName: TypeName(name: "Foo")))) expect(sut).toNot(equal(Variable(name: "other", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .public), isComputed: true, definedInTypeName: TypeName(name: "Foo")))) expect(sut).toNot(equal(Variable(name: "other", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: false, definedInTypeName: TypeName(name: "Foo")))) expect(sut).toNot(equal(Variable(name: "variable", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .internal), isComputed: true, definedInTypeName: TypeName(name: "Bar")))) } } } } } } ================================================ FILE: SourceryTests/Output/DryOutputSpec.swift ================================================ import Foundation import Quick import Nimble import PathKit #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime @testable import SourceryJS class DryOutputSpec: QuickSpec { override func spec() { // MARK: - DryOutput + JavaScriptTemplate #if canImport(ObjectiveC) describe("DryOutput+JavaScriptTemplate") { let outputDir: Path = { return Stubs.cleanTemporarySourceryDir() }() let output = Output(outputDir) it("has no stdout json output if isDryRun equal false (*also default value)") { let templatePath = Stubs.jsTemplates + Path("Equality.ejs") let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: false, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(beNil()) } it("handles includes") { let templatePath = Stubs.jsTemplates + Path("Includes.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles includes from included files relatively") { let templatePath = Stubs.jsTemplates + Path("SubfolderIncludes.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles free functions") { let templatePath = Stubs.jsTemplates + Path("Function.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Function.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } } #endif // MARK: - DryOutput + StencilTemplate describe("DryOutput+StencilTemplate") { it("has no stdout json output if isDryRun equal false (*also default value)") { var outputDir = Path("/tmp") outputDir = Stubs.cleanTemporarySourceryDir() let templatePath = Stubs.templateDirectory + Path("Include.stencil") let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: Output(outputDir), isDryRun: false, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(beNil()) } it("includes partial templates") { var outputDir = Path("/tmp") outputDir = Stubs.cleanTemporarySourceryDir() let templatePath = Stubs.templateDirectory + Path("Include.stencil") let expectedResult = "// Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery\n" + "// DO NOT EDIT\n" + "partial template content\n" let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: Output(outputDir), isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("supports different ways for code generation") { let templatePath = Stubs.templateDirectory + Path("GenerationWays.stencil") let sourcePath = Stubs.sourceForDryRun + Path("Base.swift") let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: Output("."), isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result(byOutputType: .init(id: "\(sourcePath):109", subType: .range)).value) .to(equal(""" // MARK: - Eq AutoEquatable extension Eq: Equatable {} internal func == (lhs: Eq, rhs: Eq) -> Bool { guard lhs.s == rhs.s else { return false } guard lhs.o == rhs.o else { return false } guard lhs.u == rhs.u else { return false } guard lhs.r == rhs.r else { return false } guard lhs.c == rhs.c else { return false } guard lhs.e == rhs.e else { return false } return true } """)) expect(outputInterceptor.result(byOutputType: .init(id: "\(sourcePath):387", subType: .range)).value) .to(equal(""" // MARK: - Eq2 AutoEquatable extension Eq2: Equatable {} internal func == (lhs: Eq2, rhs: Eq2) -> Bool { guard lhs.r == rhs.r else { return false } guard lhs.y == rhs.y else { return false } guard lhs.d == rhs.d else { return false } guard lhs.r2 == rhs.r2 else { return false } guard lhs.y2 == rhs.y2 else { return false } guard lhs.r3 == rhs.r3 else { return false } guard lhs.u == rhs.u else { return false } guard lhs.n == rhs.n else { return false } return true } """)) let templatePathResult = outputInterceptor .result(byOutputType: .init(id: "\(templatePath)", subType: .template)).value expect(templatePathResult) .to(equal( """ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable file_length fileprivate func compareOptionals(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { switch (lhs, rhs) { case let (lValue?, rValue?): return compare(lValue, rValue) case (nil, nil): return true default: return false } } fileprivate func compareArrays(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { guard lhs.count == rhs.count else { return false } for (idx, lhsItem) in lhs.enumerated() { guard compare(lhsItem, rhs[idx]) else { return false } } return true } // MARK: - AutoEquatable for classes, protocols, structs // sourcery:inline:Eq3.AutoEquatable // MARK: - Eq3 AutoEquatable extension Eq3: Equatable {} internal func == (lhs: Eq3, rhs: Eq3) -> Bool { guard lhs.counter == rhs.counter else { return false } guard lhs.foo == rhs.foo else { return false } guard lhs.bar == rhs.bar else { return false } return true } // sourcery:end // MARK: - AutoEquatable for Enums """ )) #if canImport(ObjectiveC) expect(outputInterceptor.result(byOutputType: .init(id: "Generated/EqEnum+TemplateName.generated.swift", subType: .path)).value) .to(equal(""" // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // MARK: - EqEnum AutoEquatable extension EqEnum: Equatable {} internal func == (lhs: EqEnum, rhs: EqEnum) -> Bool { switch (lhs, rhs) { case let (.some(lhs), .some(rhs)): return lhs == rhs case let (.other(lhs), .other(rhs)): return lhs == rhs default: return false } } """)) #endif } // supports different ways for code generation: end } // MARK: - DryOutput + SwiftTemplate describe("SwiftTemplate") { let outputDir: Path = { return Stubs.cleanTemporarySourceryDir() }() let output = Output(outputDir) let templatePath = Stubs.swiftTemplates + Path("Equality.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) it("has no stdout json output if isDryRun equal false (*also default value)") { let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: false, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(beNil()) } it("given swifttemplate, generates correct output, if isDryRun equal true") { let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } #if canImport(ObjectiveC) it("given ejs template, generates correct output, if isDryRun equal true") { let templatePath = Stubs.jsTemplates + Path("Equality.ejs") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } #endif it("handles includes") { let templatePath = Stubs.swiftTemplates + Path("Includes.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles file includes") { let templatePath = Stubs.swiftTemplates + Path("IncludeFile.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles includes without swifttemplate extension") { let templatePath = Stubs.swiftTemplates + Path("IncludesNoExtension.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles file includes without swift extension") { let templatePath = Stubs.swiftTemplates + Path("IncludeFileNoExtension.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles includes from included files relatively") { let templatePath = Stubs.swiftTemplates + Path("SubfolderIncludes.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles file includes from included files relatively") { let templatePath = Stubs.swiftTemplates + Path("SubfolderFileIncludes.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } it("handles free functions") { let templatePath = Stubs.swiftTemplates + Path("Function.swifttemplate") let expectedResult = try? (Stubs.resultDirectory + Path("Function.swift")).read(.utf8) let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.result).to(equal(expectedResult)) } // MARK: Multiple files check it("return all outputs values") { let templatePaths = ["Includes.swifttemplate", "IncludeFile.swifttemplate", "IncludesNoExtension.swifttemplate", "IncludeFileNoExtension.swifttemplate", "SubfolderIncludes.swifttemplate", "SubfolderFileIncludes.swifttemplate", "Function.swifttemplate"] .map { Stubs.swiftTemplates + Path($0) } let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) let expectedResults = ["Basic+Other.swift", "Basic.swift", "Basic+Other.swift", "Basic.swift", "Basic.swift", "Basic.swift", "Function.swift"] .compactMap { try? (Stubs.resultDirectory + Path($0)).read(.utf8) } expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: templatePaths), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect(outputInterceptor.outputModel.outputs.count).to(equal(expectedResults.count)) expect(outputInterceptor.outputModel.outputs.map { $0.value }.sorted()).to(equal(expectedResults.sorted())) } it("has same templates in outputs as in inputs") { let templatePaths = ["Includes.swifttemplate", "IncludeFile.swifttemplate", "IncludesNoExtension.swifttemplate", "IncludeFileNoExtension.swifttemplate", "SubfolderIncludes.swifttemplate", "SubfolderFileIncludes.swifttemplate", "Function.swifttemplate"] .map { Stubs.swiftTemplates + Path($0) } let sourcery = Sourcery(cacheDisabled: true) let outputInterceptor = OutputInterceptor() sourcery.dryOutput = outputInterceptor.handleOutput(_:) expect { try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: templatePaths), output: output, isDryRun: true, baseIndentation: 0) }.toNot(throwError()) expect( outputInterceptor.outputModel.outputs.compactMap { $0.type.id }.map { Path($0) }.sorted() ).to( equal(templatePaths.sorted()) ) } } } } // MARK: - Helpers private class OutputInterceptor { let jsonDecoder = JSONDecoder() var outputModel: DryOutputSuccess! var result: String? { outputModel?.outputs.first?.value } func result(byOutputType outputType: DryOutputType) -> DryOutputValue! { outputModel?.outputs .first(where: { $0.type.id == outputType.id && $0.type.subType.rawValue == outputType.subType.rawValue }) } func handleOutput(_ value: String) { outputModel = value .data(using: .utf8) .flatMap { try? jsonDecoder.decode(DryOutputSuccess.self, from: $0) } } } ================================================ FILE: SourceryTests/Parsing/ComposerSpec.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import Quick import Nimble import PathKit #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime import XCTest // swiftlint:disable type_body_length file_length class ParserComposerSpec: QuickSpec { // swiftlint:disable function_body_length override func spec() { describe("ParserComposer") { describe("uniqueTypesAndFunctions") { func parse(_ code: String) -> [Type] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return Composer.uniqueTypesAndFunctions(parserResult).types } func parseFunctions(_ code: String) -> [SourceryMethod] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return Composer.uniqueTypesAndFunctions(parserResult).functions } func parseModules(_ modules: (name: String?, contents: String)...) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias]) { let moduleResults = modules.compactMap { try? makeParser(for: $0.contents, module: $0.name).parse() } let parserResult = moduleResults.reduce(FileParserResult(path: nil, module: nil, types: [], functions: [], typealiases: [])) { acc, next in acc.typealiases += next.typealiases acc.types += next.types acc.functions += next.functions return acc } return Composer.uniqueTypesAndFunctions(parserResult) } context("given class hierarchy") { var fooType: Type! var barType: Type! var bazType: Type! beforeEach { let input = """ class Foo { var foo: Int; func fooMethod() {} } class Bar: Foo { var bar: Int } class Baz: Bar { var baz: Int; func bazMethod() {} } """ let parsedResult = parse(input) fooType = parsedResult[2] barType = parsedResult[0] bazType = parsedResult[1] } it("resolves methods definedInType") { expect(fooType.allMethods.first?.definedInType).to(equal(fooType)) expect(barType.allMethods.first?.definedInType).to(equal(fooType)) expect(bazType.allMethods.first?.definedInType).to(equal(bazType)) expect(bazType.allMethods.last?.definedInType).to(equal(fooType)) } it("resolves variables definedInType") { expect(fooType.allVariables.first?.definedInType).to(equal(fooType)) expect(barType.allVariables[0].definedInType).to(equal(barType)) expect(barType.allVariables[1].definedInType).to(equal(fooType)) expect(bazType.allVariables[0].definedInType).to(equal(bazType)) expect(bazType.allVariables[1].definedInType).to(equal(barType)) expect(bazType.allVariables[2].definedInType).to(equal(fooType)) } context("given method with return type") { it("finds actual return type") { let types = parse("class Foo { func foo() -> Bar { } }; class Bar {}") let method = types.last?.methods.first expect(method?.returnType) .to(equal(Class(name: "Bar"))) } } context("given generic method") { func assertMethods(_ types: [Type]) { let fooType = types.first(where: { $0.name == "Foo" }) let foo = fooType?.methods.first let fooBar = fooType?.methods.last expect(foo?.name).to(equal("foo()")) expect(foo?.selectorName).to(equal("foo")) expect(foo?.shortName).to(equal("foo")) expect(foo?.callName).to(equal("foo")) expect(foo?.returnTypeName).to(equal(TypeName(name: "Bar? where \nT: Equatable"))) expect(foo?.unwrappedReturnTypeName).to(equal("Bar")) expect(foo?.returnType).to(equal(Class(name: "Bar"))) expect(foo?.definedInType).to(equal(types.last)) expect(foo?.definedInTypeName).to(equal(TypeName(name: "Foo"))) expect(fooBar?.name).to(equal("fooBar(bar: T)")) expect(fooBar?.selectorName).to(equal("fooBar(bar:)")) expect(fooBar?.shortName).to(equal("fooBar")) expect(fooBar?.callName).to(equal("fooBar")) expect(fooBar?.returnTypeName).to(equal(TypeName(name: "Void where T: Equatable"))) expect(fooBar?.unwrappedReturnTypeName).to(equal("Void")) expect(fooBar?.returnType).to(beNil()) expect(fooBar?.definedInType).to(equal(types.last)) expect(fooBar?.definedInTypeName).to(equal(TypeName(name: "Foo"))) } it("extracts class method properly") { let types = parse(""" class Foo { func foo() -> Bar?\n where \nT: Equatable { }; /// Asks a Duck to quack /// /// - Parameter times: How many times the Duck will quack func fooBar(bar: T) where T: Equatable { } }; class Bar {} """) assertMethods(types) } it("extracts protocol method properly") { let types = parse(""" protocol Foo { func foo() -> Bar?\n where \nT: Equatable /// Asks a Duck to quack /// /// - Parameter times: How many times the Duck will quack func fooBar(bar: T) where T: Equatable }; class Bar {} """) assertMethods(types) } it("extracts method generic requirements properly") { let types = parse(""" class Foo { func fooBar(bar: T) where T: Equatable { } }; """) let fooType = types.first(where: { $0.name == "Foo" }) let fooBar = fooType?.methods.last expect(fooBar?.name).to(equal("fooBar(bar: T)")) expect(fooBar?.parameters.first?.type?.implements["Equatable"]).toNot(beNil()) expect(fooBar?.parameters.first?.type?.implements["Codable"]).to(beNil()) expect(fooBar?.parameters.first?.type?.genericRequirements).toNot(beNil()) } it("extracts multiple method generic requirements properly") { let types = parse(""" class Foo { func fooBar(bar: T) where T: Equatable, T: Codable { } }; """) let fooType = types.first(where: { $0.name == "Foo" }) let fooBar = fooType?.methods.last expect(fooBar?.name).to(equal("fooBar(bar: T)")) expect(fooBar?.parameters.first?.type?.implements["Equatable"]).toNot(beNil()) expect(fooBar?.parameters.first?.type?.implements["Codable"]).toNot(beNil()) expect(fooBar?.parameters.first?.type?.genericRequirements).toNot(beNil()) expect(fooBar?.parameters.first?.actualTypeName?.name).to(contain("Equatable")) expect(fooBar?.parameters.first?.actualTypeName?.name).to(contain("Codable")) expect(fooBar?.parameters.first?.actualTypeName?.name).to(contain("&")) } it("extracts multiple method generic requirements on return type properly") { let types = parse(""" class Foo { enum TestEnum: String, Codable, Equatable { case abc, def } func fooBar(bar: T) -> T where T: Equatable, T: Codable { TestEnum.abc as! T } }; """) let fooType = types.first(where: { $0.name == "Foo" }) let fooBar = fooType?.methods.last expect(fooBar?.returnType?.implements["Equatable"]).toNot(beNil()) expect(fooBar?.returnType?.implements["Codable"]).toNot(beNil()) expect(fooBar?.returnType?.genericRequirements).toNot(beNil()) expect(fooBar?.returnType?.isGeneric).to(beTrue()) expect(fooBar?.returnTypeName.actualTypeName?.name).to(contain("Equatable")) expect(fooBar?.returnTypeName.actualTypeName?.name).to(contain("Codable")) expect(fooBar?.returnTypeName.actualTypeName?.name).to(contain("&")) } it("extracts method generic requirements without protocol properly") { let types = parse(""" class Foo { func fooBar(bar: T) { } }; """) let fooType = types.first(where: { $0.name == "Foo" }) let fooBar = fooType?.methods.last expect(fooBar?.name).to(equal("fooBar(bar: T)")) expect(fooBar?.parameters.first?.type).to(beNil()) expect(fooBar?.parameters.first?.actualTypeName?.name).to(equal("T")) } } context("given initializer") { it("extracts initializer properly") { let fooType = Class(name: "Foo") let expectedInitializer = Method(name: "init()", selectorName: "init", returnTypeName: TypeName(name: "Foo"), isStatic: true, definedInTypeName: TypeName(name: "Foo")) expectedInitializer.returnType = fooType fooType.rawMethods = [Method(name: "foo()", selectorName: "foo", definedInTypeName: TypeName(name: "Foo")), expectedInitializer] let type = parse("class Foo { func foo() {}; init() {} }").first let initializer = type?.initializers.first expect(initializer).to(equal(expectedInitializer)) expect(initializer?.returnType).to(equal(fooType)) } it("extracts failable initializer properly") { let fooType = Class(name: "Foo") let expectedInitializer = Method(name: "init?()", selectorName: "init", returnTypeName: TypeName(name: "Foo?"), isStatic: true, isFailableInitializer: true, definedInTypeName: TypeName(name: "Foo")) expectedInitializer.returnType = fooType fooType.rawMethods = [Method(name: "foo()", selectorName: "foo", definedInTypeName: TypeName(name: "Foo")), expectedInitializer] let type = parse("class Foo { func foo() {}; init?() {} }").first let initializer = type?.initializers.first expect(initializer).to(equal(expectedInitializer)) expect(initializer?.returnType).to(equal(fooType)) } } } context("given protocol inheritance") { it("flattens protocol with default implementation as expected") { let parsed = parse( """ protocol UrlOpening { func open( _ url: URL, options: [UIApplication.OpenExternalURLOptionsKey: Any], completionHandler completion: ((Bool) -> Void)? ) func open(_ url: URL) } extension UrlOpening { func open(_ url: URL) { open(url, options: [:], completionHandler: nil) } func anotherFunction(key: String) { } } """ ) expect(parsed).to(haveCount(1)) let childProtocol = parsed.last expect(childProtocol?.name).to(equal("UrlOpening")) expect(childProtocol?.allMethods.map { $0.selectorName }).to(equal(["open(_:options:completionHandler:)", "open(_:)", "anotherFunction(key:)"])) } it("flattens inherited protocols with default implementation as expected") { let parsed = parse( """ protocol RemoteUrlOpening { func open(_ url: URL) } protocol UrlOpening: RemoteUrlOpening { func open( _ url: URL, options: [UIApplication.OpenExternalURLOptionsKey: Any], completionHandler completion: ((Bool) -> Void)? ) } extension UrlOpening { func open(_ url: URL) { open(url, options: [:], completionHandler: nil) } } """ ) expect(parsed).to(haveCount(2)) let childProtocol = parsed.last expect(childProtocol?.name).to(equal("UrlOpening")) expect(childProtocol?.allMethods.filter({ $0.definedInType?.isExtension == false }).map { $0.selectorName }).to(equal(["open(_:options:completionHandler:)", "open(_:)"])) } } context("given overlapping protocol inheritance") { var baseProtocol: Type! var baseClass: Type! var extendedProtocol: Type! var extendedClass: Type! beforeEach { let input = """ protocol BaseProtocol { var variable: Int { get } func baseFunction() } class BaseClass: BaseProtocol { var variable: Int = 0 func baseFunction() {} } protocol ExtendedProtocol: BaseClass { var extendedVariable: Int { get } func extendedFunction() } class ExtendedClass: BaseClass, ExtendedProtocol { var extendedVariable: Int = 0 func extendedFunction() { } } """ let parsedResult = parse(input) baseProtocol = parsedResult[1] baseClass = parsedResult[0] extendedProtocol = parsedResult[3] extendedClass = parsedResult[2] } it("finds right types") { expect(baseProtocol.name).to(equal("BaseProtocol")) expect(baseClass.name).to(equal("BaseClass")) expect(extendedProtocol.name).to(equal("ExtendedProtocol")) expect(extendedClass.name).to(equal("ExtendedClass")) } it("has matching number of methods and variables") { expect(baseProtocol.allMethods.count).to(equal(baseProtocol.allVariables.count)) expect(baseClass.allMethods.count).to(equal(baseClass.allVariables.count)) expect(extendedProtocol.allMethods.count).to(equal(extendedProtocol.allVariables.count)) expect(extendedClass.allMethods.count).to(equal(extendedClass.allVariables.count)) } } context("given extension of same type") { it("combines nested types correctly") { let innerType = Struct(name: "Bar", accessLevel: .internal, isExtension: false, variables: []) expect(parse("struct Foo {} extension Foo { struct Bar { } }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], containedTypes: [innerType]), innerType ])) } it("combines methods correctly") { expect(parse("class Baz {}; extension Baz { func foo() {} }")) .to(equal([ Class(name: "Baz", methods: [ Method(name: "foo()", selectorName: "foo", accessLevel: .internal, definedInTypeName: TypeName(name: "Baz")) ]) ])) } it("combines variables correctly") { expect(parse("class Baz {}; extension Baz { var foo: Int }")) .to(equal([ Class(name: "Baz", variables: [ .init(name: "foo", typeName: .Int, definedInTypeName: TypeName(name: "Baz")) ]) ])) } it("combines variables and methods with access information from the extension") { let foo = Struct(name: "Foo", accessLevel: .public, isExtension: false, variables: [.init(name: "boo", typeName: .Int, accessLevel: (.public, .none), isComputed: true, definedInTypeName: TypeName(name: "Foo"))], methods: [.init(name: "foo()", selectorName: "foo", accessLevel: .public, definedInTypeName: TypeName(name: "Foo"))], modifiers: [.init(name: "public")]) expect(parse( """ public struct Foo { } public extension Foo { func foo() { } var boo: Int { 0 } } """ ).last) .to(equal( foo )) } it("combines inherited types") { expect(parse("class Foo: TestProtocol { }; extension Foo: AnotherProtocol {}")) .to(equal([ Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol", "AnotherProtocol"]) ])) } it("does not use extension to infer enum rawType") { expect(parse("enum Foo { case one }; extension Foo: Equatable {}")) .to(equal([ Enum(name: "Foo", inheritedTypes: ["Equatable"], cases: [EnumCase(name: "one")] ) ])) } describe("remembers original definition type") { var input: String! var method: SourceryRuntime.Method! var defaultedMethod: SourceryRuntime.Method! var parsedResult: Type! var originalType: Type! var typeExtension: Type! beforeEach { method = Method(name: "fooMethod(bar: String)", selectorName: "fooMethod(bar:)", parameters: [MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "String"))], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) defaultedMethod = Method(name: "fooMethod(bar: String = \"Baz\")", selectorName: "fooMethod(bar:)", parameters: [MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "String"), defaultValue: "\"Baz\"")], returnTypeName: TypeName(name: "Void"), accessLevel: .internal, definedInTypeName: TypeName(name: "Foo")) } context("for enum") { beforeEach { input = "enum Foo { case A; func \(method.name) {} }; extension Foo { func \(defaultedMethod.name) {} }" parsedResult = parse(input).first originalType = Enum(name: "Foo", cases: [EnumCase(name: "A")], methods: [method, defaultedMethod]) typeExtension = Type(name: "Foo", accessLevel: .internal, isExtension: true, methods: [defaultedMethod]) } it("resolves methods definedInType") { expect(parsedResult.methods.first?.definedInType).to(equal(originalType)) expect(parsedResult.methods.last?.definedInType).to(equal(typeExtension)) } } context("for protocol") { beforeEach { input = "protocol Foo { func \(method.name) }; extension Foo { func \(defaultedMethod.name) {} }" parsedResult = parse(input).first originalType = Protocol(name: "Foo", methods: [method, defaultedMethod]) typeExtension = Type(name: "Foo", accessLevel: .internal, isExtension: true, methods: [defaultedMethod]) } it("resolves methods definedInType") { expect(parsedResult.methods.first?.definedInType).to(equal(originalType)) expect(parsedResult.methods.last?.definedInType).to(equal(typeExtension)) } } context("for class") { beforeEach { input = "class Foo { func \(method.name) {} }; extension Foo { func \(defaultedMethod.name) {} }" parsedResult = parse(input).first originalType = Class(name: "Foo", methods: [method, defaultedMethod]) typeExtension = Type(name: "Foo", accessLevel: .internal, isExtension: true, methods: [defaultedMethod]) } it("resolves methods definedInType") { expect(parsedResult.methods.first?.definedInType).to(equal(originalType)) expect(parsedResult.methods.last?.definedInType).to(equal(typeExtension)) } } context("for struct") { beforeEach { input = "struct Foo { func \(method.name) {} }; extension Foo { func \(defaultedMethod.name) {} }" parsedResult = parse(input).first originalType = Struct(name: "Foo", methods: [method, defaultedMethod]) typeExtension = Type(name: "Foo", accessLevel: .internal, isExtension: true, methods: [defaultedMethod]) } it("resolves methods definedInType") { expect(parsedResult.methods.first?.definedInType).to(equal(originalType)) expect(parsedResult.methods.last?.definedInType).to(equal(typeExtension)) } } } } context("given enum containing associated values") { it("trims whitespace from associated value names") { expect(parse("enum Foo {\n case bar(\nvalue: String,\n other: Int\n)\n}")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], rawTypeName: nil, cases: [ EnumCase( name: "bar", rawValue: nil, associatedValues: [ AssociatedValue( localName: "value", externalName: "value", typeName: TypeName(name: "String") ), AssociatedValue( localName: "other", externalName: "other", typeName: TypeName(name: "Int") ) ], annotations: [:] ) ] ) ])) } } context("given enum containing rawType") { it("extracts enums without RawRepresentable") { expect(parse("enum Foo: String, SomeProtocol { case optionA }; protocol SomeProtocol {}")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["SomeProtocol"], rawTypeName: TypeName(name: "String"), cases: [EnumCase(name: "optionA")]), Protocol(name: "SomeProtocol") ])) } it("extracts enums with RawRepresentable by inferring from variable") { expect(parse( "enum Foo: RawRepresentable { case optionA; var rawValue: String { return \"\" }; init?(rawValue: String) { self = .optionA } }")).to( equal([ Enum(name: "Foo", inheritedTypes: ["RawRepresentable"], rawTypeName: TypeName(name: "String"), cases: [EnumCase(name: "optionA")], variables: [Variable(name: "rawValue", typeName: TypeName(name: "String"), accessLevel: (read: .internal, write: .none), isComputed: true, isStatic: false, definedInTypeName: TypeName(name: "Foo"))], methods: [Method(name: "init?(rawValue: String)", selectorName: "init(rawValue:)", parameters: [MethodParameter(name: "rawValue", index: 0, typeName: TypeName(name: "String"))], returnTypeName: TypeName(name: "Foo?"), isStatic: true, isFailableInitializer: true, definedInTypeName: TypeName(name: "Foo"))] ) ])) } it("extracts enums with RawRepresentable by inferring from variable with typealias") { expect(parse( "enum Foo: RawRepresentable { case optionA; typealias RawValue = String; var rawValue: RawValue { return \"\" }; init?(rawValue: RawValue) { self = .optionA } }")).to( equal([ Enum(name: "Foo", inheritedTypes: ["RawRepresentable"], rawTypeName: TypeName(name: "String"), cases: [EnumCase(name: "optionA")], variables: [Variable(name: "rawValue", typeName: TypeName(name: "RawValue"), accessLevel: (read: .internal, write: .none), isComputed: true, isStatic: false, definedInTypeName: TypeName(name: "Foo"))], methods: [Method(name: "init?(rawValue: RawValue)", selectorName: "init(rawValue:)", parameters: [MethodParameter(name: "rawValue", index: 0, typeName: TypeName(name: "RawValue"))], returnTypeName: TypeName(name: "Foo?"), isStatic: true, isFailableInitializer: true, definedInTypeName: TypeName(name: "Foo"))], typealiases: [Typealias(aliasName: "RawValue", typeName: TypeName(name: "String"))]) ])) } it("extracts enums with RawRepresentable by inferring from typealias") { expect(parse( "enum Foo: CustomStringConvertible, RawRepresentable { case optionA; typealias RawValue = String; var rawValue: RawValue { return \"\" }; init?(rawValue: RawValue) { self = .optionA } }")).to( equal([ Enum(name: "Foo", inheritedTypes: ["CustomStringConvertible", "RawRepresentable"], rawTypeName: TypeName(name: "String"), cases: [EnumCase(name: "optionA")], variables: [Variable(name: "rawValue", typeName: TypeName(name: "RawValue"), accessLevel: (read: .internal, write: .none), isComputed: true, isStatic: false, definedInTypeName: TypeName(name: "Foo"))], methods: [Method(name: "init?(rawValue: RawValue)", selectorName: "init(rawValue:)", parameters: [MethodParameter(name: "rawValue", index: 0, typeName: TypeName(name: "RawValue"))], returnTypeName: TypeName(name: "Foo?"), isStatic: true, isFailableInitializer: true, definedInTypeName: TypeName(name: "Foo"))], typealiases: [Typealias(aliasName: "RawValue", typeName: TypeName(name: "String"))]) ])) } } context("given enum without raw type with inheriting type") { it("does not set inherited type to raw value type for enum cases") { expect(parse("enum Enum: SomeProtocol { case optionA }").first(where: { $0.name == "Enum" })) .to(equal( // ATM it is expected that we assume that first inherited type is a raw value type. To avoid that client code should specify inherited type via extension Enum(name: "Enum", inheritedTypes: ["SomeProtocol"], rawTypeName: TypeName(name: "SomeProtocol"), cases: [EnumCase(name: "optionA")]) )) } it("does not set inherited type to raw value type for enum cases with associated values ") { expect(parse("enum Enum: SomeProtocol { case optionA(Int); case optionB; }").first(where: { $0.name == "Enum" })) .to(equal( Enum(name: "Enum", inheritedTypes: ["SomeProtocol"], cases: [ EnumCase(name: "optionA", associatedValues: [AssociatedValue(typeName: TypeName(name: "Int"))]), EnumCase(name: "optionB") ]) )) } it("does not set inherited type to raw value type for enum with no cases") { expect(parse("enum Enum: SomeProtocol { }").first(where: { $0.name == "Enum" })) .to(equal( Enum(name: "Enum", inheritedTypes: ["SomeProtocol"]) )) } } context("given enum inheriting protocol composition") { it("extracts the protocol composition as the inherited type") { expect(parse("enum Enum: Composition { }; typealias Composition = Foo & Bar; protocol Foo {}; protocol Bar {}").first(where: { $0.name == "Enum" })) .to(equal( Enum(name: "Enum", inheritedTypes: ["Composition"]) )) } } context("given generic custom type") { it("extracts genericTypeName correctly") { let types = parse( """ struct GenericArgumentStruct { let value: T } struct Foo { var value: GenericArgumentStruct } """) let foo = types.first(where: { $0.name == "Foo" }) let generic = types.first(where: { $0.name == "GenericArgumentStruct" }) expect(foo).toNot(beNil()) expect(generic).toNot(beNil()) expect(foo?.instanceVariables.first?.typeName.generic).toNot(beNil()) expect(foo?.instanceVariables.first?.typeName.generic?.typeParameters).to(haveCount(1)) expect(foo?.instanceVariables.first?.typeName.generic?.typeParameters.first?.typeName.name).to(equal("Bool")) } } context("given generic custom type") { context("given generic's protocol requirements") { context("given type's variables' generic type") { it("extracts generic requirement correctly") { let types = parse( """ struct GenericStruct: Equatable where T: Equatable { let value: T } """) let generic = types.first(where: { $0.name == "GenericStruct" }) expect(generic).toNot(beNil()) expect(generic?.instanceVariables.first?.type?.implements["Equatable"]).toNot(beNil()) } it("extracts generic requirement as protocol composition correctly") { let types = parse( """ struct GenericStruct: Equatable where T: Equatable, T: Codable { let value: T } """) let generic = types.first(where: { $0.name == "GenericStruct" }) expect(generic).toNot(beNil()) expect(generic?.instanceVariables.first?.type?.implements["Equatable"]).toNot(beNil()) expect(generic?.instanceVariables.first?.type?.implements["Codable"]).toNot(beNil()) } } context("given type's methods' generic return type") { it("extracts generic requirement correctly") { let types = parse( """ struct GenericStruct: Equatable where T: Equatable { enum MyEnum: Equatable, String { case abc, def } func method() -> T { return MyEnum.abc } } """) let generic = types.first(where: { $0.name == "GenericStruct" }) expect(generic).toNot(beNil()) expect(generic?.methods.first?.returnType?.implements["Equatable"]).toNot(beNil()) } it("extracts generic requirement as protocol composition correctly") { let types = parse( """ struct GenericStruct: Equatable where T: Equatable, T: Codable { enum MyEnum: Equatable, Codable, String { case abc, def } func method() -> T { return MyEnum.abc } } """) let generic = types.first(where: { $0.name == "GenericStruct" }) expect(generic).toNot(beNil()) expect(generic?.methods.first?.returnType?.implements["Equatable"]).toNot(beNil()) expect(generic?.methods.first?.returnType?.implements["Codable"]).toNot(beNil()) } } context("given type's methods' generic argument type") { it("extracts generic requirement correctly") { let types = parse( """ struct GenericStruct: Equatable where T: Equatable { func method(_ arg: T) {} } """) let generic = types.first(where: { $0.name == "GenericStruct" }) expect(generic).toNot(beNil()) expect(generic?.methods.first?.parameters.first?.type?.implements["Equatable"]).toNot(beNil()) } it("extracts generic requirement as protocol composition correctly") { let types = parse( """ struct GenericStruct: Equatable where T: Equatable, T: Codable { func method(_ arg: T) {} } """) let generic = types.first(where: { $0.name == "GenericStruct" }) expect(generic).toNot(beNil()) expect(generic?.methods.first?.parameters.first?.type?.implements["Equatable"]).toNot(beNil()) expect(generic?.methods.first?.parameters.first?.type?.implements["Codable"]).toNot(beNil()) } } } } context("given tuple type") { it("extracts elements properly") { let types = parse("struct Foo { var tuple: (a: Int, b: Int, String, _: Float, literal: [String: [String: Float]], generic: Dictionary>, closure: (Int) -> (Int) -> Int, tuple: (Int, Int))}") let variable = types.first?.variables.first let tuple = variable?.typeName.tuple let stringToFloatDictGenericLiteral = GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String")), GenericTypeParameter(typeName: TypeName(name: "Float"))]) let stringToFloatDictLiteral = DictionaryType(name: "[String: Float]", valueTypeName: TypeName(name: "Float"), keyTypeName: TypeName(name: "String")) expect(tuple?.elements[0]).to(equal(TupleElement(name: "a", typeName: TypeName(name: "Int")))) expect(tuple?.elements[1]).to(equal(TupleElement(name: "b", typeName: TypeName(name: "Int")))) expect(tuple?.elements[2]).to(equal(TupleElement(name: "2", typeName: TypeName(name: "String")))) expect(tuple?.elements[3]).to(equal(TupleElement(name: "3", typeName: TypeName(name: "Float")))) expect(tuple?.elements[4]).to(equal( TupleElement(name: "literal", typeName: TypeName(name: "[String: [String: Float]]", dictionary: DictionaryType(name: "[String: [String: Float]]", valueTypeName: TypeName(name: "[String: Float]", dictionary: stringToFloatDictLiteral, generic: stringToFloatDictGenericLiteral), keyTypeName: TypeName(name: "String")), generic: GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String")), GenericTypeParameter(typeName: TypeName(name: "[String: Float]", dictionary: stringToFloatDictLiteral, generic: stringToFloatDictGenericLiteral))]))) )) expect(tuple?.elements[5]).to(equal( TupleElement(name: "generic", typeName: .buildDictionary(key: .String, value: .buildDictionary(key: .String, value: .Float, useGenericName: true), useGenericName: true)) )) expect(tuple?.elements[6]).to(equal( TupleElement(name: "closure", typeName: TypeName(name: "(Int) -> (Int) -> Int", closure: ClosureType(name: "(Int) -> (Int) -> Int", parameters: [ ClosureParameter(typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "(Int) -> Int", closure: ClosureType(name: "(Int) -> Int", parameters: [ ClosureParameter(typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "Int")))))) )) expect(tuple?.elements[7]).to(equal(TupleElement(name: "tuple", typeName: TypeName(name: "(Int, Int)", tuple: TupleType(name: "(Int, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Int")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]))))) } } context("given literal array type") { it("extracts element type properly") { let types = parse("struct Foo { var array: [Int]; var arrayOfTuples: [(Int, Int)]; var arrayOfArrays: [[Int]], var arrayOfClosures: [() -> ()] }") let variables = types.first?.variables expect(variables?[0].typeName.array).to(equal( ArrayType(name: "[Int]", elementTypeName: TypeName(name: "Int")) )) expect(variables?[1].typeName.array).to(equal( ArrayType(name: "[(Int, Int)]", elementTypeName: TypeName(name: "(Int, Int)", tuple: TupleType(name: "(Int, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Int")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]))) )) expect(variables?[2].typeName.array).to(equal( ArrayType(name: "[[Int]]", elementTypeName: TypeName(name: "[Int]", array: ArrayType(name: "[Int]", elementTypeName: TypeName(name: "Int")), generic: GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Int"))]))) )) expect(variables?[3].typeName).to(equal( TypeName.buildArray(of: .buildClosure(TypeName(name: "()"))) )) } } context("given generic array type") { it("extracts element type properly") { let types = parse("struct Foo { var array: Array; var arrayOfTuples: Array<(Int, Int)>; var arrayOfArrays: Array>, var arrayOfClosures: Array<() -> ()> }") let variables = types.first?.variables expect(variables?[0].typeName.array).to(equal( TypeName.buildArray(of: .Int, useGenericName: true).array )) expect(variables?[1].typeName.array).to(equal( TypeName.buildArray(of: .buildTuple(.Int, .Int), useGenericName: true).array )) expect(variables?[2].typeName.array).to(equal( TypeName.buildArray(of: .buildArray(of: .Int, useGenericName: true), useGenericName: true).array )) expect(variables?[3].typeName.array).to(equal( TypeName.buildArray(of: .buildClosure(TypeName(name: "()")), useGenericName: true).array )) } } context("given generic set type") { it("extracts element type properly") { let types = parse("struct Foo { var set: Set; var setOfTuples: Set<(Int, Int)>; var setOfSets: Set>, var setOfClosures: Set<() -> ()> }") let variables = types.first?.variables expect(variables?[0].typeName.set).to(equal( TypeName.buildSet(of: .Int).set )) expect(variables?[1].typeName.set).to(equal( TypeName.buildSet(of: .buildTuple(.Int, .Int)).set )) expect(variables?[2].typeName.set).to(equal( TypeName.buildSet(of: .buildSet(of: .Int)).set )) expect(variables?[3].typeName.set).to(equal( TypeName.buildSet(of: .buildClosure(TypeName(name: "()"))).set )) } } context("given generic dictionary type") { it("extracts key type properly") { let types = parse("struct Foo { var dictionary: Dictionary; var dictionaryOfArrays: Dictionary<[Int], [String]>; var dictonaryOfDictionaries: Dictionary; var dictionaryOfTuples: Dictionary; var dictionaryOfClosures: Dictionary ()> }") let variables = types.first?.variables expect(variables?[0].typeName.dictionary).to(equal( DictionaryType(name: "Dictionary", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "Int")) )) expect(variables?[1].typeName.dictionary).to(equal( DictionaryType(name: "Dictionary<[Int], [String]>", valueTypeName: TypeName(name: "[String]", array: ArrayType(name: "[String]", elementTypeName: TypeName(name: "String")), generic: GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String"))])), keyTypeName: TypeName(name: "[Int]", array: ArrayType(name: "[Int]", elementTypeName: TypeName(name: "Int")), generic: GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Int"))]))) )) expect(variables?[2].typeName.dictionary).to(equal( DictionaryType(name: "Dictionary", valueTypeName: TypeName(name: "[Int: String]", dictionary: DictionaryType(name: "[Int: String]", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "Int")), generic: GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Int")), GenericTypeParameter(typeName: TypeName(name: "String"))])), keyTypeName: TypeName(name: "Int")) )) expect(variables?[3].typeName.dictionary).to(equal( DictionaryType(name: "Dictionary", valueTypeName: TypeName(name: "(String, String)", tuple: TupleType(name: "(String, String)", elements: [TupleElement(name: "0", typeName: TypeName(name: "String")), TupleElement(name: "1", typeName: TypeName(name: "String"))])), keyTypeName: TypeName(name: "Int")) )) expect(variables?[4].typeName.dictionary).to(equal( TypeName.buildDictionary(key: .Int, value: .buildClosure(TypeName(name: "()")), useGenericName: true).dictionary )) } } context("given generic types extensions") { it("detects protocol conformance in extension of generic types") { let types = parse(""" protocol Bar {} extension Array: Bar {} extension Dictionary: Bar {} extension Set: Bar {} struct Foo { var array: Array var arrayLiteral: [Int] var dictionary: Dictionary var dictionaryLiteral: [String: Int] var set: Set } """) let bar = SourceryProtocol.init(name: "Bar") let variables = types[3].variables expect(variables[0].type?.implements["Bar"]).to(equal(bar)) expect(variables[1].type?.implements["Bar"]).to(equal(bar)) expect(variables[2].type?.implements["Bar"]).to(equal(bar)) expect(variables[3].type?.implements["Bar"]).to(equal(bar)) expect(variables[4].type?.implements["Bar"]).to(equal(bar)) } } context("given literal dictionary type") { it("extracts key type properly") { let types = parse("struct Foo { var dictionary: [Int: String]; var dictionaryOfArrays: [[Int]: [String]]; var dicitonaryOfDictionaries: [Int: [Int: String]]; var dictionaryOfTuples: [Int: (String, String)]; var dictionaryOfClojures: [Int: () -> ()] }") let variables = types.first?.variables expect(variables?[0].typeName.dictionary).to(equal( DictionaryType(name: "[Int: String]", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "Int")) )) expect(variables?[1].typeName.dictionary).to(equal( DictionaryType(name: "[[Int]: [String]]", valueTypeName: TypeName(name: "[String]", array: ArrayType(name: "[String]", elementTypeName: TypeName(name: "String")), generic: GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String"))])), keyTypeName: TypeName(name: "[Int]", array: ArrayType(name: "[Int]", elementTypeName: TypeName(name: "Int")), generic: GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Int"))])) ) )) expect(variables?[2].typeName.dictionary).to(equal( DictionaryType(name: "[Int: [Int: String]]", valueTypeName: TypeName(name: "[Int: String]", dictionary: DictionaryType(name: "[Int: String]", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "Int")), generic: GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Int")), GenericTypeParameter(typeName: TypeName(name: "String"))])), keyTypeName: TypeName(name: "Int") ) )) expect(variables?[3].typeName.dictionary).to(equal( DictionaryType(name: "[Int: (String, String)]", valueTypeName: TypeName(name: "(String, String)", tuple: TupleType(name: "(String, String)", elements: [TupleElement(name: "0", typeName: TypeName(name: "String")), TupleElement(name: "1", typeName: TypeName(name: "String"))])), keyTypeName: TypeName(name: "Int")) )) expect(variables?[4].typeName.dictionary).to(equal( TypeName.buildDictionary(key: .Int, value: .buildClosure(TypeName(name: "()"))).dictionary )) } } context("given closure type") { it("extracts closure return type") { let types = parse("struct Foo { var closure: () -> \n Int }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() -> Int", parameters: [], returnTypeName: TypeName(name: "Int")) )) } it("extracts throws return type") { let types = parse("struct Foo { var closure: () throws -> Int }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() throws -> Int", parameters: [], returnTypeName: TypeName(name: "Int"), throwsOrRethrowsKeyword: "throws") )) } it("extracts typed throws return type") { let types = parse("struct Foo { var closure: () throws(CustomError) -> Int }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() throws(CustomError) -> Int", parameters: [], returnTypeName: TypeName(name: "Int"), throwsOrRethrowsKeyword: "throws", throwsTypeName: TypeName("CustomError")) )) } it("extracts void return type") { let types = parse("struct Foo { var closure: () -> Void }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() -> Void", parameters: [], returnTypeName: TypeName(name: "Void")) )) } it("extracts () return type") { let types = parse("struct Foo { var closure: () -> () }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() -> ()", parameters: [], returnTypeName: TypeName(name: "()")) )) } it("extracts complex closure type") { let types = parse("struct Foo { var closure: () -> (Int) throws(CustomError) -> Int }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() -> (Int) throws(CustomError) -> Int", parameters: [], returnTypeName: TypeName(name: "(Int) throws(CustomError) -> Int", closure: ClosureType(name: "(Int) throws(CustomError) -> Int", parameters: [ ClosureParameter(typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "Int"), throwsOrRethrowsKeyword: "throws", throwsTypeName: TypeName("CustomError") ))) )) } it("extracts () parameters") { let types = parse("struct Foo { var closure: () -> Int }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "() -> Int", parameters: [], returnTypeName: TypeName(name: "Int")) )) } it("extracts Void parameters") { let types = parse("struct Foo { var closure: (Void) -> Int }") let variables = types.first?.variables expect(variables?[0].typeName.closure).to(equal( ClosureType(name: "(Void) -> Int", parameters: [.init(typeName: TypeName(name: "Void"))], returnTypeName: .Int) )) } it("extracts parameters") { let types = parse("struct Foo { var closure: (Int, Int -> Int) -> Int }") let variables = types.first?.variables expect(variables?[0].typeName) .to(equal( TypeName.buildClosure( .Int, .buildClosure(.Int, returnTypeName: .Int), returnTypeName: .Int ))) } } context("given Self instead of type name") { it("replaces variable types with actual types") { let expectedVariable = Variable( name: "variable", typeName: TypeName(name: "Self", actualTypeName: TypeName(name: "Foo")), accessLevel: (.internal, .none), isComputed: true, definedInTypeName: TypeName(name: "Foo") ) let expectedStaticVariable = Variable( name: "staticVar", typeName: TypeName(name: "Self", actualTypeName: TypeName(name: "Foo.SubType")), accessLevel: (.internal, .internal), isStatic: true, defaultValue: ".init()", modifiers: [Modifier(name: "static")], definedInTypeName: TypeName(name: "Foo.SubType") ) let subType = Struct(name: "SubType", variables: [expectedStaticVariable]) let fooType = Struct(name: "Foo", variables: [expectedVariable], containedTypes: [subType]) subType.parent = fooType expectedVariable.type = fooType expectedStaticVariable.type = subType let types = parse( """ struct Foo { var variable: Self { .init() } struct SubType { static var staticVar: Self = .init() } } """ ) func verify(_ variable: Variable?, expected: Variable) { expect(variable).to(equal(expected)) expect(variable?.actualTypeName).to(equal(expected.actualTypeName)) expect(variable?.type).to(equal(expected.type)) } verify(types.first(where: { $0.name == "Foo" })?.instanceVariables.first, expected: expectedVariable) verify(types.first(where: { $0.name == "Foo.SubType" })?.staticVariables.first, expected: expectedStaticVariable) } it("replaces method types with actual types") { let expectedMethod = Method(name: "myMethod()", selectorName: "myMethod", returnTypeName: TypeName(name: "Self", actualTypeName: TypeName(name: "Foo.SubType")), definedInTypeName: TypeName(name: "Foo.SubType")) let subType = Struct(name: "SubType", methods: [expectedMethod]) let fooType = Struct(name: "Foo", containedTypes: [subType]) subType.parent = fooType let types = parse( """ struct Foo { struct SubType { func myMethod() -> Self { return self } } } """ ) let parsedSubType = types.first(where: { $0.name == "Foo.SubType" }) expect(parsedSubType?.methods.first).to(equal(expectedMethod)) } } context("given typealiases") { func parseTypealiases(_ code: String) -> [Typealias] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return Composer.uniqueTypesAndFunctions(parserResult).typealiases } describe("Updated composer") { it("follows through typealias chain to final type") { let code = """ enum Bar {} struct Foo {} typealias Root = Bar typealias Leaf1 = Root typealias Leaf2 = Leaf1 typealias Leaf3 = Leaf1 """ parseTypealiases(code) .forEach { expect($0.type?.name) .to(equal("Bar")) } } it("follows through typealias chain contained in types to final type") { let code = """ enum Bar { typealias Root = Bar } struct Foo { typealias Leaf1 = Bar.Root } typealias Leaf2 = Foo.Leaf1 typealias Leaf3 = Leaf2 typealias Leaf4 = Bar.Root """ parseTypealiases(code) .forEach { expect($0.type?.name) .to(equal("Bar")) } } it("does not loop forever when typealiases form a cycle") { let code = """ typealias Foo = Bar typealias Bar = Foo """ guard let parserResult = try? makeParser(for: code).parse() else { fail("Failed to parse typealias cycle fixture") return } let composed = ParserResultsComposed(parserResult: parserResult) expect(composed.resolvedTypealiases.keys).to(contain("Foo", "Bar")) } xit("follows through typealias contained in other types") { let code = """ enum Module { typealias Model = ModuleModel } struct ModuleModel { class ModelID {} struct Element { let id: ModuleModel.ModelID let idUsingTypealias: Module.Model.ModelID } } """ let type = parse(code)[2] expect(type.name).to(equal("ModuleModel.Element")) type.variables.forEach { expect($0.type?.name).to(equal("ModuleModel.ModelID")) } } it("follows through typealias chain contained in different modules to final type") { // TODO: add module inference logic to typealias resolution! let typealiases = parseModules( (name: "RootModule", contents: "struct Bar {}"), (name: "LeafModule1", contents: "typealias Leaf1 = RootModule.Bar"), (name: "LeafModule2", contents: "typealias Leaf2 = LeafModule1.Leaf1") ).typealiases typealiases .forEach { expect($0.type?.name) .to(equal("Bar")) } } it("gathers full type information if a type is defined on an typealiased unknown parent via extension") { let code = """ typealias UnknownTypeAlias = Unknown extension UnknownTypeAlias { struct KnownStruct { var name: Int = 0 var meh: Float = 0 } } """ let result = parse(code) let knownType = result.first(where: { $0.localName == "KnownStruct" }) expect(knownType?.isExtension).to(beFalse()) expect(knownType?.variables).to(haveCount(2)) } it("extends the actual type when using typealias") { let code = """ struct Foo { } typealias FooAlias = Foo extension FooAlias { var name: Int { 0 } } """ let result = parse(code) expect(result.first?.variables.first?.typeName) .to(equal(TypeName.Int)) } it("resolves inheritance chain via typealias") { let code = """ class Foo { class Inner { var innerBase: Bool } typealias Hidden = Inner class InnerInherited: Hidden { var innerInherited: Bool = true } } """ let result = parse(code) let innerInherited = result.first(where: { $0.localName == "InnerInherited" }) expect(innerInherited?.inheritedTypes).to(equal(["Foo.Inner"])) } } it("resolves definedInType for methods") { let input = "class Foo { func bar() {} }; typealias FooAlias = Foo; extension FooAlias { func baz() {} }" let type = parse(input).first expect(type?.methods.first?.actualDefinedInTypeName).to(equal(TypeName(name: "Foo"))) expect(type?.methods.first?.definedInTypeName).to(equal(TypeName(name: "Foo"))) expect(type?.methods.first?.definedInType?.name).to(equal("Foo")) expect(type?.methods.first?.definedInType?.isExtension).to(beFalse()) expect(type?.methods.last?.actualDefinedInTypeName).to(equal(TypeName(name: "Foo"))) expect(type?.methods.last?.definedInTypeName).to(equal(TypeName(name: "FooAlias"))) expect(type?.methods.last?.definedInType?.name).to(equal("Foo")) expect(type?.methods.last?.definedInType?.isExtension).to(beTrue()) } it("resolves definedInType for variables") { let input = "class Foo { var bar: Int { return 1 } }; typealias FooAlias = Foo; extension FooAlias { var baz: Int { return 2 } }" let type = parse(input).first expect(type?.variables.first?.actualDefinedInTypeName).to(equal(TypeName(name: "Foo"))) expect(type?.variables.first?.definedInTypeName).to(equal(TypeName(name: "Foo"))) expect(type?.variables.first?.definedInType?.name).to(equal("Foo")) expect(type?.variables.first?.definedInType?.isExtension).to(beFalse()) expect(type?.variables.last?.actualDefinedInTypeName).to(equal(TypeName(name: "Foo"))) expect(type?.variables.last?.definedInTypeName).to(equal(TypeName(name: "FooAlias"))) expect(type?.variables.last?.definedInType?.name).to(equal("Foo")) expect(type?.variables.last?.definedInType?.isExtension).to(beTrue()) } it("sets typealias type") { let types = parse("class Bar {}; class Foo { typealias BarAlias = Bar }") let bar = types.first let foo = types.last expect(foo?.typealiases["BarAlias"]?.type).to(equal(bar)) } context("given variable") { it("replaces variable alias type with actual type") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "GlobalAlias", actualTypeName: TypeName(name: "Foo")), definedInTypeName: TypeName(name: "Bar")) expectedVariable.type = Class(name: "Foo") let type = parse("typealias GlobalAlias = Foo; class Foo {}; class Bar { var foo: GlobalAlias }").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.type).to(equal(expectedVariable.type)) } it("replaces tuple elements alias types with actual types") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Type(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "(GlobalAlias, Int)", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple), definedInTypeName: TypeName(name: "Bar")) let types = parse("typealias GlobalAlias = Foo; class Foo {}; class Bar { var foo: (GlobalAlias, Int) }") let variable = types.first?.variables.first let tupleElement = variable?.typeName.tuple?.elements.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(tupleElement?.type).to(equal(Class(name: "Foo"))) } it("replaces variable alias type with actual tuple type name") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "GlobalAlias", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple), definedInTypeName: TypeName(name: "Bar")) let type = parse("typealias GlobalAlias = (Foo, Int); class Foo {}; class Bar { var foo: GlobalAlias }").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.typeName.isTuple).to(beTrue()) } } context("given method return value type") { it("replaces method return type alias with actual type") { let expectedMethod = Method(name: "some()", selectorName: "some", returnTypeName: TypeName(name: "FooAlias", actualTypeName: TypeName(name: "Foo")), definedInTypeName: TypeName(name: "Bar")) let types = parse("typealias FooAlias = Foo; class Foo {}; class Bar { func some() -> FooAlias }") let method = types.first?.methods.first expect(method).to(equal(expectedMethod)) expect(method?.actualReturnTypeName).to(equal(expectedMethod.actualReturnTypeName)) expect(method?.returnType).to(equal(Class(name: "Foo"))) } it("replaces tuple elements alias types with actual types") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedMethod = Method(name: "some()", selectorName: "some", returnTypeName: TypeName(name: "(FooAlias, Int)", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple), definedInTypeName: TypeName(name: "Bar")) let types = parse("typealias FooAlias = Foo; class Foo {}; class Bar { func some() -> (FooAlias, Int) }") let method = types.first?.methods.first let tupleElement = method?.returnTypeName.tuple?.elements.first expect(method).to(equal(expectedMethod)) expect(method?.actualReturnTypeName).to(equal(expectedMethod.actualReturnTypeName)) expect(tupleElement?.type).to(equal(Class(name: "Foo"))) } it("replaces method return type alias with actual tuple type name") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedMethod = Method(name: "some()", selectorName: "some", returnTypeName: TypeName(name: "GlobalAlias", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple), definedInTypeName: TypeName(name: "Bar")) let types = parse("typealias GlobalAlias = (Foo, Int); class Foo {}; class Bar { func some() -> GlobalAlias }") let method = types.first?.methods.first expect(method).to(equal(expectedMethod)) expect(method?.actualReturnTypeName).to(equal(expectedMethod.actualReturnTypeName)) expect(method?.returnTypeName.isTuple).to(beTrue()) } } context("given method parameter") { it("replaces method parameter type alias with actual type") { let expectedMethodParameter = MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "FooAlias", actualTypeName: TypeName(name: "Foo")), type: Class(name: "Foo")) let types = parse("typealias FooAlias = Foo; class Foo {}; class Bar { func some(foo: FooAlias) }") let methodParameter = types.first?.methods.first?.parameters.first expect(methodParameter).to(equal(expectedMethodParameter)) expect(methodParameter?.actualTypeName).to(equal(expectedMethodParameter.actualTypeName)) expect(methodParameter?.type).to(equal(Class(name: "Foo"))) } it("replaces tuple tuple elements alias types with actual types") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedMethodParameter = MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "(FooAlias, Int)", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple)) let types = parse("typealias FooAlias = Foo; class Foo {}; class Bar { func some(foo: (FooAlias, Int)) }") let methodParameter = types.first?.methods.first?.parameters.first let tupleElement = methodParameter?.typeName.tuple?.elements.first expect(methodParameter).to(equal(expectedMethodParameter)) expect(methodParameter?.actualTypeName).to(equal(expectedMethodParameter.actualTypeName)) expect(tupleElement?.type).to(equal(Class(name: "Foo"))) } it("replaces method parameter alias type with actual tuple type name") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedMethodParameter = MethodParameter(name: "foo", index: 0, typeName: TypeName(name: "GlobalAlias", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple)) let types = parse("typealias GlobalAlias = (Foo, Int); class Foo {}; class Bar { func some(foo: GlobalAlias) }") let methodParameter = types.first?.methods.first?.parameters.first expect(methodParameter).to(equal(expectedMethodParameter)) expect(methodParameter?.actualTypeName).to(equal(expectedMethodParameter.actualTypeName)) expect(methodParameter?.typeName.isTuple).to(beTrue()) } } context("given enum case associated value") { it("replaces enum case associated value type alias with actual type") { let expectedAssociatedValue = AssociatedValue(typeName: TypeName(name: "FooAlias", actualTypeName: TypeName(name: "Foo")), type: Class(name: "Foo")) let types = parse("typealias FooAlias = Foo; class Foo {}; enum Some { case optionA(FooAlias) }") let associatedValue = (types.last as? Enum)?.cases.first?.associatedValues.first expect(associatedValue).to(equal(expectedAssociatedValue)) expect(associatedValue?.actualTypeName).to(equal(expectedAssociatedValue.actualTypeName)) expect(associatedValue?.type).to(equal(Class(name: "Foo"))) } it("replaces tuple type elements alias types with actual type") { let expectedActualTypeName = TypeName(name: "(Foo, Int)") expectedActualTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedAssociatedValue = AssociatedValue(typeName: TypeName(name: "(FooAlias, Int)", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple)) let types = parse("typealias FooAlias = Foo; class Foo {}; enum Some { case optionA((FooAlias, Int)) }") let associatedValue = (types.last as? Enum)?.cases.first?.associatedValues.first let tupleElement = associatedValue?.typeName.tuple?.elements.first expect(associatedValue).to(equal(expectedAssociatedValue)) expect(associatedValue?.actualTypeName).to(equal(expectedAssociatedValue.actualTypeName)) expect(tupleElement?.type).to(equal(Class(name: "Foo"))) } it("replaces associated value alias type with actual tuple type name") { let expectedTypeName = TypeName(name: "(Foo, Int)") expectedTypeName.tuple = TupleType(name: "(Foo, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Foo"), type: Class(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ]) let expectedAssociatedValue = AssociatedValue(typeName: TypeName(name: "GlobalAlias", actualTypeName: expectedTypeName, tuple: expectedTypeName.tuple)) let types = parse("typealias GlobalAlias = (Foo, Int); class Foo {}; enum Some { case optionA(GlobalAlias) }") let associatedValue = (types.last as? Enum)?.cases.first?.associatedValues.first expect(associatedValue).to(equal(expectedAssociatedValue)) expect(associatedValue?.actualTypeName).to(equal(expectedAssociatedValue.actualTypeName)) expect(associatedValue?.typeName.isTuple).to(beTrue()) } it("replaces associated value alias type with actual dictionary type name") { let expectedTypeName = TypeName(name: "[String: Any]") expectedTypeName.dictionary = DictionaryType(name: "[String: Any]", valueTypeName: TypeName(name: "Any"), valueType: nil, keyTypeName: TypeName(name: "String"), keyType: nil) expectedTypeName.generic = GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String"), type: nil), GenericTypeParameter(typeName: TypeName(name: "Any"), type: nil)]) let expectedAssociatedValue = AssociatedValue(typeName: TypeName(name: "JSON", actualTypeName: expectedTypeName, dictionary: expectedTypeName.dictionary, generic: expectedTypeName.generic), type: nil) let types = parse("typealias JSON = [String: Any]; enum Some { case optionA(JSON) }") let associatedValue = (types.last as? Enum)?.cases.first?.associatedValues.first expect(associatedValue?.typeName).to(equal(expectedAssociatedValue.typeName)) expect(associatedValue?.actualTypeName).to(equal(expectedAssociatedValue.actualTypeName)) } it("replaces associated value alias type with actual array type name") { let expectedTypeName = TypeName(name: "[Any]") expectedTypeName.array = ArrayType(name: "[Any]", elementTypeName: TypeName(name: "Any"), elementType: nil) expectedTypeName.generic = GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Any"), type: nil)]) let expectedAssociatedValue = AssociatedValue(typeName: TypeName(name: "JSON", actualTypeName: expectedTypeName, array: expectedTypeName.array, generic: expectedTypeName.generic), type: nil) let types = parse("typealias JSON = [Any]; enum Some { case optionA(JSON) }") let associatedValue = (types.last as? Enum)?.cases.first?.associatedValues.first expect(associatedValue).to(equal(expectedAssociatedValue)) expect(associatedValue?.actualTypeName).to(equal(expectedAssociatedValue.actualTypeName)) } it("replaces associated value alias type with actual closure type name") { let expectedTypeName = TypeName(name: "(String) -> Any") expectedTypeName.closure = ClosureType(name: "(String) -> Any", parameters: [ ClosureParameter(typeName: TypeName(name: "String")) ], returnTypeName: TypeName(name: "Any") ) let expectedAssociatedValue = AssociatedValue(typeName: TypeName(name: "JSON", actualTypeName: expectedTypeName, closure: expectedTypeName.closure), type: nil) let types = parse("typealias JSON = (String) -> Any; enum Some { case optionA(JSON) }") let associatedValue = (types.last as? Enum)?.cases.first?.associatedValues.first expect(associatedValue).to(equal(expectedAssociatedValue)) expect(associatedValue?.actualTypeName).to(equal(expectedAssociatedValue.actualTypeName)) } } it("replaces variable alias with actual type via 3 typealiases") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "FinalAlias", actualTypeName: TypeName(name: "Foo")), type: Class(name: "Foo"), definedInTypeName: TypeName(name: "Bar")) let type = parse( "typealias FooAlias = Foo; typealias BarAlias = FooAlias; typealias FinalAlias = BarAlias; class Foo {}; class Bar { var foo: FinalAlias }").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.type).to(equal(expectedVariable.type)) } it("replaces variable optional alias type with actual type") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "GlobalAlias?", actualTypeName: TypeName(name: "Foo?")), type: Class(name: "Foo"), definedInTypeName: TypeName(name: "Bar")) let type = parse("typealias GlobalAlias = Foo; class Foo {}; class Bar { var foo: GlobalAlias? }").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.type).to(equal(expectedVariable.type)) } it("extends actual type with type alias extension") { expect(parse("typealias GlobalAlias = Foo; class Foo: TestProtocol { }; extension GlobalAlias: AnotherProtocol {}")) .to(equal([ Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol", "AnotherProtocol"]) ])) } it("updates inheritedTypes with real type name") { let expectedFoo = Class(name: "Foo") let expectedClass = Class(name: "Bar", inheritedTypes: ["Foo"]) expectedClass.inherits = ["Foo": expectedFoo] expect(parse("typealias GlobalAliasFoo = Foo; class Foo { }; class Bar: GlobalAliasFoo {}")) .to(contain([expectedClass])) } context("given global protocol composition") { it("replaces variable alias type with protocol composition types") { let expectedProtocol1 = Protocol(name: "Foo") let expectedProtocol2 = Protocol(name: "Bar") let expectedProtocolComposition = ProtocolComposition(name: "GlobalComposition", inheritedTypes: ["Foo", "Bar"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar")]) let type = parse("typealias GlobalComposition = Foo & Bar; protocol Foo {}; protocol Bar {}").last as? ProtocolComposition expect(type).to(equal(expectedProtocolComposition)) expect(type?.composedTypes?.first).to(equal(expectedProtocol1)) expect(type?.composedTypes?.last).to(equal(expectedProtocol2)) } it("should deconstruct compositions of protocols for implements") { let expectedProtocol1 = Protocol(name: "Foo") let expectedProtocol2 = Protocol(name: "Bar") let expectedProtocolComposition = ProtocolComposition(name: "GlobalComposition", inheritedTypes: ["Foo", "Bar"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar")]) let type = parse("typealias GlobalComposition = Foo & Bar; protocol Foo {}; protocol Bar {}; class Implements: GlobalComposition {}").last as? Class expect(type?.implements).to(equal([ expectedProtocol1.name: expectedProtocol1, expectedProtocol2.name: expectedProtocol2, expectedProtocolComposition.name: expectedProtocolComposition ])) } it("should deconstruct compositions of class and protocol for implements") { let expectedProtocol = Protocol(name: "Foo") let type = parse("protocol Foo {}; class Bar {}; class Implements: Bar & Foo {}").last as? Class expect(type?.implements).to(equal([ expectedProtocol.name: expectedProtocol ])) } it("should deconstruct compositions of class and protocol for based") { let expectedProtocol = Protocol(name: "Foo") let expectedClass = Class(name: "Bar") let expectedProtocolComposition = ProtocolComposition(name: "Bar & Foo", inheritedTypes: ["Bar", "Foo"], composedTypeNames: [TypeName(name: "Bar"), TypeName(name: "Foo")], composedTypes: [expectedClass, expectedProtocol]) let type = parse("protocol Foo {}; class Bar {}; class Implements: Bar & Foo {}").last as? Class expect(type?.based).to(equal([ expectedClass.name: expectedClass.name, expectedProtocol.name: expectedProtocol.name, expectedProtocolComposition.name: expectedProtocolComposition.name ])) } it("should deconstruct compositions of class and protocol for inherits") { let expectedClass = Class(name: "Bar") let type = parse("protocol Foo {}; class Bar {}; class Implements: Bar & Foo {}").last as? Class expect(type?.inherits).to(equal([ expectedClass.name: expectedClass ])) } it("should deconstruct compositions of protocols and classes for implements and inherits") { let expectedProtocol = Protocol(name: "Foo") let expectedClass = Class(name: "Bar") let type = parse("typealias GlobalComposition = Foo & Bar; protocol Foo {}; class Bar {}; class Implements: GlobalComposition {}").last as? Class expect(type?.implements).to(equal([ expectedProtocol.name: expectedProtocol ])) expect(type?.inherits).to(equal([ expectedClass.name: expectedClass ])) } } context("given local typealias") { it("replaces variable alias type with actual type") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "FooAlias", actualTypeName: TypeName(name: "Foo")), type: Class(name: "Foo"), definedInTypeName: TypeName(name: "Bar")) let type = parse("class Bar { typealias FooAlias = Foo; var foo: FooAlias }; class Foo {}").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.type).to(equal(expectedVariable.type)) } it("replaces variable alias type with actual contained type") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "FooAlias", actualTypeName: TypeName(name: "Bar.Foo")), type: Class(name: "Foo", parent: Class(name: "Bar")), definedInTypeName: TypeName(name: "Bar")) let type = parse("class Bar { typealias FooAlias = Foo; var foo: FooAlias; class Foo {} }").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.type).to(equal(expectedVariable.type)) } it("replaces variable alias type with actual foreign contained type") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "FooAlias", actualTypeName: TypeName(name: "FooBar.Foo")), type: Class(name: "Foo", parent: Type(name: "FooBar")), definedInTypeName: TypeName(name: "Bar")) let type = parse("class Bar { typealias FooAlias = FooBar.Foo; var foo: FooAlias }; class FooBar { class Foo {} }").first let variable = type?.variables.first expect(variable).to(equal(expectedVariable)) expect(variable?.actualTypeName).to(equal(expectedVariable.actualTypeName)) expect(variable?.type).to(equal(expectedVariable.type)) } it("populates the local collection of typealiases") { let expectedType = Class(name: "Foo") let expectedParent = Class(name: "Bar") let type = parse("class Bar { typealias FooAlias = Foo }; class Foo {}").first let aliases = type?.typealiases expect(aliases).to(haveCount(1)) expect(aliases?["FooAlias"]).to(equal(Typealias(aliasName: "FooAlias", typeName: TypeName(name: "Foo"), parent: expectedParent))) expect(aliases?["FooAlias"]?.type).to(equal(expectedType)) } it("populates the global collection of typealiases") { let expectedType = Class(name: "Foo") let expectedParent = Class(name: "Bar") let aliases = parseTypealiases("class Bar { typealias FooAlias = Foo }; class Foo {}") expect(aliases).to(haveCount(1)) expect(aliases.first).to(equal(Typealias(aliasName: "FooAlias", typeName: TypeName(name: "Foo"), parent: expectedParent))) expect(aliases.first?.type).to(equal(expectedType)) } } context("given global typealias") { it("extracts typealiases of other typealiases") { expect(parseTypealiases("typealias Foo = Int; typealias Bar = Foo")) .to(contain([ Typealias(aliasName: "Foo", typeName: TypeName(name: "Int")), Typealias(aliasName: "Bar", typeName: TypeName(name: "Foo")) ])) } it("extracts typealiases of other typealiases of a type") { expect(parseTypealiases("typealias Foo = Baz; typealias Bar = Foo; class Baz {}")) .to(contain([ Typealias(aliasName: "Foo", typeName: TypeName(name: "Baz")), Typealias(aliasName: "Bar", typeName: TypeName(name: "Foo")) ])) } it("resolves types transitively") { let expectedType = Class(name: "Baz") let typealiases = parseTypealiases("typealias Foo = Bar; typealias Bar = Baz; class Baz {}") expect(typealiases).to(haveCount(2)) expect(typealiases.first?.type).to(equal(expectedType)) expect(typealiases.last?.type).to(equal(expectedType)) } } } context("given associated type") { context("given value with its type known") { it("extracts associated value's type") { let associatedValue = AssociatedValue(typeName: TypeName(name: "Bar"), type: Class(name: "Bar", inheritedTypes: ["Baz"])) let item = Enum(name: "Foo", cases: [EnumCase(name: "optionA", associatedValues: [associatedValue])]) let parsed = parse("protocol Baz {}; class Bar: Baz {}; enum Foo { case optionA(Bar) }") let parsedItem = parsed.compactMap { $0 as? Enum }.first expect(parsedItem).to(equal(item)) expect(associatedValue.type).to(equal(parsedItem?.cases.first?.associatedValues.first?.type)) } it("extracts associated value's optional type") { let associatedValue = AssociatedValue(typeName: TypeName(name: "Bar?"), type: Class(name: "Bar", inheritedTypes: ["Baz"])) let item = Enum(name: "Foo", cases: [EnumCase(name: "optionA", associatedValues: [associatedValue])]) let parsed = parse("protocol Baz {}; class Bar: Baz {}; enum Foo { case optionA(Bar?) }") let parsedItem = parsed.compactMap { $0 as? Enum }.first expect(parsedItem).to(equal(item)) expect(associatedValue.type).to(equal(parsedItem?.cases.first?.associatedValues.first?.type)) } it("extracts associated value's typealias") { let associatedValue = AssociatedValue(typeName: TypeName(name: "Bar2"), type: Class(name: "Bar", inheritedTypes: ["Baz"])) let item = Enum(name: "Foo", cases: [EnumCase(name: "optionA", associatedValues: [associatedValue])]) let parsed = parse("typealias Bar2 = Bar; protocol Baz {}; class Bar: Baz {}; enum Foo { case optionA(Bar2) }") let parsedItem = parsed.compactMap { $0 as? Enum }.first expect(parsedItem).to(equal(item)) expect(associatedValue.type).to(equal(parsedItem?.cases.first?.associatedValues.first?.type)) } it("extracts associated value's same (indirect) enum type") { let associatedValue = AssociatedValue(typeName: TypeName(name: "Foo")) let item = Enum(name: "Foo", inheritedTypes: ["Baz"], cases: [EnumCase(name: "optionA", associatedValues: [associatedValue])], modifiers: [ Modifier(name: "indirect") ]) associatedValue.type = item let parsed = parse("protocol Baz {}; indirect enum Foo: Baz { case optionA(Foo) }") let parsedItem = parsed.compactMap { $0 as? Enum }.first expect(parsedItem).to(equal(item)) expect(associatedValue.type).to(equal(parsedItem?.cases.first?.associatedValues.first?.type)) } } it("extracts associated type properly when constrained to a typealias") { let code = """ protocol Foo { typealias AEncodable = Encodable associatedtype Bar: AEncodable } """ let givenTypealias = Typealias(aliasName: "AEncodable", typeName: TypeName(name: "Encodable")) let expectedProtocol = Protocol(name: "Foo", typealiases: [givenTypealias]) givenTypealias.parent = expectedProtocol expectedProtocol.associatedTypes["Bar"] = AssociatedType( name: "Bar", typeName: TypeName( name: givenTypealias.aliasName, actualTypeName: givenTypealias.typeName ) ) let actualProtocol = parse(code).last expect(actualProtocol).to(equal(expectedProtocol)) let actualTypeName = (actualProtocol as? SourceryProtocol)?.associatedTypes.first?.value.typeName?.actualTypeName expect(actualTypeName).to(equal(givenTypealias.actualTypeName)) } } context("given nested type") { it("extracts method's defined in properly") { let expectedMethod = Method(name: "some()", selectorName: "some", definedInTypeName: TypeName(name: "Foo.Bar")) let types = parse("class Foo { class Bar { func some() } }") let method = types.last?.methods.first expect(method).to(equal(expectedMethod)) expect(method?.definedInType).to(equal(types.last)) } it("extracts property of nested generic type properly") { let expectedActualTypeName = TypeName(name: "Blah.Foo?") let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "Foo?", actualTypeName: expectedActualTypeName), accessLevel: (read: .internal, write: .none), definedInTypeName: TypeName(name: "Blah.Bar")) let expectedBlah = Struct(name: "Blah", containedTypes: [Struct(name: "FooBar"), Struct(name: "Foo"), Struct(name: "Bar", variables: [expectedVariable])]) expectedActualTypeName.generic = GenericType(name: "Blah.Foo", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Blah.FooBar"), type: expectedBlah.containedType["FooBar"])]) expectedVariable.typeName.generic = expectedActualTypeName.generic let types = parse(""" struct Blah { struct FooBar {} struct Foo {} struct Bar { let foo: Foo? } } """) let bar = types.first(where: { $0.name == "Blah.Bar" }) expect(bar?.variables.first).to(equal(expectedVariable)) expect(bar?.variables.first?.actualTypeName).to(equal(expectedVariable.actualTypeName)) } it("extracts property of nested type properly") { let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "Foo?", actualTypeName: TypeName(name: "Blah.Foo?")), accessLevel: (read: .internal, write: .none), definedInTypeName: TypeName(name: "Blah.Bar")) let expectedBlah = Struct(name: "Blah", containedTypes: [Struct(name: "Foo"), Struct(name: "Bar", variables: [expectedVariable])]) let types = parse("struct Blah { struct Foo {}; struct Bar { let foo: Foo? }}") let blah = types.first(where: { $0.name == "Blah" }) let bar = types.first(where: { $0.name == "Blah.Bar" }) expect(blah).to(equal(expectedBlah)) expect(bar?.variables.first).to(equal(expectedVariable)) expect(bar?.variables.first?.actualTypeName).to(equal(expectedVariable.actualTypeName)) } it("extracts property of nested type array properly") { let expectedActualTypeName = TypeName(name: "[Blah.Foo]?") let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "[Foo]?", actualTypeName: expectedActualTypeName), accessLevel: (read: .internal, write: .none), definedInTypeName: TypeName(name: "Blah.Bar")) let expectedBlah = Struct(name: "Blah", containedTypes: [Struct(name: "Foo"), Struct(name: "Bar", variables: [expectedVariable])]) expectedActualTypeName.array = ArrayType(name: "[Blah.Foo]", elementTypeName: TypeName(name: "Blah.Foo"), elementType: Struct(name: "Foo", parent: expectedBlah)) expectedVariable.typeName.array = expectedActualTypeName.array expectedActualTypeName.generic = GenericType(name: "Array", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Blah.Foo"), type: Struct(name: "Foo", parent: expectedBlah))]) expectedVariable.typeName.generic = expectedActualTypeName.generic let types = parse("struct Blah { struct Foo {}; struct Bar { let foo: [Foo]? }}") let blah = types.first(where: { $0.name == "Blah" }) let bar = types.first(where: { $0.name == "Blah.Bar" }) expect(blah).to(equal(expectedBlah)) expect(bar?.variables.first).to(equal(expectedVariable)) expect(bar?.variables.first?.actualTypeName).to(equal(expectedVariable.actualTypeName)) } it("extracts property of nested type dictionary properly") { let expectedActualTypeName = TypeName(name: "[Blah.Foo: Blah.Foo]?") let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "[Foo: Foo]?", actualTypeName: expectedActualTypeName), accessLevel: (read: .internal, write: .none), definedInTypeName: TypeName(name: "Blah.Bar")) let expectedBlah = Struct(name: "Blah", containedTypes: [Struct(name: "Foo"), Struct(name: "Bar", variables: [expectedVariable])]) expectedActualTypeName.dictionary = DictionaryType(name: "[Blah.Foo: Blah.Foo]", valueTypeName: TypeName(name: "Blah.Foo"), valueType: Struct(name: "Foo", parent: expectedBlah), keyTypeName: TypeName(name: "Blah.Foo"), keyType: Struct(name: "Foo", parent: expectedBlah)) expectedVariable.typeName.dictionary = expectedActualTypeName.dictionary expectedActualTypeName.generic = GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "Blah.Foo"), type: Struct(name: "Foo", parent: expectedBlah)), GenericTypeParameter(typeName: TypeName(name: "Blah.Foo"), type: Struct(name: "Foo", parent: expectedBlah))]) expectedVariable.typeName.generic = expectedActualTypeName.generic let types = parse("struct Blah { struct Foo {}; struct Bar { let foo: [Foo: Foo]? }}") let blah = types.first(where: { $0.name == "Blah" }) let bar = types.first(where: { $0.name == "Blah.Bar" }) expect(blah).to(equal(expectedBlah)) expect(bar?.variables.first).to(equal(expectedVariable)) expect(bar?.variables.first?.actualTypeName).to(equal(expectedVariable.actualTypeName)) } it("extracts property of nested type tuple properly") { let expectedActualTypeName = TypeName(name: "(Blah.Foo, Blah.Foo, Blah.Foo)?", tuple: TupleType(name: "(Blah.Foo, Blah.Foo, Blah.Foo)", elements: [ TupleElement(name: "a", typeName: TypeName(name: "Blah.Foo"), type: Struct(name: "Foo")), TupleElement(name: "1", typeName: TypeName(name: "Blah.Foo"), type: Struct(name: "Foo")), TupleElement(name: "2", typeName: TypeName(name: "Blah.Foo"), type: Struct(name: "Foo")) ])) let expectedVariable = Variable(name: "foo", typeName: TypeName(name: "(a: Foo, _: Foo, Foo)?", actualTypeName: expectedActualTypeName, tuple: expectedActualTypeName.tuple), accessLevel: (read: .internal, write: .none), definedInTypeName: TypeName(name: "Blah.Bar")) let expectedBlah = Struct(name: "Blah", containedTypes: [Struct(name: "Foo"), Struct(name: "Bar", variables: [expectedVariable])]) let types = parse("struct Blah { struct Foo {}; struct Bar { let foo: (a: Foo, _: Foo, Foo)? }}") let blah = types.first(where: { $0.name == "Blah" }) let bar = types.first(where: { $0.name == "Blah.Bar" }) expect(blah).to(equal(expectedBlah)) expect(bar?.variables.first).to(equal(expectedVariable)) expect(bar?.variables.first?.actualTypeName).to(equal(expectedVariable.actualTypeName)) } it("resolves protocol generic requirement types and inherits associated types") { let expectedRightType = Struct(name: "RightType") let genericProtocol = Protocol(name: "GenericProtocol", associatedTypes: ["LeftType": AssociatedType(name: "LeftType", typeName: TypeName(name: "Any"))]) let expectedProtocol = Protocol(name: "SomeGenericProtocol", inheritedTypes: ["GenericProtocol"]) expectedProtocol.associatedTypes = genericProtocol.associatedTypes expectedProtocol.genericRequirements = [ GenericRequirement(leftType: .init(name: "LeftType"), rightType: GenericTypeParameter(typeName: TypeName(name: "RightType"), type: expectedRightType), relationship: .equals) ] let results = parse( """ struct RightType {} protocol GenericProtocol { associatedtype LeftType } protocol SomeGenericProtocol: GenericProtocol where LeftType == RightType {} """ ) let parsedProtocol = results.first(where: { $0.name == "SomeGenericProtocol" }) as? SourceryProtocol expect(parsedProtocol).to(equal(expectedProtocol)) expect(parsedProtocol?.associatedTypes).to(equal(genericProtocol.associatedTypes)) expect(parsedProtocol?.implements["GenericProtocol"]).to(equal(genericProtocol)) expect(parsedProtocol?.genericRequirements[0].rightType.type).to(equal(expectedRightType)) } } context("given types within modules") { it("doesn't automatically add module name to unknown types but keeps the info in the AST via module property") { let extensionType = Type(name: "AnyPublisher", isExtension: true).asUnknownException() extensionType.module = "MyModule" let types = parseModules( (name: "MyModule", contents: """ extension AnyPublisher {} struct Foo { var publisher: AnyPublisher } """) ).types let publisher = types.first let fooVariable = types.last?.variables.last expect(publisher).to(equal(extensionType)) expect(publisher?.globalName).to(equal("AnyPublisher")) expect(fooVariable?.typeName.generic?.name).to(equal("AnyPublisher")) } it("combines unknown extensions correctly") { let extensionType = Type(name: "AnyPublisher", isExtension: true, variables: [ .init(name: "property1", typeName: .Int, accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "AnyPublisher")), .init(name: "property2", typeName: .String, accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "AnyPublisher")) ]) extensionType.isUnknownExtension = true extensionType.module = "MyModule" let types = parseModules( (name: "MyModule", contents: """ extension AnyPublisher {} extension AnyPublisher { var property1: Int { 0 } var property2: String { "" } } """) ).types expect(types).to(equal([extensionType])) expect(types.first?.globalName).to(equal("AnyPublisher")) } it("combines unknown extensions from different files correctly") { let extensionType = Type(name: "AnyPublisher", isExtension: true, variables: [ .init(name: "property1", typeName: .Int, accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "AnyPublisher")), .init(name: "property2", typeName: .String, accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "AnyPublisher")) ]) extensionType.isUnknownExtension = true extensionType.module = "MyModule" let types = parseModules( (name: "MyModule", contents: """ extension AnyPublisher { var property1: Int { 0 } } """), (name: "MyModule", contents: """ extension AnyPublisher { var property2: String { "" } } """) ).types expect(types).to(equal([extensionType])) expect(types.first?.globalName).to(equal("AnyPublisher")) } it("combines known types with extensions correctly") { let fooType = Struct(name: "Foo", variables: [ .init(name: "property1", typeName: .Int, accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "Foo")), .init(name: "property2", typeName: .String, accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "Foo")) ]) fooType.module = "MyModule" let types = parseModules( (name: "MyModule", contents: """ struct Foo {} extension Foo {} extension Foo { var property1: Int { 0 } var property2: String { "" } } """) ).types expect(types).to(equal([fooType])) expect(types.first?.globalName).to(equal("MyModule.Foo")) } context("when using global names") { it("extends type with extension") { let expectedBar = Struct(name: "Bar", variables: [ Variable(name: "foo", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, definedInTypeName: TypeName(name: "MyModule.Bar")) ]) expectedBar.module = "MyModule" let types = parseModules( (name: "MyModule", contents: "struct Bar {}"), (name: nil, contents: "extension MyModule.Bar { var foo: Int { return 0 } }") ).types expect(types).to(equal([expectedBar])) } it("resolves variable type") { let expectedBar = Struct(name: "Bar") expectedBar.module = "MyModule" let expectedFoo = Struct(name: "Foo", variables: [Variable(name: "bar", typeName: TypeName(name: "MyModule.Bar"), type: expectedBar, definedInTypeName: TypeName(name: "Foo"))]) let types = parseModules( (name: "MyModule", contents: "struct Bar {}"), (name: nil, contents: "struct Foo { var bar: MyModule.Bar }") ).types expect(types).to(equal([expectedFoo, expectedBar])) expect(types.first?.variables.first?.type).to(equal(expectedBar)) } it("resolves variable defined in type") { let expectedBar = Struct(name: "Bar") expectedBar.module = "MyModule" let expectedFoo = Struct(name: "Foo", variables: [Variable(name: "bar", typeName: TypeName(name: "MyModule.Bar"), type: expectedBar, definedInTypeName: TypeName(name: "Foo"))]) let types = parseModules( (name: "MyModule", contents: "struct Bar {}"), (name: nil, contents: "struct Foo { var bar: MyModule.Bar }") ).types expect(types).to(equal([expectedFoo, expectedBar])) expect(types.first?.variables.first?.type).to(equal(expectedBar)) expect(types.first?.variables.first?.definedInType).to(equal(expectedFoo)) } } context("when using local names") { it("resolves variable type properly") { let expectedBarA = Struct(name: "Bar") expectedBarA.module = "ModuleA" let expectedFoo = Struct(name: "Foo", variables: [Variable(name: "bar", typeName: TypeName(name: "Bar"), type: expectedBarA, definedInTypeName: TypeName(name: "Foo"))]) expectedFoo.module = "ModuleB" expectedFoo.imports = [Import(path: "ModuleA")] let expectedBarC = Struct(name: "Bar") expectedBarC.module = "ModuleC" let types = parseModules( (name: "ModuleA", contents: "struct Bar {}"), (name: "ModuleB", contents: """ import ModuleA struct Foo { var bar: Bar } """ ), (name: "ModuleC", contents: "struct Bar {}") ).types expect(types).to(equal([expectedBarA, expectedFoo, expectedBarC])) expect(types.first(where: { $0.name == "Foo" })?.variables.first?.type).to(equal(expectedBarA)) } it("resolves variable type properly even when using specialized imports") { let expectedBarA = Struct(name: "Bar") expectedBarA.module = "ModuleA.Submodule" let expectedFoo = Struct(name: "Foo", variables: [Variable(name: "bar", typeName: TypeName(name: "Bar"), type: expectedBarA, definedInTypeName: TypeName(name: "Foo"))]) expectedFoo.module = "ModuleB" expectedFoo.imports = [Import(path: "ModuleA.Submodule.Bar", kind: "struct")] let expectedBarC = Struct(name: "Bar") expectedBarC.module = "ModuleC" let types = parseModules( (name: "ModuleA.Submodule", contents: "struct Bar {}"), (name: "ModuleB", contents: """ import struct ModuleA.Submodule.Bar struct Foo { var bar: Bar } """ ), (name: "ModuleC", contents: "struct Bar {}") ).types expect(types).to(equal([expectedBarA, expectedFoo, expectedBarC])) expect(types.first(where: { $0.name == "Foo" })?.variables.first?.type).to(equal(expectedBarA)) } it("throws error when variable type is ambigious") { let expectedBarA = Struct(name: "Bar") expectedBarA.module = "ModuleA" let expectedFoo = Struct(name: "Foo", variables: [Variable(name: "bar", typeName: TypeName(name: "Bar"), type: expectedBarA, definedInTypeName: TypeName(name: "Foo"))]) expectedFoo.module = "ModuleB" let expectedBarC = Struct(name: "Bar") expectedBarC.module = "ModuleC" let types = parseModules( (name: "ModuleA", contents: "struct Bar {}"), (name: "ModuleB", contents: """ struct Foo { var bar: Bar } """ ), (name: "ModuleC", contents: "struct Bar {}") ).types let barVariable = types.last?.variables.first expect(types).to(equal([expectedBarA, expectedFoo, expectedBarC])) expect(barVariable?.typeName).to(beNil()) expect(barVariable?.type).to(beNil()) } it("resolves variable type correctly") { let expectedBar = Struct(name: "Bar", variables: [ Variable(name: "bat", typeName: TypeName(name: "Int"), type: nil, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Bar")) ]) expectedBar.module = "Foo" let expectedFoo = Struct(name: "Foo", variables: [Variable(name: "bar", typeName: TypeName(name: "Foo.Bar"), type: expectedBar, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo"))], containedTypes: [expectedBar]) expectedFoo.module = "Foo" let types = parseModules( (name: "Foo", contents: """ struct Foo { struct Bar { let bat: Int } let bar: Bar } """ )).types expect(types).to(equal([expectedFoo, expectedBar])) let parsedFoo = types.first(where: { $0.globalName == "Foo.Foo" }) expect(parsedFoo).to(equal(expectedFoo)) expect(parsedFoo?.variables.first?.type).to(equal(expectedBar)) } it("resolves variable type correctly when generics are used") { let expectedBar = Struct(name: "Bar", variables: [ Variable(name: "batDouble", typeName: TypeName(name: "Double"), type: nil, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Bar")), Variable(name: "batInt", typeName: TypeName(name: "Int"), type: nil, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Bar")) ]) expectedBar.module = "ModuleA" let expectedBaz = Struct(name: "Baz", isGeneric: true) expectedBaz.module = "ModuleA" let expectedFoo = Struct(name: "Foo", variables: [ Variable(name: "bar", typeName: TypeName(name: "Foo.Bar"), type: expectedBar, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo")), Variable(name: "bazbars", typeName: TypeName(name: "Baz", generic: .init(name: "ModuleA.Foo.Baz", typeParameters: [.init(typeName: .init("ModuleA.Foo.Bar"))])), type: expectedBaz, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo")), Variable(name: "bazDoubles", typeName: TypeName(name: "Baz", generic: .init(name: "ModuleA.Foo.Baz", typeParameters: [.init(typeName: .init("Double"))])), type: expectedBaz, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo")), Variable(name: "bazInts", typeName: TypeName(name: "Baz", generic: .init(name: "ModuleA.Foo.Baz", typeParameters: [.init(typeName: .init("Int"))])), type: expectedBaz, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo")) ], containedTypes: [expectedBar, expectedBaz]) expectedFoo.module = "ModuleA" let expectedDouble = Type(name: "Double", accessLevel: .internal, isExtension: true).asUnknownException() expectedDouble.module = "ModuleA" let types = parseModules( (name: "ModuleA", contents: """ extension Double {} struct Foo { struct Bar { let batDouble: Double let batInt: Int } struct Baz { } let bar: Bar let bazbars: Baz let bazDoubles: Baz let bazInts: Baz } """ )).types expect(types).to(equal([expectedDouble, expectedFoo, expectedBar, expectedBaz])) func check(variable: String, typeName: String?, type: String?, onType globalName: String) { let entity = types.first(where: { $0.globalName == globalName }) expect(entity).toNot(beNil()) let variable = entity?.allVariables.first(where: { $0.name == variable }) expect(variable).toNot(beNil()) if let typeName = typeName { expect(variable?.typeName.description).to(equal(typeName)) } else { expect(variable?.typeName.description).to(beNil()) } if let type = type { expect(variable?.type?.name).to(equal(type)) } else { expect(variable?.type?.name).to(beNil()) } } check(variable: "bar", typeName: "Foo.Bar", type: "Foo.Bar", onType: "ModuleA.Foo") check(variable: "bazbars", typeName: "Baz", type: "Foo.Baz", onType: "ModuleA.Foo") check(variable: "bazDoubles", typeName: "Baz", type: "Foo.Baz", onType: "ModuleA.Foo") check(variable: "bazInts", typeName: "Baz", type: "Foo.Baz", onType: "ModuleA.Foo") check(variable: "batDouble", typeName: "Double", type: "Double", onType: "ModuleA.Foo.Bar") check(variable: "batInt", typeName: "Int", type: nil, onType: "ModuleA.Foo.Bar") } it("resolves variable type correctly when typealias is used") { let expectedBar = Class(name: "Bar", variables: []) let expectedContainsTopLevelTypealias = Struct(name: "ContainsTopLevelTypealias") let expectedBaz = Struct(name: "Baz", variables: [ Variable(name: "bar", typeName: TypeName(name: "Foo.Bar"), type: expectedBar, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Baz")), Variable(name: "topLevelTypealias", typeName: TypeName(name: "TopLevelTypealias"), type: expectedBar, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Baz")), Variable(name: "topLevelType", typeName: TypeName(name: "ContainsTopLevelTypealias"), type: expectedContainsTopLevelTypealias, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Baz")), Variable(name: "usingTypealias", typeName: TypeName(name: "MyEnum.MyTypealias.Bar"), type: expectedBar, accessLevel: (.internal, .none), definedInTypeName: TypeName(name: "Foo.Baz")) ]) let expectedFoo = Struct(name: "Foo", containedTypes: [expectedBar, expectedBaz]) let types = parseModules( (name: nil, contents: """ enum MyEnum { typealias MyTypealias = Foo } typealias TopLevelTypealias = Foo.Bar struct ContainsTopLevelTypealias {} struct Foo { class Bar {} struct Baz { let bar: Foo.Bar let topLevelTypealias: TopLevelTypealias let topLevelType: ContainsTopLevelTypealias let usingTypealias: MyEnum.MyTypealias.Bar } } """ )).types let parsedFoo = types.first(where: { $0.globalName == "Foo" }) expect(parsedFoo).to(equal(expectedFoo)) let parsedBaz = parsedFoo?.containedTypes.last expect(parsedBaz).toNot(beNil()) expect(parsedBaz!.variables.first?.type).to(equal(expectedBar)) expect(parsedBaz!.variables.last?.type).to(equal(expectedBar)) for variable in parsedBaz!.variables { expect(variable.type).toNot(beNil(), description: "\(variable.typeName.name)") } } it("resolves geeneric method parameter type correctly when typealias is used") { let expectedBar = Class(name: "Foo", variables: [], methods: [ Method(name: "foo(param: Bar)", selectorName: "foo(param:)", parameters: [ MethodParameter(name: "param", index: 0, typeName: TypeName(name: "Bar", generic: GenericType(name: "Bar", typeParameters: [ GenericTypeParameter(typeName: TypeName(name: "Value"), type: nil) ])), type: nil, defaultValue: nil, annotations: [:], isInout: false, isVariadic: false) ], definedInTypeName: TypeName(name: "Foo"), genericParameters: [ GenericParameter(name: "Value", inheritedTypeName: nil) ]), Method(name: "foo(param: Bar)", selectorName: "foo(param:)", parameters: [ MethodParameter(name: "param", index: 0, typeName: TypeName(name: "Bar", generic: GenericType(name: "Bar", typeParameters: [ GenericTypeParameter(typeName: TypeName(name: "Value"), type: nil) ])), type: nil, defaultValue: nil, annotations: [:], isInout: false, isVariadic: false) ], definedInTypeName: TypeName(name: "Foo"), genericParameters: [ GenericParameter(name: "Value", inheritedTypeName: TypeName(name: "Int")) ]), Method(name: "fooBar(param: Bar)", selectorName: "fooBar(param:)", parameters: [ MethodParameter(name: "param", index: 0, typeName: TypeName(name: "Bar", generic: GenericType(name: "Bar", typeParameters: [ GenericTypeParameter(typeName: TypeName(name: "Value"), type: nil) ])), type: nil, defaultValue: nil, annotations: [:], isInout: false, isVariadic: false) ], returnTypeName: TypeName(name: "Void where Value == Int"), definedInTypeName: TypeName(name: "Foo"), genericRequirements: [ GenericRequirement(leftType: AssociatedType(name: "Value"), rightType: GenericTypeParameter(typeName: TypeName(name: "Int")), relationship: .equals) ], genericParameters: [ GenericParameter(name: "Value", inheritedTypeName: TypeName(name: "Int")) ]) ]) let types = parseModules( (name: nil, contents: """ typealias Value = String? class Foo { func foo(param: Bar) func foo(param: Bar) func fooBar(param: Bar) where Value == Int } """ )).types let parsedFoo = types.first(where: { $0.globalName == "Foo" }) expect(parsedFoo).to(equal(expectedBar)) } it("ignores empty generic arguments created by trailing commas") { let types = parse(""" struct Example where A.Element == String, B.Element == String { let asyncTaskData: OrderedDictionary< String, (status: Result, messages: [String]), > } """) let example = types.first(where: { $0.globalName == "Example" }) expect(example).toNot(beNil()) let variable = example?.variables.first(where: { $0.name == "asyncTaskData" }) let parameters = variable?.typeName.generic?.typeParameters expect(parameters).to(haveCount(2)) expect(parameters?.first?.typeName.name).to(equal("String")) expect(parameters?.last?.typeName.name).to(equal("(status: Result, messages: [String])")) } } } context("given free function") { it("resolves generic return types properly") { let functions = parseFunctions("func foo() -> Bar { }") expect(functions[0]).to(equal(SourceryMethod( name: "foo()", selectorName: "foo", parameters: [], returnTypeName: TypeName( name: "Bar", generic: GenericType( name: "Bar", typeParameters: [ GenericTypeParameter( typeName: TypeName(name: "String"), type: nil ) ]) ), definedInTypeName: nil))) } it("resolves tuple return types properly") { let functions = parseFunctions("func foo() -> (bar: String, biz: Int) { }") expect(functions[0]).to(equal(SourceryMethod( name: "foo()", selectorName: "foo", parameters: [], returnTypeName: TypeName( name: "(bar: String, biz: Int)", tuple: TupleType( name: "(bar: String, biz: Int)", elements: [ TupleElement(name: "bar", typeName: TypeName(name: "String")), TupleElement(name: "biz", typeName: TypeName(name: "Int")) ]) ), definedInTypeName: nil))) } } context("given nested types") { it("resolve extensions of nested type properly") { let types = parseModules( ("Mod1", "enum NS {}; extension NS { struct Foo { func f1() } }"), ("Mod2", "import Mod1; extension NS.Foo { func f2() }"), ("Mod3", "import Mod1; extension NS.Foo { func f3() }") ).types expect(types.map { $0.globalName }).to(equal(["Mod1.NS", "Mod1.NS.Foo"])) expect(types[1].methods.map { $0.name }).to(equal(["f1()", "f2()", "f3()"])) } it("resolve extensions with nested types properly") { let types = parseModules( ("Mod1", "enum NS {}"), ("Mod2", "import Mod1; extension NS { struct A { struct D {} } }"), ("Mod3", "import Mod1; extension Mod1.NS { struct B { struct C {} } }") ).types expect(types.map(\.globalName).sorted()).to(equal(["Mod1.NS", "Mod2.NS.A", "Mod2.NS.A.D", "Mod3.NS.B", "Mod3.NS.B.C"])) } it("resolve extensions with global names declared before nested type") { let types = parseModules( ("Mod1", "enum A {}; extension Mod1.A.B.C { enum D {} }; extension Mod1.A { enum B { enum C {} } }") ).types expect(types.map(\.globalName).sorted()).to(equal(["Mod1.A", "Mod1.A.B", "Mod1.A.B.C", "Mod1.A.B.C.D"])) } it("resolve extensions declared before nested type") { let types = parseModules( ("Mod1", "enum A {}; extension A.B.C { enum D {} }; extension A { enum B { enum C {} } }") ).types expect(types.map(\.globalName).sorted()).to(equal(["Mod1.A", "Mod1.A.B", "Mod1.A.B.C", "Mod1.A.B.C.D"])) } it("resolve extensions with nested types properly") { let types = parseModules(("Mod1", "enum NS {}; extension Mod1.NS.A.B { struct D {} } extension Mod1.NS { struct A { struct B {} } }")).types expect(types.map(\.globalName).sorted()).to(equal(["Mod1.NS", "Mod1.NS.A", "Mod1.NS.A.B", "Mod1.NS.A.B.D"])) } it("resolves extension of type with global parent name in same module") { let types = parseModules(("Mod1", "enum NS {}; extension Mod1.NS { struct A {} }; extension Mod1.NS.A { struct B {} }; extension Mod1.NS.A.B { struct C {} }")).types expect(types.map(\.globalName).sorted()).to(equal(["Mod1.NS", "Mod1.NS.A", "Mod1.NS.A.B", "Mod1.NS.A.B.C"])) } it("resolves extensions of nested types properly") { let code = """ struct Root { struct ViewState {} } extension Root.ViewState { struct Item: AutoInitializable { } } extension Root.ViewState.Item { struct ChildItem {} } """ let types = parseModules( ("Mod1", code) ).types expect(types.map { $0.globalName }).to(equal([ "Mod1.Root", "Mod1.Root.ViewState", "Mod1.Root.ViewState.Item", "Mod1.Root.ViewState.Item.ChildItem" ])) } } context("given protocols of the same name in different modules") { func parseModules(_ modules: (name: String?, contents: String)...) -> [Type] { let moduleResults = modules.compactMap { try? makeParser(for: $0.contents, module: $0.name).parse() } let parserResult = moduleResults.reduce(FileParserResult(path: nil, module: nil, types: [], functions: [], typealiases: [])) { acc, next in acc.typealiases += next.typealiases acc.types += next.types return acc } return Composer.uniqueTypesAndFunctions(parserResult).types.sorted { $0.globalName < $1.globalName } } it("resolves inherited properties") { let types = parseModules( ("A", "protocol Foo { var a: Int { get } }"), ("B", "protocol Foo { var b: Int { get } }"), ("C", "import A; import B; protocol Foo: A.Foo, B.Foo { var c: Int { get } }")) expect(types.last?.allVariables.map(\.name).sorted()).to(equal(["a", "b", "c"])) } it("resolves types properly") { let types = parseModules( ("Mod1", "protocol Foo { func foo1() }"), ("Mod2", "protocol Foo { func foo2() }")) expect(types.first?.globalName).to(equal("Mod1.Foo")) expect(types.first?.allMethods.map { $0.name }).to(equal(["foo1()"])) expect(types.last?.globalName).to(equal("Mod2.Foo")) expect(types.last?.allMethods.map { $0.name }).to(equal(["foo2()"])) } it("resolves inheritance properly with global type name") { let types = parseModules( ("Mod1", "protocol Foo { func foo1() }"), ("Mod2", "protocol Foo { func foo2() }"), ("Mod3", "import Mod1; import Mod2; protocol Bar: Mod1.Foo { func bar() }")) let bar = types.first { $0.name == "Bar" } expect(bar?.allMethods.map { $0.name }.sorted()).to(equal(["bar()", "foo1()"])) } it("resolves inheritance properly with local type name") { let types = parseModules( ("Mod1", "protocol Foo { func foo1() }"), ("Mod2", "protocol Foo { func foo2() }"), ("Mod3", "import Mod1; protocol Bar: Foo { func bar() }")) let bar = types.first { $0.name == "Bar"} expect(bar?.allMethods.map { $0.name }.sorted()).to(equal(["bar()", "foo1()"])) } } } } } } ================================================ FILE: SourceryTests/Parsing/FileParserSpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class FileParserSpec: QuickSpec { // swiftlint:disable function_body_length override func spec() { describe("Parser") { describe("parse") { func parse(_ code: String, parseDocumentation: Bool = false) -> [Type] { guard let parserResult = try? makeParser(for: code, parseDocumentation: parseDocumentation).parse() else { fail(); return [] } return parserResult.types } describe("regression files") { it("doesnt crash on localized strings") { let templatePath = Stubs.errorsDirectory + Path("localized-error.swift") guard let content = try? templatePath.read(.utf8) else { return fail() } _ = parse(content) } } context("given it has sourcery annotations") { it("extract annotations from extensions properly") { let result = parse( """ // sourcery: forceMockPublisher public extension AnyPublisher {} """ ) let annotations: [String: NSObject] = [ "forceMockPublisher": NSNumber(value: true) ] expect(result.first?.annotations).to(equal( annotations )) } it("extracts annotation block") { let annotations = [ ["skipEquality": NSNumber(value: true)], ["skipEquality": NSNumber(value: true), "extraAnnotation": NSNumber(value: Float(2))], [:] ] let expectedVariables = (1...3) .map { Variable(name: "property\($0)", typeName: TypeName(name: "Int"), annotations: annotations[$0 - 1], definedInTypeName: TypeName(name: "Foo")) } let expectedType = Class(name: "Foo", variables: expectedVariables, annotations: ["skipEquality": NSNumber(value: true)]) let result = parse(""" // sourcery:begin: skipEquality class Foo { var property1: Int // sourcery: extraAnnotation = 2 var property2: Int // sourcery:end var property3: Int } """) expect(result).to(equal([expectedType])) } it("extracts file annotation block") { let annotations: [[String: NSObject]] = [ ["fileAnnotation": NSNumber(value: true), "skipEquality": NSNumber(value: true)], ["fileAnnotation": NSNumber(value: true), "skipEquality": NSNumber(value: true), "extraAnnotation": NSNumber(value: Float(2))], ["fileAnnotation": NSNumber(value: true)] ] let expectedVariables = (1...3) .map { Variable(name: "property\($0)", typeName: TypeName(name: "Int"), annotations: annotations[$0 - 1], definedInTypeName: TypeName(name: "Foo")) } let expectedType = Class(name: "Foo", variables: expectedVariables, annotations: ["fileAnnotation": NSNumber(value: true), "skipEquality": NSNumber(value: true)]) let result = parse("// sourcery:file: fileAnnotation\n" + "// sourcery:begin: skipEquality\n\n\n\n" + "class Foo {\n" + " var property1: Int\n\n\n" + " // sourcery: extraAnnotation = 2\n" + " var property2: Int\n\n" + " // sourcery:end\n" + " var property3: Int\n" + "}") expect(result.first).to(equal(expectedType)) } it("extracts annotations which not affect consequently declared properties") { let annotations: [[String: NSObject]] = [ ["extraAnnotation": NSNumber(value: Float(2))], [:], [:] ] let attributes: [AttributeList] = [ ["objc": [Attribute(name: "objc")]], ["objc": [Attribute(name: "objc")]], [:] ] let expectedVariables = (1...3) .map { Variable(name: "property\($0)", typeName: TypeName (name: "Int"), attributes: attributes[$0 - 1], annotations: annotations[$0 - 1], definedInTypeName: TypeName (name: "Foo" )) } let expectedType = Class(name: "Foo", variables: expectedVariables, annotations: [:]) let result = parse( """ class Foo {\n // sourcery: extraAnnotation = 2 @objc var property1: Int @objc var property2: Int var property3: Int } """ ) expect(result.first).to(equal(expectedType)) } it("extracts annotations and attributes which not affect consequently declared properties") { let annotations: [[String: NSObject]] = [ ["extraAnnotation": NSNumber(value: Float(2))], [:], [:], [:], [:] ] let attributes: [AttributeList] = [ ["objc": [Attribute(name: "objc")]], ["objc": [Attribute(name: "objc")]], ["MyAttribute": [Attribute(name: "MyAttribute")]], ["MyAttribute2": [Attribute(name: "MyAttribute2", arguments: ["0": "Hello" as NSString], description: "@MyAttribute2(Hello there)")]], [:] ] let expectedVariables = (1...5) .map { Variable( name: "property\($0)", typeName: TypeName (name: "Int"), attributes: attributes[$0 - 1], annotations: annotations[$0 - 1], definedInTypeName: TypeName (name: "Foo" ) ) } let expectedType = Class(name: "Foo", variables: expectedVariables, annotations: [:]) let result = parse( """ class Foo {\n // sourcery: extraAnnotation = 2 @objc var property1: Int @objc var property2: Int @MyAttribute var property3: Int @MyAttribute2(Hello there) var property4: Int var property5: Int } """ ) expect(result.first).to(equal(expectedType)) } it("extracts annotations when declaration has an attribute on the preceding line") { let annotations = ["Annotation": NSNumber(value: true)] let expectedClass = Class(name: "SomeClass", variables: [], attributes: ["MainActor": [Attribute(name: "MainActor")]], annotations: annotations) let result = parse(""" //sourcery: Annotation @MainActor class SomeClass { } """) expect(result.first).to(equal(expectedClass)) } it("extracts annotations when declaration has a directive on the preceding line") { let annotations = ["Annotation": NSNumber(value: true)] let result = parse(""" //sourcery: Annotation #warning("some warning") class SomeClass { } """) expect(result.first?.annotations).to(equal(annotations)) } it("extracts annotations when declaration has a directive and an attribute on the preceding line") { let annotations = ["Annotation": NSNumber(value: true)] let result = parse(""" //sourcery: Annotation #warning("some warning") @MainActor class SomeClass { } """) expect(result.first?.annotations).to(equal(annotations)) } } context("given struct") { it("extracts properly") { expect(parse("struct Foo { }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: []) ])) } it("extracts import correctly") { let expectedStruct = Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: []) expectedStruct.imports = [ Import(path: "SimpleModule"), Import(path: "SpecificModule.ClassName") ] expect(parse(""" import SimpleModule import SpecificModule.ClassName struct Foo {} """).first) .to(equal(expectedStruct)) } it("extracts properly with access information") { expect(parse("public struct Foo { }")) .to(equal([ Struct(name: "Foo", accessLevel: .public, isExtension: false, variables: [], modifiers: [Modifier(name: "public")]) ])) } it("extracts properly with access information for extended types via extension") { let foo = Struct(name: "Foo", accessLevel: .public, isExtension: false, variables: [], modifiers: [Modifier(name: "public")]) expect(parse( """ public struct Foo { } public extension Foo { struct Boo {} } """ ).last) .to(equal( Struct(name: "Boo", parent: foo, accessLevel: .public, isExtension: false, variables: [], modifiers: []) )) } it("extracts generic struct properly") { expect(parse("struct Foo { }")) .to(equal([ Struct(name: "Foo", isGeneric: true) ])) } it("extracts instance variables properly") { expect(parse("struct Foo { var x: Int }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [Variable(name: "x", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: false, definedInTypeName: TypeName(name: "Foo"))]) ])) } it("extracts instance variables with custom accessors properly") { expect(parse("struct Foo { public private(set) var x: Int }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [ Variable( name: "x", typeName: TypeName(name: "Int"), accessLevel: (read: .public, write: .private), isComputed: false, modifiers: [ Modifier(name: "public"), Modifier(name: "private", detail: "set") ], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts multi-line instance variables definitions properly") { let defaultValue = """ [ "This isn't the simplest to parse", // Especially with interleaved comments "but we can deal with it", // pretty well "or so we hope" ] """ expect(parse( """ struct Foo { var complicatedArray = \(defaultValue) } """ )) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [ Variable( name: "complicatedArray", typeName: TypeName( name: "[String]", array: ArrayType(name: "[String]", elementTypeName: TypeName(name: "String") ), generic: GenericType(name: "Array", typeParameters: [.init(typeName: TypeName(name: "String"))]) ), accessLevel: (read: .internal, write: .internal), isComputed: false, defaultValue: defaultValue, definedInTypeName: TypeName(name: "Foo") )]) ])) } it("extracts instance variables with property setters properly") { expect(parse( """ struct Foo { var array = [Int]() { willSet { print("new value \\(newValue)") } } } """ )) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [ Variable( name: "array", typeName: TypeName( name: "[Int]", array: ArrayType(name: "[Int]", elementTypeName: TypeName(name: "Int") ), generic: GenericType(name: "Array", typeParameters: [.init(typeName: TypeName(name: "Int"))]) ), accessLevel: (read: .internal, write: .internal), isComputed: false, defaultValue: "[Int]()", definedInTypeName: TypeName(name: "Foo") )]) ])) } it("extracts computed variables properly") { expect(parse("struct Foo { var x: Int { return 2 } }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [ Variable(name: "x", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, isStatic: false, definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts class variables properly") { expect(parse("struct Foo { static var x: Int { return 2 }; class var y: Int = 0 }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [ Variable(name: "x", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, isStatic: true, modifiers: [ Modifier(name: "static") ], definedInTypeName: TypeName(name: "Foo")), Variable(name: "y", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: false, isStatic: true, defaultValue: "0", modifiers: [ Modifier(name: "class") ], definedInTypeName: TypeName(name: "Foo")) ]) ])) } context("given nested struct") { it("extracts properly from body") { let innerType = Struct(name: "Bar", accessLevel: .internal, isExtension: false, variables: []) expect(parse("struct Foo { struct Bar { } }")) .to(equal([ Struct(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], containedTypes: [innerType]), innerType ])) } } } context("given class") { it("extracts variables properly") { expect(parse("class Foo { var x: Int }")) .to(equal([ Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [Variable(name: "x", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: false, definedInTypeName: TypeName(name: "Foo"))]) ])) } it("extracts inherited types properly") { expect(parse("class Foo: TestProtocol, AnotherProtocol {}").first(where: { $0.name == "Foo" })) .to(equal( Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol", "AnotherProtocol"]) )) } it("extracts annotations correctly") { let expectedType = Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol"]) expectedType.annotations["firstLine"] = NSNumber(value: true) expectedType.annotations["thirdLine"] = NSNumber(value: 4543) expect(parse("// sourcery: thirdLine = 4543\n/// comment\n// sourcery: firstLine\nclass Foo: TestProtocol { }")) .to(equal([expectedType])) } it("extracts documentation correctly") { let expectedType = Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol"]) expectedType.annotations["thirdLine"] = NSNumber(value: 4543) expectedType.documentation = ["doc", "comment", "baz"] expect(parse("/// doc\n// sourcery: thirdLine = 4543\n/// comment\n// firstLine\n///baz\nclass Foo: TestProtocol { }", parseDocumentation: true)) .to(equal([expectedType])) } it("extracts documentation correctly if there is a directive on preceeding line") { let expectedType = Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol"]) expectedType.annotations["thirdLine"] = NSNumber(value: 4543) expectedType.documentation = ["doc", "comment", "baz"] expect(parse(""" /// doc // sourcery: thirdLine = 4543 /// comment // firstLine ///baz #warning("a warning") class Foo: TestProtocol { } """, parseDocumentation: true)) .to(equal([expectedType])) } it("extracts documentation correctly if there is a directive and an attribute on preceeding line") { let expectedType = Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol"], attributes: ["MainActor": [Attribute(name: "MainActor")]]) expectedType.annotations["thirdLine"] = NSNumber(value: 4543) expectedType.documentation = ["doc", "comment", "baz"] expect(parse(""" /// doc // sourcery: thirdLine = 4543 /// comment // firstLine ///baz #warning("a warning") @MainActor class Foo: TestProtocol { } """, parseDocumentation: true)) .to(equal([expectedType])) } it("extracts documentation correctly if there is a directive and an attribute on preceeding line") { let expectedType = Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol"], attributes: ["MainActor": [Attribute(name: "MainActor")]]) expectedType.annotations["thirdLine"] = NSNumber(value: 4543) expectedType.documentation = ["doc", "comment", "baz"] expect(parse(""" /// doc // sourcery: thirdLine = 4543 /// comment // firstLine ///baz #warning("a warning") @MainActor class Foo: TestProtocol { } """, parseDocumentation: true)) .to(equal([expectedType])) } it("extracts documentation correctly if there is a directive and multiline comments") { let expectedType = Class(name: "Foo", accessLevel: .internal, isExtension: false, variables: [], inheritedTypes: ["TestProtocol"], attributes: ["MainActor": [Attribute(name: "MainActor")]]) expectedType.annotations["thirdLine"] = NSNumber(value: 4543) expectedType.documentation = ["doc", "This is a documentation comment", "This is another documentation comment", "This is another another documentation comment", "This is yet another documentation comment"] let parsedType = parse(""" /// doc // sourcery: thirdLine = 4543 /* This is not a documentation comment */ /** This is a documentation comment */ /** This is another documentation comment */ /** This is another another documentation comment */ /** This is yet another documentation comment */ #warning("a warning") @MainActor class Foo: TestProtocol { } """, parseDocumentation: true) expect(parsedType) .to(equal([expectedType])) } } context("given typealias") { func parse(_ code: String) -> FileParserResult { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return FileParserResult(path: nil, module: nil, types: [], functions: [], typealiases: []) } return parserResult } context("given global typealias") { it("extracts global typealiases properly") { expect(parse("typealias GlobalAlias = Foo; class Foo { typealias FooAlias = Int; class Bar { typealias BarAlias = Int } }").typealiases) .to(equal([ Typealias(aliasName: "GlobalAlias", typeName: TypeName(name: "Foo")) ])) } it("extracts typealiases for inner types") { expect(parse("typealias GlobalAlias = Foo.Bar;").typealiases) .to(equal([ Typealias(aliasName: "GlobalAlias", typeName: TypeName(name: "Foo.Bar")) ])) } it("extracts typealiases of other typealiases") { expect(parse("typealias Foo = Int; typealias Bar = Foo").typealiases) .to(contain([ Typealias(aliasName: "Foo", typeName: TypeName(name: "Int")), Typealias(aliasName: "Bar", typeName: TypeName(name: "Foo")) ])) } it("extracts typealias for tuple") { let typealiase = parse("typealias GlobalAlias = (Foo, Bar)").typealiases.first expect(typealiase) .to(equal( Typealias(aliasName: "GlobalAlias", typeName: TypeName(name: "(Foo, Bar)", tuple: TupleType(name: "(Foo, Bar)", elements: [.init(name: "0", typeName: .init("Foo")), .init(name: "1", typeName: .init("Bar"))])) ) )) } it("extracts typealias for closure") { expect(parse("typealias GlobalAlias = (Int) -> (String)").typealiases) .to(equal([ Typealias(aliasName: "GlobalAlias", typeName: TypeName(name: "(Int) -> String", closure: ClosureType(name: "(Int) -> String", parameters: [.init(typeName: TypeName(name: "Int"))], returnTypeName: TypeName(name: "String")))) ])) } it("extracts typealias for void closure") { let parsed = parse("typealias GlobalAlias = () -> ()").typealiases.first let expected = Typealias(aliasName: "GlobalAlias", typeName: TypeName(name: "() -> ()", closure: ClosureType(name: "() -> ()", parameters: [], returnTypeName: TypeName(name: "()")))) expect(parsed).to(equal(expected)) } it("extracts private typealias") { expect(parse("private typealias GlobalAlias = () -> ()").typealiases) .to(equal([ Typealias(aliasName: "GlobalAlias", typeName: TypeName(name: "() -> ()", closure: ClosureType(name: "() -> ()", parameters: [], returnTypeName: TypeName(name: "()"))), accessLevel: .private) ])) } } context("given local typealias") { it("extracts local typealiases properly") { let foo = Type(name: "Foo") let bar = Type(name: "Bar", parent: foo) let fooBar = Type(name: "FooBar", parent: bar) let types = parse("class Foo { typealias FooAlias = String; struct Bar { typealias BarAlias = Int; struct FooBar { typealias FooBarAlias = Float } } }").types let fooAliases = types.first?.typealiases let barAliases = types.first?.containedTypes.first?.typealiases let fooBarAliases = types.first?.containedTypes.first?.containedTypes.first?.typealiases expect(fooAliases).to(equal(["FooAlias": Typealias(aliasName: "FooAlias", typeName: TypeName(name: "String"), parent: foo)])) expect(barAliases).to(equal(["BarAlias": Typealias(aliasName: "BarAlias", typeName: TypeName(name: "Int"), parent: bar)])) expect(fooBarAliases).to(equal(["FooBarAlias": Typealias(aliasName: "FooBarAlias", typeName: TypeName(name: "Float"), parent: fooBar)])) } } } context("given a protocol composition") { context("when used as typeName") { it("is extracted correctly as return type") { let expectedFoo = Method(name: "foo()", selectorName: "foo", returnTypeName: TypeName(name: "ProtocolA & ProtocolB", isProtocolComposition: true), definedInTypeName: TypeName(name: "Foo")) expectedFoo.returnType = ProtocolComposition(name: "ProtocolA & Protocol B") let expectedFooOptional = Method(name: "fooOptional()", selectorName: "fooOptional", returnTypeName: TypeName(name: "(ProtocolA & ProtocolB)", isOptional: true, isProtocolComposition: true), definedInTypeName: TypeName(name: "Foo")) expectedFooOptional.returnType = ProtocolComposition(name: "ProtocolA & Protocol B") let methods = parse(""" protocol Foo { func foo() -> ProtocolA & ProtocolB func fooOptional() -> (ProtocolA & ProtocolB)? } """)[0].methods expect(methods[0]).to(equal(expectedFoo)) expect(methods[1]).to(equal(expectedFooOptional)) } } context("of two protocols") { it("extracts protocol composition for typealias with ampersand") { expect(parse("typealias Composition = Foo & Bar; protocol Foo {}; protocol Bar {}")) .to(contain([ ProtocolComposition(name: "Composition", inheritedTypes: ["Foo", "Bar"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar")]) ])) expect(parse("private typealias Composition = Foo & Bar; protocol Foo {}; protocol Bar {}")) .to(contain([ ProtocolComposition(name: "Composition", accessLevel: .private, inheritedTypes: ["Foo", "Bar"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar")]) ])) } } context("of three protocols") { it("extracts protocol composition for typealias with ampersand") { expect(parse("typealias Composition = Foo & Bar & Baz; protocol Foo {}; protocol Bar {}; protocol Baz {}")) .to(contain([ ProtocolComposition(name: "Composition", inheritedTypes: ["Foo", "Bar", "Baz"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar"), TypeName(name: "Baz")]) ])) } it("extracts protocol composition for typealias with ampersand") { expect(parse("typealias Composition = Foo & Bar & Baz; protocol Foo {}; protocol Bar {}; protocol Baz {}")) .to(contain([ ProtocolComposition(name: "Composition", inheritedTypes: ["Foo", "Bar", "Baz"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar"), TypeName(name: "Baz")]) ])) } } context("of a protocol and a class") { it("extracts protocol composition for typealias with ampersand") { expect(parse("typealias Composition = Foo & Bar; protocol Foo {}; class Bar {}")) .to(contain([ ProtocolComposition(name: "Composition", inheritedTypes: ["Foo", "Bar"], composedTypeNames: [TypeName(name: "Foo"), TypeName(name: "Bar")]) ])) } } context("given local protocol composition") { it("extracts local protocol compositions properly") { let foo = Type(name: "Foo") let bar = Type(name: "Bar", parent: foo) let types = parse("protocol P {}; class Foo { typealias FooComposition = Bar & P; class Bar { typealias BarComposition = FooBar & P; class FooBar {} } }") let fooType = types.first(where: { $0.name == "Foo" }) let fooComposition = fooType?.containedTypes.first let barComposition = fooType?.containedTypes.last?.containedTypes.first expect(fooComposition).to(equal( ProtocolComposition(name: "FooComposition", parent: foo, inheritedTypes: ["Bar", "P"], composedTypeNames: [TypeName(name: "Bar"), TypeName(name: "P")]))) expect(barComposition).to(equal( ProtocolComposition(name: "BarComposition", parent: bar, inheritedTypes: ["FooBar", "P"], composedTypeNames: [TypeName(name: "FooBar"), TypeName(name: "P")]))) } } } context("given enum") { it("extracts empty enum properly") { expect(parse("enum Foo { }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: []) ])) } it("extracts cases properly") { expect(parse("enum Foo { case optionA; case optionB }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [EnumCase(name: "optionA"), EnumCase(name: "optionB")]) ])) } it("extracts cases with special names") { expect(parse(""" enum Foo { case `default` case `for`(something: Int, else: Float, `default`: Bool) } """)) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [ EnumCase(name: "`default`"), EnumCase(name: "`for`", associatedValues: [ AssociatedValue(name: "something", typeName: TypeName(name: "Int")), AssociatedValue(name: "else", typeName: TypeName(name: "Float")), AssociatedValue(name: "`default`", typeName: TypeName(name: "Bool")) ])]) ])) } it("extracts multi-byte cases properly") { expect(parse("enum JapaneseEnum {\ncase アイウエオ\n}")) .to(equal([ Enum(name: "JapaneseEnum", cases: [EnumCase(name: "アイウエオ")]) ])) } context("given enum cases annotations") { it("extracts cases with annotations properly") { let parsedTypes = parse(""" enum Foo { // sourcery:begin: block // sourcery: first, second=\"value\" case optionA(/* sourcery: first, third = \"value\" */Int) // sourcery: fourth case optionB case optionC // sourcery:end } """) let expectedTypes = [ Enum(name: "Foo", cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(name: nil, typeName: TypeName(name: "Int"), annotations: [ "first": NSNumber(value: true), "third": "value" as NSString, "block": NSNumber(value: true) ]) ], annotations: [ "block": NSNumber(value: true), "first": NSNumber(value: true), "second": "value" as NSString ] ), EnumCase(name: "optionB", annotations: [ "block": NSNumber(value: true), "fourth": NSNumber(value: true) ] ), EnumCase(name: "optionC", annotations: [ "block": NSNumber(value: true) ]) ]) ] expect((parsedTypes.first! as! Enum).cases[0].annotations).to(equal((expectedTypes.first!).cases[0].annotations)) expect((parsedTypes.first! as! Enum).cases[1].annotations).to(equal((expectedTypes.first!).cases[1].annotations)) expect((parsedTypes.first! as! Enum).cases[2].annotations).to(equal((expectedTypes.first!).cases[2].annotations)) expect(parsedTypes) .to(equal(expectedTypes)) } it("extracts cases with inline annotations properly") { expect(parse(""" enum Foo { //sourcery:begin: block /* sourcery: first, second = \"value\" */ case optionA(/* sourcery: first, second = \"value\" */Int); /* sourcery: third */ case optionB case optionC //sourcery:end } """).first) .to(equal( Enum(name: "Foo", cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(name: nil, typeName: TypeName(name: "Int"), annotations: [ "first": NSNumber(value: true), "second": "value" as NSString, "block": NSNumber(value: true) ]) ], annotations: [ "block": NSNumber(value: true), "first": NSNumber(value: true), "second": "value" as NSString ]), EnumCase(name: "optionB", annotations: [ "block": NSNumber(value: true), "third": NSNumber(value: true) ]), EnumCase(name: "optionC", annotations: [ "block": NSNumber(value: true) ]) ]) )) } it("extracts one line cases with inline annotations properly") { expect(parse(""" enum Foo { //sourcery:begin: block case /* sourcery: first, second = \"value\" */ optionA(Int), /* sourcery: third, fourth = \"value\" */ optionB, optionC //sourcery:end } """).first) .to(equal( Enum(name: "Foo", cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(name: nil, typeName: TypeName(name: "Int"), annotations: [ "block": NSNumber(value: true) ]) ], annotations: [ "block": NSNumber(value: true), "first": NSNumber(value: true), "second": "value" as NSString ]), EnumCase(name: "optionB", annotations: [ "block": NSNumber(value: true), "third": NSNumber(value: true), "fourth": "value" as NSString ]), EnumCase(name: "optionC", annotations: [ "block": NSNumber(value: true) ]) ]) )) } it("extracts cases with annotations and computed variables properly") { expect(parse(""" enum Foo { // sourcery: var var first: Int { return 0 } // sourcery: first, second=\"value\" case optionA(Int) // sourcery: var var second: Int { return 0 } // sourcery: third case optionB case optionC } """).first) .to(equal( Enum(name: "Foo", cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(name: nil, typeName: TypeName(name: "Int")) ], annotations: [ "first": NSNumber(value: true), "second": "value" as NSString ]), EnumCase(name: "optionB", annotations: [ "third": NSNumber(value: true) ]), EnumCase(name: "optionC") ], variables: [ Variable(name: "first", typeName: TypeName(name: "Int"), accessLevel: (.internal, .none), isComputed: true, annotations: [ "var": NSNumber(value: true) ], definedInTypeName: TypeName(name: "Foo")), Variable(name: "second", typeName: TypeName(name: "Int"), accessLevel: (.internal, .none), isComputed: true, annotations: [ "var": NSNumber(value: true) ], definedInTypeName: TypeName(name: "Foo")) ]) )) } } it("extracts associated value annotations properly") { let result = parse(""" enum Foo { case optionA( // sourcery: first // sourcery: second, third = "value" Int) case optionB } """) expect(result) .to(equal([ Enum(name: "Foo", cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(name: nil, typeName: TypeName(name: "Int"), annotations: ["first": NSNumber(value: true), "second": NSNumber(value: true), "third": "value" as NSString]) ]), EnumCase(name: "optionB") ]) ])) } it("extracts associated value inline annotations properly") { let result = parse("enum Foo {\n case optionA(/* sourcery: annotation*/Int)\n case optionB }") expect(result) .to(equal([ Enum(name: "Foo", cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(name: nil, typeName: TypeName(name: "Int"), annotations: ["annotation": NSNumber(value: true)]) ]), EnumCase(name: "optionB") ]) ])) } it("extracts variables properly") { expect(parse("enum Foo { var x: Int { return 1 } }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [], variables: [Variable(name: "x", typeName: TypeName(name: "Int"), accessLevel: (.internal, .none), isComputed: true, definedInTypeName: TypeName(name: "Foo"))]) ])) } context("given enum without rawType") { it("extracts inherited types properly") { expect(parse("enum Foo: SomeProtocol { case optionA }; protocol SomeProtocol {}")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["SomeProtocol"], rawTypeName: nil, cases: [EnumCase(name: "optionA")]), Protocol(name: "SomeProtocol") ])) } } it("extracts enums with custom values") { expect(parse(""" enum Foo: String { case optionA = "Value" } """)) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["String"], cases: [EnumCase(name: "optionA", rawValue: "Value")]) ])) expect(parse(""" enum Foo: Int { case optionA = 2 } """)) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["Int"], cases: [EnumCase(name: "optionA", rawValue: "2")]) ])) expect(parse(""" enum Foo: Int { case optionA = -1 case optionB = 0 } """)) .to(equal([ Enum( name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["Int"], cases: [ EnumCase(name: "optionA", rawValue: "-1"), EnumCase(name: "optionB", rawValue: "0") ]) ])) expect(parse(""" enum Foo: Int { case optionA = 2 // comment } """)) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: ["Int"], cases: [EnumCase(name: "optionA", rawValue: "2")]) ])) } it("extracts enums without rawType") { let expectedEnum = Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [EnumCase(name: "optionA")]) expect(parse("enum Foo { case optionA }")).to(equal([expectedEnum])) } it("extracts enums with associated types") { expect(parse("enum Foo { case optionA(Observable); case optionB(Int, named: Float, _: Int); case optionC(dict: [String: String]) }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(localName: nil, externalName: nil, typeName: TypeName(name: "Observable", generic: GenericType( name: "Observable", typeParameters: [ GenericTypeParameter(typeName: TypeName(name: "Int")), GenericTypeParameter(typeName: TypeName(name: "Int")) ]))) ]), EnumCase(name: "optionB", associatedValues: [ AssociatedValue(localName: nil, externalName: "0", typeName: TypeName(name: "Int")), AssociatedValue(localName: "named", externalName: "named", typeName: TypeName(name: "Float")), AssociatedValue(localName: nil, externalName: "2", typeName: TypeName(name: "Int")) ]), EnumCase(name: "optionC", associatedValues: [ AssociatedValue(localName: "dict", externalName: nil, typeName: TypeName(name: "[String: String]", dictionary: DictionaryType(name: "[String: String]", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "String")), generic: GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String")), GenericTypeParameter(typeName: TypeName(name: "String"))]))) ]) ]) ])) } it("parses enums with multibyte cases with associated types") { let expectedEnum = Enum(name: "Foo", cases: [ EnumCase(name: "こんにちは", associatedValues: [ AssociatedValue(localName: nil, externalName: nil, typeName: TypeName(name: "Int")) ]) ]) expect(parse("enum Foo { case こんにちは(Int) }")).to(equal([expectedEnum])) } it("extracts enums with indirect cases") { expect(parse("enum Foo { case optionA; case optionB; indirect case optionC(Foo) }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [ EnumCase(name: "optionA", indirect: false), EnumCase(name: "optionB"), EnumCase(name: "optionC", associatedValues: [AssociatedValue(typeName: TypeName(name: "Foo"))], indirect: true) ]) ])) expect(parse(""" enum Foo { /// Option A case optionA /// Option B case optionB /// Option C indirect case optionC(Foo) } """, parseDocumentation: true)) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [ EnumCase(name: "optionA", documentation: ["Option A"], indirect: false), EnumCase(name: "optionB", documentation: ["Option B"]), EnumCase(name: "optionC", associatedValues: [AssociatedValue(typeName: TypeName(name: "Foo"))], documentation: ["Option C"], indirect: true) ]) ])) } it("extracts enums with Void associated type") { expect(parse("enum Foo { case optionA(Void); case optionB(Void) }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [ EnumCase(name: "optionA", associatedValues: [AssociatedValue(typeName: TypeName(name: "Void"))]), EnumCase(name: "optionB", associatedValues: [AssociatedValue(typeName: TypeName(name: "Void"))]) ]) ])) } it("extracts default values for associated values") { expect(parse("enum Foo { case optionA(Int = 1, named: Float = 42.0, _: Bool = false); case optionB(Bool = true) }")) .to(equal([ Enum(name: "Foo", accessLevel: .internal, isExtension: false, inheritedTypes: [], cases: [ EnumCase(name: "optionA", associatedValues: [ AssociatedValue(localName: nil, externalName: "0", typeName: TypeName(name: "Int"), defaultValue: "1"), AssociatedValue(localName: "named", externalName: "named", typeName: TypeName(name: "Float"), defaultValue: "42.0"), AssociatedValue(localName: nil, externalName: "2", typeName: TypeName(name: "Bool"), defaultValue: "false") ]), EnumCase(name: "optionB", associatedValues: [ AssociatedValue(localName: nil, externalName: nil, typeName: TypeName(name: "Bool"), defaultValue: "true") ]) ]) ])) } } context("given protocol") { it("extracts generic requirements properly") { expect(parse( """ protocol SomeGenericProtocol: GenericProtocol {} """ ).first).to(equal( Protocol(name: "SomeGenericProtocol", inheritedTypes: ["GenericProtocol"]) )) expect(parse( """ protocol SomeGenericProtocol: GenericProtocol where LeftType == RightType {} """ ).first).to(equal( Protocol( name: "SomeGenericProtocol", inheritedTypes: ["GenericProtocol"], genericRequirements: [ GenericRequirement(leftType: .init(name: "LeftType"), rightType: .init(typeName: .init("RightType")), relationship: .equals) ]) )) expect(parse( """ protocol SomeGenericProtocol: GenericProtocol where LeftType: RightType {} """ ).first).to(equal( Protocol( name: "SomeGenericProtocol", inheritedTypes: ["GenericProtocol"], genericRequirements: [ GenericRequirement(leftType: .init(name: "LeftType"), rightType: .init(typeName: .init("RightType")), relationship: .conformsTo) ]) )) expect(parse( """ protocol SomeGenericProtocol: GenericProtocol where LeftType == RightType, LeftType2: RightType2 {} """ ).first).to(equal( Protocol( name: "SomeGenericProtocol", inheritedTypes: ["GenericProtocol"], genericRequirements: [ GenericRequirement(leftType: .init(name: "LeftType"), rightType: .init(typeName: .init("RightType")), relationship: .equals), GenericRequirement(leftType: .init(name: "LeftType2"), rightType: .init(typeName: .init("RightType2")), relationship: .conformsTo) ]) )) } it("extracts empty protocol properly") { expect(parse("protocol Foo { }")) .to(equal([ Protocol(name: "Foo") ])) } it("does not consider protocol variables as computed") { expect(parse("protocol Foo { var some: Int { get } }")) .to(equal([ Protocol(name: "Foo", variables: [Variable(name: "some", typeName: TypeName(name: "Int"), accessLevel: (.internal, .none), isComputed: false, definedInTypeName: TypeName(name: "Foo"))]) ])) } it("does consider type variables as computed when they are, even if they adhere to protocol") { expect(parse("protocol Foo { var some: Int { get }\nvar some2: Int { get } }\nclass Bar: Foo { var some: Int { return 2 }\nvar some2: Int { get { return 2 } } }").first(where: { $0.name == "Bar" })) .to(equal( Class(name: "Bar", variables: [ Variable(name: "some", typeName: TypeName(name: "Int"), accessLevel: (.internal, .none), isComputed: true, definedInTypeName: TypeName(name: "Bar")), Variable(name: "some2", typeName: TypeName(name: "Int"), accessLevel: (.internal, .none), isComputed: true, definedInTypeName: TypeName(name: "Bar")) ], inheritedTypes: ["Foo"]) )) } it("does not consider type variables as computed when they aren't, even if they adhere to protocol and have didSet blocks") { expect(parse("protocol Foo { var some: Int { get } }\nclass Bar: Foo { var some: Int { didSet { } }").first(where: { $0.name == "Bar" })) .to(equal( Class(name: "Bar", variables: [Variable(name: "some", typeName: TypeName(name: "Int"), accessLevel: (.internal, .internal), isComputed: false, definedInTypeName: TypeName(name: "Bar"))], inheritedTypes: ["Foo"]) )) } it("sets members access level to protocol access level") { func assert(_ accessLevel: AccessLevel, line: UInt = #line) { expect(line: line, parse("\(accessLevel) protocol Foo { var some: Int { get }; func foo() -> Void }")) .to(equal([ Protocol(name: "Foo", accessLevel: accessLevel, variables: [Variable(name: "some", typeName: TypeName(name: "Int"), accessLevel: (accessLevel, .none), isComputed: false, definedInTypeName: TypeName(name: "Foo"))], methods: [Method(name: "foo()", selectorName: "foo", returnTypeName: TypeName(name: "Void"), throws: false, rethrows: false, accessLevel: accessLevel, definedInTypeName: TypeName(name: "Foo"))], modifiers: [Modifier(name: "\(accessLevel)")]) ])) } assert(.private) assert(.internal) assert(.private) } } } } } } ================================================ FILE: SourceryTests/Parsing/FileParser_AssociatedTypeSpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime final class FileParserAssociatedTypeSpec: QuickSpec { override func spec() { describe("Parser") { #if canImport(ObjectiveC) describe("parse associated type") { func associatedType(_ code: String, protocolName: String? = nil) -> [AssociatedType] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return parserResult.types .compactMap({ type in type as? SourceryProtocol }) .first(where: { protocolName != nil ? $0.name == protocolName : true })? .associatedTypes.values.map { $0 } ?? [] } context("given protocol") { context("with an associated type") { it("extracts associated type properly") { let code = """ protocol Foo { associatedtype Bar } """ expect(associatedType(code)).to(equal([AssociatedType(name: "Bar", typeName: TypeName(name: "Any"))])) } } context("with multiple associated types") { it("extracts associated types properly") { let code = """ protocol Foo { associatedtype Bar associatedtype Baz } """ expect(associatedType(code).sorted(by: { $0.name < $1.name })).to(equal([AssociatedType(name: "Bar", typeName: TypeName(name: "Any")), AssociatedType(name: "Baz", typeName: TypeName(name: "Any"))])) } } context("with associated type constrained to an unknown type") { it("extracts associated type properly") { let code = """ protocol Foo { associatedtype Bar: Codable } """ expect(associatedType(code)).to(equal([AssociatedType( name: "Bar", typeName: TypeName(name: "Codable") )])) } } context("with associated type constrained to a known type") { it("extracts associated type properly") { let code = """ protocol A {} protocol Foo { associatedtype Bar: A } """ expect(associatedType(code, protocolName: "Foo")).to(equal([AssociatedType( name: "Bar", typeName: TypeName(name: "A") )])) } } context("with associated type constrained to a composite type") { it("extracts associated type properly and creates a protocol composition") { let parsed = associatedType(""" protocol Foo { associatedtype Bar: Encodable & Decodable } """).first expect(parsed).to(equal(AssociatedType( name: "Bar", typeName: TypeName(name: "Encodable & Decodable") ))) expect(parsed?.type).to(equal(ProtocolComposition( parent: SourceryProtocol(name: "Foo"), inheritedTypes: ["Encodable", "Decodable"], composedTypeNames: [TypeName(name: "Encodable"), TypeName(name: "Decodable")] ))) } } } } #endif } } } ================================================ FILE: SourceryTests/Parsing/FileParser_AttributesModifierSpec.swift ================================================ import Quick import Nimble import XCTest #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif import SourceryFramework import SourceryRuntime class FileParserAttributesSpec: QuickSpec { override func spec() { describe("FileParser") { func parse(_ code: String) -> [Type] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return parserResult.types } it("extracts type attribute and modifiers") { expect(parse(""" /* docs */ @objc(WAGiveRecognitionCoordinator) // sourcery: AutoProtocol, AutoMockable class GiveRecognitionCoordinator: NSObject { } """).first?.attributes).to( equal(["objc": [Attribute(name: "objc", arguments: ["0": "WAGiveRecognitionCoordinator" as NSString], description: "@objc(WAGiveRecognitionCoordinator)")]]) ) expect(parse("class Foo { func some(param: @convention(swift) @escaping ()->()) {} }").first?.methods.first?.parameters.first?.typeAttributes).to(equal([ "escaping": [Attribute(name: "escaping")], "convention": [Attribute(name: "convention", arguments: ["0": "swift" as NSString], description: "@convention(swift)")] ])) expect(parse("final class Foo { }").first?.modifiers).to(equal([ Modifier(name: "final") ])) expect((parse("final class Foo { }").first as? Class)?.isFinal).to(beTrue()) expect(parse("@objc class Foo {}").first?.attributes).to(equal([ "objc": [Attribute(name: "objc", arguments: [:], description: "@objc")] ])) expect(parse("@objc(Bar) class Foo {}").first?.attributes).to(equal([ "objc": [Attribute(name: "objc", arguments: ["0": "Bar" as NSString], description: "@objc(Bar)")] ])) expect(parse("@objcMembers class Foo {}").first?.attributes).to(equal([ "objcMembers": [Attribute(name: "objcMembers", arguments: [:], description: "@objcMembers")] ])) expect(parse("public class Foo {}").first?.modifiers).to(equal([ Modifier(name: "public") ])) } context("given attribute with arguments") { it("extracts attribute arguments with values") { expect(parse(""" @available(*, unavailable, renamed: \"NewFoo\") protocol Foo {} """ ).first?.attributes) .to(equal([ "available": [Attribute(name: "available", arguments: [ "0": "*" as NSString, "1": "unavailable" as NSString, "renamed": "\"NewFoo\"" as NSString ], description: "@available(*, unavailable, renamed: \"NewFoo\")") ]])) expect(parse(""" @available(iOS 10.0, macOS 10.12, *) protocol Foo {} """ ).first?.attributes) .to(equal([ "available": [Attribute(name: "available", arguments: [ "0": "iOS 10.0" as NSString, "1": "macOS 10.12" as NSString, "2": "*" as NSString ], description: "@available(iOS 10.0, macOS 10.12, *)") ]])) } } it("extracts method attributes and modifiers") { expect(parse("class Foo { @discardableResult\n@objc(some)\nfunc some() {} }").first?.methods.first?.attributes).to(equal([ "discardableResult": [Attribute(name: "discardableResult")], "objc": [Attribute(name: "objc", arguments: ["0": "some" as NSString], description: "@objc(some)")] ])) expect(parse("class Foo { @nonobjc convenience required init() {} }").first?.initializers.first?.attributes).to(equal([ "nonobjc": [Attribute(name: "nonobjc")] ])) let initializer = parse("class Foo { @nonobjc convenience required init() {} }").first?.initializers.first expect(initializer?.modifiers).to(equal([ Modifier(name: "convenience"), Modifier(name: "required") ])) expect(initializer?.isConvenienceInitializer).to(beTrue()) expect(initializer?.isRequired).to(beTrue()) expect(parse("struct Foo { mutating func some() {} }").first?.methods.first?.modifiers).to(equal([ Modifier(name: "mutating") ])) expect(parse("struct Foo { mutating func some() {} }").first?.methods.first?.isMutating).to(beTrue()) expect(parse("class Foo { final func some() {} }").first?.methods.first?.modifiers).to(equal([ Modifier(name: "final") ])) expect(parse("class Foo { final func some() {} }").first?.methods.first?.isFinal).to(beTrue()) expect(parse("@objc protocol Foo { @objc optional func some() }").first?.methods.first?.modifiers).to(equal([ Modifier(name: "optional") ])) expect(parse("@objc protocol Foo { @objc optional func some() }").first?.methods.first?.isOptional).to(beTrue()) expect(parse("actor Foo { nonisolated func bar() {} }").first?.methods.first?.isNonisolated).to(beTrue()) expect(parse("actor Foo { func bar() {} }").first?.methods.first?.isNonisolated).to(beFalse()) expect(parse("actor Foo { distributed func bar() {} }").first?.methods.first?.isDistributed).to(beTrue()) expect((parse("distributed actor Foo { distributed func bar() {} }").first as? Actor)?.isDistributed).to(beTrue()) } it("extracts method parameter attributes") { expect(parse("class Foo { func some(param: @escaping ()->()) {} }").first?.methods.first?.parameters.first?.typeAttributes).to(equal([ "escaping": [Attribute(name: "escaping")] ])) } it("extracts variable attributes and modifiers") { expect(parse("class Foo { @NSCopying @objc(objcName) var name: NSString = \"\" }").first?.variables.first?.attributes).to(equal([ "NSCopying": [Attribute(name: "NSCopying", description: "@NSCopying")], "objc": [Attribute(name: "objc", arguments: ["0": "objcName" as NSString], description: "@objc(objcName)")] ])) expect(parse("struct Foo { mutating var some: Int }").first?.variables.first?.modifiers).to(equal([ Modifier(name: "mutating") ])) expect(parse("class Foo { final var some: Int }").first?.variables.first?.modifiers).to(equal([ Modifier(name: "final") ])) expect(parse("class Foo { final var some: Int }").first?.variables.first?.isFinal).to(beTrue()) expect(parse("class Foo { lazy var name: String = \"Hello\" }").first?.variables.first?.modifiers).to(equal([ Modifier(name: "lazy") ])) expect(parse("class Foo { lazy var name: String = \"Hello\" }").first?.variables.first?.isLazy).to(beTrue()) func assertSetterAccess(_ access: String, line: UInt = #line) { let variable = parse("public class Foo { \(access)(set) var some: Int }").first?.variables.first expect(line: line, variable?.modifiers).to(equal([ Modifier(name: access, detail: "set") ])) expect(variable?.writeAccess).to(equal(access)) } assertSetterAccess("private") assertSetterAccess("fileprivate") assertSetterAccess("internal") assertSetterAccess("public") assertSetterAccess("open") func assertGetterAccess(_ access: String, line: UInt = #line) { let variable = parse("public class Foo { \(access) var some: Int }").first?.variables.first expect(line: line, variable?.modifiers).to(equal([ Modifier(name: access) ])) expect(variable?.readAccess).to(equal(access)) } assertGetterAccess("private") assertGetterAccess("fileprivate") assertGetterAccess("internal") assertGetterAccess("public") assertGetterAccess("open") } it("extracts type attributes") { expect(parse("@nonobjc class Foo {}").first?.attributes).to(equal([ "nonobjc": [Attribute(name: "nonobjc")] ])) } context("parsing property wrapper") { it("extracts attributes") { expect(parse(""" class Foo { @UserDefaults(key: "user_name", 123) var name: String = "abc" } """).first?.variables.first?.attributes).to(equal([ "UserDefaults": [ Attribute( name: "UserDefaults", arguments: ["key": "\"user_name\"" as NSString, "1": "123" as NSString], description: "@UserDefaults(key: \"user_name\", 123)" ) ] ])) } it("extracts and parses attributes correctly") { let expectedArguments: [String: NSObject] = [ "path": "\"provisioning_features.is_enabled\"" as NSString, "remoteFeatureName": "\"provision_enabled\"" as NSString ] let arguments = parse( """ class Foo { @FeatureFlag(remoteFeatureName: "provision_enabled", path: "provisioning_features.is_enabled", description: nil) var variable: Bool } """ ).first?.variables.first?.attributes["FeatureFlag"]?.first?.arguments expect(arguments).toNot(beNil()) if let parsedArguments = arguments { for expected in expectedArguments { expect(parsedArguments[expected.key]).to(equal(expected.value)) } } } } } } } ================================================ FILE: SourceryTests/Parsing/FileParser_MethodsSpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif import SourceryFramework import SourceryRuntime class Bar {} class FileParserMethodsSpec: QuickSpec { // swiftlint:disable function_body_length override func spec() { describe("FileParser") { describe("parseMethod") { func parse(_ code: String) -> [Type] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return parserResult.types } func parseFunctions(_ code: String) -> [SourceryMethod] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return parserResult.functions } it("extracts methods with inout properties") { let methods = parse(""" class Foo { func fooInOut(some: Int, anotherSome: inout String) } """)[0].methods expect(methods[0]).to(equal(Method(name: "fooInOut(some: Int, anotherSome: inout String)", selectorName: "fooInOut(some:anotherSome:)", parameters: [ MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int")), MethodParameter(name: "anotherSome", index: 1, typeName: TypeName(name: "inout String"), isInout: true) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")))) } it("extracts methods with inout closure") { let method = parse( """ class Foo { func fooInOut(some: Int, anotherSome: (inout String) -> Void) } """ )[0].methods.first expect(method).to(equal(Method(name: "fooInOut(some: Int, anotherSome: (inout String) -> Void)", selectorName: "fooInOut(some:anotherSome:)", parameters: [ MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int")), MethodParameter(name: "anotherSome", index: 1, typeName: TypeName.buildClosure(ClosureParameter(typeName: TypeName.String, isInout: true), returnTypeName: .Void)) ], returnTypeName: .Void, definedInTypeName: TypeName(name: "Foo")))) } it("extracts methods with async closure") { let method = parse( """ class Foo { func fooAsync(some: Int, anotherSome: (String) async -> Void) } """ )[0].methods.first expect(method).to(equal(Method(name: "fooAsync(some: Int, anotherSome: (String) async -> Void)", selectorName: "fooAsync(some:anotherSome:)", parameters: [ MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int")), MethodParameter(name: "anotherSome", index: 1, typeName: TypeName(name: "(String) async -> Void", closure: ClosureType(name: "(String) async -> Void", parameters: [ClosureParameter(typeName: TypeName(name: "String"))], returnTypeName: .Void, asyncKeyword: "async"))) ], returnTypeName: .Void, definedInTypeName: TypeName(name: "Foo")))) } it("extracts methods with attributes") { let methods = parse(""" class Foo { @discardableResult func foo() -> Foo } """)[0].methods expect(methods[0]).to(equal(Method(name: "foo()", selectorName: "foo", returnTypeName: TypeName(name: "Foo"), attributes: ["discardableResult": [Attribute(name: "discardableResult")]], definedInTypeName: TypeName(name: "Foo")))) } it("extracts methods with escaping closure attribute correctly") { let methods = parse(""" protocol ClosureProtocol { func setClosure(_ closure: @escaping () -> Void) } """)[0].methods expect(methods[0]).to(equal( Method(name: "setClosure(_ closure: @escaping () -> Void)", selectorName: "setClosure(_:)", parameters: [ MethodParameter(argumentLabel: nil, name: "closure", index: 0, typeName: .buildClosure(TypeName(name: "Void"), attributes: ["escaping": [Attribute(name: "escaping")]]), type: nil, defaultValue: nil, annotations: [:], isInout: false) ], returnTypeName: TypeName(name: "Void"), attributes: [:], definedInTypeName: TypeName(name: "ClosureProtocol"))) ) } it("extracts protocol methods properly") { let methods = parse(""" protocol Foo { init() throws; func bar(some: Int) throws ->Bar @discardableResult func foo() -> Foo func fooBar() rethrows ; func fooVoid(); func fooAsync() async; func barAsync() async throws; func fooInOut(some: Int, anotherSome: inout String) func fooTypedThrows() throws(CustomError); func fooTypedThrowsAsync() async throws(CustomError) func rethrowing(block: () throws(E) -> Int) throws(E) -> Int where E: Error } """)[0].methods expect(methods[0]).to(equal(Method(name: "init()", selectorName: "init", parameters: [], returnTypeName: TypeName(name: "Foo"), throws: true, isStatic: true, definedInTypeName: TypeName(name: "Foo")))) expect(methods[1]).to(equal(Method(name: "bar(some: Int)", selectorName: "bar(some:)", parameters: [ MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "Bar"), throws: true, definedInTypeName: TypeName(name: "Foo")))) expect(methods[2]).to(equal(Method(name: "foo()", selectorName: "foo", returnTypeName: TypeName(name: "Foo"), attributes: ["discardableResult": [Attribute(name: "discardableResult")]], definedInTypeName: TypeName(name: "Foo")))) expect(methods[3]).to(equal(Method(name: "fooBar()", selectorName: "fooBar", returnTypeName: TypeName(name: "Void"), throws: false, rethrows: true, definedInTypeName: TypeName(name: "Foo")))) expect(methods[4]).to(equal(Method(name: "fooVoid()", selectorName: "fooVoid", returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")))) expect(methods[5]).to(equal(Method(name: "fooAsync()", selectorName: "fooAsync", returnTypeName: TypeName(name: "Void"), isAsync: true, definedInTypeName: TypeName(name: "Foo")))) expect(methods[6]).to(equal(Method(name: "barAsync()", selectorName: "barAsync", returnTypeName: TypeName(name: "Void"), isAsync: true, throws: true, definedInTypeName: TypeName(name: "Foo")))) expect(methods[7]).to(equal(Method(name: "fooInOut(some: Int, anotherSome: inout String)", selectorName: "fooInOut(some:anotherSome:)", parameters: [ MethodParameter(name: "some", index: 0, typeName: TypeName(name: "Int")), MethodParameter(name: "anotherSome", index: 1, typeName: TypeName(name: "inout String"), isInout: true) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")))) expect(methods[8]).to(equal(Method(name: "fooTypedThrows()", selectorName: "fooTypedThrows", returnTypeName: TypeName(name: "Void"), throws: true, throwsTypeName: TypeName(name: "CustomError"), rethrows: false, definedInTypeName: TypeName(name: "Foo")))) expect(methods[9]).to(equal(Method(name: "fooTypedThrowsAsync()", selectorName: "fooTypedThrowsAsync", returnTypeName: TypeName(name: "Void"), isAsync: true, throws: true, throwsTypeName: TypeName(name: "CustomError"), rethrows: false, definedInTypeName: TypeName(name: "Foo")))) expect(methods[9].isThrowsTypeGeneric).to(beFalse()) expect(methods[10]).to(equal(Method(name: "rethrowing(block: () throws(E) -> Int)", selectorName: "rethrowing(block:)", parameters: [ MethodParameter(name: "block", index: 0, typeName: TypeName(name: "() throws(E) -> Int", closure: ClosureType(name: "() throws(E) -> Int", parameters: [], returnTypeName: TypeName(name: "Int"), returnType: nil, asyncKeyword: nil, throwsOrRethrowsKeyword: "throws", throwsTypeName: TypeName(name: "E")))), ], returnTypeName: TypeName(name: "Int where E: Error"), isAsync: false, throws: true, throwsTypeName: TypeName(name: "E"), rethrows: false, definedInTypeName: TypeName(name: "Foo"), genericRequirements: [ GenericRequirement.init(leftType: AssociatedType(name: "E", typeName: nil, type: nil), rightType: GenericTypeParameter(typeName: TypeName("Error"), type: nil), relationship: .conformsTo) ], genericParameters: [ GenericParameter(name: "E", inheritedTypeName: TypeName("Error")) ]))) expect(methods[10].isThrowsTypeGeneric).to(beTrue()) } it("extracts class method properly") { expect(parse("class Foo { class func foo() {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo()", selectorName: "foo", parameters: [], isClass: true, modifiers: [Modifier(name: "class")], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts enum methods properly") { expect(parse("enum Baz { case a; func foo() {} }")).to(equal([ Enum(name: "Baz", cases: [ EnumCase(name: "a") ], methods: [ Method(name: "foo()", selectorName: "foo", parameters: [], definedInTypeName: TypeName(name: "Baz")) ]) ])) } it("extracts struct methods properly") { expect(parse("struct Baz { func foo() {} }")).to(equal([ Struct(name: "Baz", methods: [ Method(name: "foo()", selectorName: "foo", parameters: [], definedInTypeName: TypeName(name: "Baz")) ]) ])) } context("extracts distirbuted modifier") { it("as item in modifiers") { let method = parseFunctions("distributed func foo() {}") expect(method).to(equal([ Method(name: "foo()", selectorName: "foo", parameters: [], modifiers: [.init(name: "distributed")]) ])) } it("and reports isDistributed correctly") { let method = parseFunctions("distributed func foo() {}") expect(method.first?.isDistributed).to(beTrue()) } } it("extracts static method properly") { expect(parse("class Foo { static func foo() {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo()", selectorName: "foo", isStatic: true, modifiers: [Modifier(name: "static")], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts free functions properly") { expect(parseFunctions("func foo() {}")).to(equal([ Method(name: "foo()", selectorName: "foo", isStatic: false, definedInTypeName: nil) ])) } it("extracts free functions properly with private access") { expect(parseFunctions("private func foo() {}")).to(equal([ Method( name: "foo()", selectorName: "foo", accessLevel: (.private), isStatic: false, modifiers: [Modifier(name: "private")], definedInTypeName: nil) ])) } context("given method with parameters") { it("extracts method with single parameter properly") { expect(parse("class Foo { func foo(bar: Int) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(bar: Int)", selectorName: "foo(bar:)", parameters: [ MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "Int"))], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts method with variadic parameter properly") { expect(parse("class Foo { func foo(bar: Int...) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(bar: Int...)", selectorName: "foo(bar:)", parameters: [ MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "Int"), isVariadic: true)], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts method with single set parameter properly") { let type = parse("protocol Foo { func someMethod(aValue: Set) }").first expect(type).to(equal( Protocol(name: "Foo", methods: [ Method(name: "someMethod(aValue: Set)", selectorName: "someMethod(aValue:)", parameters: [ MethodParameter(name: "aValue", index: 0, typeName: .buildSet(of: .Int))], definedInTypeName: TypeName(name: "Foo")) ]) )) } it("extracts method with two parameters properly") { expect(parse("class Foo { func foo( bar: Int, foo : String ) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(bar: Int, foo: String)", selectorName: "foo(bar:foo:)", parameters: [ MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "Int")), MethodParameter(name: "foo", index: 1, typeName: TypeName(name: "String")) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts method with complex parameters properly") { expect(parse("class Foo { func foo( bar: [String: String], foo : ((String, String) -> Void), other: Optional) {} }")) .to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(bar: [String: String], foo: (String, String) -> Void, other: Optional)", selectorName: "foo(bar:foo:other:)", parameters: [ MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "[String: String]", dictionary: DictionaryType(name: "[String: String]", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "String")), generic: GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String")), GenericTypeParameter(typeName: TypeName(name: "String"))]))), MethodParameter(name: "foo", index: 1, typeName: TypeName(name: "(String, String) -> Void", closure: ClosureType(name: "(String, String) -> Void", parameters: [ ClosureParameter(typeName: TypeName(name: "String")), ClosureParameter(typeName: TypeName(name: "String")) ], returnTypeName: TypeName(name: "Void")))), MethodParameter(name: "other", index: 2, typeName: TypeName(name: "Optional")) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts method with parameter with two names") { expect(parse("class Foo { func foo(bar Bar: Int, _ foo: Int, fooBar: (_ a: Int, _ b: Int) -> ()) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(bar Bar: Int, _ foo: Int, fooBar: (_ a: Int, _ b: Int) -> ())", selectorName: "foo(bar:_:fooBar:)", parameters: [ MethodParameter(argumentLabel: "bar", name: "Bar", index: 0, typeName: TypeName(name: "Int")), MethodParameter(argumentLabel: nil, name: "foo", index: 1, typeName: TypeName(name: "Int")), MethodParameter(name: "fooBar", index: 2, typeName: TypeName(name: "(_ a: Int, _ b: Int) -> ()", closure: ClosureType(name: "(_ a: Int, _ b: Int) -> ()", parameters: [ ClosureParameter(argumentLabel: nil, name: "a", typeName: TypeName(name: "Int")), ClosureParameter(argumentLabel: nil, name: "b", typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "()")))) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts parameters having inner closure") { expect(parse("class Foo { func foo(a: Int) { let handler = { (b:Int) in } } }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(a: Int)", selectorName: "foo(a:)", parameters: [ MethodParameter(argumentLabel: "a", name: "a", index: 0, typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts inout parameters") { expect(parse("class Foo { func foo(a: inout Int) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(a: inout Int)", selectorName: "foo(a:)", parameters: [ MethodParameter(argumentLabel: "a", name: "a", index: 0, typeName: TypeName(name: "inout Int"), isInout: true) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts correct typeName when a nested type shadows a global type") { let code = """ protocol Foo { } class Bar { struct Foo { } func doSomething(with foo: Foo) -> Foo { } } """ let fooProtocol = Protocol(name: "Foo") let fooStruct = Struct(name: "Foo") let barClass = Class( name: "Bar", methods: [ Method(name: "doSomething(with foo: Bar.Foo)", selectorName: "doSomething(with:)", parameters: [ MethodParameter(argumentLabel: "with", name: "foo", index: 0, typeName: TypeName("Bar.Foo"), type: fooStruct) ], returnTypeName: TypeName("Bar.Foo"), definedInTypeName: TypeName("Bar")) ], containedTypes: [ fooStruct ] ) let result = parse(code) expect(result).to(equal([fooProtocol, barClass, fooStruct])) } context("given parameter default value") { it("extracts simple default value") { expect(parse("class Foo { func foo(a: Int? = nil) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(a: Int? = nil)", selectorName: "foo(a:)", parameters: [ MethodParameter(argumentLabel: "a", name: "a", index: 0, typeName: TypeName(name: "Int?"), defaultValue: "nil") ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts complex default value") { expect(parse("class Foo { func foo(a: Int? = \n\t{ return nil } \n\t ) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(a: Int? = { return nil })", selectorName: "foo(a:)", parameters: [ MethodParameter(argumentLabel: "a", name: "a", index: 0, typeName: TypeName(name: "Int?"), defaultValue: "{ return nil }") ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } } context("given parameters are split between lines") { it("extracts method name with parametes separated by line break") { let result = parse(""" class Foo { func foo(bar: [String: String], foo: ((String, String) -> Void), other: Optional) {} } """) expect(result) .to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(bar: [String: String], foo: (String, String) -> Void, other: Optional)", selectorName: "foo(bar:foo:other:)", parameters: [ MethodParameter(name: "bar", index: 0, typeName: TypeName(name: "[String: String]", dictionary: DictionaryType(name: "[String: String]", valueTypeName: TypeName(name: "String"), keyTypeName: TypeName(name: "String")), generic: GenericType(name: "Dictionary", typeParameters: [GenericTypeParameter(typeName: TypeName(name: "String")), GenericTypeParameter(typeName: TypeName(name: "String"))]))), MethodParameter(name: "foo", index: 1, typeName: TypeName(name: "(String, String) -> Void", closure: ClosureType(name: "(String, String) -> Void", parameters: [ ClosureParameter(typeName: TypeName(name: "String")), ClosureParameter(typeName: TypeName(name: "String")) ], returnTypeName: TypeName(name: "Void")))), MethodParameter(name: "other", index: 2, typeName: TypeName(name: "Optional")) ], returnTypeName: TypeName(name: "Void"), definedInTypeName: TypeName(name: "Foo")) ]) ])) } } } context("given generic method") { func assertMethods(_ types: [Type]) { let fooType = types.first(where: { $0.name == "Foo" }) let foo = fooType?.methods.first // expect(foo?.name).to(equal("foo()")) // expect(foo?.selectorName).to(equal("foo")) // expect(foo?.shortName).to(equal("foo")) // expect(foo?.callName).to(equal("foo")) expect(foo?.returnTypeName).to(equal(TypeName(name: "Bar? where \nT: Equatable"))) // expect(foo?.unwrappedReturnTypeName).to(equal("Bar")) // expect(foo?.definedInTypeName).to(equal(TypeName(name: "Foo"))) // // expect(fooBar?.name).to(equal("fooBar(bar: T)")) // expect(fooBar?.selectorName).to(equal("fooBar(bar:)")) // expect(fooBar?.shortName).to(equal("fooBar")) // expect(fooBar?.callName).to(equal("fooBar")) // expect(fooBar?.returnTypeName).to(equal(TypeName(name: "Void where T: Equatable"))) // expect(fooBar?.unwrappedReturnTypeName).to(equal("Void")) // expect(fooBar?.definedInTypeName).to(equal(TypeName(name: "Foo"))) } it("extracts class method properly") { let types = parse(""" class Foo { func foo() -> Bar?\n where \nT: Equatable { }; /// Asks a Duck to quack /// /// - Parameter times: How many times the Duck will quack func fooBar(bar: T) where T: Equatable { } }; class Bar {} """) assertMethods(types) } it("extracts protocol method properly") { let types = parse(""" protocol Foo { func foo(t: T) -> Bar?\n where \nT: Equatable /// Asks a Duck to quack /// /// - Parameter times: How many times the Duck will quack func fooBar(bar: T) where T: Equatable }; class Bar {} """) assertMethods(types) } } context("given method with return type") { it("extracts tuple return type correctly") { let expectedTypeName = TypeName(name: "(Bar, Int)", tuple: TupleType(name: "(Bar, Int)", elements: [ TupleElement(name: "0", typeName: TypeName(name: "Bar"), type: Class(name: "Bar")), TupleElement(name: "1", typeName: TypeName(name: "Int")) ])) let types = parse("class Foo { func foo() -> (Bar, Int) { } }; class Bar {}") let method = types.first(where: { $0.name == "Foo" })?.methods.first expect(method?.returnTypeName).to(equal(expectedTypeName)) expect(method?.returnTypeName.isTuple).to(beTrue()) } it("extracts closure return type correcty") { let types = parse("class Foo { func foo() -> (Int, Int) -> () { } }") let method = types.last?.methods.first expect(method?.returnTypeName).to(equal(TypeName(name: "(Int, Int) -> ()", closure: ClosureType(name: "(Int, Int) -> ()", parameters: [ ClosureParameter(typeName: TypeName(name: "Int")), ClosureParameter(typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "()"))))) expect(method?.returnTypeName.isClosure).to(beTrue()) } it("extracts optional closure return type correctly") { let types = parse("protocol Foo { func foo() -> (() -> Void)? }") let method = types.last?.methods.first expect(method?.returnTypeName).to(equal(TypeName(name: "(() -> Void)?", closure: ClosureType(name: "() -> Void", parameters: [ ], returnTypeName: TypeName(name: "Void"))))) expect(method?.returnTypeName.isClosure).to(beTrue()) } it("extracts optional closure return type correctly") { let types = parse("protocol Foo { func foo() -> (() -> Void)? }") let method = types.last?.methods.first expect(method?.returnTypeName).to(equal(TypeName(name: "(() -> Void)?", closure: ClosureType(name: "() -> Void", parameters: [ ], returnTypeName: TypeName(name: "Void"))))) expect(method?.returnTypeName.isClosure).to(beTrue()) } } context("given initializer") { it("extracts initializer properly") { let fooType = Class(name: "Foo") let expectedInitializer = Method(name: "init()", selectorName: "init", returnTypeName: TypeName(name: "Foo"), isStatic: true, definedInTypeName: TypeName(name: "Foo")) expectedInitializer.returnType = fooType fooType.rawMethods = [Method(name: "foo()", selectorName: "foo", definedInTypeName: TypeName(name: "Foo")), expectedInitializer] let type = parse("class Foo { func foo() {}; init() {} }").first let initializer = type?.initializers.first expect(initializer).to(equal(expectedInitializer)) } it("extracts failable initializer properly") { let fooType = Class(name: "Foo") let expectedInitializer = Method(name: "init?()", selectorName: "init", returnTypeName: TypeName(name: "Foo?"), isStatic: true, isFailableInitializer: true, definedInTypeName: TypeName(name: "Foo")) expectedInitializer.returnType = fooType fooType.rawMethods = [Method(name: "foo()", selectorName: "foo", definedInTypeName: TypeName(name: "Foo")), expectedInitializer] let type = parse("class Foo { func foo() {}; init?() {} }").first let initializer = type?.initializers.first expect(initializer).to(equal(expectedInitializer)) } } it("extracts method definedIn type name") { expect(parse("class Bar { func foo() {} }")).to(equal([ Class(name: "Bar", methods: [ Method(name: "foo()", selectorName: "foo", definedInTypeName: TypeName(name: "Bar")) ]) ])) } it("extracts method annotations") { expect(parse("class Foo {\n // sourcery: annotation\nfunc foo() {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo()", selectorName: "foo", annotations: ["annotation": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts method annotations from initializers") { expect(parse(""" class Foo { // sourcery: annotation init() { } } """)).to(equal([ Class(name: "Foo", methods: [ Method(name: "init()", selectorName: "init", returnTypeName: TypeName(name: "Foo"), isStatic: true, annotations: ["annotation": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts method inline annotations") { expect(parse("class Foo {\n /* sourcery: annotation */func foo() {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo()", selectorName: "foo", annotations: ["annotation": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts parameter annotations") { expect(parse("class Foo {\n //sourcery: foo\nfunc foo(\n// sourcery: annotationA\na: Int,\n// sourcery: annotationB\nb: Int) {}\n//sourcery: bar\nfunc bar(\n// sourcery: annotationA\na: Int,\n// sourcery: annotationB\nb: Int) {} }")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(a: Int, b: Int)", selectorName: "foo(a:b:)", parameters: [ MethodParameter(name: "a", index: 0, typeName: TypeName(name: "Int"), annotations: ["annotationA": NSNumber(value: true)]), MethodParameter(name: "b", index: 1, typeName: TypeName(name: "Int"), annotations: ["annotationB": NSNumber(value: true)]) ], annotations: ["foo": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")), Method(name: "bar(a: Int, b: Int)", selectorName: "bar(a:b:)", parameters: [ MethodParameter(name: "a", index: 0, typeName: TypeName(name: "Int"), annotations: ["annotationA": NSNumber(value: true)]), MethodParameter(name: "b", index: 1, typeName: TypeName(name: "Int"), annotations: ["annotationB": NSNumber(value: true)]) ], annotations: ["bar": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts parameter inline annotations") { expect(parse("class Foo {\n//sourcery:begin:func\n //sourcery: foo\nfunc foo(/* sourcery: annotationA */a: Int, /* sourcery: annotationB*/b: Int) {}\n//sourcery: bar\nfunc bar(/* sourcery: annotationA */a: Int, /* sourcery: annotationB*/b: Int) {}\n//sourcery:end}")).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(a: Int, b: Int)", selectorName: "foo(a:b:)", parameters: [ MethodParameter(name: "a", index: 0, typeName: TypeName(name: "Int"), annotations: ["annotationA": NSNumber(value: true), "func": NSNumber(value: true)]), MethodParameter(name: "b", index: 1, typeName: TypeName(name: "Int"), annotations: ["annotationB": NSNumber(value: true), "func": NSNumber(value: true)]) ], annotations: ["foo": NSNumber(value: true), "func": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")), Method(name: "bar(a: Int, b: Int)", selectorName: "bar(a:b:)", parameters: [ MethodParameter(name: "a", index: 0, typeName: TypeName(name: "Int"), annotations: ["annotationA": NSNumber(value: true), "func": NSNumber(value: true)]), MethodParameter(name: "b", index: 1, typeName: TypeName(name: "Int"), annotations: ["annotationB": NSNumber(value: true), "func": NSNumber(value: true)]) ], annotations: ["bar": NSNumber(value: true), "func": NSNumber(value: true)], definedInTypeName: TypeName(name: "Foo")) ]) ])) } it("extracts parameter inline prefix and suffix annotations") { let parsed = parse(""" class Foo { func foo(paramA: String, // sourcery: anAnnotation = "PARAM A AND METHOD ONLY" /* sourcery: testAnnotation="PARAM B ONLY"*/ paramB: String, paramC: String, // sourcery: anotherAnnotation = "PARAM C ONLY" paramD: String ) {} } """) expect(parsed).to(equal([ Class(name: "Foo", methods: [ Method(name: "foo(paramA: String, paramB: String, paramC: String, paramD: String)", selectorName: "foo(paramA:paramB:paramC:paramD:)", parameters: [ MethodParameter(name: "paramA", index: 0, typeName: TypeName(name: "String"), annotations: ["anAnnotation": "PARAM A AND METHOD ONLY" as NSString]), MethodParameter(name: "paramB", index: 1, typeName: TypeName(name: "String"), annotations: ["testAnnotation": "PARAM B ONLY" as NSString]), MethodParameter(name: "paramC", index: 2, typeName: TypeName(name: "String"), annotations: ["anotherAnnotation": "PARAM C ONLY" as NSString]), MethodParameter(name: "paramD", index: 3, typeName: TypeName(name: "String"), annotations: [:]), ], annotations: ["anAnnotation": "PARAM A AND METHOD ONLY" as NSString], definedInTypeName: TypeName(name: "Foo")) ])])) } } } } } ================================================ FILE: SourceryTests/Parsing/FileParser_ProtocolComposition.swift ================================================ import Quick import Nimble import PathKit import Foundation #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class FileParserProtocolCompositionSpec: QuickSpec { override func spec() { describe("FileParser") { describe("parseProtocolComposition") { func parse(_ code: String) -> [Type] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return parserResult.types } it("extracts protocol compositions properly") { let types = parse(""" protocol Foo { func fooDo() } protocol Bar { var bar: String { get } } typealias FooBar = Foo & Bar """) let protocolComp = types.first(where: { $0 is ProtocolComposition }) as? ProtocolComposition expect(protocolComp).to(equal( ProtocolComposition(name: "FooBar", inheritedTypes: ["Foo", "Bar"], composedTypeNames: [ TypeName("Foo"), TypeName("Bar") ], composedTypes: [ SourceryProtocol(name: "Foo"), SourceryProtocol(name: "Bar") ]) )) } it("extracts annotations on a protocol composition") { let types = parse(""" protocol Foo { func fooDo() } protocol Bar { var bar: String { get } } // sourcery: TestAnnotation typealias FooBar = Foo & Bar """) let protocolComp = types.first(where: { $0 is ProtocolComposition }) as? ProtocolComposition expect(protocolComp?.annotations).to(equal(["TestAnnotation": NSNumber(true)])) } } } } } ================================================ FILE: SourceryTests/Parsing/FileParser_SubscriptsSpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class FileParserSubscriptsSpec: QuickSpec { override func spec() { describe("FileParser") { describe("parseSubscript") { func parse(_ code: String) -> [Type] { guard let parserResult = try? makeParser(for: code).parse() else { fail(); return [] } return parserResult.types } it("extracts subscripts properly") { let subscripts = parse(""" class Foo { final private subscript(_ index: Int, a: String) -> Int { get { return 0 } set { do {} } } public private(set) subscript(b b: Int) -> String { get { return \"\"} set { } } } """).first?.subscripts expect(subscripts?.first).to(equal( Subscript( parameters: [ MethodParameter(argumentLabel: nil, name: "index", index: 0, typeName: TypeName(name: "Int")), MethodParameter(argumentLabel: "a", name: "a", index: 1, typeName: TypeName(name: "String")) ], returnTypeName: TypeName(name: "Int"), accessLevel: (.private, .private), modifiers: [ Modifier(name: "final"), Modifier(name: "private") ], annotations: [:], definedInTypeName: TypeName(name: "Foo") ) )) expect(subscripts?.last).to(equal( Subscript( parameters: [ MethodParameter(argumentLabel: "b", name: "b", index: 0, typeName: TypeName(name: "Int")) ], returnTypeName: TypeName(name: "String"), accessLevel: (.public, .private), modifiers: [ Modifier(name: "public"), Modifier(name: "private", detail: "set") ], annotations: [:], definedInTypeName: TypeName(name: "Foo") ) )) } it("extracts subscript isMutable state properly") { let subscripts = parse(""" protocol Subscript: AnyObject { subscript(arg1: String, arg2: Int) -> Bool { get set } subscript(with arg1: String, and arg2: Int) -> String { get } } """).first?.subscripts expect(subscripts?.first?.isMutable).to(beTrue()) expect(subscripts?.last?.isMutable).to(beFalse()) expect(subscripts?.first?.readAccess).to(equal("internal")) expect(subscripts?.first?.writeAccess).to(equal("internal")) expect(subscripts?.last?.readAccess).to(equal("internal")) expect(subscripts?.last?.writeAccess).to(equal("")) } it("extracts subscript annotations") { let subscripts = parse("//sourcery: thisIsClass\nclass Foo {\n // sourcery: thisIsSubscript\nsubscript(\n\n/* sourcery: thisIsSubscriptParam */a: Int) -> Int { return 0 } }").first?.subscripts let subscriptAnnotations = subscripts?.first?.annotations expect(subscriptAnnotations).to(equal(["thisIsSubscript": NSNumber(value: true)])) let paramAnnotations = subscripts?.first?.parameters.first?.annotations expect(paramAnnotations).to(equal(["thisIsSubscriptParam": NSNumber(value: true)])) } it("extracts generic requirements") { let subscripts = parse(""" protocol Subscript: AnyObject { subscript(arg1: Int) -> Int? { get set } subscript(arg1: String) -> T? { get set } subscript(with arg1: String) -> T? where T: Cancellable { get } } """).first?.subscripts expect(subscripts?[0].isGeneric).to(beFalse()) expect(subscripts?[1].isGeneric).to(beTrue()) expect(subscripts?[2].isGeneric).to(beTrue()) expect(subscripts?[1].genericParameters.first?.name).to(equal("T")) expect(subscripts?[1].genericParameters.first?.inheritedTypeName?.name).to(equal("Hashable & Cancellable")) expect(subscripts?[2].genericParameters.first?.name).to(equal("T")) expect(subscripts?[2].genericRequirements.first?.leftType.name).to(equal("T")) expect(subscripts?[2].genericRequirements.first?.relationshipSyntax).to(equal(":")) expect(subscripts?[2].genericRequirements.first?.rightType.typeName.name).to(equal("Cancellable")) } it("extracts async and throws") { let subscripts = parse(""" protocol Subscript: AnyObject { subscript(arg1: Int) -> Int? { get async } subscript(arg2: Int) -> Int? { get throws } subscript(arg3: Int) -> Int? { get throws(CustomError) } subscript(arg4: Int) -> Int? { get async throws } subscript(arg5: Int) -> Int? { get async throws(CustomError) } } """).first?.subscripts expect(subscripts?[0].isAsync).to(beTrue()) expect(subscripts?[1].isAsync).to(beFalse()) expect(subscripts?[2].isAsync).to(beFalse()) expect(subscripts?[3].isAsync).to(beTrue()) expect(subscripts?[4].isAsync).to(beTrue()) expect(subscripts?[0].throws).to(beFalse()) expect(subscripts?[1].throws).to(beTrue()) expect(subscripts?[2].throws).to(beTrue()) expect(subscripts?[3].throws).to(beTrue()) expect(subscripts?[4].throws).to(beTrue()) expect(subscripts?[0].throwsTypeName).to(beNil()) expect(subscripts?[1].throwsTypeName).to(beNil()) expect(subscripts?[2].throwsTypeName).to(equal(TypeName("CustomError"))) expect(subscripts?[3].throwsTypeName).to(beNil()) expect(subscripts?[4].throwsTypeName).to(equal(TypeName("CustomError"))) } it("extracts optional return type") { let subscripts = parse(""" protocol Subscript: AnyObject { subscript(arg1: Int) -> Int? { get set } subscript(arg2: Int) -> Int! { get } } """).first?.subscripts expect(subscripts?[0].returnTypeName.name).to(equal("Int?")) expect(subscripts?[0].returnTypeName.unwrappedTypeName).to(equal("Int")) expect(subscripts?[1].returnTypeName.name).to(equal("Int!")) expect(subscripts?[1].returnTypeName.unwrappedTypeName).to(equal("Int")) } } } } } ================================================ FILE: SourceryTests/Parsing/FileParser_TypeNameSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif import SourceryFramework import SourceryRuntime class TypeNameSpec: QuickSpec { override func spec() { describe("TypeName") { func variableTypeName(_ variableType: String) -> TypeName { let wrappedCode = """ struct Wrapper { var myFoo: \(variableType) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() let variable = result?.types.first?.variables.first return variable?.typeName ?? TypeName(name: "") } func funcArgumentTypeName(_ functionArgumentType: String) -> MethodParameter? { let wrappedCode = """ struct Wrapper { func myFunc(_ arg: \(functionArgumentType)) {} } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return MethodParameter(name: "", index: 0, typeName: TypeName(name: "")) } let result = try? parser.parse() let methodParameter = result?.types.first?.methods.first?.parameters.first return methodParameter } func typeNameFromTypealias(_ code: String) -> TypeName { let wrappedCode = "typealias Wrapper = \(code)" guard let parser = try? makeParser(for: wrappedCode) else { fail(); return TypeName(name: "") } let result = try? parser.parse() return result?.typealiases.first?.typeName ?? TypeName(name: "") } context("given optional type with short syntax") { it("reports optional true") { expect(variableTypeName("Int?").isOptional).to(beTrue()) expect(variableTypeName("Int!").isOptional).to(beTrue()) expect(variableTypeName("Int?").isImplicitlyUnwrappedOptional).to(beFalse()) expect(variableTypeName("Int!").isImplicitlyUnwrappedOptional).to(beTrue()) } it("reports non-optional type for unwrappedTypeName") { expect(variableTypeName("Int?").unwrappedTypeName).to(equal("Int")) expect(variableTypeName("Int!").unwrappedTypeName).to(equal("Int")) } } context("given inout type") { it("reports correct unwrappedTypeName") { expect(variableTypeName("inout String").unwrappedTypeName).to(equal("String")) } } context("given optional type with long generic syntax") { it("reports optional true") { expect(variableTypeName("Optional").isOptional).to(beTrue()) expect(variableTypeName("Optional").isImplicitlyUnwrappedOptional).to(beFalse()) } it("reports non-optional type for unwrappedTypeName") { expect(variableTypeName("Optional").unwrappedTypeName).to(equal("Int")) } } context("given type wrapped with extra closures") { it("unwraps it completely") { expect(variableTypeName("(Int)").unwrappedTypeName).to(equal("Int")) expect(variableTypeName("(Int)?").unwrappedTypeName).to(equal("Int")) expect(variableTypeName("(Int, Int)").unwrappedTypeName).to(equal("(Int, Int)")) expect(variableTypeName("(Int)").unwrappedTypeName).to(equal("Int")) expect(variableTypeName("((Int, Int))").unwrappedTypeName).to(equal("(Int, Int)")) expect(variableTypeName("((Int, Int) -> ())").unwrappedTypeName).to(equal("(Int, Int) -> ()")) } } context("given tuple type") { it("reports tuple correctly") { expect(variableTypeName("(Int, Int)").isTuple).to(beTrue()) expect(variableTypeName("(Int, Int)?").isTuple).to(beTrue()) expect(variableTypeName("(Int)").isTuple).to(beFalse()) expect(variableTypeName("Int").isTuple).to(beFalse()) expect(variableTypeName("(Int) -> (Int)").isTuple).to(beFalse()) expect(variableTypeName("(Int, Int) -> (Int)").isTuple).to(beFalse()) expect(variableTypeName("(Int, (Int, Int) -> (Int))").isTuple).to(beTrue()) expect(variableTypeName("(Int, (Int, Int))").isTuple).to(beTrue()) expect(variableTypeName("(Int, (Int) -> (Int -> Int))").isTuple).to(beTrue()) } } context("given array type") { it("reports array correctly") { expect(variableTypeName("Array").isArray).to(beTrue()) expect(variableTypeName("[Int]").isArray).to(beTrue()) expect(variableTypeName("[[Int]]").isArray).to(beTrue()) expect(variableTypeName("[[Int: Int]]").isArray).to(beTrue()) } it("reports dictionary correctly") { expect(variableTypeName("[Int]").isDictionary).to(beFalse()) expect(variableTypeName("[[Int]]").isDictionary).to(beFalse()) expect(variableTypeName("[[Int: Int]]").isDictionary).to(beFalse()) } } context("given dictionary type") { context("as name") { it("reports dictionary correctly") { expect(variableTypeName("Dictionary").isDictionary).to(beTrue()) expect(variableTypeName("[Int: Int]").isDictionary).to(beTrue()) expect(variableTypeName("[[Int]: [Int]]").isDictionary).to(beTrue()) expect(variableTypeName("[Int: [Int: Int]]").isDictionary).to(beTrue()) } it("reports array correctly") { expect(variableTypeName("[Int: Int]").isArray).to(beFalse()) expect(variableTypeName("[[Int]: [Int]]").isArray).to(beFalse()) expect(variableTypeName("[Int: [Int: Int]]").isArray).to(beFalse()) } } } context("given set type") { context("as name") { it("reports set correctly") { expect(variableTypeName("Set").isSet).to(beTrue()) } } } context("given closure type") { it("reports closure correctly") { expect(variableTypeName("() -> ()").isClosure).to(beTrue()) expect(variableTypeName("(() -> ())?").isClosure).to(beTrue()) expect(variableTypeName("(Int, Int) -> ()").isClosure).to(beTrue()) expect(variableTypeName("() -> (Int, Int)").isClosure).to(beTrue()) expect(variableTypeName("() -> (Int) -> (Int)").isClosure).to(beTrue()) expect(variableTypeName("((Int) -> (Int)) -> ()").isClosure).to(beTrue()) expect(variableTypeName("(Foo) -> Bool").isClosure).to(beTrue()) expect(variableTypeName("(Int) -> Foo").isClosure).to(beTrue()) expect(variableTypeName("(Foo) -> Foo").isClosure).to(beTrue()) expect(variableTypeName("((Int, Int) -> (), Int)").isClosure).to(beFalse()) expect(typeNameFromTypealias("(Foo) -> Bar").isClosure).to(beTrue()) expect(typeNameFromTypealias("(Foo) -> Bar & Baz").isClosure).to(beTrue()) } it("reports variadicity of closure arguments correctly") { expect(funcArgumentTypeName("((String...) -> Int)")?.isVariadic).to(beFalse()) expect(funcArgumentTypeName("((String...) -> Int)")?.isClosure).to(beTrue()) expect(funcArgumentTypeName("((String...) -> Int)")?.typeName.closure?.parameters.first?.isVariadic).to(beTrue()) } it("reports optional status correctly") { expect(variableTypeName("() -> ()").isOptional).to(beFalse()) expect(variableTypeName("() -> ()?").isOptional).to(beFalse()) expect(variableTypeName("() -> ()!").isImplicitlyUnwrappedOptional).to(beFalse()) expect(variableTypeName("(() -> ()!)").isImplicitlyUnwrappedOptional).to(beFalse()) expect(variableTypeName("Optional<()> -> ()").isOptional).to(beFalse()) expect(variableTypeName("(() -> ()?)").isOptional).to(beFalse()) expect(variableTypeName("(() -> ())?").isOptional).to(beTrue()) expect(variableTypeName("(() -> ())!").isImplicitlyUnwrappedOptional).to(beTrue()) expect(variableTypeName("Optional<() -> ()>").isOptional).to(beTrue()) } } context("given closure type inside generic type") { it("reports closure correctly") { expect(variableTypeName("Foo<() -> ()>").isClosure).to(beFalse()) expect(variableTypeName("Foo<(String) -> Bool>").isClosure).to(beFalse()) expect(variableTypeName("Foo<(String) -> Bool?>").isClosure).to(beFalse()) expect(variableTypeName("Foo<(Bar) -> Bool>").isClosure).to(beFalse()) expect(variableTypeName("Foo<(Bar) -> Bar>").isClosure).to(beFalse()) } } context("given closure type with attributes") { it("removes attributes in unwrappedTypeName") { expect(variableTypeName("@escaping (@escaping ()->())->()").unwrappedTypeName).to(equal("(@escaping () -> ()) -> ()")) } it("orders attributes alphabetically") { expect(variableTypeName("@escaping @autoclosure () -> String").asSource).to(equal("@autoclosure @escaping () -> String")) expect(variableTypeName("@escaping @autoclosure () -> String").description).to(equal("@autoclosure @escaping () -> String")) } } context("given optional closure type with attributes") { it("keeps attributes in unwrappedTypeName") { expect(variableTypeName("(@MainActor @Sendable (Int) -> Void)?").unwrappedTypeName).to(equal("(@MainActor @Sendable (Int) -> Void)")) } it("keeps attributes in name") { expect(variableTypeName("(@MainActor @Sendable (Int) -> Void)?").name).to(equal("(@MainActor @Sendable (Int) -> Void)?")) } } context("given implicitly unwrapped optional closure type with attributes") { it("keeps attributes in unwrappedTypeName") { expect(variableTypeName("(@MainActor @Sendable (Int) -> Void)!").unwrappedTypeName).to(equal("(@MainActor @Sendable (Int) -> Void)")) } it("keeps attributes in name") { expect(variableTypeName("(@MainActor @Sendable (Int) -> Void)!").name).to(equal("(@MainActor @Sendable (Int) -> Void)!")) } } context("given Never type") { it("reports Never correctly") { expect(variableTypeName("Never").isNever).to(beTrue()) } } } } } ================================================ FILE: SourceryTests/Parsing/FileParser_VariableSpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class FileParserVariableSpec: QuickSpec { // swiftlint:disable:next function_body_length override func spec() { describe("Parser") { describe("parseVariable") { func parse(_ code: String, parseDocumentation: Bool = false) -> FileParserResult? { guard let parser = try? makeParser(for: code, parseDocumentation: parseDocumentation) else { fail(); return nil } return try? parser.parse() } func variable(_ code: String, parseDocumentation: Bool = false) -> Variable? { let wrappedCode = """ struct Wrapper { \(code) } """ let result = parse(wrappedCode, parseDocumentation: parseDocumentation) let variable = result?.types.first?.variables.first variable?.definedInType = nil variable?.definedInTypeName = nil return variable } it("infers generic type initializer correctly") { func verify(_ type: String) { let parsedTypeName = variable("static let generic: \(type)")?.typeName expect(variable("static let generic = \(type)(value: true)")?.typeName).to(equal(parsedTypeName)) } verify("GenericType") verify("GenericType>") verify("GenericType") expect(variable( """ var pointPool = { ReusableItemPool(something: "cool") }() """ )?.typeName).to(equal(variable("static let generic: ReusableItemPool")?.typeName)) } it("infers types for variables when it's easy") { expect(variable("static let redirectButtonDefaultURL = URL(string: \"https://www.nytimes.com\")!")?.typeName).to(equal(TypeName(name: "URL!"))) } it("reports variable mutability") { expect(variable("var name: String")?.isMutable).to(beTrue()) expect(variable("let name: String")?.isMutable).to(beFalse()) expect(variable("private(set) var name: String")?.isMutable).to(beTrue()) expect(variable("var name: String { return \"\" }")?.isMutable).to(beFalse()) } it("extracts standard property correctly") { expect(variable("var name: String")).to(equal(Variable(name: "name", typeName: TypeName(name: "String"), accessLevel: (read: .internal, write: .internal), isComputed: false))) } it("infers types for variable when type is an inner type of the contained type correctly") { let content = """ struct X { struct A {} let a: A } struct A {} """ let expectedVariable = Variable(name: "a", typeName: TypeName("X.A"), type: Type(name: "A"), accessLevel: (.internal, .none), isComputed: false, isAsync: false, throws: false, isStatic: false, defaultValue: nil, attributes: [:], modifiers: [], annotations: [:], documentation: [], definedInTypeName: TypeName("X")) let result = parse(content) let variable = result?.types.first?.variables.first expect(variable).to(equal(expectedVariable)) } it("extracts with custom access correctly") { expect(variable("private var name: String")) .to(equal( Variable(name: "name", typeName: TypeName(name: "String"), accessLevel: (read: .private, write: .private), isComputed: false, modifiers: [ Modifier(name: "private") ] ) )) expect(variable("private(set) var name: String")) .to(equal( Variable(name: "name", typeName: TypeName(name: "String"), accessLevel: (read: .internal, write: .private), isComputed: false, modifiers: [ Modifier(name: "private", detail: "set") ] ) )) expect(variable("public private(set) var name: String")) .to(equal( Variable(name: "name", typeName: TypeName(name: "String"), accessLevel: (read: .public, write: .private), isComputed: false, modifiers: [ Modifier(name: "public"), Modifier(name: "private", detail: "set") ] ) )) } context("given variable defined in protocol") { func variable(_ code: String) -> Variable? { let wrappedCode = """ protocol Wrapper { \(code) } """ guard let parser = try? makeParser(for: wrappedCode) else { fail(); return nil } let result = try? parser.parse() let variable = result?.types.first?.variables.first variable?.definedInType = nil variable?.definedInTypeName = nil return variable } it("reports variable mutability") { expect(variable("var name: String { get } ")?.isMutable).to(beFalse()) expect(variable("var name: String { get set }")?.isMutable).to(beTrue()) let internalVariable = variable("var name: String { get set }") expect(internalVariable?.writeAccess).to(equal("internal")) expect(internalVariable?.readAccess).to(equal("internal")) let publicVariable = variable("public var name: String { get set }") expect(publicVariable?.writeAccess).to(equal("public")) expect(publicVariable?.readAccess).to(equal("public")) } it("reports variable concurrency") { expect(variable("var name: String { get } ")?.isAsync).to(beFalse()) expect(variable("var name: String { get async }")?.isAsync).to(beTrue()) } it("reports variable throwability") { expect(variable("var name: String { get } ")?.throws).to(beFalse()) expect(variable("var name: String { get throws }")?.throws).to(beTrue()) expect(variable("var name: String { get throws(CustomError) }")?.throws).to(beTrue()) expect(variable("var name: String { get throws(CustomError) }")?.throwsTypeName).to(equal(TypeName("CustomError"))) } } context("given variable with initial value") { it("extracts default value") { expect(variable("var name: String = String()")?.defaultValue).to(equal("String()")) expect(variable("var name = Parent.Children.init()")?.defaultValue).to(equal("Parent.Children.init()")) expect(variable("var name = [[1, 2], [1, 2]]")?.defaultValue).to(equal("[[1, 2], [1, 2]]")) expect(variable("var name = { return 0 }()")?.defaultValue).to(equal("{ return 0 }()")) expect(variable("var name = \t\n { return 0 }() \t\n")?.defaultValue).to(equal("{ return 0 }()")) expect(variable("var name: Int = \t\n { return 0 }() \t\n")?.defaultValue).to(equal("{ return 0 }()")) expect(variable("var name: String = String() { didSet { print(0) } }")?.defaultValue).to(equal("String()")) expect(variable("var name: String = String() {\n\tdidSet { print(0) }\n}")?.defaultValue).to(equal("String()")) expect(variable("var name: String = String()\n{\n\twillSet { print(0) }\n}")?.defaultValue).to(equal("String()")) } it("extracts property with default initializer correctly") { expect(variable("var name = String()")?.typeName).to(equal(TypeName(name: "String"))) expect(variable("var name = Parent.Children.init()")?.typeName).to(equal(TypeName(name: "Parent.Children"))) expect(variable("var name: String? = String()")?.typeName).to(equal(TypeName(name: "String?"))) expect(variable("var name = { return 0 }() ")?.typeName).toNot(equal(TypeName(name: "{ return 0 }"))) expect(variable( """ var reducer = Reducer>.combine( periodizationConfiguratorReducer.optional().pullback(state: \\.periodizationConfigurator, action: /WorkoutTemplate.Action.periodizationConfigurator, environment: { $0.map { _ in Programs.Environment() } })) { somethingUnrealted.init() } """ )?.typeName).to(equal(TypeName(name: "Reducer>"))) } it("extracts property with literal value correctrly") { expect(variable("var name = 1")?.typeName).to(equal(TypeName(name: "Int"))) expect(variable("var name = 1.0")?.typeName).to(equal(TypeName(name: "Double"))) expect(variable("var name = \"1\"")?.typeName).to(equal(TypeName(name: "String"))) expect(variable("var name = true")?.typeName).to(equal(TypeName(name: "Bool"))) expect(variable("var name = false")?.typeName).to(equal(TypeName(name: "Bool"))) expect(variable("var name = nil")?.typeName).to(equal(TypeName(name: "Optional"))) expect(variable("var name = Optional.none")?.typeName).to(equal(TypeName(name: "Optional"))) expect(variable("var name = Optional.some(1)")?.typeName).to(equal(TypeName(name: "Optional"))) expect(variable("var name = Foo.Bar()")?.typeName).to(equal(TypeName(name: "Foo.Bar"))) } it("extracts property with array literal value correctly") { expect(variable("var name = [Int]()")?.typeName).to(equal(TypeName.buildArray(of: .Int))) expect(variable("var name = [1]")?.typeName).to(equal(TypeName.buildArray(of: .Int))) expect(variable("var name = [1, 2]")?.typeName).to(equal(TypeName.buildArray(of: .Int))) expect(variable("var name = [1, \"a\"]")?.typeName).to(equal(TypeName.buildArray(of: .Any))) expect(variable("var name = [1, nil]")?.typeName).to(equal(TypeName.buildArray(of: TypeName.Int.asOptional))) expect(variable("var name = [1, [1, 2]]")?.typeName).to(equal(TypeName.buildArray(of: .Any))) expect(variable("var name = [[1, 2], [1, 2]]")?.typeName).to(equal(TypeName.buildArray(of: TypeName.buildArray(of: .Int)))) expect(variable("var name = [Int()]")?.typeName).to(equal(TypeName.buildArray(of: .Int))) } it("extracts property with dictionary literal value correctly") { expect(variable("var name = [Int: Int]()")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .Int))) expect(variable("var name = [1: 2]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .Int))) expect(variable("var name = [1: 2, 2: 3]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .Int))) expect(variable("var name = [1: 1, 2: \"a\"]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .Any))) expect(variable("var name = [1: 1, 2: nil]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: TypeName.Int.asOptional))) expect(variable("var name = [1: 1, 2: [1, 2]]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .Any))) expect(variable("var name = [[1: 1, 2: 2], [1: 1, 2: 2]]")?.typeName).to(equal(TypeName.buildArray(of: .buildDictionary(key: .Int, value: .Int)))) expect(variable("var name = [1: [1: 1, 2: 2], 2: [1: 1, 2: 2]]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .buildDictionary(key: .Int, value: .Int)))) expect(variable("var name = [Int(): String()]")?.typeName).to(equal(TypeName.buildDictionary(key: .Int, value: .String))) } it("matches inference with parser tuple") { let infer = variable("var name = (1, b: \"[2,3]\", c: 1)")?.typeName let parsed = variable("var name: (Int, b: String, c: Int)")?.typeName expect(infer).to(equal(parsed)) } it("extracts property with tuple literal value correctly") { expect(variable("var name = (1, 2)")?.typeName).to(equal(TypeName.buildTuple(TypeName.Int, TypeName.Int))) expect(variable("var name = (1, b: \"[2,3]\", c: 1)")?.typeName).to(equal(TypeName.buildTuple(.init(name: "0", typeName: .Int), .init(name: "b", typeName: .String), .init(name: "c", typeName: .Int)))) expect(variable("var name = (_: 1, b: 2)")?.typeName).to(equal(TypeName.buildTuple(.init(name: "0", typeName: .Int), .init(name: "b", typeName: .Int)))) expect(variable("var name = ((1, 2), [\"a\": \"b\"])")?.typeName).to(equal(TypeName.buildTuple(TypeName.buildTuple(TypeName.Int, TypeName.Int), TypeName.buildDictionary(key: .String, value: .String)))) expect(variable("var name = ((1, 2), [1, 2])")?.typeName).to(equal(TypeName.buildTuple(TypeName.buildTuple(TypeName.Int, TypeName.Int), TypeName.buildArray(of: .Int)))) expect(variable("var name = ((1, 2), [\"a,b\": \"b\"])")?.typeName) .to( equal(TypeName.buildTuple( .buildTuple(.Int, .Int), .buildDictionary(key: .String, value: .String)) )) } } it("extracts standard let property correctly") { let r = variable("let name: String") expect(r).to(equal(Variable(name: "name", typeName: TypeName(name: "String"), accessLevel: (read: .internal, write: .none), isComputed: false))) } it("extracts computed property correctly") { expect(variable("var name: Int { return 2 }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true))) expect(variable("let name: Int")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: false))) expect(variable("var name: Int")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: false))) expect(variable("var name: Int { \nget { return 0 } \nset {} }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: true))) expect(variable("var name: Int { \nget { return 0 } }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, isAsync: false, throws: false))) expect(variable("var name: Int { \nget async { return 0 } }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, isAsync: true, throws: false))) expect(variable("var name: Int { \nget throws { return 0 } }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, isAsync: false, throws: true))) expect(variable("var name: Int { \nget async throws { return 0 } }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true, isAsync: true, throws: true))) expect(variable("var name: Int \n{ willSet { } }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: false))) expect(variable("var name: Int { \ndidSet {} }")).to(equal(Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .internal), isComputed: false))) } it("extracts generic property correctly") { expect(variable("let name: Observable")).to(equal(Variable(name: "name", typeName: TypeName(name: "Observable", generic: .init(name: "Observable", typeParameters: [.init(typeName: TypeName(name: "Int"))]) ), accessLevel: (read: .internal, write: .none), isComputed: false))) expect(variable("let name: Combine.Observable")).to(equal(Variable(name: "name", typeName: TypeName(name: "Combine.Observable", generic: .init(name: "Combine.Observable", typeParameters: [.init(typeName: TypeName(name: "Int"))]) ), accessLevel: (read: .internal, write: .none), isComputed: false))) } context("given it has sourcery annotations") { it("extracts single annotation") { let expectedVariable = Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true) expectedVariable.annotations["skipEquability"] = NSNumber(value: true) expect(variable("// sourcery: skipEquability\n" + "var name: Int { return 2 }")).to(equal(expectedVariable)) } it("extracts multiple annotations on the same line") { let expectedVariable = Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true) expectedVariable.annotations["skipEquability"] = NSNumber(value: true) expectedVariable.annotations["jsonKey"] = "json_key" as NSString expect(variable("// sourcery: skipEquability, jsonKey = \"json_key\"\n" + "var name: Int { return 2 }")).to(equal(expectedVariable)) } it("extracts multi-line annotations, including numbers") { let expectedVariable = Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true) expectedVariable.annotations["skipEquability"] = NSNumber(value: true) expectedVariable.annotations["jsonKey"] = "json_key" as NSString expectedVariable.annotations["thirdProperty"] = NSNumber(value: -3) let result = variable( "// sourcery: skipEquability, jsonKey = \"json_key\"\n" + "// sourcery: thirdProperty = -3\n" + "var name: Int { return 2 }") expect(result).to(equal(expectedVariable)) } it("extracts annotations interleaved with comments") { let expectedVariable = Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true) expectedVariable.annotations["isSet"] = NSNumber(value: true) expectedVariable.annotations["numberOfIterations"] = NSNumber(value: 2) expectedVariable.documentation = ["isSet is used for something useful"] let result = variable( "// sourcery: isSet\n" + "/// isSet is used for something useful\n" + "// sourcery: numberOfIterations = 2\n" + "var name: Int { return 2 }", parseDocumentation: true) expect(result).to(equal(expectedVariable)) } it("stops extracting annotations if it encounters a non-comment line") { let expectedVariable = Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true) expectedVariable.annotations["numberOfIterations"] = NSNumber(value: 2) let result = variable( "// sourcery: isSet\n" + "\n" + "// sourcery: numberOfIterations = 2\n" + "var name: Int { return 2 }") expect(result).to(equal(expectedVariable)) } it("separates comments correctly from variable name") { let result = variable( """ @SomeWrapper var variable2 // some comment """) let expectedVariable = Variable(name: "variable2", typeName: TypeName(name: "UnknownTypeSoAddTypeAttributionToVariable"), accessLevel: (read: .internal, write: .internal), isComputed: false, attributes: ["SomeWrapper": [Attribute(name: "SomeWrapper", arguments: [:])]]) expect(result).to(equal(expectedVariable)) } it("extracts trailing annotations") { let expectedVariable = Variable(name: "name", typeName: TypeName(name: "Int"), accessLevel: (read: .internal, write: .none), isComputed: true) expectedVariable.annotations["jsonKey"] = "json_key" as NSString expectedVariable.annotations["skipEquability"] = NSNumber(value: true) expect(variable("// sourcery: jsonKey = \"json_key\"\nvar name: Int { return 2 } // sourcery: skipEquability")).to(equal(expectedVariable)) } } } } } } ================================================ FILE: SourceryTests/Parsing/Helpers/AnnotationsParserSpec.swift ================================================ // // Created by Krzysztof Zablocki on 31/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime import SwiftParser import SwiftSyntax class AnnotationsParserSpec: QuickSpec { override func spec() { describe("AnnotationsParser") { describe("parse(line:)") { func parse(_ content: String) -> Annotations { return AnnotationsParser.parse(line: content) } it("extracts single annotation") { let annotations = ["skipEquality": NSNumber(value: true)] expect(parse("skipEquality")).to(equal(annotations)) } it("extracts repeated annotations into array") { let parsedAnnotations = parse("implements = \"Service1\", implements = \"Service2\"") expect(parsedAnnotations["implements"] as? [String]).to(equal(["Service1", "Service2"])) } it("extracts multiple annotations on the same line") { let annotations = ["skipEquality": NSNumber(value: true), "jsonKey": "json_key" as NSString] expect(parse("skipEquality, jsonKey = \"json_key\"")).to(equal(annotations)) } } describe("parse(content:)") { func parse(_ content: String) -> Annotations { let tree = Parser.parse(source: content) let fileName = "in-memory" let sourceLocationConverter = SourceLocationConverter(fileName: fileName, tree: tree) return AnnotationsParser(contents: content, sourceLocationConverter: sourceLocationConverter).all } it("extracts inline annotations") { let result = parse("//sourcery: skipDescription\n/* sourcery: skipEquality */\n/** sourcery: skipCoding */var name: Int { return 2 }") expect(result).to(equal([ "skipDescription": NSNumber(value: true), "skipEquality": NSNumber(value: true), "skipCoding": NSNumber(value: true) ])) } it("extracts inline annotations from multi line comments") { let result = parse("//**\n*Comment\n*sourcery: skipDescription\n*sourcery: skipEquality\n*/var name: Int { return 2 }") expect(result).to(equal([ "skipDescription": NSNumber(value: true), "skipEquality": NSNumber(value: true) ])) } it("extracts multi-line annotations, including numbers") { let annotations = ["skipEquality": NSNumber(value: true), "placeholder": "geo:37.332112,-122.0329753?q=1 Infinite Loop" as NSString, "jsonKey": "[\"json_key\": key, \"json_value\": value]" as NSString, "thirdProperty": NSNumber(value: -3)] let result = parse("// sourcery: skipEquality, jsonKey = [\"json_key\": key, \"json_value\": value]\n" + "// sourcery: thirdProperty = -3\n" + "// sourcery: placeholder = \"geo:37.332112,-122.0329753?q=1 Infinite Loop\"\n" + "var name: Int { return 2 }") expect(result).to(equal(annotations)) } it("extracts suffix annotations, both block and inline") { let annotations = ["anAnnotation": "PARAM A ONLY" as NSString, "testAnnotation": "PARAM B ONLY" as NSString, "anotherAnnotation": "PARAM C ONLY" as NSString] let result = parse(""" class Foo { func bar(paramA: String, // sourcery: anAnnotation = "PARAM A ONLY" /* sourcery: testAnnotation="PARAM B ONLY"*/ paramB: String, paramC: String, // sourcery: anotherAnnotation = "PARAM C ONLY" paramD: String ) {} } """) expect(result).to(equal(annotations)) } it("extracts repeated annotations into array") { let parsedAnnotations = parse("// sourcery: implements = \"Service1\"\n// sourcery: implements = \"Service2\"") expect(parsedAnnotations["implements"] as? [String]).to(equal(["Service1", "Service2"])) } it("extracts annotations interleaved with comments") { let annotations = ["isSet": NSNumber(value: true), "numberOfIterations": NSNumber(value: 2)] let result = parse("// sourcery: isSet\n" + "/// isSet is used for something useful\n" + "// sourcery: numberOfIterations = 2\n" + "var name: Int { return 2 }") expect(result).to(equal(annotations)) } it("extracts end of line annotations") { let result = parse("// sourcery: first = 1 \n let property: Int // sourcery: second = 2, third = \"three\"") expect(result).to(equal(["first": NSNumber(value: 1), "second": NSNumber(value: 2), "third": "three" as NSString])) } it("extracts end of line block comment annotations") { let result = parse("// sourcery: first = 1 \n let property: Int /* sourcery: second = 2, third = \"three\" */ // comment") expect(result).to(equal(["first": NSNumber(value: 1), "second": NSNumber(value: 2), "third": "three" as NSString])) } it ("ignores annotations in string literals") { let result = parse("// sourcery: first = 1 \n let property = \"// sourcery: second = 2\" // sourcery: third = 3") expect(result).to(equal(["first": NSNumber(value: 1), "third": NSNumber(value: 3)])) } it("extracts file annotations") { let annotations = ["isSet": NSNumber(value: true)] let result = parse("// sourcery:file: isSet\n" + "/// isSet is used for something useful\n" + "var name: Int { return 2 }") expect(result).to(equal(annotations)) } it("extracts namespace annotations") { let annotations: [String: NSObject] = ["smth": ["key": "aKey" as NSObject, "default": NSNumber(value: 0), "prune": NSNumber(value: true)] as NSObject] let result = parse("// sourcery:decoding:smth: key='aKey', default=0\n" + "// sourcery:decoding:smth: prune\n" + "var name: Int { return 2 }") expect(result["decoding"] as? Annotations).to(equal(annotations)) } it("extracts json string annotations into array") { let parsedAnnotations = parse("// sourcery: theArray=\"[22,55,88]\"") expect(parsedAnnotations["theArray"] as? [Int]).to(equal([22, 55, 88])) } it("extracts json string annotations into arrays of dictionaries") { let parsedAnnotations = parse("// sourcery: propertyMapping=\"[{\"from\": \"lockVersion\", \"to\": \"version\"},{\"from\": \"goalStatus\", \"to\": \"status\"}]\"") expect(parsedAnnotations["propertyMapping"] as? [[String: String]]).to(equal([["from": "lockVersion", "to": "version"], ["from": "goalStatus", "to": "status"]])) } it("extracts json string annotations into dictionary") { let parsedAnnotations = parse("// sourcery: theDictionary=\"{\"firstValue\": 22,\"secondValue\": 55}\"") expect(parsedAnnotations["theDictionary"] as? [String: Int]).to(equal(["firstValue": 22, "secondValue": 55])) } it("extracts json string annotations into dictionaries of arrays") { let parsedAnnotations = parse("// sourcery: theArrays=\"{\"firstArray\":[22,55,88],\"secondArray\":[1,2,3,4]}\"") expect(parsedAnnotations["theArrays"] as? [String: [Int]]).to(equal(["firstArray": [22, 55, 88], "secondArray": [1, 2, 3, 4]])) } } } } } ================================================ FILE: SourceryTests/Parsing/Helpers/StringViewSpec.swift ================================================ // // Created by Ruslan Alikhamov on 02/07/2023. // Copyright (c) 2023 Evolutions - FZCO. All rights reserved. // import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class StringViewSpec: QuickSpec { override func spec() { describe("StringView") { describe("init()") { func instantiate(_ content: String) -> [Line] { return StringView.init(content).lines } it("parses correct number of lines when utf8 comments are present") { let lines = instantiate("protocol AgeModel {\r\n var ageDesc: String { get } // 年龄的描述\r\n}\r\n") expect(lines.count).to(equal(4)) } it("parses correct number of lines when \r\n newline symbols are present") { let lines = instantiate("'struct S {}\r\nprotocol AP {}\r\n") expect(lines.count).to(equal(3)) } } } } } ================================================ FILE: SourceryTests/Parsing/Helpers/TemplateAnnotationsParserSpec.swift ================================================ // // Created by Krzysztof Zablocki on 16/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class TemplateAnnotationsParserSpec: QuickSpec { override func spec() { describe("InlineParser") { context("without indentation") { let source = "// sourcery:inline:Type.AutoCoding\n" + "var something: Int\n" + "// sourcery:end\n" let result = TemplateAnnotationsParser.parseAnnotations("inline", contents: source, forceParse: []) it("tracks it") { let annotatedRanges = result.annotatedRanges["Type.AutoCoding"] expect(annotatedRanges?.map { $0.range }).to(equal([NSRange(location: 35, length: 19)])) expect(annotatedRanges?.map { $0.indentation }).to(equal([""])) } it("removes content between the markup") { expect(result.contents).to(equal( "// sourcery:inline:Type.AutoCoding\n" + String(repeating: " ", count: 19) + "// sourcery:end\n" )) } } context("with indentation") { let source = " // sourcery:inline:Type.AutoCoding\n" + " var something: Int\n" + " // sourcery:end\n" let result = TemplateAnnotationsParser.parseAnnotations("inline", contents: source, forceParse: []) it("tracks it") { let annotatedRanges = result.annotatedRanges["Type.AutoCoding"] expect(annotatedRanges?.map { $0.range }).to(equal([NSRange(location: 39, length: 23)])) expect(annotatedRanges?.map { $0.indentation }).to(equal([" "])) } it("removes content between the markup") { expect(result.contents).to(equal( " // sourcery:inline:Type.AutoCoding\n" + String(repeating: " ", count: 23) + " // sourcery:end\n" )) } } } } } ================================================ FILE: SourceryTests/Parsing/Helpers/TemplatesAnnotationParser_ForceParseInlineCodeSpec.swift ================================================ // // TemplatesAnnotationParser+ForceParseInlineCodeSpec.swift // SourceryTests // // Created by Ranvir Prasad on 07/04/20. // Copyright © 2020 Pixle. All rights reserved. // import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime class TemplatesAnnotationParserPassInlineCodeSpec: QuickSpec { override func spec() { describe("InlineParser") { context("without indentation") { let source = "// sourcery:inline:Type.AutoCoding\n" + "var something: Int\n" + "// sourcery:end\n" let result = TemplateAnnotationsParser.parseAnnotations("inline", contents: source, aggregate: false, forceParse: ["AutoCoding"]) it("tracks it") { let annotatedRanges = result.annotatedRanges["Type.AutoCoding"] expect(annotatedRanges?.map { $0.range }).to(equal([NSRange(location: 35, length: 19)])) expect(annotatedRanges?.map { $0.indentation }).to(equal([""])) } it("does not remove content between the markup when force parse parameter is set to template name") { expect(result.contents).to(equal("// sourcery:inline:Type.AutoCoding\n" + "var something: Int\n" + "// sourcery:end\n" )) } } context("with indentation") { let source = " // sourcery:inline:Type.AutoCoding\n" + " var something: Int\n" + " // sourcery:end\n" let result = TemplateAnnotationsParser.parseAnnotations("inline", contents: source, aggregate: false, forceParse: ["AutoCoding"]) it("tracks it") { let annotatedRanges = result.annotatedRanges["Type.AutoCoding"] expect(annotatedRanges?.map { $0.range }).to(equal([NSRange(location: 39, length: 23)])) expect(annotatedRanges?.map { $0.indentation }).to(equal([" "])) } it("does not remove the content between the markup when force parse parameter is set to template name") { expect(result.contents).to(equal( " // sourcery:inline:Type.AutoCoding\n" + " var something: Int\n" + " // sourcery:end\n" )) } } } } } ================================================ FILE: SourceryTests/Parsing/Helpers/VerifierSpec.swift ================================================ import Quick import Nimble #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif @testable import SourceryFramework @testable import SourceryRuntime import SourceryUtils class VerifierSpec: QuickSpec { override func spec() { describe("Verifier") { it("allows empty strings") { expect(Verifier.canParse(content: "", path: Path("/"), generationMarker: Sourcery.generationMarker)).to(equal(Verifier.Result.approved)) } it("rejects files generated by Sourcery") { let content = Sourcery.generationMarker + "\n something\n is\n there" expect(Verifier.canParse(content: content, path: Path("/"), generationMarker: Sourcery.generationMarker)).to(equal(Verifier.Result.isCodeGenerated)) } it("rejects files generated by Sourcery when a force parse extension is defined but doesn't match file") { let content = Sourcery.generationMarker + "\n something\n is\n there" expect(Verifier.canParse(content: content, path: Path("/file.swift"), generationMarker: Sourcery.generationMarker, forceParse: ["toparse"])).to(equal(Verifier.Result.isCodeGenerated)) } it("doesn't reject files generated by Sourcery but that we want to force the parsing for") { let content = Sourcery.generationMarker + "\n something\n is\n there" expect(Verifier.canParse(content: content, path: Path("/file.toparse.swift"), generationMarker: Sourcery.generationMarker, forceParse: ["toparse"])).to(equal(Verifier.Result.approved)) } it("rejects file containing conflict marker") { let content = ["\n<<<<<\n", "\n>>>>>\n"] content.forEach { expect(Verifier.canParse(content: $0, path: Path("/"), generationMarker: Sourcery.generationMarker)).to(equal(Verifier.Result.containsConflictMarkers)) } } } } } ================================================ FILE: SourceryTests/Sourcery+PerformanceSpec.swift ================================================ /* // // Sourcery+PerformanceSpec.swift // Sourcery // // Created by Krzysztof Zabłocki on 26/12/2016. // Copyright © 2016 Pixle. All rights reserved. // import XCTest import PathKit @testable import Sourcery class SourceryPerformanceSpec: XCTestCase { let outputDir: Path = { Path.cleanTemporaryDir(name: "SourceryPerformance") }() func testParsingPerformanceOnCleanRun() { let _ = try? Path.cachesDir(sourcePath: Stubs.sourceForPerformance).delete() self.measure { let _ = try? Sourcery().processFiles(Stubs.sourceForPerformance, usingTemplates: Stubs.templateDirectory + Path("Basic.stencil"), output: self.outputDir, cacheDisabled: true) } } func testParsingPerformanceOnSubsequentRun() { let _ = try? Path.cachesDir(sourcePath: Stubs.sourceForPerformance).delete() let _ = try? Sourcery().processFiles(Stubs.sourceForPerformance, usingTemplates: Stubs.templateDirectory + Path("Basic.stencil"), output: self.outputDir) self.measure { let _ = try? Sourcery().processFiles(Stubs.sourceForPerformance, usingTemplates: Stubs.templateDirectory + Path("Basic.stencil"), output: self.outputDir) } } } */ ================================================ FILE: SourceryTests/SourcerySpec.swift ================================================ import Quick import Nimble import PathKit #if SWIFT_PACKAGE import Foundation @testable import SourceryLib #else @testable import Sourcery #endif #if !canImport(ObjectiveC) import CDispatch #endif @testable import SourceryRuntime import XcodeProj private let version = "Major.Minor.Patch" // swiftlint:disable file_length type_body_length class SourcerySpecTests: QuickSpec { // swiftlint:disable:next function_body_length override func spec() { func update(code: String, in path: Path) { guard (try? path.write(code)) != nil else { fatalError() } } describe("Sourcery") { var outputDir = Path("/tmp") var output: Output { return Output(outputDir) } beforeEach { outputDir = Stubs.cleanTemporarySourceryDir() } context("with already generated files") { let templatePath = Stubs.templateDirectory + Path("Other.stencil") let sourcePath = outputDir + Path("Source.swift") var generatedFileModificationDate: Date! var newGeneratedFileModificationDate: Date! func fileModificationDate(url: URL) -> Date? { guard let attr = try? FileManager.default.attributesOfItem(atPath: url.path) else { return nil } return attr[FileAttributeKey.modificationDate] as? Date } beforeEach { update(code: """ class Foo { } """, in: sourcePath) _ = try? Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles( .sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0 ) } context("without changes") { it("doesn't update existing files") { let generatedFilePath = outputDir + Sourcery().generatedPath(for: templatePath) generatedFileModificationDate = fileModificationDate(url: generatedFilePath.url) DispatchQueue.main.asyncAfter( deadline: DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { _ = try? Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) newGeneratedFileModificationDate = fileModificationDate(url: generatedFilePath.url) } expect(newGeneratedFileModificationDate).toEventually(equal(generatedFileModificationDate)) } } context("with changes") { let anotherSourcePath = outputDir + Path("AnotherSource.swift") beforeEach { update(code: """ class Bar { } """, in: anotherSourcePath) } it("updates existing files") { let generatedFilePath = outputDir + Sourcery().generatedPath(for: templatePath) generatedFileModificationDate = fileModificationDate(url: generatedFilePath.url) DispatchQueue.main.asyncAfter( deadline: DispatchTime.now() + Double(Int64(1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { _ = try? Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath, anotherSourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) newGeneratedFileModificationDate = fileModificationDate(url: generatedFilePath.url) } expect(newGeneratedFileModificationDate).toNotEventually(equal(generatedFileModificationDate)) } } } context("given a single template") { let templatePath = Stubs.templateDirectory + Path("Basic.stencil") let expectedResult = try? (Stubs.resultDirectory + Path("Basic.swift")).read(.utf8).withoutWhitespaces describe("using inline generation") { let templatePath = outputDir + Path("FakeTemplate.stencil") let sourcePath = outputDir + Path("Source.swift") beforeEach { update(code: """ class Foo { // sourcery:inline:Foo.Inlined // This will be replaced Last line // sourcery:end } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:Foo.Inlined var property = 2 // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) } it("replaces placeholder with generated code") { let expectedResult = """ class Foo { // sourcery:inline:Foo.Inlined var property = 2 // Line Three // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("removes code from within generated template") { let expectedResult = """ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Line One """ let generatedPath = outputDir + Sourcery().generatedPath(for: templatePath) let result = try? generatedPath.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult.withoutWhitespaces)) } context("with hide version from header enabled") { beforeEach { expect { try Sourcery(watcherEnabled: false, cacheDisabled: true, hideVersionHeader: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) } it("removes version information from within generated template") { let expectedResult = """ // Generated using Sourcery — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Line One """ let generatedPath = outputDir + Sourcery().generatedPath(for: templatePath) let result = try? generatedPath.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult.withoutWhitespaces)) } } context("with custom header prefix") { beforeEach { expect { try Sourcery(watcherEnabled: false, cacheDisabled: true, hideVersionHeader: true, headerPrefix: "// swiftlint:disable all").processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) } it("removes version information from within generated template") { let expectedResult = """ // swiftlint:disable all // Generated using Sourcery — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Line One """ let generatedPath = outputDir + Sourcery().generatedPath(for: templatePath) let result = try? generatedPath.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult.withoutWhitespaces)) } } it("does not remove code from within generated template when missing origin") { update(code: """ class Foo { // sourcery:inline:Bar.Inlined // This will be replaced Last line // sourcery:end } """, in: sourcePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Line One // sourcery:inline:Foo.Inlined var property = 2 // Line Three // sourcery:end """ let generatedPath = outputDir + Sourcery().generatedPath(for: templatePath) let result = try? generatedPath.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult.withoutWhitespaces)) } it("does not create generated file with empty content") { update(code: """ // sourcery:inline:Foo.Inlined var property = 2 // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true, prune: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let generatedPath = outputDir + Sourcery().generatedPath(for: templatePath) let result = try? generatedPath.read(.utf8) expect(result).to(beNil()) } it("inline multiple generated code blocks correctly") { update(code: """ class Foo { // sourcery:inline:Foo.Inlined // This will be replaced Last line // sourcery:end } class Bar { // sourcery:inline:Bar.Inlined // This will be replaced Last line // sourcery:end } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:Bar.Inlined var property = bar // Line Three // sourcery:end // Line One // sourcery:inline:Foo.Inlined var property = foo // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:Foo.Inlined var property = foo // Line Three // sourcery:end } class Bar { // sourcery:inline:Bar.Inlined var property = bar // Line Three // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("indents generated code blocks correctly") { update(code: """ class Foo { // sourcery:inline:Foo.Inlined // This will be replaced Last line // sourcery:end class Bar { // sourcery:inline:Bar.Inlined // This will be replaced Last line // sourcery:end } } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:Bar.Inlined var property = bar // Line Three // sourcery:end // Line One // sourcery:inline:Foo.Inlined var property = foo // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:Foo.Inlined var property = foo // Line Three // sourcery:end class Bar { // sourcery:inline:Bar.Inlined var property = bar // Line Three // sourcery:end } } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } } describe("using automatic inline generation") { let templatePath = outputDir + Path("FakeTemplate.stencil") let sourcePath = outputDir + Path("Source.swift") it("insert generated code in the end of type body") { update(code: "class Foo {}", in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.Inlined var property = 2 // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.Inlined var property = 2 // Line Three // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code in the end of type body maintaining identation, accomodates for baseIdent") { update(code: """ class Foo { struct Inner { } } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.Inner.Inlined var property = 3 // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 4) }.toNot(throwError()) let expectedResult = """ class Foo { struct Inner { // sourcery:inline:auto:Foo.Inner.Inlined var property = 3 // Line Three // sourcery:end } } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code after the end of type body when using after-auto") { update(code: "class Foo {}\nstruct Boo {}", in: sourcePath) update(code: """ // sourcery:inline:after-auto:Foo.Inlined var property = 2 // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo {} // sourcery:inline:after-auto:Foo.Inlined var property = 2 // sourcery:end struct Boo {} """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code line before the end of type body") { update(code: """ class Foo { var property = 1 } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.Inlined var property = 2 // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.Inlined var property = 2 // Line Three // sourcery:end var property = 1 } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("handles UTF16 characters") { update(code: """ class A { let 👩‍🚀: String } """, in: sourcePath) update(code: """ {% for type in types.all %} // sourcery:inline:auto:{{ type.name }}.init init({% for variable in type.storedVariables %}{{variable.name}}: {{variable.typeName}}{% ifnot forloop.last %}, {% endif %}{% endfor %}) { {% for variable in type.storedVariables %} self.{{variable.name}} = {{variable.name}} {% endfor %} } // sourcery:end {% endfor %} """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class A { let 👩‍🚀: String // sourcery:inline:auto:A.init init(👩‍🚀: String) { self.👩‍🚀 = 👩‍🚀 } // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("extracts annotations when prefix contains case noun") { update(code: """ struct MyStruct { // sourcery:inline:MyStruct.Inlined // This will be replaced // sourcery:end // sourcery: stub = "A" let basic: String; // sourcery: stub = "B" let caseProperty: String; // sourcery: stub = "C" let casesProperty: String; // sourcery: stub = "D" let CaseProperty: String; } """, in: sourcePath) update(code: """ // sourcery:inline:MyStruct.Inlined {% for type in types.all %} {% for variable in type.storedVariables %} let {{ variable.name }}XXX = "{{ variable.annotations["stub"] }}"; {% endfor %} {% endfor %} // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ struct MyStruct { // sourcery:inline:MyStruct.Inlined let basicXXX = "A"; let casePropertyXXX = "B"; let casesPropertyXXX = "C"; let CasePropertyXXX = "D"; // sourcery:end // sourcery: stub = "A" let basic: String; // sourcery: stub = "B" let caseProperty: String; // sourcery: stub = "C" let casesProperty: String; // sourcery: stub = "D" let CaseProperty: String; } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("replaces inline contents without crashing") { update(code: """ struct MyStruct { // sourcery:inline:MyStruct.Inlined // This will be replaced // sourcery:end // sourcery:inline:MyStruct.Inlined.Foo // sourcery: stub = "A" let basic: String; // sourcery: stub = "B" let caseProperty: String; // sourcery: stub = "C" let casesProperty: String; // sourcery: stub = "D" let CaseProperty: String; // sourcery:end } """, in: sourcePath) update(code: """ // sourcery:inline:MyStruct.Inlined {% for type in types.all %} {% for variable in type.storedVariables %} let {{ variable.name }}XXX = "{{ variable.annotations["stub"] }}"; {% endfor %} {% endfor %} // sourcery:end // sourcery:inline:MyStruct.Inlined.Foo // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ struct MyStruct { // sourcery:inline:MyStruct.Inlined // sourcery:end // sourcery:inline:MyStruct.Inlined.Foo // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("handles previously generated code with UTF16 characters") { update(code: """ class A { let 👩‍🚀: String // sourcery:inline:auto:A.init init(👩‍🚀: String) { self.👩‍🚀 = 👩‍🚀 } // sourcery:end } class B { let 👩‍🚀: String } """, in: sourcePath) update(code: """ {% for type in types.all %} // sourcery:inline:auto:{{ type.name }}.init init({% for variable in type.storedVariables %}{{variable.name}}: {{variable.typeName}}{% ifnot forloop.last %}, {% endif %}{% endfor %}) { {% for variable in type.storedVariables %} self.{{variable.name}} = {{variable.name}} {% endfor %} } // sourcery:end {% endfor %} """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class A { let 👩‍🚀: String // sourcery:inline:auto:A.init init(👩‍🚀: String) { self.👩‍🚀 = 👩‍🚀 } // sourcery:end } class B { let 👩‍🚀: String // sourcery:inline:auto:B.init init(👩‍🚀: String) { self.👩‍🚀 = 👩‍🚀 } // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code in multiple types") { update(code: """ class Foo {} class Bar {} """, in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Bar.Inlined var property = bar // Line Three // sourcery:end // Line One // sourcery:inline:auto:Foo.Inlined var property = foo // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.Inlined var property = foo // Line Three // sourcery:end } class Bar { // sourcery:inline:auto:Bar.Inlined var property = bar // Line Three // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert same generated code in multiple types") { update(code: """ class Foo { // sourcery:inline:auto:Foo.fake // sourcery:end } class Bar {} """, in: sourcePath) update(code: """ // Line One {% for type in types.all %} // sourcery:inline:auto:{{ type.name }}.fake var property = bar // Line Three // sourcery:end {% endfor %} """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.fake var property = bar // Line Three // sourcery:end } class Bar { // sourcery:inline:auto:Bar.fake var property = bar // Line Three // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code in a nested type") { update(code: """ class Foo { class Bar {} } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.Bar.AutoInlined var property = bar // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { class Bar { // sourcery:inline:auto:Foo.Bar.AutoInlined var property = bar // Line Three // sourcery:end } } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code in a nested type with extension") { update(code: """ class Foo {} extension Foo { class Bar {} } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.Bar.AutoInlined var property = bar // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo {} extension Foo { class Bar { // sourcery:inline:auto:Foo.Bar.AutoInlined var property = bar // Line Three // sourcery:end } } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("insert generated code in both type and its nested type") { update(code: """ class Foo {} extension Foo { class Bar {} } """, in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.AutoInlined var property = foo // Line Three // sourcery:end // sourcery:inline:auto:Foo.Bar.AutoInlined var property = bar // Line Three // sourcery:end """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.AutoInlined var property = foo // Line Three // sourcery:end } extension Foo { class Bar { // sourcery:inline:auto:Foo.Bar.AutoInlined var property = bar // Line Three // sourcery:end } } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("inserts generated code from different templates (both inline:auto)") { update(code: "class Foo {}", in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.fake var property = 2 // Line Three // sourcery:end """, in: templatePath) let secondTemplatePath = outputDir + Path("OtherFakeTemplate.stencil") update(code: """ // sourcery:inline:auto:Foo.otherFake // Line Four // sourcery:end """, in: secondTemplatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true) .processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [secondTemplatePath, templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.fake var property = 2 // Line Three // sourcery:end // sourcery:inline:auto:Foo.otherFake // Line Four // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) // when regenerated expect { try Sourcery(watcherEnabled: false, cacheDisabled: true) .processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [secondTemplatePath, templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let newResult = try? sourcePath.read(.utf8) expect(newResult).to(equal(expectedResult)) } it("inserts generated code from different templates (both inline)") { let templatePathA = outputDir + Path("InlineTemplateA.stencil") let templatePathB = outputDir + Path("InlineTemplateB.stencil") let sourcePath = outputDir + Path("ClassWithMultipleInlineAnnotations.swift") update(code: """ class ClassWithMultipleInlineAnnotations { // sourcery:inline:ClassWithMultipleInlineAnnotations.A var a0: Int // sourcery:end // sourcery:inline:ClassWithMultipleInlineAnnotations.B var b0: String // sourcery:end } """, in: sourcePath) update(code: """ {% for type in types.all %} // sourcery:inline:{{ type.name }}.A var a0: Int var a1: Int var a2: Int // sourcery:end {% endfor %} """, in: templatePathA) update(code: """ {% for type in types.all %} // sourcery:inline:{{ type.name }}.B var b0: Int var b1: Int var b2: Int // sourcery:end {% endfor %} """, in: templatePathB) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true) .processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePathA, templatePathB]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class ClassWithMultipleInlineAnnotations { // sourcery:inline:ClassWithMultipleInlineAnnotations.A var a0: Int var a1: Int var a2: Int // sourcery:end // sourcery:inline:ClassWithMultipleInlineAnnotations.B var b0: Int var b1: Int var b2: Int // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } it("inserts generated code from different templates (inline and inline:auto)") { let templatePathA = outputDir + Path("InlineTemplateA.stencil") let templatePathB = outputDir + Path("InlineTemplateB.stencil") let sourcePath = outputDir + Path("ClassWithMultipleInlineAnnotations.swift") /* inline:auto annotations are inserted at the beginning of the last line of a declaration, OR at the beginning of the last line of the containing file, if proposed location out of bounds, which should not be. To differentiate such cases the last line of a declaration shall not be the last line of the file. */ update(code: """ class ClassWithMultipleInlineAnnotations { // sourcery:inline:ClassWithMultipleInlineAnnotations.A var a0: Int // sourcery:end } // the last line of the file """, in: sourcePath) update(code: """ {% for type in types.all %} // sourcery:inline:{{ type.name }}.A var a0: Int var a1: Int var a2: Int // sourcery:end {% endfor %} """, in: templatePathA) update(code: """ {% for type in types.all %} // sourcery:inline:auto:{{ type.name }}.B var b0: Int var b1: Int var b2: Int // sourcery:end {% endfor %} """, in: templatePathB) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true) .processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePathA, templatePathB]), output: output, baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class ClassWithMultipleInlineAnnotations { // sourcery:inline:ClassWithMultipleInlineAnnotations.A var a0: Int var a1: Int var a2: Int // sourcery:end // sourcery:inline:auto:ClassWithMultipleInlineAnnotations.B var b0: Int var b1: Int var b2: Int // sourcery:end } // the last line of the file """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } context("with cache of already inserted code") { beforeEach { Sourcery.removeCache(for: [sourcePath]) update(code: "class Foo {}", in: sourcePath) update(code: """ // Line One // sourcery:inline:auto:Foo.Inlined var property = 2 // Line Three // sourcery:end """, in: templatePath) _ = try? Sourcery(watcherEnabled: false, cacheDisabled: false).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: Output(outputDir, linkTo: nil), baseIndentation: 0) } it("inserts the generated code if it was deleted") { update(code: "class Foo {}", in: sourcePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: false).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: Output(outputDir, linkTo: nil), baseIndentation: 0) }.toNot(throwError()) let expectedResult = """ class Foo { // sourcery:inline:auto:Foo.Inlined var property = 2 // Line Three // sourcery:end } """ let result = try? sourcePath.read(.utf8) expect(result).to(equal(expectedResult)) } afterEach { Sourcery.removeCache(for: [sourcePath]) } } } describe("using per file generation") { let templatePath = outputDir + Path("FakeTemplate.stencil") let sourcePath = outputDir + Path("Source.swift") beforeEach { update(code: "class Foo { }", in: sourcePath) update(code: """ // Line One {% for type in types.all %} // sourcery:file:Generated/{{ type.name }} extension {{ type.name }} { var property = 2 // Line Three } // sourcery:end {% endfor %} """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) } it("replaces placeholder with generated code") { let expectedResult = """ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension Foo { var property = 2 // Line Three } """ let generatedPath = outputDir + Path("Generated/Foo.generated.swift") let result = try? generatedPath.read(.utf8) expect(result).to(equal(expectedResult)) } it("removes code from within generated template") { let expectedResult = """ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Line One """ let generatedPath = outputDir + Sourcery().generatedPath(for: templatePath) let result = try? generatedPath.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult.withoutWhitespaces)) } it("does not create generated file with empty content") { update(code: """ {% for type in types.all %} // sourcery:file:Generated/{{ type.name }} // sourcery:end {% endfor %} """, in: templatePath) expect { try Sourcery(watcherEnabled: false, cacheDisabled: true, prune: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let generatedPath = outputDir + Path("Generated/Foo.generated.swift") let result = try? generatedPath.read(.utf8) expect(result).to(beNil()) } it("appends content of several annotations into one file") { update(code: """ // Line One // sourcery:file:Generated/Foo extension Foo { var property1 = 1 } // sourcery:end // sourcery:file:Generated/Foo extension Foo { var property2 = 2 } // sourcery:end """, in: templatePath) let expectedResult = """ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension Foo { var property1 = 1 } extension Foo { var property2 = 2 } """ expect { try Sourcery(watcherEnabled: false, cacheDisabled: true, prune: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let generatedPath = outputDir + Path("Generated/Foo.generated.swift") let result = try? generatedPath.read(.utf8) expect(result).to(equal(expectedResult)) } } context("given a restricted file") { let targetPath = outputDir + Sourcery().generatedPath(for: templatePath) it("ignores files that are marked with generated by Sourcery") { _ = try? targetPath.delete() expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.resultDirectory] + Path("Basic.swift"))), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) expect(targetPath.exists).to(beFalse()) } it("throws error when file contains merge conflict markers") { let sourcePath = outputDir + Path("Source.swift") update(code: """ <<<<< """, in: sourcePath) expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.to(throwError()) } it("does not throw when source file does not exist") { let sourcePath = outputDir + Path("Missing.swift") expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: Output(outputDir, linkTo: nil), baseIndentation: 0) }.toNot(throwError()) } } context("given excluded source paths") { it("ignores excluded sources") { expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.sourceDirectory], exclude: [Stubs.sourceDirectory + "Foo.swift"])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) let expectedResult = try? (Stubs.resultDirectory + Path("BasicFooExcluded.swift")).read(.utf8).withoutWhitespaces expect(result.flatMap { $0.withoutWhitespaces }).to(equal(expectedResult?.withoutWhitespaces)) } } context("without a watcher") { it("creates expected output file") { expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) let result = (try? (outputDir + Sourcery().generatedPath(for: templatePath)).read(.utf8)) expect(result.flatMap { $0.withoutWhitespaces }).to(equal(expectedResult?.withoutWhitespaces)) } } #if canImport(ObjectiveC) context("with watcher") { var watcher: Any? let tmpTemplate = outputDir + Path("FakeTemplate.stencil") func updateTemplate(code: String) { guard (try? tmpTemplate.write(code)) != nil else { fatalError() } } it("re-generates on template change") { updateTemplate(code: "Found {{ types.enums.count }} Enums") let sourcery = Sourcery(watcherEnabled: true, cacheDisabled: true) expect { watcher = try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [tmpTemplate]), output: output, baseIndentation: 0) }.toNot(throwError()) // ! Change the template updateTemplate(code: "Found {{ types.all.count }} Types") let result: () -> String? = { (try? (outputDir + Sourcery().generatedPath(for: tmpTemplate)).read(.utf8)) } expect(result()).toEventually(contain("\(sourcery.generationHeader)Found 3 Types")) _ = watcher } } #endif } context("given a template folder") { context("given a single file output") { let outputFile = outputDir + "Composed.swift" #if canImport(JavaScriptCore) let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other+SourceryTemplates.swift")).read(.utf8).withoutWhitespaces it("joins generated code into single file") { expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [ Stubs.templateDirectory + "Basic.stencil", Stubs.templateDirectory + "Other.stencil", Stubs.templateDirectory + "SourceryTemplateStencil.sourcerytemplate", Stubs.templateDirectory + "SourceryTemplateEJS.sourcerytemplate" ]), output: Output(outputFile), baseIndentation: 0) }.toNot(throwError()) let result = try? outputFile.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult?.withoutWhitespaces)) } #else let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other+SourceryTemplates_Linux.swift")).read(.utf8).withoutWhitespaces it("joins generated code into single file") { expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [ Stubs.templateDirectory + "Basic.stencil", Stubs.templateDirectory + "Other.stencil", Stubs.templateDirectory + "SourceryTemplateStencil.sourcerytemplate" ]), output: Output(outputFile), baseIndentation: 0) }.toNot(throwError()) let result = try? outputFile.read(.utf8) expect(result?.withoutWhitespaces).to(equal(expectedResult?.withoutWhitespaces)) } #endif it("does not create generated file with empty content") { let templatePath = Stubs.templateDirectory + Path("Empty.stencil") update(code: "", in: templatePath) expect { try Sourcery(cacheDisabled: true, prune: true).processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [templatePath]), output: Output(outputFile), baseIndentation: 0) }.toNot(throwError()) let result = try? outputFile.read(.utf8) expect(result).to(beNil()) } } context("given an output directory") { it("creates corresponding output file for each template") { let templateNames = ["Basic", "Other"] let generated = templateNames.map { outputDir + Sourcery().generatedPath(for: Stubs.templateDirectory + "\($0).stencil") } let expected = templateNames.map { Stubs.resultDirectory + Path("\($0).swift") } expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [Stubs.templateDirectory]), output: output, baseIndentation: 0) }.toNot(throwError()) for (idx, outputPath) in generated.enumerated() { let output = try? outputPath.read(.utf8) let expected = try? expected[idx].read(.utf8) expect(output?.withoutWhitespaces).to(equal(expected?.withoutWhitespaces)) } } } context("given excluded template paths") { let outputFile = outputDir + "Composed.swift" let expectedResult = try? (Stubs.resultDirectory + Path("Basic+Other.swift")).read(.utf8).withoutWhitespaces it("do not create generated file for excluded templates") { expect { try Sourcery(cacheDisabled: true) .processFiles(.sources(Paths(include: [Stubs.sourceDirectory])), usingTemplates: Paths(include: [Stubs.templateDirectory], exclude: [ Stubs.templateDirectory + "GenerationWays.stencil", Stubs.templateDirectory + "Include.stencil", Stubs.templateDirectory + "Partial.stencil", Stubs.templateDirectory + "SourceryTemplateStencil.sourcerytemplate", Stubs.templateDirectory + "SourceryTemplateEJS.sourcerytemplate" ]), output: Output(outputFile), baseIndentation: 0) }.toNot(throwError()) let result = try? outputFile.read(.utf8) expect(result.flatMap { $0.withoutWhitespaces }).to(equal(expectedResult?.withoutWhitespaces)) } } } #if canImport(ObjectiveC) context("given project") { var originalProject: XcodeProj? let projectPath = Stubs.sourceDirectory + "TestProject" let projectFilePath = Stubs.sourceDirectory + "TestProject/TestProject.xcodeproj" // swiftlint:disable:next force_try let sources = try! Source(dict: [ "project": [ "file": "TestProject.xcodeproj", "target": ["name": "TestProject"] ]], relativePath: projectPath) var templatePath = Stubs.templateDirectory + "Other.stencil" var templates: Paths { return Paths(include: [templatePath]) } var output: Output { // swiftlint:disable:next force_try return try! Output(dict: [ "path": outputDir.string, "link": ["project": "TestProject.xcodeproj", "target": "TestProject"] ], relativePath: projectPath) } var sourceFilesPaths: [Path] { guard let project = try? XcodeProj(path: projectFilePath), let target = project.target(named: "TestProject") else { return [] } return project.sourceFilesPaths(target: target, sourceRoot: projectPath) } beforeEach { expect { originalProject = try XcodeProj(path: projectFilePath) }.toNot(throwError()) } afterEach { expect { try originalProject?.writePBXProj(path: projectFilePath, outputSettings: .init()) }.toNot(throwError()) } it("links generated files") { expect { try Sourcery(cacheDisabled: true, prune: true).processFiles(sources, usingTemplates: templates, output: output, baseIndentation: 0) }.toNot(throwError()) expect(sourceFilesPaths.contains(outputDir + "Other.generated.swift")).to(beTrue()) } it("links generated files when using per file generation") { templatePath = outputDir + "PerFileGeneration.stencil" update(code: """ // Line One {% for type in types.all %} // sourcery:file:Generated/{{ type.name }}.generated.swift extension {{ type.name }} { var property = 2 // Line Three } // sourcery:end {% endfor %} """, in: templatePath) expect { try Sourcery(cacheDisabled: true, prune: true).processFiles(sources, usingTemplates: templates, output: output, baseIndentation: 0) }.toNot(throwError()) expect { let paths = sourceFilesPaths expect(paths.contains(outputDir + "PerFileGeneration.generated.swift")).to(beTrue()) expect(paths.contains(outputDir + "Generated/FooBarBaz.generated.swift")).to(beTrue()) }.toNot(throwError()) } } #endif } } } ================================================ FILE: SourceryTests/Stub/Configs/invalid.yml ================================================ invalid configuration ================================================ FILE: SourceryTests/Stub/Configs/multi.yml ================================================ configurations: - sources: - "${SOURCE_PATH}/0" templates: - "Templates/0" output: "Output/0" args: serverUrl: "${serverUrl}/0" serverPort: "${serverPort}/0" - sources: - "${SOURCE_PATH}/1" templates: - "Templates/1" output: "Output/1" args: serverUrl: "${serverUrl}/1" serverPort: "${serverPort}1" ================================================ FILE: SourceryTests/Stub/Configs/parent.yml ================================================ configurations: - child: valid.yml ================================================ FILE: SourceryTests/Stub/Configs/valid.yml ================================================ sources: - "${SOURCE_PATH}" templates: - "Templates" output: "Output" args: serverUrl: ${serverUrl} serverPort: ${serverPort} ================================================ FILE: SourceryTests/Stub/DryRun-Code/Base.swift ================================================ import Foundation protocol AutoEquatable {} struct Eq: AutoEquatable { // sourcery:inline:Eq.AutoEquatable // sourcery:end let s: Int let o: String let u: String let r: Int let c: [Int] let e: Bool } struct Eq3: AutoEquatable { let counter: Int let foo: String let bar: Set } struct Eq2: AutoEquatable { // sourcery:inline:Eq2.AutoEquatable // sourcery:end let r: Int let y: String let d: [Int: Bool] let r2: Int let y2: [Int] let r3: Bool let u: Int64 let n: Double } enum EqEnum: AutoEquatable { case some(Int) case other(Bool) } ================================================ FILE: SourceryTests/Stub/Errors/localized-error.swift ================================================ import Foundation final class Localized: NSObject { fileprivate override init() {} } extension Localized { static func storeEnterRecipientNickname() -> String { return NSLocalizedString("Please enter the recipient's nickname", comment: "") } static func storeNameCannotBeEmpty() -> String { return NSLocalizedString("Sorry, the name can't be empty. Please enter a nickname to send the gift to. You can also send the gift to yourself!", comment: "") } static func storeSendGiftToUser() -> String { return NSLocalizedString("Send a gift to ", comment: "") } static func storeSendStickerPackToUser() -> String { return NSLocalizedString("Send Free Sticker Pack to ", comment: "label") } static func storeBuyStickerPackForUser() -> String { return NSLocalizedString("Buy Sticker Pack for ", comment: "label") } static func storeAddFreeStickerPackToUser() -> String { return NSLocalizedString("Add Free Sticker Pack to ", comment: "button") } static func storeAddFreeStickerPack() -> String { return NSLocalizedString("Add Free Sticker Pack", comment: "button") } static func storeNoUserWithNickname() -> String { return NSLocalizedString("No user exists with that nickname", comment: "") } static func storeWhosThisGiftGoigTo() -> String { return NSLocalizedString("Who's this gift going to?", comment:"") } static func profileGiftFrom(_ nick: String) -> String { return NSLocalizedString("Gift from %@", comment: "label") } static func profileGiftFromAnonymous() -> String { return NSLocalizedString("Gift from Anonymous", comment: "label") } static func profileInvisibleModeAlert() -> String { return NSLocalizedString("Invisible mode makes you appear to be offline. To allow special friends to know you are online go to your Settings and add their name to the Visible User List.\nAre you sure you want to do this?", comment: "Alert") } static func profileNextDateDisplayNameAlert(_ nextChangeDate: String) -> String { return NSLocalizedString("Please note that you will not be able to change this until %@", comment: "Warning") } static func profileGiftSendIMButton() -> String { return NSLocalizedString("Send IM", comment: "Button") } static func profileYouHaveNoSubscription() -> String { return NSLocalizedString("You have no subscription", comment: "Label") } static func roomSortingMaleFemale() -> String { return NSLocalizedString("Females/Males", comment: "") } static func roomSortingAlphabetical() -> String { return NSLocalizedString("Alphabetical", comment: "") } static func roomSortingWhosViewingYou() -> String { return NSLocalizedString("Who's viewing you", comment: "") } static func roomSortingOnlyAvailableToSubscribers() -> String { return NSLocalizedString("Sorting features are only available to subscribers", comment: "") } static func roomSortingUpgradeToChange() -> String { return NSLocalizedString("Upgrade to change sorting to:", comment: "") } static func roomPositiveBarUserViewedYourCam(_ userDisplayName: String) -> String { return NSLocalizedString("%@ viewed your webcam", comment: "") } static func roomPositiveBarUserSentRoomGift(_ userDisplayName: String) -> String { return NSLocalizedString("%@ sent room a gift", comment: "") } static func roomPositiveBarUserSentUserGift(_ userDisplayName: String) -> String { return NSLocalizedString("%@ sent you a gift", comment: "") } static func roomPositiveBarYouSentUserGift(_ userDisplayName: String) -> String { return NSLocalizedString("You sent a gift to %@", comment: "") } static var coinsAreNotAvailableForPurchase: String { return NSLocalizedString("Sorry, coins aren’t available to be purchased right now. Please try again later", comment: "") } } ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/AllTypealiases.ejs ================================================ <%_ for (alias of types.typealiases.filter((t) => t.annotations.AutoStruct != null)) { %> struct Any<%- alias.name %>: <%- alias.type.name %> { <%_ for (variable of alias.type.instanceVariables) { -%> var <%- variable.name %>: <%- variable.typeName.asSource %> <% } -%> } <%_ } -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/Equality.ejs ================================================ <% for (type of types.classes) { -%> <%_ %><%# this is a comment -%> extension <%= type.name %>: Equatable {} <%_ if (type.annotations.showComment) { -%> <% _%> // <%= type.name %> has Annotations <% } -%> func == (lhs: <%= type.name %>, rhs: <%= type.name %>) -> Bool { <%_ for (variable of type.variables) { -%> if lhs.<%= variable.name %> != rhs.<%= variable.name %> { return false } <%_ } %> return true } <% } -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/Function.ejs ================================================ <%_ for (func of functions) { let functionName = String(func.name.split("(")[0]) let capitalizedName = functionName.charAt(0).toUpperCase() + functionName.slice(1) -%> func wrapped<%= capitalizedName %>(<%= func.parameters.map((param) => { return param.name + ": " + param.typeName.name }).join(", ") %>) { <%= functionName %>(<%= func.parameters.map((param) => { return param.name + ": " + param.name }).join(", ") %>) } <%_ } -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/Includes.ejs ================================================ <%- include('Equality') -%><%- include('Other.ejs') -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/Other.ejs ================================================ // Found <%- types.all.length %> types ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/ProtocolCompositions.ejs ================================================ <%_ for (composition of types.protocolCompositions.filter((t) => t.annotations.AutoStruct != null)) { %> struct Any<%- composition.name %>: <%- composition.name %> { <%_ for (type of composition.composedTypes) { -%> // MARK: <%- type.name %> properties <%_ for (variable of type.instanceVariables) { -%> var <%- variable.name %>: <%- variable.typeName.asSource %> <% } } -%> } <%_ } -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/SubfolderIncludes.ejs ================================================ <%- include('lib/One') %><% -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/Typealiases.ejs ================================================ <%_ for (type of types.all) { -%> // Typealiases in <%= type.name %> <%_ for (const [aliasName, aliasValue] of Object.entries(type.typealiases)) { -%> // - name '<%= aliasName %>', type '<%= aliasValue.typeName.name %>' <% } } -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/lib/One.ejs ================================================ <%- include('Two') %><% -%> ================================================ FILE: SourceryTests/Stub/JavaScriptTemplates/lib/Two.ejs ================================================ <%- include('../Equality') %><% -%> ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Admin/AdminCardTestingViewController.swift ================================================ import Foundation import RxSwift import Keys class AdminCardTestingViewController: UIViewController { lazy var keys = EidolonKeys() var cardHandler: CardHandler! @IBOutlet weak var logTextView: UITextView! override func viewDidLoad() { super.viewDidLoad() self.logTextView.text = "" if AppSetup.sharedState.useStaging { cardHandler = CardHandler(apiKey: self.keys.cardflightStagingAPIClientKey(), accountToken: self.keys.cardflightStagingMerchantAccountToken()) } else { cardHandler = CardHandler(apiKey: self.keys.cardflightProductionAPIClientKey(), accountToken: self.keys.cardflightProductionMerchantAccountToken()) } cardHandler.cardStatus .subscribe { (event) in switch event { case .next(let message): self.log("\(message)") case .error(let error): self.log("\n====Error====\n\(error)\nThe card reader may have become disconnected.\n\n") if self.cardHandler.card != nil { self.log("==\n\(self.cardHandler.card!)\n\n") } case .completed: guard let card = self.cardHandler.card else { // Restarts the card reader self.cardHandler.startSearching() return } let cardDetails = "Card: \(card.name) - \(card.last4) \n \(card.cardToken)" self.log(cardDetails) } } .addDisposableTo(rx_disposeBag) cardHandler.startSearching() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) cardHandler.end() } func log(_ string: String) { self.logTextView.text = "\(self.logTextView.text ?? "")\n\(string)" } @IBAction func backTapped(_ sender: AnyObject) { _ = navigationController?.popViewController(animated: true) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Admin/AdminLogViewController.swift ================================================ import UIKit class AdminLogViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() textView.text = try? NSString(contentsOf: logPath(), encoding: String.Encoding.ascii.rawValue) as String } @IBOutlet weak var textView: UITextView! @IBAction func backButtonTapped(_ sender: AnyObject) { _ = self.navigationController?.popViewController(animated: true) } func logPath() -> URL { let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! return docs.appendingPathComponent("logger.txt") } @IBAction func scrollTapped(_ sender: AnyObject) { textView.scrollRangeToVisible(NSMakeRange(textView.text.count - 1, 1)) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Admin/AdminPanelViewController.swift ================================================ import UIKit import Artsy_UILabels class AdminPanelViewController: UIViewController { @IBOutlet weak var auctionIDLabel: UILabel! @IBAction func backTapped(_ sender: AnyObject) { self.presentingViewController?.dismiss(animated: true, completion: nil) appDelegate().setHelpButtonHidden(false) } @IBAction func closeAppTapped(_ sender: AnyObject) { exit(1) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) appDelegate().setHelpButtonHidden(true) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .LoadAdminWebViewController { let webVC = segue.destination as! AuctionWebViewController let auctionID = AppSetup.sharedState.auctionID let base = AppSetup.sharedState.useStaging ? "staging.artsy.net" : "artsy.net" webVC.url = URL(string: "https://\(base)/feature/\(auctionID)")! // TODO: Hide help button } } override func viewDidLoad() { super.viewDidLoad() let state = AppSetup.sharedState if APIKeys.sharedKeys.stubResponses { auctionIDLabel.text = "STUBBING API RESPONSES\nNOT CONTACTING ARTSY API" } else { let version = (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String) ?? "Unknown" auctionIDLabel.text = "\(state.auctionID), Kiosk version: \(version)" } let environment = state.useStaging ? "PRODUCTION" : "STAGING" environmentChangeButton.setTitle("USE \(environment)", for: .normal) let buttonsTitle = state.showDebugButtons ? "HIDE" : "SHOW" showAdminButtonsButton.setTitle(buttonsTitle, for: .normal) let readStatus = state.disableCardReader ? "ENABLE" : "DISABLE" toggleCardReaderButton.setTitle(readStatus, for: .normal) } @IBOutlet weak var environmentChangeButton: UIButton! @IBAction func switchStagingProductionTapped(_ sender: AnyObject) { let defaults = UserDefaults.standard defaults.set(!AppSetup.sharedState.useStaging, forKey: "KioskUseStaging") defaults.removeObject(forKey: XAppToken.DefaultsKeys.TokenKey.rawValue) defaults.removeObject(forKey: XAppToken.DefaultsKeys.TokenExpiry.rawValue) defaults.synchronize() delayToMainThread(1) { exit(1) } } @IBOutlet weak var showAdminButtonsButton: UIButton! @IBAction func toggleAdminButtons(_ sender: UIButton) { let defaults = UserDefaults.standard defaults.set(!AppSetup.sharedState.showDebugButtons, forKey: "KioskShowDebugButtons") defaults.synchronize() delayToMainThread(1) { exit(1) } } @IBOutlet weak var cardReaderLabel: ARSerifLabel! @IBOutlet weak var toggleCardReaderButton: SecondaryActionButton! @IBAction func toggleCardReaderTapped(_ sender: AnyObject) { let defaults = UserDefaults.standard defaults.set(!AppSetup.sharedState.disableCardReader, forKey: "KioskDisableCardReader") defaults.synchronize() delayToMainThread(1) { exit(1) } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Admin/AuctionWebViewController.swift ================================================ import UIKit class AuctionWebViewController: WebViewController { override func viewDidLoad() { super.viewDidLoad() let flexibleSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil) let exitImage = UIImage(named: "toolbar_close") let backwardBarItem = UIBarButtonItem(image: exitImage, style: .plain, target: self, action: #selector(exit)) let allItems = self.toolbarItems! + [flexibleSpace, backwardBarItem] toolbarItems = allItems } func exit() { let passwordVC = PasswordAlertViewController.alertView { [weak self] in _ = self?.navigationController?.popViewController(animated: true) return } self.present(passwordVC, animated: true) {} } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Admin/ChooseAuctionViewController.swift ================================================ import UIKit import ORStackView import FLKAutoLayout import Artsy_UIFonts import Artsy_UIButtons class ChooseAuctionViewController: UIViewController { var auctions: [Sale]! let provider = appDelegate().provider override func viewDidLoad() { super.viewDidLoad() stackScrollView.backgroundColor = .white stackScrollView.bottomMarginHeight = CGFloat(NSNotFound) stackScrollView.updateConstraints() let endpoint: ArtsyAPI = ArtsyAPI.activeAuctions provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(arrayOf: Sale.self) .subscribe(onNext: { activeSales in self.auctions = activeSales for i in 0 ..< self.auctions.count { let sale = self.auctions[i] let title = " \(sale.name) - #\(sale.auctionState) - \(sale.artworkCount)" let button = ARFlatButton() button.setTitle(title, for: .normal) button.setTitleColor(.black, for: .normal) button.tag = i button.rx.tap.subscribe(onNext: { (_) in let defaults = UserDefaults.standard defaults.set(sale.id, forKey: "KioskAuctionID") defaults.synchronize() exit(1) }) .addDisposableTo(self.rx_disposeBag) self.stackScrollView.addSubview(button, withTopMargin: "12", sideMargin: "0") button.constrainHeight("50") } }) .addDisposableTo(rx_disposeBag) } @IBOutlet weak var stackScrollView: ORStackView! @IBAction func backButtonTapped(_ sender: AnyObject) { _ = self.navigationController?.popViewController(animated: true) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Admin/PasswordAlertViewController.swift ================================================ import UIKit class PasswordAlertViewController: UIAlertController { class func alertView(completion: @escaping () -> ()) -> PasswordAlertViewController { let alertController = PasswordAlertViewController(title: "Exit Kiosk", message: nil, preferredStyle: .alert) let exitAction = UIAlertAction(title: "Exit", style: .default) { (_) in completion() return } if detectDevelopmentEnvironment() { exitAction.isEnabled = true } else { exitAction.isEnabled = false } let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in } alertController.addTextField { (textField) in textField.placeholder = "Exit Password" NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextFieldTextDidChange, object: textField, queue: OperationQueue.main) { (notification) in // compiler crashes when using weak exitAction.isEnabled = textField.text == "Genome401" } } alertController.addAction(exitAction) alertController.addAction(cancelAction) return alertController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/APIPingManager.swift ================================================ import Foundation import Moya import RxSwift class APIPingManager { let syncInterval: TimeInterval = 2 var letOnline: Observable! var provider: Networking init(provider: Networking) { self.provider = provider letOnline = Observable.interval(syncInterval, scheduler: MainScheduler.instance) .flatMap { [weak self] _ in return self?.ping() ?? .empty() } .retry() // Retry because ping may fail when disconnected and error. .startWith(true) } fileprivate func ping() -> Observable { return provider.request(ArtsyAPI.ping).map(responseIsOK) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/AppDelegate+GlobalActions.swift ================================================ import UIKit import QuartzCore import ARAnalytics import RxSwift import Action func appDelegate() -> AppDelegate { return UIApplication.shared.delegate as! AppDelegate } extension AppDelegate { // Registration var sale: Sale! { return appViewController!.sale.value } internal var appViewController: AppViewController! { let nav = self.window?.rootViewController?.findChildViewControllerOfType(UINavigationController.self) as? UINavigationController return nav?.delegate as? AppViewController } // Help button and menu func setupHelpButton() { helpButton = MenuButton() helpButton.setTitle("Help", for: .normal) helpButton.rx.action = helpButtonCommand() window?.addSubview(helpButton) helpButton.alignTop(nil, leading: nil, bottom: "-24", trailing: "-24", to: window) window?.layoutIfNeeded() helpIsVisisble.subscribe(onNext: { visisble in let image: UIImage? = visisble ? UIImage(named: "xbtn_white")?.withRenderingMode(.alwaysOriginal) : nil let text: String? = visisble ? nil : "HELP" self.helpButton.setTitle(text, for: .normal) self.helpButton.setImage(image, for: .normal) let transition = CATransition() transition.duration = AnimationDuration.Normal transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) transition.type = kCATransitionFade self.helpButton.layer.add(transition, forKey: "fade") }).addDisposableTo(rx_disposeBag) } func setHelpButtonHidden(_ hidden: Bool) { helpButton.isHidden = hidden } } // MARK: - ReactiveCocoa extensions fileprivate var retainedAction: CocoaAction? extension AppDelegate { // In this extension, I'm omitting [weak self] because the app delegate will outlive everyone. func showBuyersPremiumCommand(enabled: Observable = .just(true)) -> CocoaAction { return CocoaAction(enabledIf: enabled) { _ in self.hideAllTheThings() .then(self.showWebController(address: "https://m.artsy.net/auction/\(self.sale.id)/buyers-premium")) .map(void) } } func registerToBidCommand(enabled: Observable = .just(true)) -> CocoaAction { return CocoaAction(enabledIf: enabled) { _ in self.hideAllTheThings() .then(self.showRegistration()) } } func requestBidderDetailsCommand(enabled: Observable = .just(true)) -> CocoaAction { return CocoaAction(enabledIf: enabled) { _ in self.hideHelp() .then(self.showBidderDetailsRetrieval()) } } func helpButtonCommand() -> CocoaAction { return CocoaAction { _ in let showHelp = self.hideAllTheThings().then(self.showHelp()) return self.helpIsVisisble.take(1).flatMap { (visible: Bool) -> Observable in if visible { return self.hideHelp() } else { return showHelp } } } } /// This is a hack around the fact that the command might dismiss the view controller whose UI owns the command itself. /// So we store the CocoaAction in a variable private to this file to retain it. Once the action is complete, then we /// release our reference to the CocoaAction. This ensures that the action isn't cancelled while it's executing. func ensureAction(action: CocoaAction) -> CocoaAction { retainedAction = action let action = CocoaAction { input -> Observable in return retainedAction? .execute(input) .doOnCompleted { retainedAction = nil } ?? Observable.just(Void()) } return action } func showPrivacyPolicyCommand() -> CocoaAction { return ensureAction(action: CocoaAction { _ in self.hideAllTheThings().then(self.showWebController(address: "https://artsy.net/privacy")) }) } func showConditionsOfSaleCommand() -> CocoaAction { return ensureAction(action: CocoaAction { _ in self.hideAllTheThings().then(self.showWebController(address: "https://artsy.net/conditions-of-sale")) }) } } // MARK: - Private ReactiveCocoa Extension private extension AppDelegate { // MARK: - s that do things func ツ() -> Observable { return hideAllTheThings() } func hideAllTheThings() -> Observable { return self.closeFulfillmentViewController().then(self.hideHelp()) } func showBidderDetailsRetrieval() -> Observable { let appVC = self.appViewController let presentingViewController: UIViewController = (appVC!.presentedViewController ?? appVC!) return presentingViewController.promptForBidderDetailsRetrieval(provider: self.provider) } func showRegistration() -> Observable { return Observable.create { observer in ARAnalytics.event("Register To Bid Tapped") let storyboard = UIStoryboard.fulfillment() let containerController = storyboard.instantiateInitialViewController() as! FulfillmentContainerViewController containerController.allowAnimations = self.appViewController.allowAnimations if let internalNav: FulfillmentNavigationController = containerController.internalNavigationController() { internalNav.auctionID = self.appViewController.auctionID let registerVC = storyboard.viewController(withID: .RegisterAnAccount) as! RegisterViewController registerVC.placingBid = false registerVC.provider = self.provider internalNav.auctionID = self.appViewController.auctionID internalNav.viewControllers = [registerVC] } self.appViewController.present(containerController, animated: false) { containerController.viewDidAppearAnimation(containerController.allowAnimations) sendDispatchCompleted(to: observer) } return Disposables.create() } } func showHelp() -> Observable { return Observable.create { observer in let helpViewController = HelpViewController() helpViewController.modalPresentationStyle = .custom helpViewController.transitioningDelegate = self self.window?.rootViewController?.present(helpViewController, animated: true, completion: { self.helpViewController.value = helpViewController sendDispatchCompleted(to: observer) }) return Disposables.create() } } func closeFulfillmentViewController() -> Observable { let close: Observable = Observable.create { observer in (self.appViewController.presentedViewController as? FulfillmentContainerViewController)?.closeFulfillmentModal() { sendDispatchCompleted(to: observer) } return Disposables.create() } return fullfilmentVisible.flatMap { visible -> Observable in if visible { return close } else { return .empty() } } } func showWebController(address: String) -> Observable { return hideWebViewController().then ( Observable.create { observer in let webController = ModalWebViewController(url: NSURL(string: address)! as URL) let nav = UINavigationController(rootViewController: webController) nav.modalPresentationStyle = .formSheet ARAnalytics.event("Show Web View", withProperties: ["url" : address]) self.window?.rootViewController?.present(nav, animated: true) { sendDispatchCompleted(to: observer) } self.webViewController = nav return Disposables.create() } ) } func hideHelp() -> Observable { return Observable.create { observer in if let presentingViewController = self.helpViewController.value?.presentingViewController { presentingViewController.dismiss(animated: true) { DispatchQueue.main.async { observer.onCompleted() self.helpViewController.value = nil } sendDispatchCompleted(to: observer) } } else { observer.onCompleted() } return Disposables.create() } } func hideWebViewController() -> Observable { return Observable.create { observer in if let webViewController = self.webViewController { webViewController.presentingViewController?.dismiss(animated: true) { sendDispatchCompleted(to: observer) } } else { observer.onCompleted() } return Disposables.create() } } // MARK: - Computed property observables var fullfilmentVisible: Observable { return Observable.deferred { return Observable.create { observer in observer.onNext((self.appViewController.presentedViewController as? FulfillmentContainerViewController) != nil) observer.onCompleted() return Disposables.create() } } } var helpIsVisisble: Observable { return helpViewController.asObservable().map { controller in return controller.hasValue } } } // MARK: - Help transtion animation extension AppDelegate: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return HelpAnimator(presenting: true) } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return HelpAnimator() } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/AppDelegate.swift ================================================ import UIKit import ARAnalytics import SDWebImage import RxSwift import Keys import Stripe @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { let helpViewController = Variable(nil) var helpButton: UIButton! weak var webViewController: UIViewController? var window: UIWindow? = UIWindow(frame:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.height, height: UIScreen.main.bounds.width)) fileprivate(set) var provider = Networking.newDefaultNetworking() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Disable sleep timer UIApplication.shared.isIdleTimerDisabled = true // Set up network layer if StubResponses.stubResponses() { provider = Networking.newStubbingNetworking() } // I couldn't figure how to swizzle this out like we do in objc. if let _ = NSClassFromString("XCTest") { return true } // Clear possible old contents from cache and defaults. let imageCache = SDImageCache.shared() imageCache?.clearDisk() let defaults = UserDefaults.standard defaults.removeObject(forKey: XAppToken.DefaultsKeys.TokenKey.rawValue) defaults.removeObject(forKey: XAppToken.DefaultsKeys.TokenExpiry.rawValue) let auctionStoryboard = UIStoryboard.auction() let appViewController = auctionStoryboard.instantiateInitialViewController() as? AppViewController appViewController?.provider = provider window?.rootViewController = appViewController window?.makeKeyAndVisible() let keys = EidolonKeys() if AppSetup.sharedState.useStaging { Stripe.setDefaultPublishableKey(keys.stripeStagingPublishableKey()) } else { Stripe.setDefaultPublishableKey(keys.stripeProductionPublishableKey()) } // let mixpanelToken = AppSetup.sharedState.useStaging ? keys.mixpanelStagingAPIClientKey() : keys.mixpanelProductionAPIClientKey() ARAnalytics.setup(withAnalytics: [ ARHockeyAppBetaID: keys.hockeyBetaSecret(), ARHockeyAppLiveID: keys.hockeyProductionSecret(), // ARMixpanelToken: mixpanelToken // TODO: Restore mixpanel ]) setupHelpButton() setupUserAgent() logger.log("App Started") ARAnalytics.event("Session Started") return true } func setupUserAgent() { let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String? let build = Bundle.main.infoDictionary?["CFBundleVersion"] as! String? let webView = UIWebView(frame: CGRect.zero) let oldAgent = webView.stringByEvaluatingJavaScript(from: "navigator.userAgent") let agentString = "\(oldAgent) Artsy-Mobile/\(version!) Eigen/\(build!) Kiosk Eidolon" let defaults = UserDefaults.standard let userAgentDict = ["UserAgent": agentString] defaults.register(defaults: userAgentDict) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/AppSetup.swift ================================================ import UIKit class AppSetup { var auctionID = "los-angeles-modern-auctions-march-2015" lazy var useStaging = true lazy var showDebugButtons = false lazy var disableCardReader = false var isTesting = false class var sharedState: AppSetup { struct Static { static let instance = AppSetup() } return Static.instance } init() { let defaults = UserDefaults.standard if let auction = defaults.string(forKey: "KioskAuctionID") { auctionID = auction } useStaging = defaults.bool(forKey: "KioskUseStaging") showDebugButtons = defaults.bool(forKey: "KioskShowDebugButtons") disableCardReader = defaults.bool(forKey: "KioskDisableCardReader") if let _ = NSClassFromString("XCTest") { isTesting = true } } var needsZipCode: Bool { // If we're swiping with the card reaer, we don't need to collect a zip code. return false } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/AppViewController.swift ================================================ import UIKit import RxSwift import Action class AppViewController: UIViewController, UINavigationControllerDelegate { var allowAnimations = true var auctionID = AppSetup.sharedState.auctionID @IBOutlet var countdownManager: ListingsCountdownManager! @IBOutlet var offlineBlockingView: UIView! @IBOutlet weak var registerToBidButton: ActionButton! var provider: Networking! lazy var _apiPinger: APIPingManager = { return APIPingManager(provider: self.provider) }() lazy var reachability: Observable = { [connectedToInternetOrStubbing(), self.apiPinger].combineLatestAnd() }() lazy var apiPinger: Observable = { self._apiPinger.letOnline }() var registerToBidCommand = { () -> CocoaAction in appDelegate().registerToBidCommand() } class func instantiate(from storyboard: UIStoryboard) -> AppViewController { return storyboard.viewController(withID: .AppViewController) as! AppViewController } var sale = Variable(Sale(id: "", name: "", isAuction: true, startDate: Date(), endDate: Date(), artworkCount: 0, state: "")) override func viewDidLoad() { super.viewDidLoad() registerToBidButton.rx.action = registerToBidCommand() countdownManager.setFonts() countdownManager.provider = provider reachability .bindTo(offlineBlockingView.rx_hidden) .addDisposableTo(rx_disposeBag) auctionRequest(provider, auctionID: auctionID) .bindTo(sale) .addDisposableTo(rx_disposeBag) sale .asObservable() .mapToOptional() .bindTo(countdownManager.sale) .addDisposableTo(rx_disposeBag) for controller in childViewControllers { if let nav = controller as? UINavigationController { nav.delegate = self } } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // This is the embed segue guard let navigtionController = segue.destination as? UINavigationController else { return } guard let listingsViewController = navigtionController.topViewController as? ListingsViewController else { return } listingsViewController.provider = provider } deinit { countdownManager.invalidate() } func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { let hide = (viewController as? SaleArtworkZoomViewController != nil) countdownManager.setLabelsHiddenIfSynced(hide) registerToBidButton.isHidden = hide } } extension AppViewController { @IBAction func longPressForAdmin(_ sender: UIGestureRecognizer) { if sender.state != .began { return } let passwordVC = PasswordAlertViewController.alertView { [weak self] in self?.performSegue(.ShowAdminOptions) return } self.present(passwordVC, animated: true) {} } func auctionRequest(_ provider: Networking, auctionID: String) -> Observable { let auctionEndpoint: ArtsyAPI = ArtsyAPI.auctionInfo(auctionID: auctionID) return provider.request(auctionEndpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(object: Sale.self) .logError() .retry() .throttle(1, scheduler: MainScheduler.instance) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/BidderDetailsRetrieval.swift ================================================ import UIKit import RxSwift import SVProgressHUD import Action extension UIViewController { func promptForBidderDetailsRetrieval(provider: Networking) -> Observable { return Observable.deferred { () -> Observable in let alertController = self.emailPromptAlertController(provider: provider) self.present(alertController, animated: true) { } return .empty() } } func retrieveBidderDetails(provider: Networking, email: String) -> Observable { return Observable.just(email) .take(1) .doOnNext { _ in SVProgressHUD.show() } .flatMap { email -> Observable in let endpoint = ArtsyAPI.bidderDetailsNotification(auctionID: appDelegate().appViewController.sale.value.id, identifier: email) return provider.request(endpoint).filterSuccessfulStatusCodes().map(void) } .throttle(1, scheduler: MainScheduler.instance) .doOnNext { _ in SVProgressHUD.dismiss() self.present(UIAlertController.successfulBidderDetailsAlertController(), animated: true, completion: nil) } .doOnError { _ in SVProgressHUD.dismiss() self.present(UIAlertController.failedBidderDetailsAlertController(), animated: true, completion: nil) } } func emailPromptAlertController(provider: Networking) -> UIAlertController { let alertController = UIAlertController(title: "Send Bidder Details", message: "Enter your email address or phone number registered with Artsy and we will send your bidder number and PIN.", preferredStyle: .alert) var ok = UIAlertAction.Action("OK", style: .default) let action = CocoaAction { _ -> Observable in let text = (alertController.textFields?.first)?.text ?? "" return self.retrieveBidderDetails(provider: provider, email: text) } ok.rx.action = action let cancel = UIAlertAction.Action("Cancel", style: .cancel) alertController.addTextField(configurationHandler: nil) alertController.addAction(ok) alertController.addAction(cancel) return alertController } } extension UIAlertController { class func successfulBidderDetailsAlertController() -> UIAlertController { let alertController = self.init(title: "Your details have been sent", message: nil, preferredStyle: .alert) alertController.addAction(UIAlertAction.Action("OK", style: .default)) return alertController } class func failedBidderDetailsAlertController() -> UIAlertController { let alertController = self.init(title: "Incorrect Email", message: "Email was not recognized. You may not be registered to bid yet.", preferredStyle: .alert) alertController.addAction(UIAlertAction.Action("Cancel", style: .cancel)) var retryAction = UIAlertAction.Action("Retry", style: .default) retryAction.rx.action = appDelegate().requestBidderDetailsCommand() alertController.addAction(retryAction) return alertController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/CardHandler.swift ================================================ import UIKit import RxSwift class CardHandler: NSObject, CFTReaderDelegate { fileprivate let _cardStatus = PublishSubject() var cardStatus: Observable { return _cardStatus.asObservable() } var card: CFTCard? let APIKey: String let APIToken: String var reader: CFTReader! lazy var sessionManager = CFTSessionManager.sharedInstance()! init(apiKey: String, accountToken: String) { APIKey = apiKey APIToken = accountToken super.init() sessionManager.setApiToken(APIKey, accountToken: APIToken) } func startSearching() { sessionManager.setLogging(true) reader = CFTReader(reader: 1) reader.delegate = self reader.swipeHasTimeout(false) _cardStatus.onNext("Started searching") } func end() { reader.cancelTransaction() reader = nil } func readerCardResponse(_ card: CFTCard?, withError error: Error?) { if let card = card { self.card = card _cardStatus.onNext("Got Card") card.tokenizeCard(success: { [weak self] in self?._cardStatus.onCompleted() logger.log("Card was tokenized") }, failure: { [weak self] (error) in self?._cardStatus.onNext("Card Flight Error: \(error)") logger.log("Card was not tokenizable") }) } else if let error = error { self._cardStatus.onNext("response Error \(error)") logger.log("CardReader got a response it cannot handle") reader.beginSwipe() } } func transactionResult(_ charge: CFTCharge!, withError error: Error!) { logger.log("Unexcepted call to transactionResult callback: \(charge)\n\(error)") } // handle other delegate call backs with the status messages func readerIsAttached() { _cardStatus.onNext("Reader is attatched") } func readerIsConnecting() { _cardStatus.onNext("Reader is connecting") } func readerIsDisconnected() { _cardStatus.onNext("Reader is disconnected") logger.log("Card Reader Disconnected") } func readerSwipeDidCancel() { _cardStatus.onNext("Reader did cancel") logger.log("Card Reader was Cancelled") } func readerGenericResponse(_ cardData: String!) { _cardStatus.onNext("Reader received non-card data: \(cardData) ") reader.beginSwipe() } func readerIsConnected(_ isConnected: Bool, withError error: Error!) { if isConnected { _cardStatus.onNext("Reader is connected") reader.beginSwipe() } else { if (error != nil) { _cardStatus.onNext("Reader is disconnected: \(error.localizedDescription)") } else { _cardStatus.onNext("Reader is disconnected") } } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Constants.swift ================================================ import Foundation struct AnimationDuration { static let Normal: TimeInterval = 0.30 static let Short: TimeInterval = 0.15 } let SyncInterval: TimeInterval = 60 let ButtonHeight: CGFloat = 50 ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/GlobalFunctions.swift ================================================ import RxSwift import Reachability import Moya // Ideally a Pod. For now a file. func delayToMainThread(_ delay: Double, closure:@escaping ()->()) { DispatchQueue.main.asyncAfter ( deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure) } func logPath() -> URL { let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! return docs.appendingPathComponent("logger.txt") } let logger = Logger(destination: logPath()) private let reachabilityManager = ReachabilityManager() // An observable that completes when the app gets online (possibly completes immediately). func connectedToInternetOrStubbing() -> Observable { let online = reachabilityManager.reach let stubbing = Observable.just(APIKeys.sharedKeys.stubResponses) return [online, stubbing].combineLatestOr() } func responseIsOK(_ response: Response) -> Bool { return response.statusCode == 200 } func detectDevelopmentEnvironment() -> Bool { var developmentEnvironment = false #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) developmentEnvironment = true #endif return developmentEnvironment } private class ReachabilityManager: NSObject { let _reach = ReplaySubject.create(bufferSize: 1) var reach: Observable { return _reach.asObservable() } fileprivate let reachability = Reachability.forInternetConnection() override init() { super.init() reachability?.reachableBlock = { [weak self] _ in DispatchQueue.main.async { self?._reach.onNext(true) } } reachability?.unreachableBlock = { [weak self] _ in DispatchQueue.main.async { self?._reach.onNext(false) } } reachability?.startNotifier() _reach.onNext(reachability?.isReachable() ?? false) } } func bindingErrorToInterface(_ error: Swift.Error) { let error = "Binding error to UI: \(error)" #if DEBUG fatalError(error) #else print(error) #endif } // Applies an instance method to the instance with an unowned reference. func applyUnowned(_ instance: Type, _ function: @escaping ((Type) -> (Parameters) -> ReturnValue)) -> ((Parameters) -> ReturnValue) { return { [unowned instance] parameters -> ReturnValue in return function(instance)(parameters) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/KioskDateFormatter.h ================================================ #import @interface KioskDateFormatter :NSObject + (NSDate * __nullable)fromString:(NSString * _Nonnull)string; @end ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/KioskDateFormatter.m ================================================ #import "KioskDateFormatter.h" @import ISO8601DateFormatter; @implementation KioskDateFormatter + (NSDate *)fromString:(NSString *)string { ISO8601DateFormatter *formatter = [[ISO8601DateFormatter alloc] init]; return [formatter dateFromString:string]; } @end ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Logger.swift ================================================ import Foundation class Logger { let destination: URL lazy fileprivate var dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale.current formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS" return formatter }() lazy fileprivate var fileHandle: FileHandle? = { let path = self.destination.path FileManager.default.createFile(atPath: path, contents: nil, attributes: nil) do { let fileHandle = try FileHandle(forWritingTo: self.destination) print("Successfully logging to: \(path)") return fileHandle } catch let error as NSError { print("Serious error in logging: could not open path to log file. \(error).") } return nil }() init(destination: URL) { self.destination = destination } deinit { fileHandle?.closeFile() } func log(_ message: String, function: String = #function, file: String = #file, line: Int = #line) { let logMessage = stringRepresentation(message, function: function, file: file, line: line) printToConsole(logMessage) printToDestination(logMessage) } } private extension Logger { func stringRepresentation(_ message: String, function: String, file: String, line: Int) -> String { let dateString = dateFormatter.string(from: Date()) let file = URL(fileURLWithPath: file).lastPathComponent return "\(dateString) [\(file):\(line)] \(function): \(message)\n" } func printToConsole(_ logMessage: String) { print(logMessage) } func printToDestination(_ logMessage: String) { if let data = logMessage.data(using: String.Encoding.utf8) { fileHandle?.write(data) } else { print("Serious error in logging: could not encode logged string into data.") } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/MarkdownParser.swift ================================================ import Foundation import XNGMarkdownParser import Artsy_UIFonts class MarkdownParser: XNGMarkdownParser { override init() { super.init() paragraphFont = UIFont.serifFont(withSize: 16) linkFontName = UIFont.serifItalicFont(withSize: 16).fontName boldFontName = UIFont.serifBoldFont(withSize: 16).fontName italicFontName = UIFont.serifItalicFont(withSize: 16).fontName shouldParseLinks = false let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = 16 topAttributes = [ NSParagraphStyleAttributeName: paragraphStyle, NSForegroundColorAttributeName: UIColor.black ] } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Artist.swift ================================================ import Foundation import SwiftyJSON final class Artist: NSObject, JSONAbleType { let id: String dynamic var name: String let sortableID: String? var blurb: String? init(id: String, name: String, sortableID: String?) { self.id = id self.name = name self.sortableID = sortableID } static func fromJSON(_ json: [String: Any]) -> Artist { let json = JSON(json) let id = json["id"].stringValue let name = json["name"].stringValue let sortableID = json["sortable_id"].string return Artist(id: id, name:name, sortableID:sortableID) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Artwork.swift ================================================ import Foundation import SwiftyJSON final class Artwork: NSObject, JSONAbleType { enum SoldStatus { case notSold case sold static func fromString(_ string: String) -> SoldStatus { switch string.lowercased() { case "sold": return .sold default: return .notSold } } } let id: String let dateString: String dynamic let title: String var titleAndDate: NSAttributedString { return titleAndDateAttributedString(self.title, dateString: self.date) } dynamic let price: String dynamic let date: String dynamic var soldStatus: String dynamic var medium: String? dynamic var dimensions = [String]() dynamic var imageRights: String? dynamic var additionalInfo: String? dynamic var blurb: String? dynamic var artists: [Artist]? dynamic var culturalMarker: String? dynamic var images: [Image]? lazy var defaultImage: Image? = { let defaultImages = self.images?.filter { $0.isDefault } return defaultImages?.first ?? self.images?.first }() init(id: String, dateString: String, title: String, price: String, date: String, sold: String) { self.id = id self.dateString = dateString self.title = title self.price = price self.date = date self.soldStatus = sold } static func fromJSON(_ json: [String: Any]) -> Artwork { let json = JSON(json) let id = json["id"].stringValue let title = json["title"].stringValue let dateString = json["date"].stringValue let price = json["price"].stringValue let date = json["date"].stringValue let sold = json["sold"].stringValue let artwork = Artwork(id: id, dateString: dateString, title: title, price: price, date: date, sold: sold) artwork.additionalInfo = json["additional_information"].string artwork.medium = json["medium"].string artwork.blurb = json["blurb"].string if let artistDictionary = json["artist"].object as? [String: AnyObject] { artwork.artists = [Artist.fromJSON(artistDictionary)] } if let imageDicts = json["images"].object as? Array> { // There's a possibility that image_versions comes back as null from the API, which fromJSON() is allergic to. artwork.images = imageDicts.filter { dict -> Bool in let imageVersions = (dict["image_versions"] as? [String]) ?? [] return imageVersions.count > 0 }.map { return Image.fromJSON($0) } } if let dimensions = json["dimensions"].dictionary { artwork.dimensions = ["in", "cm"].reduce([String](), { (array, key) -> [String] in if let dimension = dimensions[key]?.string { return array + [dimension] } else { return array } }) } return artwork } func updateWithValues(_ newArtwork: Artwork) { // soldStatus is the only value we expect to change at runtime. soldStatus = newArtwork.soldStatus } func sortableArtistID() -> String { return artists?.first?.sortableID ?? "_" } } private func titleAndDateAttributedString(_ title: String, dateString: String) -> NSAttributedString { let workTitle = title.isEmpty ? "Untitled" : title let workFont = UIFont.serifItalicFont(withSize: 16)! let attributedString = NSMutableAttributedString(string: workTitle, attributes: [NSFontAttributeName : workFont]) if dateString.isNotEmpty { let dateFont = UIFont.serifFont(withSize: 16)! let dateString = NSAttributedString(string: ", " + dateString, attributes: [NSFontAttributeName : dateFont]) attributedString.append(dateString) } return attributedString.copy() as! NSAttributedString } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Bid.swift ================================================ import Foundation import SwiftyJSON final class Bid: NSObject, JSONAbleType { let id: String let amountCents: Int init(id: String, amountCents: Int) { self.id = id self.amountCents = amountCents } static func fromJSON(_ json: [String: Any]) -> Bid { let json = JSON(json) let id = json["id"].stringValue let amount = json["amount_cents"].int return Bid(id: id, amountCents: amount!) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Bidder.swift ================================================ import UIKit import SwiftyJSON final class Bidder: NSObject, JSONAbleType { let id: String let saleID: String let createdByAdmin: Bool var pin: String? init(id: String, saleID: String, createdByAdmin: Bool, pin: String?) { self.id = id self.saleID = saleID self.createdByAdmin = createdByAdmin self.pin = pin } static func fromJSON(_ json: [String: Any]) -> Bidder { let json = JSON(json) let id = json["id"].stringValue let saleID = json["sale"]["id"].stringValue let createdByAdmin = json["created_by_admin"].bool ?? false let pin = json["pin"].stringValue return Bidder(id: id, saleID: saleID, createdByAdmin: createdByAdmin, pin: pin) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/BidderPosition.swift ================================================ import Foundation import SwiftyJSON final class BidderPosition: NSObject, JSONAbleType { let id: String let highestBid: Bid? let maxBidAmountCents: Int let processedAt: Date? init(id: String, highestBid: Bid?, maxBidAmountCents: Int, processedAt: Date?) { self.id = id self.highestBid = highestBid self.maxBidAmountCents = maxBidAmountCents self.processedAt = processedAt } static func fromJSON(_ source: [String: Any]) -> BidderPosition { let json = JSON(source) let id = json["id"].stringValue let maxBidAmount = json["max_bid_amount_cents"].intValue let processedAt = KioskDateFormatter.fromString(json["processed_at"].stringValue) var bid: Bid? if let bidDictionary = json["highest_bid"].object as? [String: AnyObject] { bid = Bid.fromJSON(bidDictionary) } return BidderPosition(id: id, highestBid: bid, maxBidAmountCents: maxBidAmount, processedAt: processedAt) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/BuyersPremium.swift ================================================ import UIKit import SwiftyJSON final class BuyersPremium: NSObject, JSONAbleType { let id: String let name: String init(id: String, name: String) { self.id = id self.name = name } static func fromJSON(_ json: [String: Any]) -> BuyersPremium { let json = JSON(json) let id = json["id"].stringValue let name = json["name"].stringValue return BuyersPremium(id: id, name: name) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Card.swift ================================================ import Foundation import SwiftyJSON final class Card: NSObject, JSONAbleType { let id: String let name: String let lastDigits: String let expirationMonth: String let expirationYear: String init(id: String, name: String, lastDigits: String, expirationMonth: String, expirationYear: String) { self.id = id self.name = name self.lastDigits = lastDigits self.expirationMonth = expirationMonth self.expirationYear = expirationYear } static func fromJSON(_ json: [String: Any]) -> Card { let json = JSON(json) let id = json["id"].stringValue let name = json["name"].stringValue let lastDigits = json["last_digits"].stringValue let expirationMonth = json["expiration_month"].stringValue let expirationYear = json["expiration_year"].stringValue return Card(id: id, name: name, lastDigits: lastDigits, expirationMonth: expirationMonth, expirationYear: expirationYear) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/GenericError.swift ================================================ import Foundation import SwiftyJSON final class GenericError: NSObject, JSONAbleType { let detail: [String:AnyObject] let message: String let type: String init(type: String, message: String, detail: [String:AnyObject]) { self.detail = detail self.message = message self.type = type } static func fromJSON(_ json: [String: Any]) -> GenericError { let json = JSON(json) let type = json["type"].stringValue let message = json["message"].stringValue var detailDictionary = json["detail"].object as? [String: AnyObject] detailDictionary = detailDictionary ?? [:] return GenericError(type: type, message: message, detail: detailDictionary!) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Image.swift ================================================ import Foundation import SwiftyJSON final class Image: NSObject, JSONAbleType { let id: String let imageFormatString: String let imageVersions: [String] let imageSize: CGSize let aspectRatio: CGFloat? let baseURL: String let tileSize: Int let maxTiledHeight: Int let maxTiledWidth: Int let maxLevel: Int let isDefault: Bool init(id: String, imageFormatString: String, imageVersions: [String], imageSize: CGSize, aspectRatio: CGFloat?, baseURL: String, tileSize: Int, maxTiledHeight: Int, maxTiledWidth: Int, maxLevel: Int, isDefault: Bool) { self.id = id self.imageFormatString = imageFormatString self.imageVersions = imageVersions self.imageSize = imageSize self.aspectRatio = aspectRatio self.baseURL = baseURL self.tileSize = tileSize self.maxTiledHeight = maxTiledHeight self.maxTiledWidth = maxTiledWidth self.maxLevel = maxLevel self.isDefault = isDefault } static func fromJSON(_ json: [String: Any]) -> Image { let json = JSON(json) let id = json["id"].stringValue let imageFormatString = json["image_url"].stringValue let imageVersions = (json["image_versions"].object as? [String]) ?? [] let imageSize = CGSize(width: json["original_width"].int ?? 1, height: json["original_height"].int ?? 1) let aspectRatio = { () -> CGFloat? in if let aspectRatio = json["aspect_ratio"].float { return CGFloat(aspectRatio) } return nil }() let baseURL = json["tile_base_url"].stringValue let tileSize = json["tile_size"].intValue let maxTiledHeight = json["max_tiled_height"].int ?? 1 let maxTiledWidth = json["max_tiled_width"].int ?? 1 let isDefault = json["is_default"].bool ?? false let dimension = max( maxTiledWidth, maxTiledHeight) let logD = logf( Float(dimension) ) let log2 = Float(logf(2)) let maxLevel = Int( ceilf( logD / log2) ) return Image(id: id, imageFormatString: imageFormatString, imageVersions: imageVersions, imageSize: imageSize, aspectRatio: aspectRatio, baseURL: baseURL, tileSize: tileSize, maxTiledHeight: maxTiledHeight, maxTiledWidth: maxTiledWidth, maxLevel: maxLevel, isDefault: isDefault) } func thumbnailURL() -> URL? { let preferredVersions = { () -> Array in // For very tall images, the "medium" version looks terribad. // In the long-term, we have an issue to fix this for good: https://github.com/artsy/eidolon/issues/396 if ["57be35d7a09a6711ab004fa5", "57be1fb4cd530e65fe000862"].contains(self.id) { return ["large", "larger"] } else { return ["medium", "large", "larger"] } }() return urlFromPreferenceList(preferredVersions) } func fullsizeURL() -> URL? { return urlFromPreferenceList(["larger", "large", "medium"]) } fileprivate func urlFromPreferenceList(_ preferenceList: Array) -> URL? { if let format = preferenceList.filter({ self.imageVersions.contains($0) }).first { let path = NSString(string: self.imageFormatString).replacingOccurrences(of: ":version", with: format) return URL(string: path) } return nil } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/JSONAble.swift ================================================ protocol JSONAbleType { static func fromJSON(_: [String: Any]) -> Self } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Location.swift ================================================ import UIKit import SwiftyJSON final class Location: NSObject, JSONAbleType { let address: String let address2: String let city: String let state: String let stateCode: String var postalCode: String init(address: String, address2: String, city: String, state: String, stateCode: String, postalCode: String) { self.address = address self.address2 = address2 self.city = city self.state = state self.stateCode = stateCode self.postalCode = postalCode } static func fromJSON(_ json: [String: Any]) -> Location { let json = JSON(json) let address = json["address"].stringValue let address2 = json["address_2"].stringValue let city = json["city"].stringValue let state = json["state"].stringValue let stateCode = json["state_code"].stringValue let postalCode = json["postal_code"].stringValue return Location(address: address, address2: address2, city: city, state: state, stateCode: stateCode, postalCode: postalCode) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/Sale.swift ================================================ import UIKit import SwiftyJSON final class Sale: NSObject, JSONAbleType { dynamic let id: String dynamic let isAuction: Bool dynamic let startDate: Date dynamic let endDate: Date dynamic let name: String dynamic var artworkCount: Int dynamic let auctionState: String dynamic var buyersPremium: BuyersPremium? init(id: String, name: String, isAuction: Bool, startDate: Date, endDate: Date, artworkCount: Int, state: String) { self.id = id self.name = name self.isAuction = isAuction self.startDate = startDate self.endDate = endDate self.artworkCount = artworkCount self.auctionState = state } static func fromJSON(_ json: [String: Any]) -> Sale { let json = JSON(json) let id = json["id"].stringValue let isAuction = json["is_auction"].boolValue let startDate = KioskDateFormatter.fromString(json["start_at"].stringValue)! let endDate = KioskDateFormatter.fromString(json["end_at"].stringValue)! let name = json["name"].stringValue let artworkCount = json["eligible_sale_artworks_count"].intValue let state = json["auction_state"].stringValue let sale = Sale(id: id, name:name, isAuction: isAuction, startDate: startDate, endDate: endDate, artworkCount: artworkCount, state: state) if let buyersPremiumDict = json["buyers_premium"].object as? [String: AnyObject] { sale.buyersPremium = BuyersPremium.fromJSON(buyersPremiumDict) } return sale } func isActive(_ systemTime: SystemTime) -> Bool { let now = systemTime.date() return (now as NSDate).earlierDate(startDate) == startDate && (now as NSDate).laterDate(endDate) == endDate } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/SaleArtwork.swift ================================================ import UIKit import SwiftyJSON enum ReserveStatus: String { case ReserveNotMet = "reserve_not_met" case NoReserve = "no_reserve" case ReserveMet = "reserve_met" var reserveNotMet: Bool { return self == .ReserveNotMet } static func initOrDefault (_ rawValue: String?) -> ReserveStatus { return ReserveStatus(rawValue: rawValue ?? "") ?? .NoReserve } } struct SaleNumberFormatter { static let dollarFormatter = createDollarFormatter() } final class SaleArtwork: NSObject, JSONAbleType { let id: String let artwork: Artwork var auctionID: String? var saleHighestBid: Bid? dynamic var bidCount: NSNumber? var userBidderPosition: BidderPosition? var positions: [String]? var openingBidCents: NSNumber? var minimumNextBidCents: NSNumber? dynamic var highestBidCents: NSNumber? var estimateCents: Int? var lowEstimateCents: Int? var highEstimateCents: Int? dynamic var reserveStatus: String? dynamic var lotNumber: NSNumber? init(id: String, artwork: Artwork) { self.id = id self.artwork = artwork } lazy var viewModel: SaleArtworkViewModel = { return SaleArtworkViewModel(saleArtwork: self) }() static func fromJSON(_ json: [String: Any]) -> SaleArtwork { let json = JSON(json) let id = json["id"].stringValue let artworkDict = json["artwork"].object as! [String: AnyObject] let artwork = Artwork.fromJSON(artworkDict) let saleArtwork = SaleArtwork(id: id, artwork: artwork) as SaleArtwork if let highestBidDict = json["highest_bid"].object as? [String: AnyObject] { saleArtwork.saleHighestBid = Bid.fromJSON(highestBidDict) } saleArtwork.auctionID = json["sale_id"].string saleArtwork.openingBidCents = json["opening_bid_cents"].int as NSNumber? saleArtwork.minimumNextBidCents = json["minimum_next_bid_cents"].int as NSNumber? saleArtwork.highestBidCents = json["highest_bid_amount_cents"].int as NSNumber? saleArtwork.estimateCents = json["estimate_cents"].int saleArtwork.lowEstimateCents = json["low_estimate_cents"].int saleArtwork.highEstimateCents = json["high_estimate_cents"].int saleArtwork.bidCount = json["bidder_positions_count"].int as NSNumber? saleArtwork.reserveStatus = json["reserve_status"].string saleArtwork.lotNumber = json["lot_number"].int as NSNumber? return saleArtwork } func updateWithValues(_ newSaleArtwork: SaleArtwork) { saleHighestBid = newSaleArtwork.saleHighestBid auctionID = newSaleArtwork.auctionID openingBidCents = newSaleArtwork.openingBidCents minimumNextBidCents = newSaleArtwork.minimumNextBidCents highestBidCents = newSaleArtwork.highestBidCents estimateCents = newSaleArtwork.estimateCents lowEstimateCents = newSaleArtwork.lowEstimateCents highEstimateCents = newSaleArtwork.highEstimateCents bidCount = newSaleArtwork.bidCount reserveStatus = newSaleArtwork.reserveStatus lotNumber = newSaleArtwork.lotNumber ?? lotNumber artwork.updateWithValues(newSaleArtwork.artwork) } } func createDollarFormatter() -> NumberFormatter { let formatter = NumberFormatter() formatter.numberStyle = NumberFormatter.Style.currency // This is always dollars, so let's make sure that's how it shows up // regardless of locale. formatter.currencyGroupingSeparator = "," formatter.currencySymbol = "$" formatter.maximumFractionDigits = 0 return formatter } func ==(lhs: SaleArtwork, rhs: SaleArtwork) -> Bool { return lhs.id == rhs.id } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/SaleArtworkViewModel.swift ================================================ import Foundation import RxSwift private let kNoBidsString = "" class SaleArtworkViewModel: NSObject { fileprivate let saleArtwork: SaleArtwork init (saleArtwork: SaleArtwork) { self.saleArtwork = saleArtwork } } // Extension for computed properties extension SaleArtworkViewModel { // MARK: Computed values we don't expect to ever change. var estimateString: String { // Default to estimateCents switch (saleArtwork.estimateCents, saleArtwork.lowEstimateCents, saleArtwork.highEstimateCents) { // Default to estimateCents. case (.some(let estimateCents), _, _): let dollars = NumberFormatter.currencyString(forDollarCents: estimateCents as NSNumber!)! return "Estimate: \(dollars)" // Try to extract non-nil low/high estimates. case (_, .some(let lowCents), .some(let highCents)): let lowDollars = NumberFormatter.currencyString(forDollarCents: lowCents as NSNumber!)! let highDollars = NumberFormatter.currencyString(forDollarCents: highCents as NSNumber!)! return "Estimate: \(lowDollars)–\(highDollars)" default: return "" } } var thumbnailURL: URL? { return saleArtwork.artwork.defaultImage?.thumbnailURL() as URL? } var thumbnailAspectRatio: CGFloat? { return saleArtwork.artwork.defaultImage?.aspectRatio } var artistName: String? { return saleArtwork.artwork.artists?.first?.name } var titleAndDateAttributedString: NSAttributedString { return saleArtwork.artwork.titleAndDate } var saleArtworkID: String { return saleArtwork.id } // Observables representing values that change over time. func numberOfBids() -> Observable { return saleArtwork.rx.observe(NSNumber.self, "bidCount").map { optionalBidCount -> String in guard let bidCount = optionalBidCount, bidCount.intValue > 0 else { return kNoBidsString } let suffix = bidCount == 1 ? "" : "s" return "\(bidCount) bid\(suffix) placed" } } // The language used here is very specific – see https://github.com/artsy/eidolon/pull/325#issuecomment-64121996 for details var numberOfBidsWithReserve: Observable { // Ignoring highestBidCents; only there to trigger on bid update. let highestBidString = saleArtwork.rx.observe(NSNumber.self, "highestBidCents").map { "\($0)" } let reserveStatus = saleArtwork.rx.observe(String.self, "reserveStatus").map { input -> String in switch input { case .some(let reserveStatus): return reserveStatus default: return "" } } return Observable.combineLatest([numberOfBids(), reserveStatus, highestBidString]) { strings -> String in let numberOfBidsString = strings[0] let reserveStatus = ReserveStatus.initOrDefault(strings[1]) // if there is no reserve, just return the number of bids string. if reserveStatus == .NoReserve { return numberOfBidsString } else { if numberOfBidsString == kNoBidsString { // If there are no bids, then return only this string. return "This lot has a reserve" } else if reserveStatus == .ReserveNotMet { return "(\(numberOfBidsString), Reserve not met)" } else { // implicitly, reserveStatus is .ReserveMet return "(\(numberOfBidsString), Reserve met)" } } } } func lotNumber() -> Observable { return saleArtwork.rx.observe(NSNumber.self, "lotNumber").map { lotNumber in if let lotNumber = lotNumber as? Int { return "Lot \(lotNumber)" } else { return "" } } } func forSale() -> Observable { return saleArtwork.artwork.rx.observe(String.self, "soldStatus").filterNil().map { status in return Artwork.SoldStatus.fromString(status) == .notSold } } func currentBid(prefix: String = "", missingPrefix: String = "") -> Observable { return saleArtwork.rx.observe(NSNumber.self, "highestBidCents").map { [weak self] highestBidCents in if let currentBidCents = highestBidCents as? Int { let formatted = NumberFormatter.currencyString(forDollarCents: currentBidCents as NSNumber) ?? "" return "\(prefix)\(formatted)" } else { let formatted = NumberFormatter.currencyString(forDollarCents: self?.saleArtwork.openingBidCents ?? 0) ?? "" return "\(missingPrefix)\(formatted)" } } } func currentBidOrOpeningBid() -> Observable { let observables = [ saleArtwork.rx.observe(NSNumber.self, "bidCount"), saleArtwork.rx.observe(NSNumber.self, "openingBidCents"), saleArtwork.rx.observe(NSNumber.self, "highestBidCents") ] return Observable.combineLatest(observables) { numbers -> Int in let bidCount = (numbers[0] ?? 0) as Int let openingBid = numbers[1] as Int? let highestBid = numbers[2] as Int? return (bidCount > 0 ? highestBid : openingBid) ?? 0 }.map(centsToPresentableDollarsString) } func currentBidOrOpeningBidLabel() -> Observable { return saleArtwork.rx.observe(NSNumber.self, "bidCount").map { input in guard let count = input as? Int else { return "" } if count > 0 { return "Current Bid:" } else { return "Opening Bid:" } } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/SystemTime.swift ================================================ import Foundation import RxSwift class SystemTime { var systemTimeInterval: TimeInterval? = nil init () {} func sync(_ provider: Networking) -> Observable { let endpoint: ArtsyAPI = ArtsyAPI.systemTime return provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .doOnNext { [weak self] response in guard let dictionary = response as? NSDictionary else { return } let timestamp: String = (dictionary["iso8601"] as? String) ?? "" if let artsyDate = KioskDateFormatter.fromString(timestamp) { self?.systemTimeInterval = Date().timeIntervalSince(artsyDate) } }.logError().map(void) } func inSync() -> Bool { return systemTimeInterval != nil } func date() -> Date { let now = Date() if let systemTimeInterval = systemTimeInterval { return now.addingTimeInterval(-systemTimeInterval) } else { return now } } func reset() { systemTimeInterval = nil } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Models/User.swift ================================================ import Foundation import SwiftyJSON final class User: NSObject, JSONAbleType { dynamic let id: String dynamic let email: String dynamic let name: String dynamic let paddleNumber: String dynamic let phoneNumber: String dynamic var bidder: Bidder? dynamic var location: Location? init(id: String, email: String, name: String, paddleNumber: String, phoneNumber: String, location: Location?) { self.id = id self.name = name self.paddleNumber = paddleNumber self.email = email self.phoneNumber = phoneNumber self.location = location } static func fromJSON(_ json: [String: Any]) -> User { let json = JSON(json) let id = json["id"].stringValue let name = json["name"].stringValue let email = json["email"].stringValue let paddleNumber = json["paddle_number"].stringValue let phoneNumber = json["phone"].stringValue var location: Location? if let bidDictionary = json["location"].object as? [String: AnyObject] { location = Location.fromJSON(bidDictionary) } return User(id: id, email: email, name: name, paddleNumber: paddleNumber, phoneNumber: phoneNumber, location:location) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/NSErrorExtensions.swift ================================================ import Foundation import Moya extension NSError { func artsyServerError() -> NSString { if let errorJSON = userInfo["data"] as? [String: AnyObject] { let error = GenericError.fromJSON(errorJSON) return "\(error.message) - \(error.detail) + \(error.detail)" as NSString } else if let response = userInfo["data"] as? Response { let stringData = NSString(data: response.data, encoding: String.Encoding.utf8.rawValue) return "Status Code: \(response.statusCode), Data Length: \(response.data.count), String Data: \(stringData)" as NSString } return "\(userInfo)" as NSString } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Networking/APIKeys.swift ================================================ import Foundation import Keys private let minimumKeyLength = 2 // Mark: - API Keys struct APIKeys { let key: String let secret: String // MARK: Shared Keys fileprivate struct SharedKeys { static var instance = APIKeys() } static var sharedKeys: APIKeys { get { return SharedKeys.instance } set (newSharedKeys) { SharedKeys.instance = newSharedKeys } } // MARK: Methods var stubResponses: Bool { return key.count < minimumKeyLength || secret.count < minimumKeyLength } // MARK: Initializers init(key: String, secret: String) { self.key = key self.secret = secret } init(keys: EidolonKeys) { self.init(key: keys.artsyAPIClientKey() ?? "", secret: keys.artsyAPIClientSecret() ?? "") } init() { let keys = EidolonKeys() self.init(keys: keys) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Networking/ArtsyAPI.swift ================================================ import Foundation import RxSwift import Moya import Alamofire protocol ArtsyAPIType { var addXAuth: Bool { get } } enum ArtsyAPI { case xApp case xAuth(email: String, password: String) case trustToken(number: String, auctionPIN: String) case systemTime case ping case artwork(id: String) case artist(id: String) case auctions case auctionListings(id: String, page: Int, pageSize: Int) case auctionInfo(auctionID: String) case auctionInfoForArtwork(auctionID: String, artworkID: String) case findBidderRegistration(auctionID: String, phone: String) case activeAuctions case createUser(email: String, password: String, phone: String, postCode: String, name: String) case bidderDetailsNotification(auctionID: String, identifier: String) case lostPasswordNotification(email: String) case findExistingEmailRegistration(email: String) } enum ArtsyAuthenticatedAPI { case myCreditCards case createPINForBidder(bidderID: String) case registerToBid(auctionID: String) case myBiddersForAuction(auctionID: String) case myBidPositionsForAuctionArtwork(auctionID: String, artworkID: String) case myBidPosition(id: String) case findMyBidderRegistration(auctionID: String) case placeABid(auctionID: String, artworkID: String, maxBidCents: String) case updateMe(email: String, phone: String, postCode: String, name: String) case registerCard(stripeToken: String, swiped: Bool) case me } extension ArtsyAPI : TargetType, ArtsyAPIType { public var task: Task { return .request } var path: String { switch self { case .xApp: return "/api/v1/xapp_token" case .xAuth: return "/oauth2/access_token" case .auctionInfo(let id): return "/api/v1/sale/\(id)" case .auctions: return "/api/v1/sales" case .auctionListings(let id, _, _): return "/api/v1/sale/\(id)/sale_artworks" case .auctionInfoForArtwork(let auctionID, let artworkID): return "/api/v1/sale/\(auctionID)/sale_artwork/\(artworkID)" case .systemTime: return "/api/v1/system/time" case .ping: return "/api/v1/system/ping" case .findBidderRegistration: return "/api/v1/bidder" case .activeAuctions: return "/api/v1/sales" case .createUser: return "/api/v1/user" case .artwork(let id): return "/api/v1/artwork/\(id)" case .artist(let id): return "/api/v1/artist/\(id)" case .trustToken: return "/api/v1/me/trust_token" case .bidderDetailsNotification: return "/api/v1/bidder/bidding_details_notification" case .lostPasswordNotification: return "/api/v1/users/send_reset_password_instructions" case .findExistingEmailRegistration: return "/api/v1/user" } } var base: String { return AppSetup.sharedState.useStaging ? "https://stagingapi.artsy.net" : "https://api.artsy.net" } var baseURL: URL { return URL(string: base)! } var parameters: [String: Any]? { switch self { case .xAuth(let email, let password): return [ "client_id": APIKeys.sharedKeys.key as AnyObject? ?? "" as AnyObject, "client_secret": APIKeys.sharedKeys.secret as AnyObject? ?? "" as AnyObject, "email": email as AnyObject, "password": password as AnyObject, "grant_type": "credentials" as AnyObject ] case .xApp: return ["client_id": APIKeys.sharedKeys.key as AnyObject? ?? "" as AnyObject, "client_secret": APIKeys.sharedKeys.secret as AnyObject? ?? "" as AnyObject] case .auctions: return ["is_auction": "true" as AnyObject] case .trustToken(let number, let auctionID): return ["number": number as AnyObject, "auction_pin": auctionID as AnyObject] case .createUser(let email, let password, let phone, let postCode, let name): return [ "email": email as AnyObject, "password": password as AnyObject, "phone": phone as AnyObject, "name": name as AnyObject, "location": [ "postal_code": postCode ] as AnyObject ] case .bidderDetailsNotification(let auctionID, let identifier): return ["sale_id": auctionID as AnyObject, "identifier": identifier as AnyObject] case .lostPasswordNotification(let email): return ["email": email as AnyObject] case .findExistingEmailRegistration(let email): return ["email": email as AnyObject] case .findBidderRegistration(let auctionID, let phone): return ["sale_id": auctionID as AnyObject, "number": phone as AnyObject] case .auctionListings(_, let page, let pageSize): return ["size": pageSize as AnyObject, "page": page as AnyObject] case .activeAuctions: return ["is_auction": true as AnyObject, "live": true as AnyObject] default: return nil } } var method: Moya.Method { switch self { case .lostPasswordNotification, .createUser: return .post case .findExistingEmailRegistration: return .head case .bidderDetailsNotification: return .put default: return .get } } var sampleData: Data { switch self { case .xApp: return stubbedResponse("XApp") case .xAuth: return stubbedResponse("XAuth") case .trustToken: return stubbedResponse("XAuth") case .auctions: return stubbedResponse("Auctions") case .auctionListings: return stubbedResponse("AuctionListings") case .systemTime: return stubbedResponse("SystemTime") case .activeAuctions: return stubbedResponse("ActiveAuctions") case .createUser: return stubbedResponse("Me") case .artwork: return stubbedResponse("Artwork") case .artist: return stubbedResponse("Artist") case .auctionInfo: return stubbedResponse("AuctionInfo") // This API returns a 302, so stubbed response isn't valid case .findBidderRegistration: return stubbedResponse("Me") case .bidderDetailsNotification: return stubbedResponse("RegisterToBid") case .lostPasswordNotification: return stubbedResponse("ForgotPassword") case .findExistingEmailRegistration: return stubbedResponse("ForgotPassword") case .auctionInfoForArtwork: return stubbedResponse("AuctionInfoForArtwork") case .ping: return stubbedResponse("Ping") } } var addXAuth: Bool { switch self { case .xApp: return false case .xAuth: return false default: return true } } } extension ArtsyAuthenticatedAPI: TargetType, ArtsyAPIType { public var task: Task { return .request } var path: String { switch self { case .registerToBid: return "/api/v1/bidder" case .myCreditCards: return "/api/v1/me/credit_cards" case .createPINForBidder(let bidderID): return "/api/v1/bidder/\(bidderID)/pin" case .me: return "/api/v1/me" case .updateMe: return "/api/v1/me" case .myBiddersForAuction: return "/api/v1/me/bidders" case .myBidPositionsForAuctionArtwork: return "/api/v1/me/bidder_positions" case .myBidPosition(let id): return "/api/v1/me/bidder_position/\(id)" case .findMyBidderRegistration: return "/api/v1/me/bidders" case .placeABid: return "/api/v1/me/bidder_position" case .registerCard: return "/api/v1/me/credit_cards" } } var base: String { return AppSetup.sharedState.useStaging ? "https://stagingapi.artsy.net" : "https://api.artsy.net" } var baseURL: URL { return URL(string: base)! } var parameters: [String: Any]? { switch self { case .registerToBid(let auctionID): return ["sale_id": auctionID as AnyObject] case .myBiddersForAuction(let auctionID): return ["sale_id": auctionID as AnyObject] case .placeABid(let auctionID, let artworkID, let maxBidCents): return [ "sale_id": auctionID as AnyObject, "artwork_id": artworkID as AnyObject, "max_bid_amount_cents": maxBidCents as AnyObject ] case .findMyBidderRegistration(let auctionID): return ["sale_id": auctionID as AnyObject] case .updateMe(let email, let phone, let postCode, let name): return [ "email": email as AnyObject, "phone": phone as AnyObject, "name": name as AnyObject, "location": [ "postal_code": postCode ] ] case .registerCard(let token, let swiped): return ["provider": "stripe" as AnyObject, "token": token as AnyObject, "created_by_trusted_client": swiped as AnyObject] case .myBidPositionsForAuctionArtwork(let auctionID, let artworkID): return ["sale_id": auctionID as AnyObject, "artwork_id": artworkID as AnyObject] default: return nil } } var method: Moya.Method { switch self { case .placeABid, .registerCard, .registerToBid, .createPINForBidder: return .post case .updateMe: return .put default: return .get } } var sampleData: Data { switch self { case .createPINForBidder: return stubbedResponse("CreatePINForBidder") case .myCreditCards: return stubbedResponse("MyCreditCards") case .registerToBid: return stubbedResponse("RegisterToBid") case .myBiddersForAuction: return stubbedResponse("MyBiddersForAuction") case .me: return stubbedResponse("Me") case .updateMe: return stubbedResponse("Me") case .placeABid: return stubbedResponse("CreateABid") case .findMyBidderRegistration: return stubbedResponse("FindMyBidderRegistration") case .registerCard: return stubbedResponse("RegisterCard") case .myBidPositionsForAuctionArtwork: return stubbedResponse("MyBidPositionsForAuctionArtwork") case .myBidPosition: return stubbedResponse("MyBidPosition") } } var addXAuth: Bool { return true } } // MARK: - Provider support func stubbedResponse(_ filename: String) -> Data! { @objc class TestClass: NSObject { } let bundle = Bundle(for: TestClass.self) let path = bundle.path(forResource: filename, ofType: "json") return (try? Data(contentsOf: URL(fileURLWithPath: path!))) } private extension String { var URLEscapedString: String { return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)! } } func url(_ route: TargetType) -> String { return route.baseURL.appendingPathComponent(route.path).absoluteString } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Networking/NetworkLogger.swift ================================================ import Foundation import Moya import Result /// Logs network activity (outgoing requests and incoming responses). class NetworkLogger: PluginType { typealias Comparison = (TargetType) -> Bool let whitelist: Comparison let blacklist: Comparison init(whitelist: @escaping Comparison = { _ -> Bool in return true }, blacklist: @escaping Comparison = { _ -> Bool in return true }) { self.whitelist = whitelist self.blacklist = blacklist } func willSendRequest(_ request: RequestType, target: TargetType) { // If the target is in the blacklist, don't log it. guard blacklist(target) == false else { return } logger.log("Sending request: \(request.request?.url?.absoluteString ?? String())") } func didReceiveResponse(_ result: Result, target: TargetType) { // If the target is in the blacklist, don't log it. guard blacklist(target) == false else { return } switch result { case .success(let response): if 200..<400 ~= (response.statusCode ) && whitelist(target) == false { // If the status code is OK, and if it's not in our whitelist, then don't worry about logging its response body. logger.log("Received response(\(response.statusCode )) from \(response.response?.url?.absoluteString ?? String()).") } case .failure(let error): // Otherwise, log everything. logger.log("Received networking error: \(error)") } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Networking/Networking.swift ================================================ import Foundation import Moya import RxSwift import Alamofire class OnlineProvider: RxMoyaProvider where Target: TargetType { fileprivate let online: Observable init(endpointClosure: @escaping EndpointClosure = MoyaProvider.DefaultEndpointMapping, requestClosure: @escaping RequestClosure = MoyaProvider.DefaultRequestMapping, stubClosure: @escaping StubClosure = MoyaProvider.NeverStub, manager: Manager = RxMoyaProvider.DefaultAlamofireManager(), plugins: [PluginType] = [], trackInflights: Bool = false, online: Observable = connectedToInternetOrStubbing()) { self.online = online super.init(endpointClosure: endpointClosure, requestClosure: requestClosure, stubClosure: stubClosure, manager: manager, plugins: plugins, trackInflights: trackInflights) } override func request(_ token: Target) -> Observable { let actualRequest = super.request(token) return online .ignore(value: false) // Wait until we're online .take(1) // Take 1 to make sure we only invoke the API once. .flatMap { _ in // Turn the online state into a network request return actualRequest } } } protocol NetworkingType { associatedtype T: TargetType, ArtsyAPIType var provider: OnlineProvider { get } } struct Networking: NetworkingType { typealias T = ArtsyAPI let provider: OnlineProvider } struct AuthorizedNetworking: NetworkingType { typealias T = ArtsyAuthenticatedAPI let provider: OnlineProvider } private extension Networking { /// Request to fetch and store new XApp token if the current token is missing or expired. func XAppTokenRequest(_ defaults: UserDefaults) -> Observable { var appToken = XAppToken(defaults: defaults) // If we have a valid token, return it and forgo a request for a fresh one. if appToken.isValid { return Observable.just(appToken.token) } let newTokenRequest = self.provider.request(ArtsyAPI.xApp) .filterSuccessfulStatusCodes() .mapJSON() .map { element -> (token: String?, expiry: String?) in guard let dictionary = element as? NSDictionary else { return (token: nil, expiry: nil) } return (token: dictionary["xapp_token"] as? String, expiry: dictionary["expires_in"] as? String) } .do(onNext: { element in // These two lines set the defaults values injected into appToken appToken.token = element.0 appToken.expiry = KioskDateFormatter.fromString(element.1 ?? "") }) .map { (token, expiry) -> String? in return token } .logError() return newTokenRequest } } // "Public" interfaces extension Networking { /// Request to fetch a given target. Ensures that valid XApp tokens exist before making request func request(_ token: ArtsyAPI, defaults: UserDefaults = UserDefaults.standard) -> Observable { let actualRequest = self.provider.request(token) return self.XAppTokenRequest(defaults).flatMap { _ in actualRequest } } } extension AuthorizedNetworking { func request(_ token: ArtsyAuthenticatedAPI, defaults: UserDefaults = UserDefaults.standard) -> Observable { return self.provider.request(token) } } // Static methods extension NetworkingType { static func newDefaultNetworking() -> Networking { return Networking(provider: newProvider(plugins)) } static func newAuthorizedNetworking(_ xAccessToken: String) -> AuthorizedNetworking { return AuthorizedNetworking(provider: newProvider(authenticatedPlugins, xAccessToken: xAccessToken)) } static func newStubbingNetworking() -> Networking { return Networking(provider: OnlineProvider(endpointClosure: endpointsClosure(), requestClosure: Networking.endpointResolver(), stubClosure: MoyaProvider.ImmediatelyStub, online: .just(true))) } static func newAuthorizedStubbingNetworking() -> AuthorizedNetworking { return AuthorizedNetworking(provider: OnlineProvider(endpointClosure: endpointsClosure(), requestClosure: Networking.endpointResolver(), stubClosure: MoyaProvider.ImmediatelyStub, online: .just(true))) } static func endpointsClosure(_ xAccessToken: String? = nil) -> (T) -> Endpoint where T: TargetType, T: ArtsyAPIType { return { target in var endpoint: Endpoint = Endpoint(URL: url(target), sampleResponseClosure: {.networkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters) // If we were given an xAccessToken, add it if let xAccessToken = xAccessToken { endpoint = endpoint.adding(httpHeaderFields: ["X-Access-Token": xAccessToken]) } // Sign all non-XApp, non-XAuth token requests if target.addXAuth { return endpoint.adding(httpHeaderFields:["X-Xapp-Token": XAppToken().token ?? ""]) } else { return endpoint } } } static func APIKeysBasedStubBehaviour(_: T) -> Moya.StubBehavior { return APIKeys.sharedKeys.stubResponses ? .immediate : .never } static var plugins: [PluginType] { return [ NetworkLogger(blacklist: { target -> Bool in guard let target = target as? ArtsyAPI else { return false } switch target { case .ping: return true default: return false } }) ] } static var authenticatedPlugins: [PluginType] { return [NetworkLogger(whitelist: { target -> Bool in guard let target = target as? ArtsyAuthenticatedAPI else { return false } switch target { case .myBidPosition: return true case .findMyBidderRegistration: return true default: return false } }) ] } // (Endpoint, NSURLRequest -> Void) -> Void static func endpointResolver() -> MoyaProvider.RequestClosure where T: TargetType { return { (endpoint, closure) in var request = endpoint.urlRequest! request.httpShouldHandleCookies = false closure(.success(request)) } } } private func newProvider(_ plugins: [PluginType], xAccessToken: String? = nil) -> OnlineProvider where T: TargetType, T: ArtsyAPIType { return OnlineProvider(endpointClosure: Networking.endpointsClosure(xAccessToken), requestClosure: Networking.endpointResolver(), stubClosure: Networking.APIKeysBasedStubBehaviour, plugins: plugins) } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Networking/UserCredentials.swift ================================================ import Foundation struct UserCredentials { let user: User let accessToken: String init(user: User, accessToken: String) { self.user = user self.accessToken = accessToken } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Networking/XAppToken.swift ================================================ import Foundation private extension Date { var isInPast: Bool { let now = Date() return self.compare(now) == ComparisonResult.orderedAscending } } struct XAppToken { enum DefaultsKeys: String { case TokenKey = "TokenKey" case TokenExpiry = "TokenExpiry" } // MARK: - Initializers let defaults: UserDefaults init(defaults: UserDefaults) { self.defaults = defaults } init() { self.defaults = UserDefaults.standard } // MARK: - Properties var token: String? { get { let key = defaults.string(forKey: DefaultsKeys.TokenKey.rawValue) return key } set(newToken) { defaults.set(newToken, forKey: DefaultsKeys.TokenKey.rawValue) } } var expiry: Date? { get { return defaults.object(forKey: DefaultsKeys.TokenExpiry.rawValue) as? Date } set(newExpiry) { defaults.set(newExpiry, forKey: DefaultsKeys.TokenExpiry.rawValue) } } var expired: Bool { if let expiry = expiry { return expiry.isInPast } return true } var isValid: Bool { if let token = token { return token.isNotEmpty && !expired } return false } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/OfflineViewController.swift ================================================ import UIKit import Artsy_UIFonts class OfflineViewController: UIViewController { @IBOutlet var offlineLabel: UILabel! @IBOutlet var subtitleLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() offlineLabel.font = UIFont.serifFont(withSize: 49) subtitleLabel.font = UIFont.serifItalicFont(withSize: 32) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/STPCard+Validation.h ================================================ #import #import @interface STPCard (Validation) + (BOOL)validateCardNumber:(NSString *)cardNumber; @end ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/STPCard+Validation.m ================================================ #import "STPCard+Validation.h" @implementation STPCard (Validation) + (BOOL)validateCardNumber:(NSString *)cardNumber { STPCard *card = [[STPCard alloc] init]; card.number = cardNumber; __autoreleasing NSString *cardNumberCopy = [cardNumber copy]; return [card validateNumber:&cardNumberCopy error:nil]; } @end ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/StubResponses.h ================================================ #import @interface StubResponses : NSObject + (BOOL)stubResponses; @end ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/StubResponses.m ================================================ #import "StubResponses.h" #define STUB_RESPONSES YES // We're inferring if you have access to the private Artsy fonts, then you have access to our API. #if __has_include() #undef STUB_RESPONSES #define STUB_RESPONSES NO #endif @implementation StubResponses + (BOOL)stubResponses { return STUB_RESPONSES; } @end ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/SwiftExtensions.swift ================================================ extension Optional { var hasValue: Bool { switch self { case .none: return false case .some(_): return true } } } extension String { func toUInt() -> UInt? { return UInt(self) } func toUInt(withDefault defaultValue: UInt) -> UInt { return UInt(self) ?? defaultValue } } // Anything that can hold a value (strings, arrays, etc) protocol Occupiable { var isEmpty: Bool { get } var isNotEmpty: Bool { get } } // Give a default implementation of isNotEmpty, so conformance only requires one implementation extension Occupiable { var isNotEmpty: Bool { return !isEmpty } } extension String: Occupiable { } // I can't think of a way to combine these collection types. Suggestions welcome. extension Array: Occupiable { } extension Dictionary: Occupiable { } extension Set: Occupiable { } // Extend the idea of occupiability to optionals. Specifically, optionals wrapping occupiable things. extension Optional where Wrapped: Occupiable { var isNilOrEmpty: Bool { switch self { case .none: return true case .some(let value): return value.isEmpty } } var isNotNilNotEmpty: Bool { return !isNilOrEmpty } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/UIStoryboardSegueExtensions.swift ================================================ import UIKit extension UIStoryboardSegue { } func ==(lhs: UIStoryboardSegue, rhs: SegueIdentifier) -> Bool { return lhs.identifier == rhs.rawValue } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/UIViewControllerExtensions.swift ================================================ import UIKit extension UIViewController { /// Short hand syntax for loading the view controller func loadViewProgrammatically() { self.beginAppearanceTransition(true, animated: false) self.endAppearanceTransition() } /// Short hand syntax for performing a segue with a known hardcoded identity func performSegue(_ identifier: SegueIdentifier) { self.performSegue(withIdentifier: identifier.rawValue, sender: self) } func fulfillmentNav() -> FulfillmentNavigationController { return (navigationController! as! FulfillmentNavigationController) } func fulfillmentContainer() -> FulfillmentContainerViewController? { return fulfillmentNav().parent as? FulfillmentContainerViewController } func findChildViewControllerOfType(_ klass: AnyClass) -> UIViewController? { for child in childViewControllers { if child.isKind(of: klass) { return child } } return nil } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/UIViewSubclassesErrorExtensions.swift ================================================ import UIKit extension Button { func flashError(_ message: String) { let originalTitle = self.title(for: .normal) setTitleColor(.white, for: .disabled) setBackgroundColor(.artsyRedRegular(), for: .disabled, animated: true) setBorderColor(.artsyRedRegular(), for: .disabled, animated: true) setTitle(message.uppercased(), for: .disabled) delayToMainThread(2) { self.setTitleColor(.artsyGrayMedium(), for: .disabled) self.setBackgroundColor(.white, for: .disabled, animated: true) self.setTitle(originalTitle, for: .disabled) self.setBorderColor(.artsyGrayMedium(), for: .disabled, animated: true) } } } extension TextField { func flashForError() { self.setBorderColor(.artsyRedRegular()) delayToMainThread(2) { self.setBorderColor(.artsyPurpleRegular()) } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/Button Subclasses/Button.swift ================================================ import UIKit import QuartzCore import Artsy_UIButtons class Button: ARFlatButton { override func setup() { super.setup() setTitleShadowColor(UIColor.clear, for: .normal) setTitleShadowColor(UIColor.clear, for: .highlighted) setTitleShadowColor(UIColor.clear, for: .disabled) shouldDimWhenDisabled = false } } class ActionButton: Button { override var intrinsicContentSize: CGSize { return CGSize(width: UIViewNoIntrinsicMetric, height: ButtonHeight) } override func setup() { super.setup() setBorderColor(.black, for: .normal, animated: false) setBorderColor(.artsyPurpleRegular(), for: .highlighted, animated: false) setBorderColor(.artsyGraySemibold(), for: .disabled, animated: false) setBackgroundColor(.black, for: .normal, animated: false) setBackgroundColor(.artsyPurpleRegular(), for: .highlighted, animated: false) setBackgroundColor(.white, for: .disabled, animated: false) setTitleColor(.white, for: .normal) setTitleColor(.white, for: .highlighted) setTitleColor(.artsyGraySemibold(), for: .disabled) } } class SecondaryActionButton: Button { override var intrinsicContentSize: CGSize { return CGSize(width: UIViewNoIntrinsicMetric, height: ButtonHeight) } override func setup() { super.setup() setBorderColor(.artsyGrayMedium(), for: .normal, animated: false) setBorderColor(.artsyPurpleRegular(), for: .highlighted, animated: false) setBorderColor(.artsyGrayLight(), for: .disabled, animated: false) setBackgroundColor(.white, for: .normal, animated: false) setBackgroundColor(.artsyPurpleRegular(), for: .highlighted, animated: false) setBackgroundColor(.white, for: .disabled, animated: false) setTitleColor(.black, for:.normal) setTitleColor(.white, for:.highlighted) setTitleColor(.artsyGrayBold(), for:.disabled) } } class CancelModalButton: Button { override func setup() { super.setup() setBorderColor(.clear, for: .normal, animated: false) setBorderColor(.clear, for: .highlighted, animated: false) setBorderColor(.clear, for: .disabled, animated: false) } } class KeypadButton: Button { override func setup() { super.setup() shouldAnimateStateChange = false layer.borderWidth = 0 setBackgroundColor(.black, for: .highlighted, animated: false) setBackgroundColor(.white, for: .normal, animated: false) } } class LargeKeypadButton: KeypadButton { override func setup() { super.setup() self.titleLabel!.font = UIFont.sansSerifFont(withSize: 20) } } class MenuButton: ARMenuButton { override func setup() { super.setup() if let titleLabel = titleLabel { titleLabel.font = titleLabel.font.withSize(12) } } override func layoutSubviews() { super.layoutSubviews() if let titleLabel = titleLabel { self.bringSubview(toFront: titleLabel) } if let imageView = imageView { self.bringSubview(toFront: imageView) } } override var intrinsicContentSize: CGSize { return CGSize(width: 45, height: 45) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/RegisterFlowView.swift ================================================ import UIKit import ORStackView import RxSwift class RegisterFlowView: ORStackView { let highlightedIndex = Variable(0) lazy var appSetup: AppSetup = .sharedState var details: BidDetails? { didSet { update() } } override func awakeFromNib() { super.awakeFromNib() backgroundColor = .white bottomMarginHeight = CGFloat(NSNotFound) updateConstraints() } fileprivate struct SubViewParams { let title: String let getters: Array<(NewUser) -> String?> } fileprivate lazy var subViewParams: Array = { return [ [SubViewParams(title: "Mobile", getters: [ { $0.phoneNumber.value }])], [SubViewParams(title: "Email", getters: [ { $0.email.value }])], [SubViewParams(title: "Postal/Zip", getters: [ { $0.zipCode.value }])].filter { _ in self.appSetup.needsZipCode }, [SubViewParams(title: "Credit Card", getters: [ { $0.creditCardName.value }, { $0.creditCardType.value }])] ].flatMap {$0} }() func update() { let user = details!.newUser removeAllSubviews() for (i, subViewParam) in subViewParams.enumerated() { let itemView = ItemView(frame: bounds) itemView.createTitleViewWithTitle(subViewParam.title) addSubview(itemView, withTopMargin: "10", sideMargin: "0") if let value = (subViewParam.getters.flatMap { $0(user) }.first) { itemView.createInfoLabel(value) let button = itemView.createJumpToButtonAtIndex(i) button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside) itemView.constrainHeight("44") } else { itemView.constrainHeight("20") } if i == highlightedIndex.value { itemView.highlight() } } let spacer = UIView(frame: bounds) spacer.setContentHuggingPriority(12, for: .horizontal) addSubview(spacer, withTopMargin: "0", sideMargin: "0") bottomMarginHeight = 0 } func pressed(_ sender: UIButton!) { highlightedIndex.value = sender.tag } class ItemView: UIView { var titleLabel: UILabel? func highlight() { titleLabel?.textColor = .artsyPurpleRegular() } func createTitleViewWithTitle(_ title: String) { let label = UILabel(frame: bounds) label.font = UIFont.sansSerifFont(withSize: 16) label.text = title.uppercased() titleLabel = label addSubview(label) label.constrainWidth(to: self, predicate: "0") label.alignLeadingEdge(with: self, predicate: "0") label.alignTopEdge(with: self, predicate: "0") } func createInfoLabel(_ info: String) { let label = UILabel(frame: bounds) label.font = UIFont.serifFont(withSize: 16) label.text = info addSubview(label) label.constrainWidth(to: self, predicate: "-52") label.alignLeadingEdge(with: self, predicate: "0") label.constrainTopSpace(to: titleLabel!, predicate: "8") } func createJumpToButtonAtIndex(_ index: NSInteger) -> UIButton { let button = UIButton(type: .custom) button.tag = index button.setImage(UIImage(named: "edit_button"), for: .normal) button.isUserInteractionEnabled = true button.isEnabled = true addSubview(button) button.alignTopEdge(with: self, predicate: "0") button.alignTrailingEdge(with: self, predicate: "0") button.constrainWidth("36") button.constrainHeight("36") return button } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/SimulatorOnlyView.swift ================================================ import UIKit class DeveloperOnlyView: UIView { override func awakeFromNib() { // Show only if we're supposed to show AND we're on staging. self.isHidden = !(AppSetup.sharedState.showDebugButtons && AppSetup.sharedState.useStaging) if let _ = NSClassFromString("XCTest") { // We are running in a test. self.isHidden = true self.alpha = 0 } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/Spinner.swift ================================================ import UIKit class Spinner: UIView { var spinner: UIView! let rotationDuration = 0.9 func createSpinner() -> UIView { let view = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 5)) view.backgroundColor = .black return view } override func awakeFromNib() { spinner = createSpinner() addSubview(spinner) backgroundColor = .clear animateN(Float.infinity) } override func layoutSubviews() { // .center uses frame spinner.center = CGPoint( x: bounds.width / 2, y: bounds.height / 2) } func animateN(_ times: Float) { let transformOffset = -1.01 * M_PI let transform = CATransform3DMakeRotation( CGFloat(transformOffset), 0, 0, 1) let rotationAnimation = CABasicAnimation(keyPath:"transform") rotationAnimation.toValue = NSValue(caTransform3D:transform) rotationAnimation.duration = rotationDuration rotationAnimation.isCumulative = true rotationAnimation.repeatCount = Float(times) layer.add(rotationAnimation, forKey:"spin") } func animate(_ animate: Bool) { let isAnimating = layer.animation(forKey: "spin") != nil if (isAnimating && !animate) { layer.removeAllAnimations() } else if (!isAnimating && animate) { self.animateN(Float.infinity) } } func stopAnimating() { layer.removeAllAnimations() animateN(1) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/SwitchView.swift ================================================ import UIKit import RxSwift let SwitchViewBorderWidth: CGFloat = 2 class SwitchView: UIView { fileprivate var _selectedIndex = Variable(0) var selectedIndex: Observable { return _selectedIndex.asObservable() } var shouldAnimate = true var animationDuration: TimeInterval = AnimationDuration.Short fileprivate let buttons: Array fileprivate let selectionIndicator: UIView fileprivate let topSelectionIndicator: UIView fileprivate let bottomSelectionIndicator: UIView fileprivate let topBar = CALayer() fileprivate let bottomBar = CALayer() var selectionConstraint: NSLayoutConstraint! init(buttonTitles: Array) { buttons = buttonTitles.map { (buttonTitle: String) -> UIButton in let button = UIButton(type: .custom) button.setTitle(buttonTitle, for: .normal) button.setTitle(buttonTitle, for: .disabled) if let titleLabel = button.titleLabel { titleLabel.font = UIFont.sansSerifFont(withSize: 13) titleLabel.backgroundColor = .white titleLabel.isOpaque = true } button.backgroundColor = .white button.setTitleColor(.black, for: .disabled) button.setTitleColor(.black, for: .selected) button.setTitleColor(.artsyGrayMedium(), for: .normal) return button } selectionIndicator = UIView() topSelectionIndicator = UIView() bottomSelectionIndicator = UIView() super.init(frame: CGRect.zero) setup() } override func layoutSubviews() { super.layoutSubviews() var rect = CGRect(x: 0, y: 0, width: layer.bounds.width, height: SwitchViewBorderWidth) topBar.frame = rect rect.origin.y = layer.bounds.height - SwitchViewBorderWidth bottomBar.frame = rect } required convenience init(coder aDecoder: NSCoder) { self.init(buttonTitles: []) } override var intrinsicContentSize: CGSize { return CGSize(width: UIViewNoIntrinsicMetric, height: 46) } func selectedButton(_ button: UIButton!) { let index = buttons.index(of: button)! setSelectedIndex(index, animated: shouldAnimate) } subscript(index: Int) -> UIButton? { get { if index >= 0 && index < buttons.count { return buttons[index] } return nil } } } private extension SwitchView { func setup() { if let firstButton = buttons.first { firstButton.isEnabled = false } let widthPredicateMultiplier = "*\(widthMultiplier())" for i in 0 ..< buttons.count { let button = buttons[i] self.addSubview(button) button.addTarget(self, action: #selector(SwitchView.selectedButton(_:)), for: .touchUpInside) button.constrainWidth(to: self, predicate: widthPredicateMultiplier) if (i == 0) { button.alignLeadingEdge(with: self, predicate: nil) } else { button.constrainLeadingSpace(to: buttons[i-1], predicate: nil) } button.alignTop("\(SwitchViewBorderWidth)", bottom: "\(-SwitchViewBorderWidth)", to: self) } topBar.backgroundColor = UIColor.artsyGrayMedium().cgColor bottomBar.backgroundColor = UIColor.artsyGrayMedium().cgColor layer.addSublayer(topBar) layer.addSublayer(bottomBar) selectionIndicator.addSubview(topSelectionIndicator) selectionIndicator.addSubview(bottomSelectionIndicator) topSelectionIndicator.backgroundColor = .black bottomSelectionIndicator.backgroundColor = .black topSelectionIndicator.alignTop("0", leading: "0", bottom: nil, trailing: "0", to: selectionIndicator) bottomSelectionIndicator.alignTop(nil, leading: "0", bottom: "0", trailing: "0", to: selectionIndicator) topSelectionIndicator.constrainHeight("\(SwitchViewBorderWidth)") bottomSelectionIndicator.constrainHeight("\(SwitchViewBorderWidth)") addSubview(selectionIndicator) selectionIndicator.constrainWidth(to: self, predicate: widthPredicateMultiplier) selectionIndicator.alignTop("0", bottom: "0", to: self) selectionConstraint = selectionIndicator.alignLeadingEdge(with: self, predicate: nil).last! as! NSLayoutConstraint } func widthMultiplier() -> Float { return 1.0 / Float(buttons.count) } func setSelectedIndex(_ index: Int) { setSelectedIndex(index, animated: false) } func setSelectedIndex(_ index: Int, animated: Bool) { UIView.animateIf(shouldAnimate && animated, duration: animationDuration, options: .curveEaseOut) { let button = self.buttons[index] self.buttons.forEach { (button: UIButton) in button.isEnabled = true } button.isEnabled = false // Set the x-position of the selection indicator as a fraction of the total width of the switch view according to which button was pressed. let multiplier = CGFloat(index) / CGFloat(self.buttons.count) self.removeConstraint(self.selectionConstraint) // It's illegal to have a multiplier of zero, so if we're at index zero, we .just stick to the left side. if multiplier == 0 { self.selectionConstraint = self.selectionIndicator.alignLeadingEdge(with: self, predicate: nil).last! as! NSLayoutConstraint } else { self.selectionConstraint = NSLayoutConstraint(item: self.selectionIndicator, attribute: .left, relatedBy: .equal, toItem: self, attribute: .right, multiplier: multiplier, constant: 0) } self.addConstraint(self.selectionConstraint) self.layoutIfNeeded() } self._selectedIndex.value = index } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/Text Fields/CursorView.swift ================================================ import UIKit class CursorView: UIView { let cursorLayer: CALayer = CALayer() override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } override func awakeFromNib() { setupCursorLayer() startAnimating() } func setup() { layer.addSublayer(cursorLayer) setupCursorLayer() } func setupCursorLayer() { cursorLayer.frame = CGRect(x: layer.frame.width/2 - 1, y: 0, width: 2, height: layer.frame.height) cursorLayer.backgroundColor = UIColor.black.cgColor cursorLayer.opacity = 0.0 } func startAnimating() { animate(Float.infinity) } fileprivate func animate(_ times: Float) { let fade = CABasicAnimation() fade.duration = 0.5 fade.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) fade.repeatCount = times fade.autoreverses = true fade.fromValue = 0.0 fade.toValue = 1.0 cursorLayer.add(fade, forKey: "opacity") } func stopAnimating() { cursorLayer.removeAllAnimations() } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/App/Views/Text Fields/TextField.swift ================================================ import UIKit class TextField: UITextField { var shouldAnimateStateChange: Bool = true var shouldChangeColorWhenEditing: Bool = true override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } override func awakeFromNib() { super.awakeFromNib() setup() } func setup() { borderStyle = .none layer.cornerRadius = 0 layer.masksToBounds = true layer.borderWidth = 1 tintColor = .black font = UIFont.serifFont(withSize: self.font?.pointSize ?? 26) stateChangedAnimated(false) setupEvents() } func setupEvents () { addTarget(self, action: #selector(TextField.editingDidBegin(_:)), for: .editingDidBegin) addTarget(self, action: #selector(TextField.editingDidFinish(_:)), for: .editingDidEnd) } func editingDidBegin (_ sender: AnyObject) { stateChangedAnimated(shouldAnimateStateChange) } func editingDidFinish(_ sender: AnyObject) { stateChangedAnimated(shouldAnimateStateChange) } func stateChangedAnimated(_ animated: Bool) { let newBorderColor = borderColorForState().cgColor if newBorderColor == layer.borderColor { return } if animated { let fade = CABasicAnimation() if layer.borderColor == nil { layer.borderColor = UIColor.clear.cgColor } fade.fromValue = self.layer.borderColor ?? UIColor.clear.cgColor fade.toValue = newBorderColor fade.duration = AnimationDuration.Short layer.add(fade, forKey: "borderColor") } layer.borderColor = newBorderColor } func borderColorForState() -> UIColor { if isEditing && shouldChangeColorWhenEditing { return .artsyPurpleRegular() } else { return .artsyGrayMedium() } } func setBorderColor(_ color: UIColor) { self.layer.borderColor = color.cgColor } override func textRect(forBounds bounds: CGRect) -> CGRect { return bounds.insetBy(dx: 10, dy: 0 ) } override func editingRect(forBounds bounds: CGRect) -> CGRect { return bounds.insetBy(dx: 10, dy: 0 ) } } class SecureTextField: TextField { var actualText: String = "" override var text: String! { get { if isEditing { return super.text } else { return actualText } } set { super.text=(newValue) } } override func setup() { super.setup() clearsOnBeginEditing = true } override func setupEvents () { super.setupEvents() addTarget(self, action: #selector(SecureTextField.editingDidChange(_:)), for: .editingChanged) } override func editingDidBegin (_ sender: AnyObject) { super.editingDidBegin(sender) isSecureTextEntry = true actualText = text } func editingDidChange(_ sender: AnyObject) { actualText = text } override func editingDidFinish(_ sender: AnyObject) { super.editingDidFinish(sender) isSecureTextEntry = false actualText = text text = dotPlaceholder() } func dotPlaceholder() -> String { var index = 0 let dots = NSMutableString() while (index < text.count) { dots.append("•") index += 1 } return dots as String } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Auction Listings/ListingsCountdownManager.swift ================================================ import UIKit import RxSwift class ListingsCountdownManager: NSObject { @IBOutlet weak var countdownLabel: UILabel! @IBOutlet weak var countdownContainerView: UIView! let formatter = NumberFormatter() let sale = Variable(nil) let time = SystemTime() var provider: Networking! { didSet { time.sync(provider) .dispatchAsyncMainScheduler() .take(1) .subscribe(onNext: { [weak self] (_) in self?.startTimer() self?.setLabelsHidden(false) }) .addDisposableTo(rx_disposeBag) } } fileprivate var _timer: Timer? = nil override func awakeFromNib() { super.awakeFromNib() formatter.minimumIntegerDigits = 2 } /// Immediately invalidates the timer. No further updates will be made to the UI after this method is called. func invalidate() { _timer?.invalidate() } func setFonts() { (countdownContainerView.subviews).forEach { (view) -> () in if let label = view as? UILabel { label.font = UIFont.serifFont(withSize: 15) } } countdownLabel.font = UIFont.sansSerifFont(withSize: 20) } func setLabelsHidden(_ hidden: Bool) { countdownContainerView.isHidden = hidden } func setLabelsHiddenIfSynced(_ hidden: Bool) { if time.inSync() { setLabelsHidden(hidden) } } func hideDenomenatorLabels() { for subview in countdownContainerView.subviews { subview.isHidden = subview != countdownLabel } } func startTimer() { let timer = Timer(timeInterval: 0.49, target: self, selector: #selector(ListingsCountdownManager.tick(_:)), userInfo: nil, repeats: true) RunLoop.main.add(timer, forMode: RunLoopMode.commonModes) _timer = timer self.tick(timer) } func tick(_ timer: Timer) { guard let sale = sale.value else { return } guard time.inSync() else { return } guard sale.id != "" else { return } if sale.isActive(time) { let now = time.date() let components = Calendar.current.dateComponents([.hour, .minute, .second], from: now, to: sale.endDate) self.countdownLabel.text = "\(formatter.string(from: (components.hour ?? 0) as NSNumber)!) : \(formatter.string(from: (components.minute ?? 0) as NSNumber)!) : \(formatter.string(from: (components.second ?? 0) as NSNumber)!)" } else { self.countdownLabel.text = "CLOSED" hideDenomenatorLabels() timer.invalidate() _timer = nil } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Auction Listings/ListingsViewController.swift ================================================ import UIKit import SystemConfiguration import ARAnalytics import RxSwift import ARCollectionViewMasonryLayout import NSObject_Rx let HorizontalMargins = 65 let VerticalMargins = 26 let MasonryCellIdentifier = "MasonryCell" let TableCellIdentifier = "TableCell" class ListingsViewController: UIViewController { var allowAnimations = true var downloadImage: ListingsCollectionViewCell.DownloadImageClosure = { (url, imageView) -> () in if let url = url { imageView.sd_setImage(with: url as URL!) } else { imageView.image = nil } } var cancelDownloadImage: ListingsCollectionViewCell.CancelDownloadImageClosure = { (imageView) -> () in imageView.sd_cancelCurrentImageLoad() } var provider: Networking! lazy var viewModel: ListingsViewModelType = { return ListingsViewModel(provider: self.provider, selectedIndex: self.switchView.selectedIndex, showDetails: applyUnowned(self, ListingsViewController.showDetails), presentModal: applyUnowned(self, ListingsViewController.presentModalForSaleArtwork) ) }() var cellIdentifier = Variable(MasonryCellIdentifier) @IBOutlet var stagingFlag: UIImageView! @IBOutlet var loadingSpinner: Spinner! lazy var collectionView: UICollectionView = { return .listingsCollectionViewWithDelegateDatasource(self) }() lazy var switchView: SwitchView = { return SwitchView(buttonTitles: ListingsViewModel.SwitchValues.allSwitchValueNames()) }() override func viewDidLoad() { super.viewDidLoad() // Set up development environment. if AppSetup.sharedState.isTesting { stagingFlag.isHidden = true } else { if APIKeys.sharedKeys.stubResponses { stagingFlag.image = UIImage(named: "StubbingFlag") } else if detectDevelopmentEnvironment() { let flagImageName = AppSetup.sharedState.useStaging ? "StagingFlag" : "ProductionFlag" stagingFlag.image = UIImage(named: flagImageName) } else { stagingFlag.isHidden = AppSetup.sharedState.useStaging == false } } // Add subviews view.addSubview(switchView) view.insertSubview(collectionView, belowSubview: loadingSpinner) // Set up reactive bindings viewModel .showSpinner .not() .bindTo(loadingSpinner.rx_hidden) .addDisposableTo(rx_disposeBag) // Map switch selection to cell reuse identifier. viewModel .gridSelected .map { gridSelected -> String in if gridSelected { return MasonryCellIdentifier } else { return TableCellIdentifier } } .bindTo(cellIdentifier) .addDisposableTo(rx_disposeBag) // Reload collection view when there is new content. viewModel .updatedContents .mapReplace(with: collectionView) .doOnNext { collectionView in collectionView.reloadData() } .dispatchAsyncMainScheduler() .subscribe(onNext: { [weak self] collectionView in // Make sure we're on screen and not in a test or something. guard let _ = self?.view.window else { return } // Need to dispatchAsyncMainScheduler, since the changes in the CV's model aren't imediate, so we may scroll to a cell that doesn't exist yet. collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: false) }) .addDisposableTo(rx_disposeBag) // Respond to changes in layout, driven by switch selection. viewModel .gridSelected .map { [weak self] gridSelected -> UICollectionViewLayout in switch gridSelected { case true: return ListingsViewController.masonryLayout() default: return ListingsViewController.tableLayout(width: (self?.switchView.frame ?? CGRect.zero).width) } } .subscribe(onNext: { [weak self] layout in // Need to explicitly call animated: false and reload to avoid animation self?.collectionView.setCollectionViewLayout(layout, animated: false) }) .addDisposableTo(rx_disposeBag) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .ShowSaleArtworkDetails { let saleArtwork = sender as! SaleArtwork! let detailsViewController = segue.destination as! SaleArtworkDetailsViewController detailsViewController.saleArtwork = saleArtwork detailsViewController.provider = provider ARAnalytics.event("Show Artwork Details", withProperties: ["id": saleArtwork?.artwork.id]) } } override func viewWillAppear(_ animated: Bool) { let switchHeightPredicate = "\(switchView.intrinsicContentSize.height)" switchView.constrainHeight(switchHeightPredicate) switchView.alignTop("\(64+VerticalMargins)", leading: "\(HorizontalMargins)", bottom: nil, trailing: "-\(HorizontalMargins)", to: view) collectionView.constrainTopSpace(to: switchView, predicate: "0") collectionView.alignTop(nil, leading: "0", bottom: "0", trailing: "0", to: view) collectionView.contentInset = UIEdgeInsets(top: 40, left: 0, bottom: 80, right: 0) } } extension ListingsViewController { class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ListingsViewController { return storyboard.viewController(withID: .AuctionListings) as! ListingsViewController } } // MARK: - Collection View extension ListingsViewController: UICollectionViewDataSource, UICollectionViewDelegate, ARCollectionViewMasonryLayoutDelegate { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return viewModel.numberOfSaleArtworks } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier.value, for: indexPath) if let listingsCell = cell as? ListingsCollectionViewCell { listingsCell.downloadImage = downloadImage listingsCell.cancelDownloadImage = cancelDownloadImage listingsCell.setViewModel(viewModel.saleArtworkViewModel(atIndexPath: indexPath)) let bid = listingsCell.bidPressed.takeUntil(listingsCell.preparingForReuse) let moreInfo = listingsCell.moreInfo.takeUntil(listingsCell.preparingForReuse) bid .subscribe(onNext: { [weak self] _ in self?.viewModel.presentModalForSaleArtwork(atIndexPath: indexPath) }) .addDisposableTo(rx_disposeBag) moreInfo .subscribe(onNext: { [weak self] _ in self?.viewModel.showDetailsForSaleArtwork(atIndexPath: indexPath) }) .addDisposableTo(rx_disposeBag) } return cell } func collectionView(_ collectionView: UICollectionView!, layout collectionViewLayout: ARCollectionViewMasonryLayout!, variableDimensionForItemAt indexPath: IndexPath!) -> CGFloat { let aspectRatio = viewModel.imageAspectRatioForSaleArtwork(atIndexPath: indexPath) let hasEstimate = viewModel.hasEstimateForSaleArtwork(atIndexPath: indexPath) return MasonryCollectionViewCell.heightForCellWithImageAspectRatio(aspectRatio, hasEstimate: hasEstimate) } } // MARK: Private Methods private extension ListingsViewController { func showDetails(forSaleArtwork saleArtwork: SaleArtwork) { ARAnalytics.event("Artwork Details Tapped", withProperties: ["id": saleArtwork.artwork.id]) self.performSegue(withIdentifier: SegueIdentifier.ShowSaleArtworkDetails.rawValue, sender: saleArtwork) } func presentModalForSaleArtwork(_ saleArtwork: SaleArtwork) { bid(auctionID: viewModel.auctionID, saleArtwork: saleArtwork, allowAnimations: self.allowAnimations, provider: provider) } // MARK: Class methods class func masonryLayout() -> ARCollectionViewMasonryLayout { let layout = ARCollectionViewMasonryLayout(direction: .vertical) layout?.itemMargins = CGSize(width: 65, height: 20) layout?.dimensionLength = CGFloat(MasonryCollectionViewCellWidth) layout?.rank = 3 layout?.contentInset = UIEdgeInsetsMake(0.0, 0.0, CGFloat(VerticalMargins), 0.0) return layout! } class func tableLayout(width: CGFloat) -> UICollectionViewFlowLayout { let layout = UICollectionViewFlowLayout() TableCollectionViewCell.Width = width layout.itemSize = CGSize(width: width, height: TableCollectionViewCell.Height) layout.minimumLineSpacing = 0.0 return layout } } // MARK: Collection view setup extension UICollectionView { class func listingsCollectionViewWithDelegateDatasource(_ delegateDatasource: ListingsViewController) -> UICollectionView { let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: ListingsViewController.masonryLayout()) collectionView.backgroundColor = .clear collectionView.dataSource = delegateDatasource collectionView.delegate = delegateDatasource collectionView.alwaysBounceVertical = true collectionView.register(MasonryCollectionViewCell.self, forCellWithReuseIdentifier: MasonryCellIdentifier) collectionView.register(TableCollectionViewCell.self, forCellWithReuseIdentifier: TableCellIdentifier) collectionView.allowsSelection = false return collectionView } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Auction Listings/ListingsViewModel.swift ================================================ import Foundation import RxSwift typealias ShowDetailsClosure = (SaleArtwork) -> Void typealias PresentModalClosure = (SaleArtwork) -> Void protocol ListingsViewModelType { var auctionID: String { get } var syncInterval: TimeInterval { get } var pageSize: Int { get } var logSync: (Date) -> Void { get } var numberOfSaleArtworks: Int { get } var showSpinner: Observable! { get } var gridSelected: Observable! { get } var updatedContents: Observable { get } var scheduleOnBackground: (_ observable: Observable) -> Observable { get } var scheduleOnForeground: (_ observable: Observable<[SaleArtwork]>) -> Observable<[SaleArtwork]> { get } func saleArtworkViewModel(atIndexPath indexPath: IndexPath) -> SaleArtworkViewModel func showDetailsForSaleArtwork(atIndexPath indexPath: IndexPath) func presentModalForSaleArtwork(atIndexPath indexPath: IndexPath) func imageAspectRatioForSaleArtwork(atIndexPath indexPath: IndexPath) -> CGFloat? func hasEstimateForSaleArtwork(atIndexPath indexPath: IndexPath) -> Bool } // Cheating here, should be in the instance but there's only ever one instance, so ¯\_(ツ)_/¯ private let backgroundScheduler = SerialDispatchQueueScheduler(qos: .default) class ListingsViewModel: NSObject, ListingsViewModelType { // These are private to the view model – should not be accessed directly fileprivate var saleArtworks = Variable(Array()) fileprivate var sortedSaleArtworks = Variable>([]) let auctionID: String let pageSize: Int let syncInterval: TimeInterval let logSync: (Date) -> Void var scheduleOnBackground: (_ observable: Observable) -> Observable var scheduleOnForeground: (_ observable: Observable<[SaleArtwork]>) -> Observable<[SaleArtwork]> var numberOfSaleArtworks: Int { return sortedSaleArtworks.value.count } var showSpinner: Observable! var gridSelected: Observable! var updatedContents: Observable { return sortedSaleArtworks .asObservable() .map { $0.count > 0 } .ignore(value: false) .map { _ in NSDate() } } let showDetails: ShowDetailsClosure let presentModal: PresentModalClosure let provider: Networking init(provider: Networking, selectedIndex: Observable, showDetails: @escaping ShowDetailsClosure, presentModal: @escaping PresentModalClosure, pageSize: Int = 10, syncInterval: TimeInterval = SyncInterval, logSync:@escaping (Date) -> Void = ListingsViewModel.DefaultLogging, scheduleOnBackground: @escaping (_ observable: Observable) -> Observable = ListingsViewModel.DefaultScheduler(onBackground: true), scheduleOnForeground: @escaping (_ observable: Observable<[SaleArtwork]>) -> Observable<[SaleArtwork]> = ListingsViewModel.DefaultScheduler(onBackground: false), auctionID: String = AppSetup.sharedState.auctionID) { self.provider = provider self.auctionID = auctionID self.showDetails = showDetails self.presentModal = presentModal self.pageSize = pageSize self.syncInterval = syncInterval self.logSync = logSync self.scheduleOnBackground = scheduleOnBackground self.scheduleOnForeground = scheduleOnForeground super.init() setup(selectedIndex) } // MARK: Private Methods fileprivate func setup(_ selectedIndex: Observable) { recurringListingsRequest() .takeUntil(rx.deallocated) .bindTo(saleArtworks) .addDisposableTo(rx_disposeBag) showSpinner = sortedSaleArtworks.asObservable().map { sortedSaleArtworks in return sortedSaleArtworks.count == 0 } gridSelected = selectedIndex.map { ListingsViewModel.SwitchValues(rawValue: $0) == .some(.grid) } let distinctSaleArtworks = saleArtworks .asObservable() .distinctUntilChanged { (lhs, rhs) -> Bool in return lhs == rhs } .mapReplace(with: 0) // To use in combineLatest, we must have an array of identically-typed observables. Observable.combineLatest([selectedIndex, distinctSaleArtworks]) { ints in // We use distinctSaleArtworks to trigger an update, but ints[1] is unused. return ints[0] } .startWith(0) .map { selectedIndex in return ListingsViewModel.SwitchValues(rawValue: selectedIndex) } .filterNil() .map { [weak self] switchValue -> [SaleArtwork] in guard let me = self else { return [] } return switchValue.sortSaleArtworks(me.saleArtworks.value) } .bindTo(sortedSaleArtworks) .addDisposableTo(rx_disposeBag) } fileprivate func listingsRequest(forPage page: Int) -> Observable { return provider.request(.auctionListings(id: auctionID, page: page, pageSize: self.pageSize)).filterSuccessfulStatusCodes().mapJSON() } // Repeatedly calls itself with page+1 until the count of the returned array is < pageSize. fileprivate func retrieveAllListingsRequest(_ page: Int) -> Observable { return Observable.create { [weak self] observer in guard let me = self else { return Disposables.create() } return me.listingsRequest(forPage: page).subscribe(onNext: { object in guard let array = object as? Array else { return } guard let me = self else { return } // This'll either be the next page request or .empty. let nextPage: Observable // We must have more results to retrieve if array.count >= me.pageSize { nextPage = me.retrieveAllListingsRequest(page+1) } else { nextPage = .empty() } // TODO: Anything with this disposable? _ = Observable.just(object) .concat(nextPage) .subscribe(observer) }) } } // Fetches all pages of the auction fileprivate func allListingsRequest() -> Observable<[SaleArtwork]> { let backgroundJSONParsing = scheduleOnBackground(retrieveAllListingsRequest(1)).reduce([Any]()) { (memo, object) in guard let array = object as? Array else { return memo } return memo + array } .mapTo(arrayOf: SaleArtwork.self) .logServerError(message: "Sale artworks failed to retrieve+parse") .catchErrorJustReturn([]) return scheduleOnForeground(backgroundJSONParsing) } fileprivate func recurringListingsRequest() -> Observable> { let recurring = Observable.interval(syncInterval, scheduler: MainScheduler.instance) .map { _ in Date() } .startWith(Date()) .takeUntil(rx.deallocated) return recurring .doOnNext(logSync) .flatMap { [weak self] _ in return self?.allListingsRequest() ?? .empty() } .map { [weak self] newSaleArtworks -> [SaleArtwork] in guard let me = self else { return [] } let currentSaleArtworks = me.saleArtworks.value // So we want to do here is pretty simple – if the existing and new arrays are of the same length, // then update the individual values in the current array and return the existing value. // If the array's length has changed, then we pass through the new array if newSaleArtworks.count == currentSaleArtworks.count { if update(currentSaleArtworks, newSaleArtworks: newSaleArtworks) { return currentSaleArtworks } } return newSaleArtworks } } // MARK: Private class methods fileprivate class func DefaultLogging(_ date: Date) { #if (arch(i386) || arch(x86_64)) && os(iOS) logger.log("Syncing on \(date)") #endif } fileprivate class func DefaultScheduler(onBackground background: Bool) -> (_ observable: Observable) -> Observable { return { observable in if background { return observable.observeOn(backgroundScheduler) } else { return observable.observeOn(MainScheduler.instance) } } } // MARK: Public methods func saleArtworkViewModel(atIndexPath indexPath: IndexPath) -> SaleArtworkViewModel { return sortedSaleArtworks.value[indexPath.item].viewModel } func imageAspectRatioForSaleArtwork(atIndexPath indexPath: IndexPath) -> CGFloat? { return sortedSaleArtworks.value[indexPath.item].artwork.defaultImage?.aspectRatio } func hasEstimateForSaleArtwork(atIndexPath indexPath: IndexPath) -> Bool { let saleArtwork = sortedSaleArtworks.value[indexPath.item] switch (saleArtwork.estimateCents, saleArtwork.lowEstimateCents, saleArtwork.highEstimateCents) { case (.some, _, _): return true case (_, .some, .some): return true default: return false } } func showDetailsForSaleArtwork(atIndexPath indexPath: IndexPath) { showDetails(sortedSaleArtworks.value[indexPath.item]) } func presentModalForSaleArtwork(atIndexPath indexPath: IndexPath) { presentModal(sortedSaleArtworks.value[indexPath.item]) } // MARK: - Switch Values enum SwitchValues: Int { case grid = 0 case leastBids case mostBids case highestCurrentBid case lowestCurrentBid case alphabetical var name: String { switch self { case .grid: return "Grid" case .leastBids: return "Least Bids" case .mostBids: return "Most Bids" case .highestCurrentBid: return "Highest Bid" case .lowestCurrentBid: return "Lowest Bid" case .alphabetical: return "A–Z" } } func sortSaleArtworks(_ saleArtworks: [SaleArtwork]) -> [SaleArtwork] { switch self { case .grid: return saleArtworks case .leastBids: return saleArtworks.sorted(by: leastBidsSort) case .mostBids: return saleArtworks.sorted(by: mostBidsSort) case .highestCurrentBid: return saleArtworks.sorted(by: highestCurrentBidSort) case .lowestCurrentBid: return saleArtworks.sorted(by: lowestCurrentBidSort) case .alphabetical: return saleArtworks.sorted(by: alphabeticalSort) } } static func allSwitchValues() -> [SwitchValues] { return [grid, leastBids, mostBids, highestCurrentBid, lowestCurrentBid, alphabetical] } static func allSwitchValueNames() -> [String] { return allSwitchValues().map {$0.name.uppercased()} } } } // MARK: - Sorting Functions protocol IntOrZeroable { var intOrZero: Int { get } } extension NSNumber: IntOrZeroable { var intOrZero: Int { return self as Int } } extension Optional where Wrapped: IntOrZeroable { var intOrZero: Int { return self.value?.intOrZero ?? 0 } } func leastBidsSort(_ lhs: SaleArtwork, _ rhs: SaleArtwork) -> Bool { return (lhs.bidCount.intOrZero) < (rhs.bidCount.intOrZero) } func mostBidsSort(_ lhs: SaleArtwork, _ rhs: SaleArtwork) -> Bool { return !leastBidsSort(lhs, rhs) } func lowestCurrentBidSort(_ lhs: SaleArtwork, _ rhs: SaleArtwork) -> Bool { return (lhs.highestBidCents.intOrZero) < (rhs.highestBidCents.intOrZero) } func highestCurrentBidSort(_ lhs: SaleArtwork, _ rhs: SaleArtwork) -> Bool { return !lowestCurrentBidSort(lhs, rhs) } func alphabeticalSort(_ lhs: SaleArtwork, _ rhs: SaleArtwork) -> Bool { return lhs.artwork.sortableArtistID().caseInsensitiveCompare(rhs.artwork.sortableArtistID()) == .orderedAscending } func sortById(_ lhs: SaleArtwork, _ rhs: SaleArtwork) -> Bool { return lhs.id.caseInsensitiveCompare(rhs.id) == .orderedAscending } private func update(_ currentSaleArtworks: [SaleArtwork], newSaleArtworks: [SaleArtwork]) -> Bool { assert(currentSaleArtworks.count == newSaleArtworks.count, "Arrays' counts must be equal.") // Updating the currentSaleArtworks is easy. Both are already sorted as they came from the API (by lot #). // Because we assume that their length is the same, we just do a linear scan through and // copy values from the new to the existing. let saleArtworksCount = currentSaleArtworks.count for i in 0 ..< saleArtworksCount { if currentSaleArtworks[i].id == newSaleArtworks[i].id { currentSaleArtworks[i].updateWithValues(newSaleArtworks[i]) } else { // Failure: the list was the same size but had different artworks. return false } } return true } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Auction Listings/MasonryCollectionViewCell.swift ================================================ import UIKit import RxSwift import ORStackView let MasonryCollectionViewCellWidth: CGFloat = 254 class MasonryCollectionViewCell: ListingsCollectionViewCell { fileprivate lazy var bidView: UIView = { let view = UIView() for subview in [self.currentBidLabel, self.numberOfBidsLabel] { view.addSubview(subview) subview.alignTopEdge(with: view, predicate:"13") subview.alignBottomEdge(with: view, predicate:"0") subview.constrainHeight("18") } self.currentBidLabel.alignLeadingEdge(with: view, predicate: "0") self.numberOfBidsLabel.alignTrailingEdge(with: view, predicate: "0") return view }() private var artworkImageViewHeightConstraint: NSLayoutConstraint? private let stackView = ORTagBasedAutoStackView() override func setup() { super.setup() contentView.constrainWidth("\(MasonryCollectionViewCellWidth)") contentView.addSubview(stackView) stackView.align(to: contentView) let whitespaceGobbler = WhitespaceGobbler() let stackViewSubviews = [artworkImageView, lotNumberLabel, artistNameLabel, artworkTitleLabel, estimateLabel, bidView, bidButton, moreInfoLabel, whitespaceGobbler] for (index, subview) in stackViewSubviews.enumerated() { subview.tag = index } stackView.addSubview(artworkImageView, withTopMargin: "0", sideMargin: "0") stackView.addSubview(lotNumberLabel, withTopMargin: "20", sideMargin: "0") stackView.addSubview(artistNameLabel, withTopMargin: "20", sideMargin: "0") stackView.addSubview(artworkTitleLabel, withTopMargin: "10", sideMargin: "0") stackView.addSubview(estimateLabel, withTopMargin: "10", sideMargin: "0") stackView.addSubview(bidView, withTopMargin: "13", sideMargin: "0") stackView.addSubview(bidButton, withTopMargin: "13", sideMargin: "0") stackView.addSubview(moreInfoLabel, withTopMargin: "0", sideMargin: "0") stackView.addSubview(whitespaceGobbler, withTopMargin: "0", sideMargin: "0") artistNameLabel.constrainHeight("20") artworkTitleLabel.constrainHeight("16") estimateLabel.constrainHeight("16") moreInfoLabel.constrainHeight("44") viewModel.flatMapTo(SaleArtworkViewModel.lotNumber) .map { $0.isNilOrEmpty } .subscribe(onNext: removeLabelWhenEmpty(label: lotNumberLabel, topMargin: "20")) .addDisposableTo(rx_disposeBag) viewModel .map { $0.estimateString } .map { $0.isEmpty } .subscribe(onNext: removeLabelWhenEmpty(label: estimateLabel, topMargin: "10")) .addDisposableTo(rx_disposeBag) viewModel .map { $0.artistName } .map { $0.isNilOrEmpty } .subscribe(onNext: removeLabelWhenEmpty(label: artistNameLabel, topMargin: "20")) .addDisposableTo(rx_disposeBag) // Binds the imageView to always be the correct aspect ratio viewModel.subscribe(onNext: { [weak self] viewModel in if let artworkImageViewHeightConstraint = self?.artworkImageViewHeightConstraint { self?.artworkImageView.removeConstraint(artworkImageViewHeightConstraint) } let imageHeight = heightForImage(withAspectRatio: viewModel.thumbnailAspectRatio) self?.artworkImageViewHeightConstraint = self?.artworkImageView.constrainHeight("\(imageHeight)").first as? NSLayoutConstraint self?.layoutIfNeeded() }) .addDisposableTo(rx_disposeBag) } override func layoutSubviews() { super.layoutSubviews() bidView.drawTopDottedBorder(with: .artsyGrayMedium()) } func removeLabelWhenEmpty(label: UIView, topMargin: String) -> (Bool) -> Void { return { [weak self] isEmpty in guard let `self` = self else { return } if isEmpty { self.stackView.removeSubview(label) } else { self.stackView.addSubview(label, withTopMargin: topMargin, sideMargin: "0") } } } } extension MasonryCollectionViewCell { class func heightForCellWithImageAspectRatio(_ aspectRatio: CGFloat?, hasEstimate: Bool) -> CGFloat { let imageHeight = heightForImage(withAspectRatio: aspectRatio) let estimateHeight = 16 + // estimate 13 // padding let remainingHeight = 20 + // padding 20 + // artist name 10 + // padding 16 + // artwork name 10 + // padding 13 + // padding 16 + // bid 13 + // padding 44 + // more info button 12 // padding return imageHeight + ButtonHeight + CGFloat(remainingHeight) + CGFloat(hasEstimate ? estimateHeight : 0) } } private func heightForImage(withAspectRatio aspectRatio: CGFloat?) -> CGFloat { if let ratio = aspectRatio { if ratio != 0 { return CGFloat(MasonryCollectionViewCellWidth) / ratio } } return CGFloat(MasonryCollectionViewCellWidth) } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Auction Listings/TableCollectionViewCell.swift ================================================ import UIKit import RxCocoa class TableCollectionViewCell: ListingsCollectionViewCell { fileprivate lazy var infoView: UIView = { let view = UIView() view.addSubview(self.lotNumberLabel) view.addSubview(self.artistNameLabel) view.addSubview(self.artworkTitleLabel) self.lotNumberLabel.alignTop("0", bottom: nil, to: view) self.lotNumberLabel.alignLeading("0", trailing: "0", to: view) self.artistNameLabel.alignAttribute(.top, to: .bottom, of: self.lotNumberLabel, predicate: "5") self.artistNameLabel.alignLeading("0", trailing: "0", to: view) self.artworkTitleLabel.alignLeading("0", trailing: "0", to: view) self.artworkTitleLabel.alignAttribute(.top, to: .bottom, of: self.artistNameLabel, predicate: "0") self.artworkTitleLabel.alignTop(nil, bottom: "0", to: view) return view }() fileprivate lazy var cellSubviews: [UIView] = [self.artworkImageView, self.infoView, self.currentBidLabel, self.numberOfBidsLabel, self.bidButton] override func setup() { super.setup() contentView.constrainWidth("\(TableCollectionViewCell.Width)") // Configure subviews numberOfBidsLabel.textAlignment = .center artworkImageView.contentMode = .scaleAspectFill artworkImageView.clipsToBounds = true // Add subviews cellSubviews.forEach { self.contentView.addSubview($0) } // Constrain subviews artworkImageView.alignAttribute(.width, to: .height, of: artworkImageView, predicate: nil) artworkImageView.alignTop("14", leading: "0", bottom: "-14", trailing: nil, to: contentView) artworkImageView.constrainHeight("56") infoView.alignAttribute(.left, to: .right, of: artworkImageView, predicate: "28") infoView.alignCenterY(with: artworkImageView, predicate: "0") infoView.constrainWidth("300") currentBidLabel.alignAttribute(.left, to: .right, of: infoView, predicate: "33") currentBidLabel.alignCenterY(with: artworkImageView, predicate: "0") currentBidLabel.constrainWidth("180") numberOfBidsLabel.alignAttribute(.left, to: .right, of: currentBidLabel, predicate: "33") numberOfBidsLabel.alignCenterY(with: artworkImageView, predicate: "0") numberOfBidsLabel.alignAttribute(.right, to: .left, of: bidButton, predicate: "-33") bidButton.alignBottom(nil, trailing: "0", to: contentView) bidButton.alignCenterY(with: artworkImageView, predicate: "0") bidButton.constrainWidth("127") // Replaces the observable defined in the superclass, normally used to emit taps to a "More Info" label, which we don't have. let recognizer = UITapGestureRecognizer() contentView.addGestureRecognizer(recognizer) self.moreInfo = recognizer.rx.event.map { _ -> Date in return Date() } } override func layoutSubviews() { super.layoutSubviews() contentView.drawBottomSolidBorder(with: .artsyGrayMedium()) } } extension TableCollectionViewCell { fileprivate struct SharedDimensions { var width: CGFloat = 0 var height: CGFloat = 84 static var instance = SharedDimensions() } class var Width: CGFloat { get { return SharedDimensions.instance.width } set (newWidth) { SharedDimensions.instance.width = newWidth } } class var Height: CGFloat { return SharedDimensions.instance.height } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Auction Listings/WebViewController.swift ================================================ import DZNWebViewController let modalHeight: CGFloat = 660 class WebViewController: DZNWebViewController { var showToolbar = true convenience override init(url: URL) { self.init() self.url = url } override func viewDidLoad() { super.viewDidLoad() let webView = view as! UIWebView webView.scalesPageToFit = true self.navigationItem.rightBarButtonItem = nil } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(true, animated:false) navigationController?.setToolbarHidden(!showToolbar, animated:false) } } class ModalWebViewController: WebViewController { var closeButton: UIButton! override func viewDidLoad() { super.viewDidLoad() closeButton = UIButton() view.addSubview(closeButton) closeButton.titleLabel?.font = UIFont.sansSerifFont(withSize: 14) closeButton.setTitleColor(.artsyGrayMedium(), for:.normal) closeButton.setTitle("CLOSE", for:.normal) closeButton.constrainWidth("140", height: "72") closeButton.alignTop("0", leading:"0", bottom:nil, trailing:nil, to:view) closeButton.addTarget(self, action:#selector(closeTapped(_:)), for:.touchUpInside) var height = modalHeight if let nav = navigationController { if !nav.isNavigationBarHidden { height -= nav.navigationBar.frame.height } if !nav.isToolbarHidden { height -= nav.toolbar.frame.height } } preferredContentSize = CGSize(width: 815, height: height) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.view.superview?.layer.cornerRadius = 0 } func closeTapped(_ sender: AnyObject) { presentingViewController?.dismiss(animated: true, completion:nil) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/AdminCCBypassNetworkModel.swift ================================================ import Foundation import RxSwift import Moya enum BypassResult { case requireCC case skipCCRequirement } protocol AdminCCBypassNetworkModelType { func checkForAdminCCBypass(_ saleID: String, authorizedNetworking: AuthorizedNetworking) -> Observable } class AdminCCBypassNetworkModel: AdminCCBypassNetworkModelType { /// Returns an Observable of (Bool, AuthorizedNetworking) /// The Bool represents if the Credit Card requirement should be waived. /// THe AuthorizedNetworking is the same instance that's passed in, which is a convenience for chaining observables. func checkForAdminCCBypass(_ saleID: String, authorizedNetworking: AuthorizedNetworking) -> Observable { return authorizedNetworking .request(ArtsyAuthenticatedAPI.findMyBidderRegistration(auctionID: saleID)) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(arrayOf: Bidder.self) .map { bidders in return bidders.first } .map { bidder -> BypassResult in guard let bidder = bidder else { return .requireCC } switch bidder.createdByAdmin { case true: return .skipCCRequirement case false: return .requireCC } } .logError() } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/BidCheckingNetworkModel.swift ================================================ import UIKit import RxSwift import Moya enum BidCheckingError: String { case PollingExceeded } extension BidCheckingError: Swift.Error { } protocol BidCheckingNetworkModelType { var bidDetails: BidDetails { get } var bidIsResolved: Variable { get } var isHighestBidder: Variable { get } var reserveNotMet: Variable { get } func waitForBidResolution (bidderPositionId: String, provider: AuthorizedNetworking) -> Observable } class BidCheckingNetworkModel: NSObject, BidCheckingNetworkModelType { fileprivate var pollInterval = TimeInterval(1) fileprivate var maxPollRequests = 20 fileprivate var pollRequests = 0 // inputs let provider: Networking let bidDetails: BidDetails // outputs var bidIsResolved = Variable(false) var isHighestBidder = Variable(false) var reserveNotMet = Variable(false) fileprivate var mostRecentSaleArtwork: SaleArtwork? init(provider: Networking, bidDetails: BidDetails) { self.provider = provider self.bidDetails = bidDetails } func waitForBidResolution (bidderPositionId: String, provider: AuthorizedNetworking) -> Observable { return self .poll(forUpdatedBidderPosition: bidderPositionId, provider: provider) .then { return self.getUpdatedSaleArtwork() .flatMap { saleArtwork -> Observable in // This is an updated model – hooray! self.mostRecentSaleArtwork = saleArtwork self.bidDetails.saleArtwork?.updateWithValues(saleArtwork) self.reserveNotMet.value = ReserveStatus.initOrDefault(saleArtwork.reserveStatus).reserveNotMet return .just(Void()) } .doOnError { _ in logger.log("Bidder position was processed but corresponding saleArtwork was not found") } .catchErrorJustReturn() .flatMap { _ -> Observable in return self.checkForMaxBid(provider: provider) } } .doOnNext { _ in self.bidIsResolved.value = true // If polling fails, we can still show bid confirmation. Do not error. }.catchErrorJustReturn() } fileprivate func poll(forUpdatedBidderPosition bidderPositionId: String, provider: AuthorizedNetworking) -> Observable { let updatedBidderPosition = getUpdatedBidderPosition(bidderPositionId: bidderPositionId, provider: provider) .flatMap { bidderPositionObject -> Observable in self.pollRequests += 1 logger.log("Polling \(self.pollRequests) of \(self.maxPollRequests) for updated sale artwork") if let processedAt = bidderPositionObject.processedAt { logger.log("BidPosition finished processing at \(processedAt), proceeding...") return .just(Void()) } else { // The backend hasn't finished processing the bid yet guard self.pollRequests < self.maxPollRequests else { // We have exceeded our max number of polls, fail. throw BidCheckingError.PollingExceeded } // We didn't get an updated value, so let's try again. return Observable.interval(self.pollInterval, scheduler: MainScheduler.instance) .take(1) .map(void) .then { return self.poll(forUpdatedBidderPosition: bidderPositionId, provider: provider) } } } return Observable.interval(pollInterval, scheduler: MainScheduler.instance) .take(1) .map(void) .then { updatedBidderPosition } } fileprivate func checkForMaxBid(provider: AuthorizedNetworking) -> Observable { return getMyBidderPositions(provider: provider) .doOnNext { newBidderPositions in if let topBidID = self.mostRecentSaleArtwork?.saleHighestBid?.id { for position in newBidderPositions where position.highestBid?.id == topBidID { self.isHighestBidder.value = true } } } .map(void) } fileprivate func getMyBidderPositions(provider: AuthorizedNetworking) -> Observable<[BidderPosition]> { let artworkID = bidDetails.saleArtwork!.artwork.id let auctionID = bidDetails.saleArtwork!.auctionID! let endpoint = ArtsyAuthenticatedAPI.myBidPositionsForAuctionArtwork(auctionID: auctionID, artworkID: artworkID) return provider .request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(arrayOf: BidderPosition.self) } fileprivate func getUpdatedSaleArtwork() -> Observable { let artworkID = bidDetails.saleArtwork!.artwork.id let auctionID = bidDetails.saleArtwork!.auctionID! let endpoint: ArtsyAPI = ArtsyAPI.auctionInfoForArtwork(auctionID: auctionID, artworkID: artworkID) return provider .request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(object: SaleArtwork.self) } fileprivate func getUpdatedBidderPosition(bidderPositionId: String, provider: AuthorizedNetworking) -> Observable { let endpoint = ArtsyAuthenticatedAPI.myBidPosition(id: bidderPositionId) return provider .request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(object: BidderPosition.self) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/BidDetailsPreviewView.swift ================================================ import UIKit import Artsy_UILabels import Artsy_UIButtons import UIImageViewAligned import RxSwift import RxCocoa class BidDetailsPreviewView: UIView { let _bidDetails = Variable(nil) var bidDetails: BidDetails? { didSet { self._bidDetails.value = bidDetails } } dynamic let artworkImageView = UIImageViewAligned() dynamic let artistNameLabel = ARSansSerifLabel() dynamic let artworkTitleLabel = ARSerifLabel() dynamic let currentBidPriceLabel = ARSerifLabel() override func awakeFromNib() { self.backgroundColor = .white artistNameLabel.numberOfLines = 1 artworkTitleLabel.numberOfLines = 1 currentBidPriceLabel.numberOfLines = 1 artworkImageView.alignRight = true artworkImageView.alignBottom = true artworkImageView.contentMode = .scaleAspectFit artistNameLabel.font = UIFont.sansSerifFont(withSize: 14) currentBidPriceLabel.font = UIFont.serifBoldFont(withSize: 14) let artwork = _bidDetails .asObservable() .filterNil() .map { bidDetails in return bidDetails.saleArtwork?.artwork } .take(1) artwork .subscribe(onNext: { [weak self] artwork in if let url = artwork?.defaultImage?.thumbnailURL() { self?.bidDetails?.setImage(url, self!.artworkImageView) } else { self?.artworkImageView.image = nil } }) .addDisposableTo(rx_disposeBag) artwork .map { artwork in return artwork?.artists?.first?.name } .map { name in return name ?? "" } .bindTo(artistNameLabel.rx.text) .addDisposableTo(rx_disposeBag) artwork .map { artwork -> NSAttributedString in guard let artwork = artwork else { return NSAttributedString() } return artwork.titleAndDate } .mapToOptional() .bindTo(artworkTitleLabel.rx.attributedText) .addDisposableTo(rx_disposeBag) _bidDetails .asObservable() .filterNil() .take(1) .map { bidDetails in guard let cents = bidDetails.bidAmountCents.value else { return "" } return "Your bid: " + NumberFormatter.currencyString(forDollarCents: cents) } .bindTo(currentBidPriceLabel.rx.text) .addDisposableTo(rx_disposeBag) for subview in [artworkImageView, artistNameLabel, artworkTitleLabel, currentBidPriceLabel] { self.addSubview(subview) } self.constrainHeight("60") artworkImageView.alignTop("0", leading: "0", bottom: "0", trailing: nil, to: self) artworkImageView.constrainWidth("84") artworkImageView.constrainHeight("60") artistNameLabel.alignAttribute(.top, to: .top, of: self, predicate: "0") artistNameLabel.constrainHeight("16") artworkTitleLabel.alignAttribute(.top, to: .bottom, of: artistNameLabel, predicate: "8") artworkTitleLabel.constrainHeight("16") currentBidPriceLabel.alignAttribute(.top, to: .bottom, of: artworkTitleLabel, predicate: "4") currentBidPriceLabel.constrainHeight("16") UIView.alignAttribute(.leading, ofViews: [artistNameLabel, artworkTitleLabel, currentBidPriceLabel], to:.trailing, ofViews: [artworkImageView, artworkImageView, artworkImageView], predicate: "20") UIView.alignAttribute(.trailing, ofViews: [artistNameLabel, artworkTitleLabel, currentBidPriceLabel], to:.trailing, ofViews: [self, self, self], predicate: "0") } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/BidderNetworkModel.swift ================================================ import Foundation import RxSwift import Moya protocol BidderNetworkModelType { var createdNewUser: Observable { get } var bidDetails: BidDetails { get } func createOrGetBidder() -> Observable } class BidderNetworkModel: NSObject, BidderNetworkModelType { let bidDetails: BidDetails let provider: Networking var createdNewUser: Observable { return self.bidDetails.newUser.hasBeenRegistered.asObservable() } init(provider: Networking, bidDetails: BidDetails) { self.provider = provider self.bidDetails = bidDetails } // MARK: - Main observable /// Returns an authorized provider func createOrGetBidder() -> Observable { return createOrUpdateUser() .flatMap { provider -> Observable in return self.createOrUpdateBidder(provider: provider).mapReplace(with: provider) } .flatMap { provider -> Observable in self.getMyPaddleNumber(provider: provider).mapReplace(with: provider) } } } private extension BidderNetworkModel { // MARK: - Chained observables func checkUserEmailExists(_ email: String) -> Observable { let request = provider.request(.findExistingEmailRegistration(email: email)) return request.map { response in return response.statusCode != 404 } } func createOrUpdateUser() -> Observable { // observable to test for user existence (does a user exist with this email?) let bool = self.checkUserEmailExists(bidDetails.newUser.email.value ?? "") // If the user exists, update their info to the API, otherwise create a new user. return bool .flatMap { emailExists -> Observable in if emailExists { return self.updateUser() } else { return self.createNewUser() } } .flatMap { provider -> Observable in self.addCardToUser(provider: provider).mapReplace(with: provider) // After update/create observable finishes, add a CC to their account (if we've collected one) } } func createNewUser() -> Observable { let newUser = bidDetails.newUser let endpoint: ArtsyAPI = ArtsyAPI.createUser(email: newUser.email.value!, password: newUser.password.value!, phone: newUser.phoneNumber.value!, postCode: newUser.zipCode.value ?? "", name: newUser.name.value ?? "") return provider.request(endpoint) .filterSuccessfulStatusCodes() .map(void) .doOnError { error in logger.log("Creating user failed.") logger.log("Error: \((error as NSError).localizedDescription). \n \((error as NSError).artsyServerError())") }.flatMap { _ -> Observable in self.bidDetails.authenticatedNetworking(provider: self.provider) } } func updateUser() -> Observable { let newUser = bidDetails.newUser let endpoint = ArtsyAuthenticatedAPI.updateMe(email: newUser.email.value!, phone: newUser.phoneNumber.value!, postCode: newUser.zipCode.value ?? "", name: newUser.name.value ?? "") return bidDetails.authenticatedNetworking(provider: provider) .flatMap { (provider) -> Observable in provider.request(endpoint) .mapJSON() .logNext() .mapReplace(with: provider) } .logServerError(message: "Updating user failed.") } func addCardToUser(provider: AuthorizedNetworking) -> Observable { // If the user was asked to swipe a card, we'd have stored the token. // If the token is not there, then the user must already have one on file. So we can skip this step. guard let token = bidDetails.newUser.creditCardToken.value else { return .just(Void()) } let swiped = bidDetails.newUser.swipedCreditCard let endpoint = ArtsyAuthenticatedAPI.registerCard(stripeToken: token, swiped: swiped) return provider.request(endpoint) .filterSuccessfulStatusCodes() .map(void) .doOnCompleted { [weak self] in // Adding the credit card succeeded, so we should clear the newUser.creditCardToken so that we don't // inadvertently try to re-add their card token if they need to increase their bid. self?.bidDetails.newUser.creditCardToken.value = nil } .logServerError(message: "Adding Card to User failed") } // MARK: - Auction / Bidder observables func createOrUpdateBidder(provider: AuthorizedNetworking) -> Observable { let bool = self.checkForBidderOnAuction(auctionID: bidDetails.auctionID, provider: provider) return bool.flatMap { exists -> Observable in if exists { return .just(Void()) } else { return self.register(toAuction: self.bidDetails.auctionID, provider: provider).then { [weak self] in self?.generateAPIN(provider: provider) } } } } func checkForBidderOnAuction(auctionID: String, provider: AuthorizedNetworking) -> Observable { let endpoint = ArtsyAuthenticatedAPI.myBiddersForAuction(auctionID: auctionID) let request = provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(arrayOf: Bidder.self) return request.map { [weak self] bidders -> Bool in if let bidder = bidders.first { self?.bidDetails.bidderID.value = bidder.id self?.bidDetails.bidderPIN.value = bidder.pin return true } return false }.logServerError(message: "Getting user bidders failed.") } func register(toAuction auctionID: String, provider: AuthorizedNetworking) -> Observable { let endpoint = ArtsyAuthenticatedAPI.registerToBid(auctionID: auctionID) let register = provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(object: Bidder.self) return register.doOnNext { [weak self] bidder in self?.bidDetails.bidderID.value = bidder.id self?.bidDetails.newUser.hasBeenRegistered.value = true } .logServerError(message: "Registering for Auction Failed.") .map(void) } func generateAPIN(provider: AuthorizedNetworking) -> Observable { let endpoint = ArtsyAuthenticatedAPI.createPINForBidder(bidderID: bidDetails.bidderID.value!) return provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .doOnNext { [weak self] json in let pin = (json as AnyObject)["pin"] as? String self?.bidDetails.bidderPIN.value = pin } .logServerError(message: "Generating a PIN for bidder has failed.") .map(void) } func getMyPaddleNumber(provider: AuthorizedNetworking) -> Observable { let endpoint = ArtsyAuthenticatedAPI.me return provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(object: User.self) .doOnNext { [weak self] user in self?.bidDetails.paddleNumber.value = user.paddleNumber } .logServerError(message: "Getting Bidder ID failed.") .map(void) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ConfirmYourBidArtsyLoginViewController.swift ================================================ import UIKit import Moya import RxSwift import Action class ConfirmYourBidArtsyLoginViewController: UIViewController { @IBOutlet var emailTextField: UITextField! @IBOutlet var passwordTextField: TextField! @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! @IBOutlet var useArtsyBidderButton: UIButton! @IBOutlet var confirmCredentialsButton: Button! fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } var createNewAccount = false var provider: Networking! class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ConfirmYourBidArtsyLoginViewController { return storyboard.viewController(withID: .ConfirmYourBidArtsyLogin) as! ConfirmYourBidArtsyLoginViewController } override func viewDidLoad() { super.viewDidLoad() let titleString = useArtsyBidderButton.title(for: useArtsyBidderButton.state) ?? "" let attributes = [NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue, NSFontAttributeName: useArtsyBidderButton.titleLabel!.font] as [String : Any] let attrTitle = NSAttributedString(string: titleString, attributes:attributes) useArtsyBidderButton.setAttributedTitle(attrTitle, for:useArtsyBidderButton.state) let nav = self.fulfillmentNav() let bidDetails = nav.bidDetails bidDetailsPreviewView.bidDetails = bidDetails emailTextField.text = nav.bidDetails.newUser.email.value ?? "" let emailText = emailTextField.rx.text.takeUntil(viewWillDisappear) let passwordText = passwordTextField.rx.text.takeUntil(viewWillDisappear) emailText .bindTo(nav.bidDetails.newUser.email) .addDisposableTo(rx_disposeBag) passwordText .bindTo(nav.bidDetails.newUser.password) .addDisposableTo(rx_disposeBag) let inputIsEmail = emailText.asObservable().replaceNil(with: "").map(stringIsEmailAddress) let passwordIsLongEnough = passwordText.asObservable().replaceNil(with: "").map(isZeroLength).not() let formIsValid = [inputIsEmail, passwordIsLongEnough].combineLatestAnd() let provider = self.provider confirmCredentialsButton.rx.action = CocoaAction(enabledIf: formIsValid) { [weak self] _ -> Observable in guard let me = self else { return .empty() } return bidDetails.authenticatedNetworking(provider: provider!) .flatMap { provider -> Observable in return me.fulfillmentNav() .updateUserCredentials(loggedInProvider: provider) .mapReplace(with: provider) }.flatMap { provider -> Observable in return me.creditCard(provider) .doOnNext { cards in guard let me = self else { return } if cards.count > 0 { me.performSegue(.EmailLoginConfirmedHighestBidder) } else { me.performSegue(.ArtsyUserHasNotRegisteredCard) } } .map(void) }.doOnError { [weak self] error in logger.log("Error logging in: \((error as NSError).localizedDescription)") logger.log("Error Logging in, likely bad auth creds, email = \(self?.emailTextField.text)") self?.showAuthenticationError() } } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) if segue == .EmailLoginConfirmedHighestBidder { let viewController = segue.destination as! LoadingViewController viewController.provider = provider } else if segue == .ArtsyUserHasNotRegisteredCard { let viewController = segue.destination as! RegisterViewController viewController.provider = provider } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if emailTextField.text.isNilOrEmpty { emailTextField.becomeFirstResponder() } else { passwordTextField.becomeFirstResponder() } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } func showAuthenticationError() { confirmCredentialsButton.flashError("Wrong login info") passwordTextField.flashForError() fulfillmentNav().bidDetails.newUser.password.value = "" passwordTextField.text = "" } @IBAction func forgotPasswordTapped(_ sender: AnyObject) { let alertController = UIAlertController(title: "Forgot Password", message: "Please enter your email address and we'll send you a reset link.", preferredStyle: .alert) var submitAction = UIAlertAction.Action("Send", style: .default) let email = Variable("") submitAction.rx.action = CocoaAction(enabledIf: email.asObservable().map(stringIsEmailAddress), workFactory: { () -> Observable in let endpoint: ArtsyAPI = ArtsyAPI.lostPasswordNotification(email: email.value) return self.provider.request(endpoint) .filterSuccessfulStatusCodes() .doOnNext { _ in logger.log("Sent forgot password request") } .map(void) }) let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in } alertController.addTextField { textField in textField.placeholder = "email@domain.com" textField.text = self.emailTextField.text textField .rx.text .asObservable() .replaceNil(with: "") .bindTo(email) .addDisposableTo(textField.rx_disposeBag) NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextFieldTextDidChange, object: textField, queue: OperationQueue.main) { (notification) in submitAction.isEnabled = stringIsEmailAddress(textField.text ?? "").boolValue } } alertController.addAction(submitAction) alertController.addAction(cancelAction) self.present(alertController, animated: true) {} } func creditCard(_ provider: AuthorizedNetworking) -> Observable<[Card]> { let endpoint = ArtsyAuthenticatedAPI.myCreditCards return provider .request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(arrayOf: Card.self) } @IBAction func useBidderTapped(_ sender: AnyObject) { for controller in navigationController!.viewControllers { if controller.isKind(of: ConfirmYourBidViewController.self) { navigationController!.popToViewController(controller, animated:true) break } } } } private extension ConfirmYourBidArtsyLoginViewController { @IBAction func dev_hasCardTapped(_ sender: AnyObject) { self.performSegue(.EmailLoginConfirmedHighestBidder) } @IBAction func dev_noCardFoundTapped(_ sender: AnyObject) { self.performSegue(.ArtsyUserHasNotRegisteredCard) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ConfirmYourBidEnterYourEmailViewController.swift ================================================ import UIKit import RxSwift import RxCocoa import Action class ConfirmYourBidEnterYourEmailViewController: UIViewController { @IBOutlet var emailTextField: UITextField! @IBOutlet var confirmButton: UIButton! @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ConfirmYourBidEnterYourEmailViewController { return storyboard.viewController(withID: .ConfirmYourBidEnterEmail) as! ConfirmYourBidEnterYourEmailViewController } var provider: Networking! override func viewDidLoad() { super.viewDidLoad() let emailText = emailTextField.rx.textInput.text.asObservable().replaceNil(with: "") let inputIsEmail = emailText.map(stringIsEmailAddress) let action = CocoaAction(enabledIf: inputIsEmail) { [weak self] _ in guard let me = self else { return .empty() } let endpoint: ArtsyAPI = ArtsyAPI.findExistingEmailRegistration(email: me.emailTextField.text ?? "") return self?.provider.request(endpoint) .filterStatusCode(200) .doOnNext { _ in me.performSegue(.ExistingArtsyUserFound) } .doOnError { error in self?.performSegue(.EmailNotFoundonArtsy) } .map(void) ?? .empty() } confirmButton.rx.action = action let unbind = action.executing.ignore(value: false) let nav = self.fulfillmentNav() bidDetailsPreviewView.bidDetails = nav.bidDetails emailText .asObservable() .mapToOptional() .takeUntil(unbind) .bindTo(nav.bidDetails.newUser.email) .addDisposableTo(rx_disposeBag) emailTextField.rx_returnKey.subscribe(onNext: { _ in action.execute() }).addDisposableTo(rx_disposeBag) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.emailTextField.becomeFirstResponder() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) if segue == .EmailNotFoundonArtsy { let viewController = segue.destination as! RegisterViewController viewController.provider = provider } else if segue == .ExistingArtsyUserFound { let viewController = segue.destination as! ConfirmYourBidArtsyLoginViewController viewController.provider = provider } } } private extension ConfirmYourBidEnterYourEmailViewController { @IBAction func dev_emailFound(_ sender: AnyObject) { performSegue(.ExistingArtsyUserFound) } @IBAction func dev_emailNotFound(_ sender: AnyObject) { performSegue(.EmailNotFoundonArtsy) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ConfirmYourBidPINViewController.swift ================================================ import UIKit import Moya import RxSwift import Action class ConfirmYourBidPINViewController: UIViewController { fileprivate var _pin = Variable("") @IBOutlet var keypadContainer: KeypadContainerView! @IBOutlet var pinTextField: TextField! @IBOutlet var confirmButton: Button! @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! lazy var pin: Observable = { self.keypadContainer.stringValue }() lazy var networkModel: AdminCCBypassNetworkModelType = AdminCCBypassNetworkModel() var provider: Networking! // TODO: These all need to be changed. class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ConfirmYourBidPINViewController { return storyboard.viewController(withID: .ConfirmYourBidPIN) as! ConfirmYourBidPINViewController } override func viewDidLoad() { super.viewDidLoad() pin .bindTo(_pin) .addDisposableTo(rx_disposeBag) pin .bindTo(pinTextField.rx.text) .addDisposableTo(rx_disposeBag) pin .mapToOptional() .bindTo(fulfillmentNav().bidDetails.bidderPIN) .addDisposableTo(rx_disposeBag) let pinExists = pin.map { $0.isNotEmpty } let bidDetails = fulfillmentNav().bidDetails let provider = self.provider bidDetailsPreviewView.bidDetails = bidDetails /// verify if we can connect with number & pin confirmButton.rx.action = CocoaAction(enabledIf: pinExists) { [weak self] _ in guard let me = self else { return .empty() } var loggedInProvider: AuthorizedNetworking! return bidDetails.authenticatedNetworking(provider: provider!) .doOnNext { provider in loggedInProvider = provider } .flatMap { provider -> Observable in return provider .request(ArtsyAuthenticatedAPI.me) .filterSuccessfulStatusCodes() .mapReplace(with: provider) } .flatMap { provider -> Observable in return me .fulfillmentNav() .updateUserCredentials(loggedInProvider: loggedInProvider) .mapReplace(with: provider) } .flatMap { provider -> Observable in return me .networkModel .checkForAdminCCBypass(bidDetails.auctionID, authorizedNetworking: provider) .flatMap { result -> Observable in switch result { case .skipCCRequirement: // We should bypass the CC requirement and move directly onto placing the bid. me.performSegue(.PINConfirmedhasCard) return .empty() case .requireCC: // We must check for a CC, and collect one if necessary. return me .checkForCreditCard(loggedInProvider: provider) .doOnNext(me.got) .map(void) } } } .doOnError { error in if let response = (error as? Moya.Error)?.response { let responseBody = NSString(data: response.data, encoding: String.Encoding.utf8.rawValue) print("Error authenticating(\(response.statusCode)): \(responseBody)") } me.showAuthenticationError() } } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) if segue == .ArtsyUserviaPINHasNotRegisteredCard { let viewController = segue.destination as! RegisterViewController viewController.provider = provider } else if segue == .PINConfirmedhasCard { let viewController = segue.destination as! LoadingViewController viewController.provider = provider } } @IBAction func forgotPINTapped(_ sender: AnyObject) { let auctionID = fulfillmentNav().auctionID ?? "" let number = fulfillmentNav().bidDetails.newUser.phoneNumber.value ?? "" let endpoint: ArtsyAPI = ArtsyAPI.bidderDetailsNotification(auctionID: auctionID, identifier: number) let alertController = UIAlertController(title: "Forgot PIN", message: "We have sent your bidder details to your device.", preferredStyle: .alert) let cancelAction = UIAlertAction(title: "Back", style: .cancel) { (_) in } alertController.addAction(cancelAction) self.present(alertController, animated: true) {} provider.request(endpoint) .filterSuccessfulStatusCodes() .subscribe(onNext: { _ in // Necessary to subscribe to the actual observable. This should be in a CocoaAction of the button, instead. logger.log("Sent forgot PIN request") }) .addDisposableTo(rx_disposeBag) } func showAuthenticationError() { confirmButton.flashError("Wrong PIN") pinTextField.flashForError() keypadContainer.resetAction.execute() } func checkForCreditCard(loggedInProvider: AuthorizedNetworking) -> Observable<[Card]> { let endpoint = ArtsyAuthenticatedAPI.myCreditCards return loggedInProvider.request(endpoint).filterSuccessfulStatusCodes().mapJSON().mapTo(arrayOf: Card.self) } func got(cards: [Card]) { // If the cards list doesn't exist, or its .empty, then perform the segue to collect one. // Otherwise, proceed directly to the loading view controller to place the bid. if cards.isEmpty { performSegue(.ArtsyUserviaPINHasNotRegisteredCard) } else { performSegue(.PINConfirmedhasCard) } } } private extension ConfirmYourBidPINViewController { @IBAction func dev_loggedInTapped(_ sender: AnyObject) { self.performSegue(.PINConfirmedhasCard) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ConfirmYourBidPasswordViewController.swift ================================================ import UIKit // Unused ATM class ConfirmYourBidPasswordViewController: UIViewController { @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ConfirmYourBidPasswordViewController { return storyboard.viewController(withID: .ConfirmYourBid) as! ConfirmYourBidPasswordViewController } override func viewDidLoad() { super.viewDidLoad() bidDetailsPreviewView.bidDetails = fulfillmentNav().bidDetails } @IBAction func dev_noPhoneNumberFoundTapped(_ sender: AnyObject) { } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ConfirmYourBidViewController.swift ================================================ import UIKit import ECPhoneNumberFormatter import Moya import RxSwift import Action class ConfirmYourBidViewController: UIViewController { fileprivate var _number = Variable("") let phoneNumberFormatter = ECPhoneNumberFormatter() @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! @IBOutlet var numberAmountTextField: TextField! @IBOutlet var cursor: CursorView! @IBOutlet var keypadContainer: KeypadContainerView! @IBOutlet var enterButton: UIButton! @IBOutlet var useArtsyLoginButton: UIButton! fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } // Need takeUntil because we bind this observable eventually to bidDetails, making us stick around longer than we should! lazy var number: Observable = { self.keypadContainer.stringValue.takeUntil(self.viewWillDisappear) }() var provider: Networking! class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ConfirmYourBidViewController { return storyboard.viewController(withID: .ConfirmYourBid) as! ConfirmYourBidViewController } override func viewDidLoad() { super.viewDidLoad() let titleString = useArtsyLoginButton.title(for: useArtsyLoginButton.state)! let attributes = [NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue, NSFontAttributeName: useArtsyLoginButton.titleLabel!.font] as [String : Any] let attrTitle = NSAttributedString(string: titleString, attributes:attributes) useArtsyLoginButton.setAttributedTitle(attrTitle, for:useArtsyLoginButton.state) number .bindTo(_number) .addDisposableTo(rx_disposeBag) number .map(toPhoneNumberString) .bindTo(numberAmountTextField.rx.text) .addDisposableTo(rx_disposeBag) let nav = self.fulfillmentNav() bidDetailsPreviewView.bidDetails = nav.bidDetails let optionalNumber = number.mapToOptional() // We don't know if it's a paddle number or a phone number yet, so bind both ¯\_(ツ)_/¯ [nav.bidDetails.paddleNumber, nav.bidDetails.newUser.phoneNumber].forEach { variable in optionalNumber .bindTo(variable) .addDisposableTo(rx_disposeBag) } // Does a bidder exist for this phone number? // if so forward to PIN input VC // else send to enter email let auctionID = nav.auctionID ?? "" let numberIsZeroLength = number.map(isZeroLength) enterButton.rx.action = CocoaAction(enabledIf: numberIsZeroLength.not(), workFactory: { [weak self] _ in guard let me = self else { return .empty() } let endpoint = ArtsyAPI.findBidderRegistration(auctionID: auctionID, phone: String(me._number.value)) return me.provider.request(endpoint) .filterStatusCode(400) .map(void) .doOnError { error in guard let me = self else { return } // Due to AlamoFire restrictions we can't stop HTTP redirects // so to figure out if we got 302'd we have to introspect the // error to see if it's the original URL to know if the // request succeeded. var response: Moya.Response? if case .statusCode(let receivedResponse)? = error as? Moya.Error { response = receivedResponse } if let responseURL = response?.response?.url?.absoluteString, responseURL.contains("v1/bidder/") { me.performSegue(.ConfirmyourBidBidderFound) } else { me.performSegue(.ConfirmyourBidBidderNotFound) } } }) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .ConfirmyourBidBidderFound { let nextViewController = segue.destination as! ConfirmYourBidPINViewController nextViewController.provider = provider } else if segue == .ConfirmyourBidBidderNotFound { let viewController = segue.destination as! ConfirmYourBidEnterYourEmailViewController viewController.provider = provider } else if segue == .ConfirmyourBidArtsyLogin { let viewController = segue.destination as! ConfirmYourBidArtsyLoginViewController viewController.provider = provider } else if segue == .ConfirmyourBidBidderFound { let viewController = segue.destination as! ConfirmYourBidPINViewController viewController.provider = provider } } func toOpeningBidString(_ cents: AnyObject!) -> AnyObject! { if let dollars = NumberFormatter.currencyString(forDollarCents: cents as? Int as NSNumber!) { return "Enter \(dollars) or more" as AnyObject! } return "" as AnyObject! } func toPhoneNumberString(_ number: String) -> String { if number.count >= 7 { return phoneNumberFormatter.string(for: number) ?? number } else { return number } } } private extension ConfirmYourBidViewController { @IBAction func dev_noPhoneNumberFoundTapped(_ sender: AnyObject) { self.performSegue(.ConfirmyourBidArtsyLogin ) } @IBAction func dev_phoneNumberFoundTapped(_ sender: AnyObject) { self.performSegue(.ConfirmyourBidBidderFound) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/FulfillmentContainerViewController.swift ================================================ import UIKit class FulfillmentContainerViewController: UIViewController { var allowAnimations = true @IBOutlet var cancelButton: UIButton! @IBOutlet var contentView: UIView! @IBOutlet var backgroundView: UIView! override func viewDidLoad() { super.viewDidLoad() modalPresentationStyle = UIModalPresentationStyle.overCurrentContext contentView.alpha = 0 backgroundView.alpha = 0 cancelButton.alpha = 0 } // We force viewDidAppear to access the PlaceBidViewController // so this allow animations in the modal // This is mostly a placeholder for a more complex animation in the future func viewDidAppearAnimation(_ animated: Bool) { self.contentView.frame = self.contentView.frame.offsetBy(dx: 0, dy: 100) UIView.animateTwoStepIf(animated, duration: 0.3, { self.backgroundView.alpha = 1 }, midway: { self.contentView.alpha = 1 self.cancelButton.alpha = 1 self.contentView.frame = self.contentView.frame.offsetBy(dx: 0, dy: -100) }) { (complete) in } } @IBAction func closeModalTapped(_ sender: AnyObject) { closeFulfillmentModal() } func closeFulfillmentModal(completion: (() -> ())? = nil) -> Void { UIView.animateIf(allowAnimations, duration: 0.4, { self.contentView.alpha = 0 self.backgroundView.alpha = 0 self.cancelButton.alpha = 0 }) { (completed: Bool) in let presentingVC = self.presentingViewController! presentingVC.dismiss(animated: false, completion: nil) completion?() } } func internalNavigationController() -> FulfillmentNavigationController? { self.loadViewProgrammatically() return self.childViewControllers.first as? FulfillmentNavigationController } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> FulfillmentContainerViewController { return storyboard.viewController(withID: .FulfillmentContainer) as! FulfillmentContainerViewController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/FulfillmentNavigationController.swift ================================================ import UIKit import Moya import RxSwift // We abstract this out so that we don't have network models, etc, aware of the view controller. // This is a "source of truth" that should be referenced in lieu of many independent variables. protocol FulfillmentController: AnyObject { var bidDetails: BidDetails { get set } var auctionID: String! { get set } } class FulfillmentNavigationController: UINavigationController, FulfillmentController { // MARK: - FulfillmentController bits /// The the collection of details necessary to eventually create a bid lazy var bidDetails: BidDetails = { return BidDetails(saleArtwork:nil, paddleNumber: nil, bidderPIN: nil, bidAmountCents:nil, auctionID: self.auctionID) }() var auctionID: String! var user: User! var provider: Networking! // MARK: - Everything else override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func reset() { let storage = HTTPCookieStorage.shared let cookies = storage.cookies cookies?.forEach { storage.deleteCookie($0) } } func updateUserCredentials(loggedInProvider: AuthorizedNetworking) -> Observable { let endpoint = ArtsyAuthenticatedAPI.me let request = loggedInProvider.request(endpoint).filterSuccessfulStatusCodes().mapJSON().mapTo(object: User.self) return request .doOnNext { [weak self] fullUser in guard let me = self else { return } me.user = fullUser let newUser = me.bidDetails.newUser newUser.email.value = me.user.email newUser.phoneNumber.value = me.user.phoneNumber newUser.zipCode.value = me.user.location?.postalCode newUser.name.value = me.user.name } .logError(prefix: "error, the authentication for admin is likely wrong: ") .map(void) } } extension FulfillmentNavigationController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { guard let viewController = viewController as? PlaceBidViewController else { return } viewController.provider = provider } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/GenericFormValidationViewModel.swift ================================================ import Foundation import RxSwift import Action class GenericFormValidationViewModel { let command: CocoaAction let disposeBag = DisposeBag() init(isValid: Observable, manualInvocation: Observable, finishedSubject: PublishSubject) { command = CocoaAction(enabledIf: isValid) { _ in return Observable.create { observer in finishedSubject.onCompleted() observer.onCompleted() return Disposables.create() } } manualInvocation .subscribe(onNext: { [weak self] _ in self?.command.execute() }) .addDisposableTo(disposeBag) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/KeypadContainerView.swift ================================================ import UIKit import Foundation import RxSwift import Action import FLKAutoLayout //@IBDesignable class KeypadContainerView: UIView { fileprivate var keypad: KeypadView! fileprivate let viewModel = KeypadViewModel() var stringValue: Observable! var intValue: Observable! var deleteAction: CocoaAction! var resetAction: CocoaAction! override func prepareForInterfaceBuilder() { for subview in subviews { subview.removeFromSuperview() } let bundle = Bundle(for: type(of: self)) let image = UIImage(named: "KeypadViewPreviewIB", in: bundle, compatibleWith: self.traitCollection) let imageView = UIImageView(frame: self.bounds) imageView.image = image self.addSubview(imageView) } override func awakeFromNib() { super.awakeFromNib() keypad = Bundle(for: type(of: self)).loadNibNamed("KeypadView", owner: self, options: nil)?.first as? KeypadView keypad.leftAction = viewModel.deleteAction keypad.rightAction = viewModel.clearAction keypad.keyAction = viewModel.addDigitAction intValue = viewModel.intValue.asObservable() stringValue = viewModel.stringValue.asObservable() deleteAction = viewModel.deleteAction resetAction = viewModel.clearAction self.addSubview(keypad) keypad.align(to: self) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/KeypadView.swift ================================================ import UIKit import RxSwift import Action class KeypadView: UIView { var leftAction: CocoaAction? { didSet { self.leftButton.rx.action = leftAction } } var rightAction: CocoaAction? { didSet { self.rightButton.rx.action = rightAction } } var keyAction: Action? @IBOutlet fileprivate var keys: [Button]! @IBOutlet fileprivate var leftButton: Button! @IBOutlet fileprivate var rightButton: Button! @IBAction func keypadButtonTapped(_ sender: UIButton) { keyAction?.execute(sender.tag) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/KeypadViewModel.swift ================================================ import Foundation import Action import RxSwift let KeypadViewModelMaxIntegerValue = 10_000_000 class KeypadViewModel: NSObject { //MARK: - Variables lazy var intValue = Variable(0) lazy var stringValue = Variable("") // MARK: - Actions lazy var deleteAction: CocoaAction = { return CocoaAction { [weak self] _ in self?.delete() ?? .empty() } }() lazy var clearAction: CocoaAction = { return CocoaAction { [weak self] _ in self?.clear() ?? .empty() } }() lazy var addDigitAction: Action = { let localSelf = self return Action { [weak localSelf] input in return localSelf?.addDigit(input) ?? .empty() } }() } private extension KeypadViewModel { func delete() -> Observable { return Observable.create { [weak self] observer in if let strongSelf = self { strongSelf.intValue.value = Int(strongSelf.intValue.value / 10) if strongSelf.stringValue.value.isNotEmpty { let string = strongSelf.stringValue.value strongSelf.stringValue.value = string.substring(to: string.index(before: string.endIndex)) } } observer.onCompleted() return Disposables.create() } } func clear() -> Observable { return Observable.create { [weak self] observer in self?.intValue.value = 0 self?.stringValue.value = "" observer.onCompleted() return Disposables.create() } } func addDigit(_ input: Int) -> Observable { return Observable.create { [weak self] observer in if let strongSelf = self { let newValue = (10 * strongSelf.intValue.value) + input if (newValue < KeypadViewModelMaxIntegerValue) { strongSelf.intValue.value = newValue } strongSelf.stringValue.value = "\(strongSelf.stringValue.value)\(input)" } observer.onCompleted() return Disposables.create() } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/LoadingViewController.swift ================================================ import UIKit import Artsy_UILabels import ARAnalytics import RxSwift class LoadingViewController: UIViewController { var provider: Networking! @IBOutlet weak var titleLabel: ARSerifLabel! @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! @IBOutlet weak var statusMessage: ARSerifLabel! @IBOutlet weak var spinner: Spinner! @IBOutlet weak var bidConfirmationImageView: UIImageView! var placingBid = true var animate = true @IBOutlet weak var backToAuctionButton: SecondaryActionButton! @IBOutlet weak var placeHigherBidButton: ActionButton! fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } lazy var viewModel: LoadingViewModelType = { return LoadingViewModel( provider: self.provider, bidNetworkModel: BidderNetworkModel(provider: self.provider, bidDetails: self.fulfillmentNav().bidDetails), placingBid: self.placingBid, actionsComplete: self.viewWillDisappear ) }() lazy var recognizer = UITapGestureRecognizer() lazy var closeSelf: () -> Void = { [weak self] in self?.fulfillmentContainer()?.closeFulfillmentModal() return } override func viewDidLoad() { super.viewDidLoad() if placingBid { bidDetailsPreviewView.bidDetails = viewModel.bidDetails } else { bidDetailsPreviewView.isHidden = true } statusMessage.isHidden = true backToAuctionButton.isHidden = true placeHigherBidButton.isHidden = true spinner.animate(animate) titleLabel.text = placingBid ? "Placing bid..." : "Registering..." // Either finishUp() or bidderError() are responsible for providing a way back to the auction. fulfillmentContainer()?.cancelButton.isHidden = true // The view model will perform actions like registering a user if necessary, // placing a bid if requested, and polling for results. viewModel.performActions().subscribe(onNext: nil, onError: { [weak self] error in logger.log("Bidder error \(error)") self?.bidderError(error as NSError) }, onCompleted: { [weak self] in logger.log("Bid placement and polling completed") self?.finishUp() }, onDisposed: { [weak self] in // Regardless of error or completion. hide the spinner. self?.spinner.isHidden = true }) .addDisposableTo(rx_disposeBag) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .PushtoRegisterConfirmed { let detailsVC = segue.destination as! YourBiddingDetailsViewController detailsVC.confirmationImage = bidConfirmationImageView.image detailsVC.provider = provider } if segue == .PlaceaHigherBidAfterNotBeingHighestBidder { let placeBidVC = segue.destination as! PlaceBidViewController placeBidVC.hasAlreadyPlacedABid = true placeBidVC.provider = provider } } } extension LoadingViewController { func finishUp() { let reserveNotMet = viewModel.reserveNotMet.value let isHighestBidder = viewModel.isHighestBidder.value let bidIsResolved = viewModel.bidIsResolved.value let createdNewBidder = viewModel.createdNewBidder.value logger.log("Bidding process result: reserveNotMet \(reserveNotMet), isHighestBidder \(isHighestBidder), bidIsResolved \(bidIsResolved), createdNewbidder \(createdNewBidder)") if placingBid { ARAnalytics.event("Placed a bid", withProperties: ["top_bidder" : isHighestBidder, "sale_artwork": viewModel.bidDetails.saleArtwork?.artwork.id ?? ""]) if bidIsResolved { if reserveNotMet { handleReserveNotMet() } else if isHighestBidder { handleHighestBidder() } else { handleLowestBidder() } } else { handleUnknownBidder() } } else { // Not placing bid if createdNewBidder { // Creating new user handleRegistered() } else { // Updating existing user handleUpdate() } } let showPlaceHigherButton = placingBid && (!isHighestBidder || reserveNotMet) placeHigherBidButton.isHidden = !showPlaceHigherButton let showAuctionButton = showPlaceHigherButton || isHighestBidder || (!placingBid && !createdNewBidder) backToAuctionButton.isHidden = !showAuctionButton let title = reserveNotMet ? "NO, THANKS" : (createdNewBidder ? "CONTINUE" : "BACK TO AUCTION") backToAuctionButton.setTitle(title, for: .normal) fulfillmentContainer()?.cancelButton.isHidden = false } func handleRegistered() { titleLabel.text = "Registration Complete" bidConfirmationImageView.image = UIImage(named: "BidHighestBidder") fulfillmentContainer()?.cancelButton.setTitle("DONE", for: .normal) Observable.interval(1, scheduler: MainScheduler.instance) .take(1) .subscribe(onCompleted: { [weak self] in self?.performSegue(.PushtoRegisterConfirmed) }) .addDisposableTo(rx_disposeBag) } func handleUpdate() { titleLabel.text = "Updated your Information" bidConfirmationImageView.image = UIImage(named: "BidHighestBidder") fulfillmentContainer()?.cancelButton.setTitle("DONE", for: .normal) } func handleUnknownBidder() { titleLabel.text = "Bid Submitted" bidConfirmationImageView.image = UIImage(named: "BidHighestBidder") } func handleReserveNotMet() { titleLabel.text = "Reserve Not Met" statusMessage.isHidden = false statusMessage.text = "Your bid is still below this lot's reserve. Please place a higher bid." bidConfirmationImageView.image = UIImage(named: "BidNotHighestBidder") } func handleHighestBidder() { titleLabel.text = "High Bid!" statusMessage.isHidden = false statusMessage.text = "You are the high bidder for this lot." bidConfirmationImageView.image = UIImage(named: "BidHighestBidder") recognizer.rx.event.subscribe(onNext: { [weak self] _ in self?.closeSelf() }).addDisposableTo(rx_disposeBag) bidConfirmationImageView.isUserInteractionEnabled = true bidConfirmationImageView.addGestureRecognizer(recognizer) fulfillmentContainer()?.cancelButton.setTitle("DONE", for: .normal) } func handleLowestBidder() { titleLabel.text = "Higher bid needed" titleLabel.textColor = .artsyRedRegular() statusMessage.isHidden = false statusMessage.text = "Another bidder has placed a higher maximum bid. Place a higher bid to secure the lot." bidConfirmationImageView.image = UIImage(named: "BidNotHighestBidder") placeHigherBidButton.isHidden = false } // MARK: - Error Handling func bidderError(_ error: NSError) { if placingBid { // If you are bidding, we show a bidding error regardless of whether or not you're also registering. if error.domain == OutbidDomain { handleLowestBidder() } else { bidPlacementFailed(error: error) } } else { // If you're not placing a bid, you're here because you're .just registering. handleRegistrationFailed(error: error) } } func handleRegistrationFailed(error: NSError) { handleError(withTitle: "Registration Failed", message: "There was a problem registering for the auction. Please speak to an Artsy representative.", error: error) } func bidPlacementFailed(error: NSError) { handleError(withTitle: "Bid Failed", message: "There was a problem placing your bid. Please speak to an Artsy representative.", error: error) } func handleError(withTitle title: String, message: String, error: NSError) { titleLabel.textColor = .artsyRedRegular() titleLabel.text = title statusMessage.text = message statusMessage.isHidden = false backToAuctionButton.isHidden = false statusMessage.presentOnLongPress("Error: \(error.localizedDescription). \n \(error.artsyServerError())", title: title) { [weak self] alertController in self?.present(alertController, animated: true, completion: nil) } } @IBAction func placeHigherBidTapped(_ sender: AnyObject) { self.fulfillmentNav().bidDetails.bidAmountCents.value = 0 self.performSegue(.PlaceaHigherBidAfterNotBeingHighestBidder) } @IBAction func backToAuctionTapped(_ sender: AnyObject) { if viewModel.createdNewBidder.value { self.performSegue(.PushtoRegisterConfirmed) } else { closeSelf() } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/LoadingViewModel.swift ================================================ import Foundation import ARAnalytics import RxSwift protocol LoadingViewModelType { var createdNewBidder: Variable { get } var bidIsResolved: Variable { get } var isHighestBidder: Variable { get } var reserveNotMet: Variable { get } var bidDetails: BidDetails { get } func performActions() -> Observable } /// Encapsulates activities of the LoadingViewController. class LoadingViewModel: NSObject, LoadingViewModelType { let placingBid: Bool let bidderNetworkModel: BidderNetworkModelType lazy var placeBidNetworkModel: PlaceBidNetworkModelType = { return PlaceBidNetworkModel(bidDetails: self.bidderNetworkModel.bidDetails) }() lazy var bidCheckingModel: BidCheckingNetworkModelType = { return BidCheckingNetworkModel(provider: self.provider, bidDetails: self.bidderNetworkModel.bidDetails) }() let provider: Networking let createdNewBidder = Variable(false) let bidIsResolved = Variable(false) let isHighestBidder = Variable(false) let reserveNotMet = Variable(false) var bidDetails: BidDetails { return bidderNetworkModel.bidDetails } init(provider: Networking, bidNetworkModel: BidderNetworkModelType, placingBid: Bool, actionsComplete: Observable) { self.provider = provider self.bidderNetworkModel = bidNetworkModel self.placingBid = placingBid super.init() // Set up bindings. [ (bidderNetworkModel.createdNewUser, createdNewBidder), (bidCheckingModel.bidIsResolved.asObservable(), bidIsResolved), (bidCheckingModel.isHighestBidder.asObservable(), isHighestBidder), (bidCheckingModel.reserveNotMet.asObservable(), reserveNotMet) ].forEach { pair in pair.0 .takeUntil(actionsComplete) .bindTo(pair.1) .addDisposableTo(rx_disposeBag) } } /// Encapsulates essential activities of the LoadingViewController, including: /// - Registering new users /// - Placing bids for users /// - Polling for bid results func performActions() -> Observable { return bidderNetworkModel .createOrGetBidder() .flatMap { [weak self] provider -> Observable<(String, AuthorizedNetworking)> in guard let me = self else { return .empty() } guard me.placingBid else { ARAnalytics.event("Registered New User Only") // Skipping all further actions, since we're not placing a bid. return .empty() } ARAnalytics.event("Started Placing Bid", withProperties: ["id": me.bidDetails.saleArtwork?.artwork.id ?? ""]) return me .placeBidNetworkModel .bid(provider) .map { return ($0, provider) } } .flatMap { [weak self] tuple -> Observable in guard let me = self else { return .empty() } guard me.placingBid else { return .empty() } return me.bidCheckingModel.waitForBidResolution(bidderPositionId: tuple.0, provider: tuple.1).map(void) } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ManualCreditCardInputViewController.swift ================================================ import UIKit import RxSwift import Keys class ManualCreditCardInputViewController: UIViewController, RegistrationSubController { let finished = PublishSubject() @IBOutlet weak var cardNumberTextField: TextField! @IBOutlet weak var expirationMonthTextField: TextField! @IBOutlet weak var expirationYearTextField: TextField! @IBOutlet weak var securitycodeTextField: TextField! @IBOutlet weak var billingZipTextField: TextField! @IBOutlet weak var cardNumberWrapperView: UIView! @IBOutlet weak var expirationDateWrapperView: UIView! @IBOutlet weak var securityCodeWrapperView: UIView! @IBOutlet weak var billingZipWrapperView: UIView! @IBOutlet weak var billingZipErrorLabel: UILabel! @IBOutlet weak var cardConfirmButton: ActionButton! @IBOutlet weak var dateConfirmButton: ActionButton! @IBOutlet weak var securityCodeConfirmButton: ActionButton! @IBOutlet weak var billingZipConfirmButton: ActionButton! lazy var keys = EidolonKeys() lazy var viewModel: ManualCreditCardInputViewModel = { var bidDetails = self.navigationController?.fulfillmentNav().bidDetails return ManualCreditCardInputViewModel(bidDetails: bidDetails, finishedSubject: self.finished) }() override func viewDidLoad() { super.viewDidLoad() expirationDateWrapperView.isHidden = true securityCodeWrapperView.isHidden = true billingZipWrapperView.isHidden = true // We show the enter credit card number, then the date switching the views around viewModel .cardFullDigits .asObservable() .bindTo(cardNumberTextField.rx.text) .addDisposableTo(rx_disposeBag) viewModel .expirationYear .asObservable() .bindTo(expirationYearTextField.rx.text) .addDisposableTo(rx_disposeBag) viewModel .expirationMonth .asObservable() .bindTo(expirationMonthTextField.rx.text) .addDisposableTo(rx_disposeBag) viewModel .securityCode .asObservable() .bindTo(securitycodeTextField.rx.text) .addDisposableTo(rx_disposeBag) viewModel .billingZip .asObservable() .bindTo(billingZipTextField.rx.text) .addDisposableTo(rx_disposeBag) viewModel .creditCardNumberIsValid .bindTo(cardConfirmButton.rx.isEnabled) .addDisposableTo(rx_disposeBag) let action = viewModel.registerButtonCommand() billingZipConfirmButton.rx.action = action action .errors // Based on errors .take(1) // On the first error, then forever .mapReplace(with: false) // Replace the error with false .startWith(true) // But begin with true .bindTo(billingZipErrorLabel.rx_hidden) // show the error label .addDisposableTo(rx_disposeBag) viewModel.moveToYear.take(1).subscribe(onNext: { [weak self] _ in self?.expirationYearTextField.becomeFirstResponder() }).addDisposableTo(rx_disposeBag) cardNumberTextField.becomeFirstResponder() } func textField(_ textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { return viewModel.isEntryValid(string) } @IBAction func cardNumberconfirmTapped(_ sender: AnyObject) { cardNumberWrapperView.isHidden = true expirationDateWrapperView.isHidden = false securityCodeWrapperView.isHidden = true billingZipWrapperView.isHidden = true expirationDateWrapperView.frame = CGRect(x: 0, y: 0, width: expirationDateWrapperView.frame.width, height: expirationDateWrapperView.frame.height) expirationMonthTextField.becomeFirstResponder() } @IBAction func expirationDateConfirmTapped(_ sender: AnyObject) { cardNumberWrapperView.isHidden = true expirationDateWrapperView.isHidden = true securityCodeWrapperView.isHidden = false billingZipWrapperView.isHidden = true securityCodeWrapperView.frame = CGRect(x: 0, y: 0, width: securityCodeWrapperView.frame.width, height: securityCodeWrapperView.frame.height) securitycodeTextField.becomeFirstResponder() } @IBAction func securityCodeConfirmTapped(_ sender: AnyObject) { cardNumberWrapperView.isHidden = true expirationDateWrapperView.isHidden = true securityCodeWrapperView.isHidden = true billingZipWrapperView.isHidden = false billingZipWrapperView.frame = CGRect(x: 0, y: 0, width: billingZipWrapperView.frame.width, height: billingZipWrapperView.frame.height) billingZipTextField.becomeFirstResponder() } @IBAction func backToCardNumber(_ sender: AnyObject) { cardNumberWrapperView.isHidden = false expirationDateWrapperView.isHidden = true securityCodeWrapperView.isHidden = true billingZipWrapperView.isHidden = true cardNumberTextField.becomeFirstResponder() } @IBAction func backToExpirationDate(_ sender: AnyObject) { cardNumberWrapperView.isHidden = true expirationDateWrapperView.isHidden = false securityCodeWrapperView.isHidden = true billingZipWrapperView.isHidden = true expirationMonthTextField.becomeFirstResponder() } @IBAction func backToSecurityCode(_ sender: AnyObject) { cardNumberWrapperView.isHidden = true expirationDateWrapperView.isHidden = true securityCodeWrapperView.isHidden = false billingZipWrapperView.isHidden = true securitycodeTextField.becomeFirstResponder() } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> ManualCreditCardInputViewController { return storyboard.viewController(withID: .ManualCardDetailsInput) as! ManualCreditCardInputViewController } } private extension ManualCreditCardInputViewController { func applyCardWithSuccess(_ success: Bool) { cardNumberTextField.text = success ? "4242424242424242" : "4000000000000002" cardNumberTextField.sendActions(for: .allEditingEvents) cardConfirmButton.sendActions(for: .touchUpInside) expirationMonthTextField.text = "04" expirationMonthTextField.sendActions(for: .allEditingEvents) expirationYearTextField.text = "2018" expirationYearTextField.sendActions(for: .allEditingEvents) dateConfirmButton.sendActions(for: .touchUpInside) securitycodeTextField.text = "123" securitycodeTextField.sendActions(for: .allEditingEvents) securityCodeConfirmButton.sendActions(for: .touchUpInside) billingZipTextField.text = "10001" billingZipTextField.sendActions(for: .allEditingEvents) billingZipTextField.sendActions(for: .touchUpInside) } @IBAction func dev_creditCardOKTapped(_ sender: AnyObject) { applyCardWithSuccess(true) } @IBAction func dev_creditCardFailTapped(_ sender: AnyObject) { applyCardWithSuccess(false) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/ManualCreditCardInputViewModel.swift ================================================ import Foundation import RxSwift import Action import Stripe class ManualCreditCardInputViewModel: NSObject { /// MARK: - Things the user is entering (expecting to be bound to s) var cardFullDigits = Variable("") var expirationMonth = Variable("") var expirationYear = Variable("") var securityCode = Variable("") var billingZip = Variable("") fileprivate(set) var bidDetails: BidDetails! fileprivate(set) var finishedSubject: PublishSubject? /// Mark: - Public members init(bidDetails: BidDetails!, finishedSubject: PublishSubject? = nil) { super.init() self.bidDetails = bidDetails self.finishedSubject = finishedSubject } var creditCardNumberIsValid: Observable { return cardFullDigits.asObservable().map(stripeManager.stringIsCreditCard) } var expiryDatesAreValid: Observable { let month = expirationMonth.asObservable().map(isStringLength(in: 1..<3)) let year = expirationYear.asObservable().map(isStringLength(oneOf: [2, 4])) return [month, year].combineLatestAnd() } var securityCodeIsValid: Observable { return securityCode.asObservable().map(isStringLength(in: 3..<5)) } var billingZipIsValid: Observable { return billingZip.asObservable().map(isStringLength(in: 4..<8)) } var moveToYear: Observable { return expirationMonth.asObservable().filter { value in return value.count == 2 }.map(void) } func registerButtonCommand() -> CocoaAction { let newUser = bidDetails.newUser let enabled = [creditCardNumberIsValid, expiryDatesAreValid, securityCodeIsValid, billingZipIsValid].combineLatestAnd() return CocoaAction(enabledIf: enabled) { [weak self] _ in guard let me = self else { return .empty() } return me.registerCard(newUser: newUser).doOnCompleted { me.finishedSubject?.onCompleted() }.map(void) } } func isEntryValid(_ entry: String) -> Bool { // Allow delete if (entry.isEmpty) { return true } // the API doesn't accept chars let notNumberChars = CharacterSet.decimalDigits.inverted return entry.trimmingCharacters(in: notNumberChars).isNotEmpty } /// MARK: - Private Methods fileprivate func registerCard(newUser: NewUser) -> Observable { let month = expirationMonth.value.toUInt(withDefault: 0) let year = expirationYear.value.toUInt(withDefault: 0) return stripeManager.registerCard(digits: cardFullDigits.value, month: month, year: year, securityCode: securityCode.value, postalCode: billingZip.value).doOnNext { token in newUser.creditCardName.value = token.card.name newUser.creditCardType.value = token.card.brand.name newUser.creditCardToken.value = token.tokenId newUser.creditCardDigit.value = token.card.last4 } } // Only set for testing purposes, otherwise ignore. lazy var stripeManager: StripeManager = StripeManager() } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/Models/BidDetails.swift ================================================ import UIKit import RxSwift import Moya @objc class BidDetails: NSObject { typealias DownloadImageClosure = (_ url: URL, _ imageView: UIImageView) -> () let auctionID: String var newUser: NewUser = NewUser() var saleArtwork: SaleArtwork? var paddleNumber = Variable(nil) var bidderPIN = Variable(nil) var bidAmountCents = Variable(nil) var bidderID = Variable(nil) var setImage: DownloadImageClosure = { (url, imageView) -> () in imageView.sd_setImage(with: url) } init(saleArtwork: SaleArtwork?, paddleNumber: String?, bidderPIN: String?, bidAmountCents: Int?, auctionID: String) { self.auctionID = auctionID self.saleArtwork = saleArtwork self.paddleNumber.value = paddleNumber self.bidderPIN.value = bidderPIN self.bidAmountCents.value = bidAmountCents as NSNumber? } /// Creates a new authenticated networking provider based on either: /// - User's paddle/phone # and PIN, or /// - User's email and password func authenticatedNetworking(provider: Networking) -> Observable { let auctionID = saleArtwork?.auctionID ?? "" if let number = paddleNumber.value, let pin = bidderPIN.value { let newEndpointsClosure = { (target: ArtsyAuthenticatedAPI) -> Endpoint in // Grab existing endpoint to piggy-back off of any existing configurations being used by the sharedprovider. let endpoint = Networking.endpointsClosure()(target) return endpoint.adding(newParameters: ["auction_pin": pin, "number": number, "sale_id": auctionID]) } let provider = OnlineProvider(endpointClosure: newEndpointsClosure, requestClosure: Networking.endpointResolver(), stubClosure: Networking.APIKeysBasedStubBehaviour, plugins: Networking.authenticatedPlugins) return .just(AuthorizedNetworking(provider: provider)) } else { let endpoint: ArtsyAPI = ArtsyAPI.xAuth(email: newUser.email.value ?? "", password: newUser.password.value ?? "") return provider.request(endpoint) .filterSuccessfulStatusCodes() .mapJSON() .flatMap { accessTokenDict -> Observable in guard let accessToken = (accessTokenDict as AnyObject)["access_token"] as? String else { return Observable.error(EidolonError.couldNotParseJSON) } return .just(Networking.newAuthorizedNetworking(accessToken)) } .logServerError(message: "Getting Access Token failed.") } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/Models/NewUser.swift ================================================ import RxSwift class NewUser { var email = Variable(nil) var password = Variable(nil) var phoneNumber = Variable(nil) var creditCardDigit = Variable(nil) var creditCardToken = Variable(nil) var creditCardName = Variable(nil) var creditCardType = Variable(nil) var zipCode = Variable(nil) var name = Variable(nil) var hasBeenRegistered = Variable(false) var swipedCreditCard = false } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/Models/RegistrationCoordinator.swift ================================================ import UIKit import RxSwift enum RegistrationIndex { case mobileVC case emailVC case passwordVC case creditCardVC case zipCodeVC case confirmVC func toInt() -> Int { switch (self) { case .mobileVC: return 0 case .emailVC: return 1 case .passwordVC: return 1 case .zipCodeVC: return 2 case .creditCardVC: return 3 case .confirmVC: return 4 } } static func fromInt(_ index: Int) -> RegistrationIndex { switch (index) { case 0: return .mobileVC case 1: return .emailVC case 1: return .passwordVC case 2: return .zipCodeVC case 3: return .creditCardVC default : return .confirmVC } } } class RegistrationCoordinator: NSObject { let currentIndex = Variable(0) var storyboard: UIStoryboard! func viewControllerForIndex(_ index: RegistrationIndex) -> UIViewController { currentIndex.value = index.toInt() switch index { case .mobileVC: return storyboard.viewController(withID: .RegisterMobile) case .emailVC: return storyboard.viewController(withID: .RegisterEmail) case .passwordVC: return storyboard.viewController(withID: .RegisterPassword) case .zipCodeVC: return storyboard.viewController(withID: .RegisterPostalorZip) case .creditCardVC: if AppSetup.sharedState.disableCardReader { return storyboard.viewController(withID: .ManualCardDetailsInput) } else { return storyboard.viewController(withID: .RegisterCreditCard) } case .confirmVC: return storyboard.viewController(withID: .RegisterConfirm) } } func nextViewControllerForBidDetails(_ details: BidDetails) -> UIViewController { if notSet(details.newUser.phoneNumber.value) { return viewControllerForIndex(.mobileVC) } if notSet(details.newUser.email.value) { return viewControllerForIndex(.emailVC) } if notSet(details.newUser.password.value) { return viewControllerForIndex(.passwordVC) } if notSet(details.newUser.zipCode.value) && AppSetup.sharedState.needsZipCode { return viewControllerForIndex(.zipCodeVC) } if notSet(details.newUser.creditCardToken.value) { return viewControllerForIndex(.creditCardVC) } return viewControllerForIndex(.confirmVC) } } private func notSet(_ string: String?) -> Bool { return string?.isEmpty ?? true } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/PlaceBidNetworkModel.swift ================================================ import Foundation import RxSwift import Moya import SwiftyJSON let OutbidDomain = "Outbid" protocol PlaceBidNetworkModelType { var bidDetails: BidDetails { get } func bid(_ provider: AuthorizedNetworking) -> Observable } class PlaceBidNetworkModel: NSObject, PlaceBidNetworkModelType { let bidDetails: BidDetails init(bidDetails: BidDetails) { self.bidDetails = bidDetails super.init() } func bid(_ provider: AuthorizedNetworking) -> Observable { let saleArtwork = bidDetails.saleArtwork.value assert(saleArtwork.hasValue, "Sale artwork cannot nil at bidding stage.") let cents = (bidDetails.bidAmountCents.value as? Int) ?? 0 return bidOnSaleArtwork(saleArtwork!, bidAmountCents: String(cents), provider: provider) } fileprivate func bidOnSaleArtwork(_ saleArtwork: SaleArtwork, bidAmountCents: String, provider: AuthorizedNetworking) -> Observable { let bidEndpoint = ArtsyAuthenticatedAPI.placeABid(auctionID: saleArtwork.auctionID!, artworkID: saleArtwork.artwork.id, maxBidCents: bidAmountCents) let request = provider .request(bidEndpoint) .filterSuccessfulStatusCodes() .mapJSON() .mapTo(object: BidderPosition.self) return request .map { position in return position.id }.catchError { e -> Observable in // We've received an error. We're going to check to see if it's type is "param_error", which indicates we were outbid. guard let error = e as? Moya.Error else { throw e } guard case .statusCode(let response) = error else { throw e } let json = JSON(data: response.data) if let type = json["type"].string, type == "param_error" { throw NSError(domain: OutbidDomain, code: 0, userInfo: [NSUnderlyingErrorKey: error as NSError]) } else { throw error } } .logError() } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/PlaceBidViewController.swift ================================================ import UIKit import Artsy_UILabels import RxSwift import Artsy_UIButtons import Artsy_UILabels import ORStackView import Action class PlaceBidViewController: UIViewController { var provider: Networking! fileprivate var _bidDollars = Variable(0) var hasAlreadyPlacedABid: Bool = false @IBOutlet var bidAmountTextField: TextField! @IBOutlet var cursor: CursorView! @IBOutlet var keypadContainer: KeypadContainerView! @IBOutlet var currentBidTitleLabel: UILabel! @IBOutlet var yourBidTitleLabel: UILabel! @IBOutlet var currentBidAmountLabel: UILabel! @IBOutlet var nextBidAmountLabel: UILabel! @IBOutlet var artworkImageView: UIImageView! @IBOutlet weak var detailsStackView: ORTagBasedAutoStackView! @IBOutlet var bidButton: Button! @IBOutlet weak var conditionsOfSaleButton: UIButton! @IBOutlet weak var privacyPolictyButton: UIButton! var showBuyersPremiumCommand = { () -> CocoaAction in appDelegate().showBuyersPremiumCommand() } var showPrivacyPolicyCommand = { () -> CocoaAction in appDelegate().showPrivacyPolicyCommand() } var showConditionsOfSaleCommand = { () -> CocoaAction in appDelegate().showConditionsOfSaleCommand() } lazy var bidDollars: Observable = { self.keypadContainer.intValue }() var buyersPremium: () -> (BuyersPremium?) = { appDelegate().sale.buyersPremium } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> PlaceBidViewController { return storyboard.viewController(withID: .PlaceYourBid) as! PlaceBidViewController } fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } override func viewDidLoad() { super.viewDidLoad() if !hasAlreadyPlacedABid { self.fulfillmentNav().reset() } currentBidTitleLabel.font = UIFont.serifSemiBoldFont(withSize: 17) yourBidTitleLabel.font = UIFont.serifSemiBoldFont(withSize: 17) conditionsOfSaleButton.rx.action = showConditionsOfSaleCommand() privacyPolictyButton.rx.action = showPrivacyPolicyCommand() bidDollars .bindTo(_bidDollars) .addDisposableTo(rx_disposeBag) bidDollars .map(dollarsToCurrencyString) .bindTo(bidAmountTextField.rx.text) .addDisposableTo(rx_disposeBag) if let nav = self.navigationController as? FulfillmentNavigationController { bidDollars .map { $0 * 100 } .takeUntil(viewWillDisappear) .map { bid in return bid as NSNumber? } .bindTo(nav.bidDetails.bidAmountCents) .addDisposableTo(rx_disposeBag) if let saleArtwork = nav.bidDetails.saleArtwork { let minimumNextBid = saleArtwork .rx.observe(NSNumber.self, "minimumNextBidCents") .filterNil() .map { $0 as Int } saleArtwork.viewModel .currentBidOrOpeningBidLabel() .mapToOptional() .bindTo(currentBidTitleLabel.rx.text) .addDisposableTo(rx_disposeBag) saleArtwork.viewModel .currentBidOrOpeningBid() .mapToOptional() .bindTo(currentBidAmountLabel.rx.text) .addDisposableTo(rx_disposeBag) minimumNextBid .map { $0 as Int } .map(toNextBidString) .bindTo(nextBidAmountLabel.rx.text) .addDisposableTo(rx_disposeBag) Observable.combineLatest([bidDollars, minimumNextBid], { ints in return (ints[0]) * 100 >= (ints[1]) }) .bindTo(bidButton.rx.isEnabled) .addDisposableTo(rx_disposeBag) enum LabelTags: Int { case lotNumber = 1 case artistName case artworkTitle case artworkPrice case buyersPremium case gobbler } let lotNumber = nav.bidDetails.saleArtwork?.lotNumber if let _ = lotNumber { let lotNumberLabel = smallSansSerifLabel() lotNumberLabel.tag = LabelTags.lotNumber.rawValue detailsStackView.addSubview(lotNumberLabel, withTopMargin: "10", sideMargin: "0") saleArtwork.viewModel .lotNumber() .filterNilKeepOptional() .takeUntil(viewWillDisappear) .bindTo(lotNumberLabel.rx.text) .addDisposableTo(rx_disposeBag) } let artistNameLabel = sansSerifLabel() artistNameLabel.tag = LabelTags.artistName.rawValue detailsStackView.addSubview(artistNameLabel, withTopMargin: "15", sideMargin: "0") let artworkTitleLabel = serifLabel() artworkTitleLabel.tag = LabelTags.artworkTitle.rawValue detailsStackView.addSubview(artworkTitleLabel, withTopMargin: "15", sideMargin: "0") let artworkPriceLabel = serifLabel() artworkPriceLabel.tag = LabelTags.artworkPrice.rawValue detailsStackView.addSubview(artworkPriceLabel, withTopMargin: "15", sideMargin: "0") if let _ = buyersPremium() { let buyersPremiumView = UIView() buyersPremiumView.tag = LabelTags.buyersPremium.rawValue let buyersPremiumLabel = ARSerifLabel() buyersPremiumLabel.font = buyersPremiumLabel.font.withSize(16) buyersPremiumLabel.text = "This work has a " buyersPremiumLabel.textColor = .artsyGrayBold() var buyersPremiumButton = ARUnderlineButton() buyersPremiumButton.titleLabel?.font = buyersPremiumLabel.font buyersPremiumButton.setTitle("buyers premium", for: .normal) buyersPremiumButton.setTitleColor(.artsyGrayBold(), for: .normal) buyersPremiumButton.rx.action = showBuyersPremiumCommand() buyersPremiumView.addSubview(buyersPremiumLabel) buyersPremiumView.addSubview(buyersPremiumButton) buyersPremiumLabel.alignTop("0", leading: "0", bottom: "0", trailing: nil, to: buyersPremiumView) buyersPremiumLabel.alignBaseline(with: buyersPremiumButton, predicate: nil) buyersPremiumButton.alignAttribute(.left, to: .right, of: buyersPremiumLabel, predicate: "0") detailsStackView.addSubview(buyersPremiumView, withTopMargin: "15", sideMargin: "0") } let gobbler = WhitespaceGobbler() gobbler.tag = LabelTags.gobbler.rawValue detailsStackView.addSubview(gobbler, withTopMargin: "0") if let artist = saleArtwork.artwork.artists?.first { artist .rx.observe(String.self, "name") .filterNil() .mapToOptional() .bindTo(artistNameLabel.rx.text) .addDisposableTo(rx_disposeBag) } saleArtwork .artwork .rx.observe(NSAttributedString.self, "titleAndDate") .takeUntil(rx.deallocated) .bindTo(artworkTitleLabel.rx.attributedText) .addDisposableTo(rx_disposeBag) saleArtwork .artwork .rx.observe(String.self, "price") .filterNil() .mapToOptional() .takeUntil(rx.deallocated) .bindTo(artworkPriceLabel.rx.text) .addDisposableTo(rx_disposeBag) if let url = saleArtwork.artwork.defaultImage?.thumbnailURL() { self.artworkImageView.sd_setImage(with: url as URL!) } else { self.artworkImageView.image = nil } } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } @IBAction func bidButtonTapped(_ sender: AnyObject) { let identifier = hasAlreadyPlacedABid ? SegueIdentifier.PlaceAnotherBid : SegueIdentifier.ConfirmBid performSegue(identifier) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .PlaceAnotherBid { let nextViewController = segue.destination as! LoadingViewController nextViewController.provider = provider nextViewController.placingBid = true } else if segue == .ConfirmBid { let viewController = segue.destination as! ConfirmYourBidViewController viewController.provider = provider } } } private extension PlaceBidViewController { func smallSansSerifLabel() -> UILabel { let label = sansSerifLabel() label.font = label.font.withSize(12) return label } func sansSerifLabel() -> UILabel { let label = ARSansSerifLabel() label.numberOfLines = 1 return label } func serifLabel() -> UILabel { let label = ARSerifLabel() label.numberOfLines = 1 label.font = label.font.withSize(16) return label } } /// These are for RAC only func dollarsToCurrencyString(_ dollars: Int) -> String { if dollars == 0 { return "" } let formatter = NumberFormatter() formatter.locale = Locale(identifier: "en_US") formatter.numberStyle = .decimal return formatter.string(from: dollars as NSNumber) ?? "" } func toNextBidString(_ cents: Int) -> String { guard let dollars = NumberFormatter.currencyString(forDollarCents: cents as NSNumber!) else { return "" } return "Enter \(dollars) or more" } typealias DeveloperOnly = PlaceBidViewController extension DeveloperOnly { @IBAction func dev_nextIncrementPressed(_ sender: AnyObject) { let bidDetails = (self.navigationController as? FulfillmentNavigationController)?.bidDetails bidDetails?.bidAmountCents.value = bidDetails?.saleArtwork?.minimumNextBidCents performSegue(SegueIdentifier.ConfirmBid) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/RegisterViewController.swift ================================================ import UIKit import RxSwift protocol RegistrationSubController { // I know, leaky abstraction, but the amount // of useless syntax to change it isn't worth it. var finished: PublishSubject { get } } class RegisterViewController: UIViewController { @IBOutlet var flowView: RegisterFlowView! @IBOutlet var bidDetailsPreviewView: BidDetailsPreviewView! @IBOutlet var confirmButton: UIButton! var provider: Networking! let coordinator = RegistrationCoordinator() dynamic var placingBid = true fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } func internalNavController() -> UINavigationController? { return self.childViewControllers.first as? UINavigationController } override func viewDidLoad() { super.viewDidLoad() coordinator.storyboard = self.storyboard! let registerIndex = coordinator.currentIndex.asObservable() let indexIsConfirmed = registerIndex.map { return ($0 == RegistrationIndex.confirmVC.toInt()) } indexIsConfirmed .not() .bindTo(confirmButton.rx_hidden) .addDisposableTo(rx_disposeBag) registerIndex .bindTo(flowView.highlightedIndex) .addDisposableTo(rx_disposeBag) let details = self.fulfillmentNav().bidDetails flowView.details = details bidDetailsPreviewView.bidDetails = details flowView .highlightedIndex .asObservable() .distinctUntilChanged() .subscribe(onNext: { [weak self] (index) in if let _ = self?.fulfillmentNav() { let registrationIndex = RegistrationIndex.fromInt(index) let nextVC = self?.coordinator.viewControllerForIndex(registrationIndex) self?.goToViewController(nextVC!) } }) .addDisposableTo(rx_disposeBag) goToNextVC() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } func goToNextVC() { let nextVC = coordinator.nextViewControllerForBidDetails(fulfillmentNav().bidDetails) goToViewController(nextVC) } func goToViewController(_ controller: UIViewController) { self.internalNavController()!.viewControllers = [controller] if let subscribableVC = controller as? RegistrationSubController { subscribableVC .finished .subscribe(onCompleted: { [weak self] in self?.goToNextVC() self?.flowView.update() }) .addDisposableTo(rx_disposeBag) } if let viewController = controller as? RegistrationPasswordViewController { viewController.provider = provider } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .ShowLoadingView { let nextViewController = segue.destination as! LoadingViewController nextViewController.placingBid = placingBid nextViewController.provider = provider } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/RegistrationEmailViewController.swift ================================================ import UIKit import RxSwift class RegistrationEmailViewController: UIViewController, RegistrationSubController, UITextFieldDelegate { @IBOutlet var emailTextField: TextField! @IBOutlet var confirmButton: ActionButton! var finished = PublishSubject() lazy var viewModel: GenericFormValidationViewModel = { let emailIsValid = self.emailTextField.rx.textInput.text.asObservable().replaceNil(with: "").map(stringIsEmailAddress) return GenericFormValidationViewModel(isValid: emailIsValid, manualInvocation: self.emailTextField.rx_returnKey, finishedSubject: self.finished) }() fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } lazy var bidDetails: BidDetails! = { self.navigationController!.fulfillmentNav().bidDetails }() override func viewDidLoad() { super.viewDidLoad() emailTextField.text = bidDetails.newUser.email.value emailTextField.rx.textInput.text .asObservable() .takeUntil(viewWillDisappear) .bindTo(bidDetails.newUser.email) .addDisposableTo(rx_disposeBag) confirmButton.rx.action = viewModel.command emailTextField.becomeFirstResponder() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Allow delete if (string.isEmpty) { return true } // the API doesn't accept spaces return string != " " } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> RegistrationEmailViewController { return storyboard.viewController(withID: .RegisterEmail) as! RegistrationEmailViewController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/RegistrationMobileViewController.swift ================================================ import UIKit import RxSwift class RegistrationMobileViewController: UIViewController, RegistrationSubController, UITextFieldDelegate { @IBOutlet var numberTextField: TextField! @IBOutlet var confirmButton: ActionButton! let finished = PublishSubject() lazy var viewModel: GenericFormValidationViewModel = { let numberIsValid = self.numberTextField.rx.text.asObservable().replaceNil(with: "").map(isZeroLength).not() return GenericFormValidationViewModel(isValid: numberIsValid, manualInvocation: self.numberTextField.rx_returnKey, finishedSubject: self.finished) }() fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } lazy var bidDetails: BidDetails! = { self.navigationController!.fulfillmentNav().bidDetails }() override func viewDidLoad() { super.viewDidLoad() numberTextField.text = bidDetails.newUser.phoneNumber.value numberTextField .rx.text .asObservable() .takeUntil(viewWillDisappear) .bindTo(bidDetails.newUser.phoneNumber) .addDisposableTo(rx_disposeBag) confirmButton.rx.action = viewModel.command numberTextField.becomeFirstResponder() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Allow delete if string.isEmpty { return true } // the API doesn't accept chars let notNumberChars = CharacterSet.decimalDigits.inverted return string.trimmingCharacters(in: notNumberChars).isNotEmpty } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> RegistrationMobileViewController { return storyboard.viewController(withID: .RegisterMobile) as! RegistrationMobileViewController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/RegistrationPasswordViewController.swift ================================================ import UIKit import RxSwift import Moya import Action class RegistrationPasswordViewController: UIViewController, RegistrationSubController { @IBOutlet var passwordTextField: TextField! @IBOutlet var confirmButton: ActionButton! @IBOutlet var subtitleLabel: UILabel! @IBOutlet var forgotPasswordButton: UIButton! let finished = PublishSubject() var provider: Networking! fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } lazy var viewModel: RegistrationPasswordViewModelType = { let email = self.navigationController?.fulfillmentNav().bidDetails.newUser.email.value ?? "" return RegistrationPasswordViewModel( provider: self.provider, password: self.passwordTextField.rx.text.asObservable().replaceNil(with: ""), execute: self.passwordTextField.rx_returnKey, completed: self.finished, email: email) }() lazy var bidDetails: BidDetails! = { self.navigationController!.fulfillmentNav().bidDetails }() override func viewDidLoad() { super.viewDidLoad() forgotPasswordButton.isHidden = false let passwordText = passwordTextField.rx.text passwordText .asObservable() .takeUntil(viewWillDisappear) .bindTo(bidDetails.newUser.password) .addDisposableTo(rx_disposeBag) confirmButton.rx.action = viewModel.action viewModel .action .errors .subscribe(onNext: { [weak self] _ in self?.showAuthenticationError() return }) .addDisposableTo(rx_disposeBag) viewModel .emailExists .not() .startWith(true) .bindTo(forgotPasswordButton.rx_hidden) .addDisposableTo(rx_disposeBag) forgotPasswordButton.rx.action = CocoaAction { [weak self] _ in return self? .viewModel .userForgotPassword() .then { self?.alertUserPasswordSent() } ?? .empty() } viewModel .emailExists .map { emailExists in if emailExists { return "Enter your Artsy password" } else { return "Create a password" } } .bindTo(subtitleLabel.rx.text) .addDisposableTo(rx_disposeBag) passwordTextField.becomeFirstResponder() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } func alertUserPasswordSent() -> Observable { return Observable.create { observer in let alertController = UIAlertController(title: "Forgot Password", message: "We have sent you your password.", preferredStyle: .alert) let okAction = UIAlertAction(title: "OK", style: .default) { (_) in } alertController.addAction(okAction) self.present(alertController, animated: true) { observer.onCompleted() } return Disposables.create() } } func showAuthenticationError() { confirmButton.flashError("Incorrect") passwordTextField.flashForError() confirmButton.setEnabled(false, animated: false) navigationController!.fulfillmentNav().bidDetails.newUser.password.value = "" passwordTextField.text = "" } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> RegistrationPasswordViewController { return storyboard.viewController(withID: .RegisterPassword) as! RegistrationPasswordViewController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/RegistrationPasswordViewModel.swift ================================================ import Foundation import RxSwift import Moya import Action protocol RegistrationPasswordViewModelType { var emailExists: Observable { get } var action: CocoaAction! { get } func userForgotPassword() -> Observable } class RegistrationPasswordViewModel: RegistrationPasswordViewModelType { fileprivate let password = Variable("") var action: CocoaAction! let provider: Networking let email: String let emailExists: Observable let disposeBag = DisposeBag() init(provider: Networking, password: Observable, execute: Observable, completed: PublishSubject, email: String) { self.provider = provider self.email = email let checkEmail = provider .request(ArtsyAPI.findExistingEmailRegistration(email: email)) .map(responseIsOK) .shareReplay(1) emailExists = checkEmail password.bindTo(self.password).addDisposableTo(disposeBag) let password = self.password // Action takes nothing, is enabled if the password is valid, and does the following: // Check if the email exists, it tries to log in. // If it doesn't exist, then it does nothing. let action = CocoaAction(enabledIf: password.asObservable().map(isStringLengthAtLeast(length: 6))) { _ in return self.emailExists .flatMap { exists -> Observable in if exists { let endpoint: ArtsyAPI = ArtsyAPI.xAuth(email: email, password: password.value ) return provider .request(endpoint) .filterSuccessfulStatusCodes() .map(void) } else { // Return a non-empty observable, so that the action sends something on its elements observable. return .just(Void()) } } .doOnCompleted { completed.onCompleted() } } self.action = action execute .subscribe { _ in action.execute(Void()) } .addDisposableTo(disposeBag) } func userForgotPassword() -> Observable { let endpoint = ArtsyAPI.lostPasswordNotification(email: email) return provider.request(endpoint) .filterSuccessfulStatusCodes() .map(void) .doOnNext { _ in logger.log("Sent forgot password request") } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/RegistrationPostalZipViewController.swift ================================================ import RxSwift class RegistrationPostalZipViewController: UIViewController, RegistrationSubController { @IBOutlet var zipCodeTextField: TextField! @IBOutlet var confirmButton: ActionButton! let finished = PublishSubject() lazy var viewModel: GenericFormValidationViewModel = { let zipCodeIsValid = self.zipCodeTextField.rx.text.asObservable().replaceNil(with: "").map(isZeroLength).not() return GenericFormValidationViewModel(isValid: zipCodeIsValid, manualInvocation: self.zipCodeTextField.rx_returnKey, finishedSubject: self.finished) }() fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } lazy var bidDetails: BidDetails! = { self.navigationController!.fulfillmentNav().bidDetails }() override func viewDidLoad() { super.viewDidLoad() zipCodeTextField.text = bidDetails.newUser.zipCode.value zipCodeTextField .rx.text .asObservable() .takeUntil(viewWillDisappear) .bindTo(bidDetails.newUser.zipCode) .addDisposableTo(rx_disposeBag) confirmButton.rx.action = viewModel.command zipCodeTextField.becomeFirstResponder() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> RegistrationPostalZipViewController { return storyboard.viewController(withID: .RegisterPostalorZip) as! RegistrationPostalZipViewController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/StripeManager.swift ================================================ import Foundation import RxSwift import Stripe class StripeManager: NSObject { var stripeClient = STPAPIClient.shared() func registerCard(digits: String, month: UInt, year: UInt, securityCode: String, postalCode: String) -> Observable { let card = STPCard() card.number = digits card.expMonth = month card.expYear = year card.cvc = securityCode card.addressZip = postalCode return Observable.create { [weak self] observer in guard let me = self else { observer.onCompleted() return Disposables.create() } me.stripeClient?.createToken(with: card) { (token, error) in if (token as STPToken?).hasValue { observer.onNext(token!) observer.onCompleted() } else { observer.onError(error!) } } return Disposables.create() } } func stringIsCreditCard(_ cardNumber: String) -> Bool { return STPCard.validateNumber(cardNumber) } } extension STPCardBrand { var name: String? { switch self { case .visa: return "Visa" case .amex: return "American Express" case .masterCard: return "MasterCard" case .discover: return "Discover" case .JCB: return "JCB" case .dinersClub: return "Diners Club" default: return nil } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/SwipeCreditCardViewController.swift ================================================ import UIKit import Artsy_UILabels import RxSwift import Keys import Stripe class SwipeCreditCardViewController: UIViewController, RegistrationSubController { @IBOutlet var cardStatusLabel: ARSerifLabel! let finished = PublishSubject() @IBOutlet weak var spinner: Spinner! @IBOutlet weak var processingLabel: UILabel! @IBOutlet weak var illustrationImageView: UIImageView! @IBOutlet weak var titleLabel: ARSerifLabel! class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> SwipeCreditCardViewController { return storyboard.viewController(withID: .RegisterCreditCard) as! SwipeCreditCardViewController } let cardName = Variable("") let cardLastDigits = Variable("") let cardToken = Variable("") lazy var keys = EidolonKeys() lazy var bidDetails: BidDetails! = { self.navigationController!.fulfillmentNav().bidDetails }() lazy var appSetup = AppSetup.sharedState lazy var cardHandler: CardHandler = { if self.appSetup.useStaging { return CardHandler(apiKey: self.keys.cardflightStagingAPIClientKey(), accountToken: self.keys.cardflightStagingMerchantAccountToken()) } else { return CardHandler(apiKey: self.keys.cardflightProductionAPIClientKey(), accountToken: self.keys.cardflightProductionMerchantAccountToken()) } }() fileprivate let _viewWillDisappear = PublishSubject() var viewWillDisappear: Observable { return self._viewWillDisappear.asObserver() } override func viewDidLoad() { super.viewDidLoad() self.setInProgress(false) cardHandler.cardStatus .takeUntil(self.viewWillDisappear) .subscribe(onNext: { message in self.cardStatusLabel.text = "Card Status: \(message)" if message == "Got Card" { self.setInProgress(true) } if message.hasPrefix("Card Flight Error") { self.processingLabel.text = "ERROR PROCESSING CARD - SEE ADMIN" } }, onError: { error in self.cardStatusLabel.text = "Card Status: Errored" self.setInProgress(false) self.titleLabel.text = "Please Swipe a Valid Credit Card" self.titleLabel.textColor = .artsyRedRegular() }, onCompleted: { self.cardStatusLabel.text = "Card Status: completed" if let card = self.cardHandler.card { self.cardName.value = card.name self.cardLastDigits.value = card.last4 self.cardToken.value = card.cardToken if let newUser = self.navigationController?.fulfillmentNav().bidDetails.newUser { newUser.name.value = (newUser.name.value.isNilOrEmpty) ? card.name : newUser.name.value } } self.cardHandler.end() self.finished.onCompleted() }, onDisposed: nil) .addDisposableTo(rx_disposeBag) cardHandler.startSearching() cardName .asObservable() .takeUntil(viewWillDisappear) .mapToOptional() .bindTo(bidDetails.newUser.creditCardName) .addDisposableTo(rx_disposeBag) cardLastDigits .asObservable() .takeUntil(viewWillDisappear) .mapToOptional() .bindTo(bidDetails.newUser.creditCardDigit) .addDisposableTo(rx_disposeBag) cardToken .asObservable() .takeUntil(viewWillDisappear) .mapToOptional() .bindTo(bidDetails.newUser.creditCardToken) .addDisposableTo(rx_disposeBag) bidDetails.newUser.swipedCreditCard = true } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) _viewWillDisappear.onNext() } func setInProgress(_ show: Bool) { illustrationImageView.alpha = show ? 0.1 : 1 processingLabel.isHidden = !show spinner.isHidden = !show } // Used only for development, in private extension for testing. fileprivate lazy var stripeManager = StripeManager() } private extension SwipeCreditCardViewController { func applyCardWithSuccess(_ success: Bool) { let cardFullDigits = success ? "4242424242424242" : "4000000000000002" stripeManager.registerCard(digits: cardFullDigits, month: 04, year: 2018, securityCode: "123", postalCode: "10013") .subscribe(onNext: { [weak self] token in self?.cardName.value = "Kiosk Staging CC Test" self?.cardToken.value = token.tokenId self?.cardLastDigits.value = token.card.last4 if let newUser = self?.navigationController?.fulfillmentNav().bidDetails.newUser { newUser.name.value = token.card.brand.name } self?.finished.onCompleted() }) .addDisposableTo(rx_disposeBag) } @IBAction func dev_creditCardOKTapped(_ sender: AnyObject) { applyCardWithSuccess(true) } @IBAction func dev_creditCardFailTapped(_ sender: AnyObject) { applyCardWithSuccess(false) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Bid Fulfillment/YourBiddingDetailsViewController.swift ================================================ import UIKit import Artsy_UILabels import Artsy_UIButtons import RxCocoa import RxSwift class YourBiddingDetailsViewController: UIViewController { var provider: Networking! @IBOutlet dynamic var bidderNumberLabel: UILabel! @IBOutlet dynamic var pinNumberLabel: UILabel! @IBOutlet weak var confirmationImageView: UIImageView! @IBOutlet weak var subtitleLabel: ARSerifLabel! @IBOutlet weak var bodyLabel: ARSerifLabel! @IBOutlet weak var notificationLabel: ARSerifLabel! var confirmationImage: UIImage? lazy var bidDetails: BidDetails! = { (self.navigationController as! FulfillmentNavigationController).bidDetails }() override func viewDidLoad() { super.viewDidLoad() [notificationLabel, bidderNumberLabel, pinNumberLabel].forEach { $0.makeTransparent() } notificationLabel.setLineHeight(5) bodyLabel.setLineHeight(10) if let image = confirmationImage { confirmationImageView.image = image } bodyLabel?.makeSubstringsBold(["Bidder Number", "PIN"]) bidDetails .paddleNumber .asObservable() .filterNilKeepOptional() .bindTo(bidderNumberLabel.rx.text) .addDisposableTo(rx_disposeBag) bidDetails .bidderPIN .asObservable() .filterNilKeepOptional() .bindTo(pinNumberLabel.rx.text) .addDisposableTo(rx_disposeBag) } @IBAction func confirmButtonTapped(_ sender: AnyObject) { fulfillmentContainer()?.closeFulfillmentModal() } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> YourBiddingDetailsViewController { return storyboard.viewController(withID: .YourBidderDetails) as! YourBiddingDetailsViewController } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Help/HelpAnimator.swift ================================================ import UIKit import RxSwift class HelpAnimator: NSObject, UIViewControllerAnimatedTransitioning { let presenting: Bool init(presenting: Bool = false) { self.presenting = presenting super.init() } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return AnimationDuration.Normal } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let containerView = transitionContext.containerView let fromView: UIView! = transitionContext.view(forKey: UITransitionContextViewKey.from) ?? transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view let toView: UIView! = transitionContext.view(forKey: UITransitionContextViewKey.to) ?? transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view if presenting { let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)! as! HelpViewController let dismissTapGestureRecognizer = UITapGestureRecognizer() dismissTapGestureRecognizer .rx.event .subscribe(onNext: { [weak toView] sender in let pointInContainer = sender.location(in: toView) if toView?.point(inside: pointInContainer, with: nil) == false { appDelegate().helpButtonCommand().execute() } }) .addDisposableTo(rx_disposeBag) toViewController.dismissTapGestureRecognizer = dismissTapGestureRecognizer containerView.addGestureRecognizer(dismissTapGestureRecognizer) fromView.isUserInteractionEnabled = false containerView.backgroundColor = .black containerView.addSubview(fromView) containerView.addSubview(toView) toView.alignTop("0", bottom: "0", to: containerView) toView.constrainWidth("\(HelpViewController.width)") toViewController.positionConstraints = toView.alignAttribute(.left, to: .right, of: containerView, predicate: "0") as? [NSLayoutConstraint] containerView.layoutIfNeeded() UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { containerView.removeConstraints(toViewController.positionConstraints ?? []) toViewController.positionConstraints = toView.alignLeading(nil, trailing: "0", to: containerView) as? [NSLayoutConstraint] containerView.layoutIfNeeded() fromView.alpha = 0.5 }, completion: { (value: Bool) in transitionContext.completeTransition(true) }) } else { let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)! as! HelpViewController if let dismissTapGestureRecognizer = fromViewController.dismissTapGestureRecognizer { containerView.removeGestureRecognizer(dismissTapGestureRecognizer) } toView.isUserInteractionEnabled = true containerView.addSubview(toView) containerView.addSubview(fromView) UIView.animate(withDuration: self.transitionDuration(using: transitionContext), animations: { containerView.removeConstraints(fromViewController.positionConstraints ?? []) fromViewController.positionConstraints = fromView.alignAttribute(.left, to: .right, of: containerView, predicate: "0") as? [NSLayoutConstraint] containerView.layoutIfNeeded() toView.alpha = 1.0 }, completion: { (value: Bool) in transitionContext.completeTransition(true) // This following line is to work around a bug in iOS 8 💩 UIApplication.shared.keyWindow!.insertSubview(transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view, at: 0) }) } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Help/HelpViewController.swift ================================================ import UIKit import ORStackView import Artsy_UILabels import Artsy_UIButtons import Action import RxSwift import RxCocoa class HelpViewController: UIViewController { var positionConstraints: [NSLayoutConstraint]? var dismissTapGestureRecognizer: UITapGestureRecognizer? fileprivate let stackView = ORTagBasedAutoStackView() fileprivate var buyersPremiumButton: UIButton! fileprivate let sideMargin: Float = 90.0 fileprivate let topMargin: Float = 45.0 fileprivate let headerMargin: Float = 25.0 fileprivate let inbetweenMargin: Float = 10.0 var showBuyersPremiumCommand = { () -> CocoaAction in appDelegate().showBuyersPremiumCommand() } var registerToBidCommand = { (enabled: Observable) -> CocoaAction in appDelegate().registerToBidCommand(enabled: enabled) } var requestBidderDetailsCommand = { (enabled: Observable) -> CocoaAction in appDelegate().requestBidderDetailsCommand(enabled: enabled) } var showPrivacyPolicyCommand = { () -> CocoaAction in appDelegate().showPrivacyPolicyCommand() } var showConditionsOfSaleCommand = { () -> CocoaAction in appDelegate().showConditionsOfSaleCommand() } lazy var hasBuyersPremium: Observable = { return appDelegate() .appViewController .sale .value .rx.observe(String.self, "buyersPremium") .map { $0.hasValue } }() class var width: Float { get { return 415.0 } } override func viewDidLoad() { super.viewDidLoad() // Configure view view.backgroundColor = .white addSubviews() } } private extension HelpViewController { enum SubviewTag: Int { case assistanceLabel = 0 case stuckLabel, stuckExplainLabel case bidLabel, bidExplainLabel case registerButton case bidderDetailsLabel, bidderDetailsExplainLabel, bidderDetailsButton case conditionsOfSaleButton, buyersPremiumButton, privacyPolicyButton } func addSubviews() { // Configure subviews let assistanceLabel = ARSerifLabel() assistanceLabel.font = assistanceLabel.font.withSize(35) assistanceLabel.text = "Assistance" assistanceLabel.tag = SubviewTag.assistanceLabel.rawValue let stuckLabel = titleLabel(tag: .stuckLabel, title: "Stuck in the process?") let stuckExplainLabel = wrappingSerifLabel(tag: .stuckExplainLabel, text: "Find the nearest Artsy representative and they will assist you.") let bidLabel = titleLabel(tag: .bidLabel, title: "How do I place a bid?") let bidExplainLabel = wrappingSerifLabel(tag: .bidExplainLabel, text: "Enter the amount you would like to bid. You will confirm this bid in the next step. Enter your mobile number or bidder number and PIN that you received when you registered.") bidExplainLabel.makeSubstringsBold(["mobile number", "bidder number", "PIN"]) var registerButton = blackButton(tag: .registerButton, title: "Register") registerButton.rx.action = registerToBidCommand(connectedToInternetOrStubbing()) let bidderDetailsLabel = titleLabel(tag: .bidderDetailsLabel, title: "What Are Bidder Details?") let bidderDetailsExplainLabel = wrappingSerifLabel(tag: .bidderDetailsExplainLabel, text: "The bidder number is how you can identify yourself to bid and see your place in bid history. The PIN is a four digit number that authenticates your bid.") bidderDetailsExplainLabel.makeSubstringsBold(["bidder number", "PIN"]) var sendDetailsButton = blackButton(tag: .bidderDetailsButton, title: "Send me my details") sendDetailsButton.rx.action = requestBidderDetailsCommand(connectedToInternetOrStubbing()) var conditionsButton = serifButton(tag: .conditionsOfSaleButton, title: "Conditions of Sale") conditionsButton.rx.action = showConditionsOfSaleCommand() buyersPremiumButton = serifButton(tag: .buyersPremiumButton, title: "Buyers Premium") buyersPremiumButton.rx.action = showBuyersPremiumCommand() var privacyButton = serifButton(tag: .privacyPolicyButton, title: "Privacy Policy") privacyButton.rx.action = showPrivacyPolicyCommand() // Add subviews view.addSubview(stackView) stackView.alignTop("0", leading: "0", bottom: nil, trailing: "0", to: view) stackView.addSubview(assistanceLabel, withTopMargin: "\(topMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(stuckLabel, withTopMargin: "\(headerMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(stuckExplainLabel, withTopMargin: "\(inbetweenMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(bidLabel, withTopMargin: "\(headerMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(bidExplainLabel, withTopMargin: "\(inbetweenMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(registerButton, withTopMargin: "20", sideMargin: "\(sideMargin)") stackView.addSubview(bidderDetailsLabel, withTopMargin: "\(headerMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(bidderDetailsExplainLabel, withTopMargin: "\(inbetweenMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(sendDetailsButton, withTopMargin: "\(inbetweenMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(conditionsButton, withTopMargin: "\(headerMargin)", sideMargin: "\(sideMargin)") stackView.addSubview(privacyButton, withTopMargin: "\(inbetweenMargin)", sideMargin: "\(self.sideMargin)") hasBuyersPremium .subscribe(onNext: { [weak self] hasBuyersPremium in if hasBuyersPremium { self?.stackView.addSubview(self!.buyersPremiumButton, withTopMargin: "\(self!.inbetweenMargin)", sideMargin: "\(self!.sideMargin)") } else { self?.stackView.removeSubview(self!.buyersPremiumButton) } }) .addDisposableTo(rx_disposeBag) } func blackButton(tag: SubviewTag, title: String) -> ARBlackFlatButton { let button = ARBlackFlatButton() button.setTitle(title, for: .normal) button.tag = tag.rawValue return button } func serifButton(tag: SubviewTag, title: String) -> ARUnderlineButton { let button = ARUnderlineButton() button.setTitle(title, for: .normal) button.setTitleColor(.artsyGrayBold(), for: .normal) button.titleLabel?.font = UIFont.serifFont(withSize: 18) button.contentHorizontalAlignment = .left button.tag = tag.rawValue return button } func wrappingSerifLabel(tag: SubviewTag, text: String) -> UILabel { let label = ARSerifLabel() label.font = label.font.withSize(18) label.lineBreakMode = .byWordWrapping label.preferredMaxLayoutWidth = CGFloat(HelpViewController.width - sideMargin) label.tag = tag.rawValue let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = 4 label.attributedText = NSAttributedString(string: text, attributes: [NSParagraphStyleAttributeName: paragraphStyle]) return label } func titleLabel(tag: SubviewTag, title: String) -> ARSerifLabel { let label = ARSerifLabel() label.font = label.font.withSize(24) label.text = title label.tag = tag.rawValue return label } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/HelperFunctions.swift ================================================ import Foundation // Collection of stanardised mapping funtions for Rx work func stringIsEmailAddress(_ text: String) -> Bool { let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}" let testPredicate = NSPredicate(format:"SELF MATCHES %@", emailRegex) return testPredicate.evaluate(with: text) } func centsToPresentableDollarsString(_ cents: Int) -> String { guard let dollars = NumberFormatter.currencyString(forDollarCents: cents as NSNumber!) else { return "" } return dollars } func isZeroLength(string: String) -> Bool { return string.isEmpty } func isStringLength(in range: Range) -> (String) -> Bool { return { string in return range.contains(string.count) } } func isStringOf(length: Int) -> (String) -> Bool { return { string in return string.count == length } } func isStringLengthAtLeast(length: Int) -> (String) -> Bool { return { string in return string.count >= length } } func isStringLength(oneOf lengths: [Int]) -> (String) -> Bool { return { string in return lengths.contains(string.count) } } // Useful for mapping an Observable into an Observable to hide details. func void(_: T) -> Void { return Void() } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/ListingsCollectionViewCell.swift ================================================ import Foundation import Artsy_UILabels import RxSwift import RxCocoa import NSObject_Rx class ListingsCollectionViewCell: UICollectionViewCell { typealias DownloadImageClosure = (_ url: URL?, _ imageView: UIImageView) -> () typealias CancelDownloadImageClosure = (_ imageView: UIImageView) -> () dynamic let lotNumberLabel = ListingsCollectionViewCell._sansSerifLabel() dynamic let artworkImageView = ListingsCollectionViewCell._artworkImageView() dynamic let artistNameLabel = ListingsCollectionViewCell._largeLabel() dynamic let artworkTitleLabel = ListingsCollectionViewCell._italicsLabel() dynamic let estimateLabel = ListingsCollectionViewCell._normalLabel() dynamic let currentBidLabel = ListingsCollectionViewCell._boldLabel() dynamic let numberOfBidsLabel = ListingsCollectionViewCell._rightAlignedNormalLabel() dynamic let bidButton = ListingsCollectionViewCell._bidButton() dynamic let moreInfoLabel = ListingsCollectionViewCell._infoLabel() var downloadImage: DownloadImageClosure? var cancelDownloadImage: CancelDownloadImageClosure? var reuseBag: DisposeBag? lazy var moreInfo: Observable = { return Observable.from([self.imageGestureSigal, self.infoGesture]).merge() }() fileprivate lazy var imageGestureSigal: Observable = { let recognizer = UITapGestureRecognizer() self.artworkImageView.addGestureRecognizer(recognizer) self.artworkImageView.isUserInteractionEnabled = true return recognizer.rx.event.map { _ in Date() } }() fileprivate lazy var infoGesture: Observable = { let recognizer = UITapGestureRecognizer() self.moreInfoLabel.addGestureRecognizer(recognizer) self.moreInfoLabel.isUserInteractionEnabled = true return recognizer.rx.event.map { _ in Date() } }() fileprivate var _preparingForReuse = PublishSubject() var preparingForReuse: Observable { return _preparingForReuse.asObservable() } var viewModel = PublishSubject() func setViewModel(_ newViewModel: SaleArtworkViewModel) { self.viewModel.onNext(newViewModel) } fileprivate var _bidPressed = PublishSubject() var bidPressed: Observable { return _bidPressed.asObservable() } override init(frame: CGRect) { super.init(frame: frame) setupSubscriptions() setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupSubscriptions() setup() } override func prepareForReuse() { super.prepareForReuse() cancelDownloadImage?(artworkImageView) _preparingForReuse.onNext() setupSubscriptions() } func setup() { // Necessary to use Autolayout contentView.translatesAutoresizingMaskIntoConstraints = false } func setupSubscriptions() { // Bind subviews reuseBag = DisposeBag() guard let reuseBag = reuseBag else { return } // Start with things not expected to ever change. viewModel.flatMapTo(SaleArtworkViewModel.lotNumber) .replaceNil(with: "") .mapToOptional() .bindTo(lotNumberLabel.rx.text) .addDisposableTo(reuseBag) viewModel.map { (viewModel) -> URL? in return viewModel.thumbnailURL }.subscribe(onNext: { [weak self] url in guard let imageView = self?.artworkImageView else { return } self?.downloadImage?(url, imageView) }).addDisposableTo(reuseBag) viewModel.map { $0.artistName ?? "" } .bindTo(artistNameLabel.rx.text) .addDisposableTo(reuseBag) viewModel.map { $0.titleAndDateAttributedString } .mapToOptional() .bindTo(artworkTitleLabel.rx.attributedText) .addDisposableTo(reuseBag) viewModel.map { $0.estimateString } .bindTo(estimateLabel.rx.text) .addDisposableTo(reuseBag) // Now do properties that _do_ change. viewModel.flatMap { (viewModel) -> Observable in return viewModel.currentBid(prefix: "Current Bid: ", missingPrefix: "Starting Bid: ") } .mapToOptional() .bindTo(currentBidLabel.rx.text) .addDisposableTo(reuseBag) viewModel.flatMapTo(SaleArtworkViewModel.numberOfBids) .mapToOptional() .bindTo(numberOfBidsLabel.rx.text) .addDisposableTo(reuseBag) viewModel.flatMapTo(SaleArtworkViewModel.forSale) .doOnNext { [weak bidButton] forSale in // Button titles aren't KVO-able bidButton?.setTitle((forSale ? "BID" : "SOLD"), for: .normal) } .bindTo(bidButton.rx.isEnabled) .addDisposableTo(reuseBag) bidButton.rx.tap.subscribe(onNext: { [weak self] in self?._bidPressed.onNext(Date()) }) .addDisposableTo(reuseBag) } } private extension ListingsCollectionViewCell { // Mark: UIView-property-methods – need an _ prefix to appease the compiler ¯\_(ツ)_/¯ class func _artworkImageView() -> UIImageView { let imageView = UIImageView() imageView.backgroundColor = .artsyGrayLight() return imageView } class func _rightAlignedNormalLabel() -> UILabel { let label = _normalLabel() label.textAlignment = .right label.numberOfLines = 1 return label } class func _normalLabel() -> UILabel { let label = ARSerifLabel() label.font = label.font.withSize(16) label.numberOfLines = 1 return label } class func _sansSerifLabel() -> UILabel { let label = ARSansSerifLabel() label.font = label.font.withSize(12) label.numberOfLines = 1 return label } class func _italicsLabel() -> UILabel { let label = ARItalicsSerifLabel() label.font = label.font.withSize(16) label.numberOfLines = 1 return label } class func _largeLabel() -> UILabel { let label = _normalLabel() label.font = label.font.withSize(20) return label } class func _bidButton() -> ActionButton { let button = ActionButton() button.setTitle("BID", for: .normal) return button } class func _boldLabel() -> UILabel { let label = _normalLabel() label.font = UIFont.serifBoldFont(withSize: label.font.pointSize) label.numberOfLines = 1 return label } class func _infoLabel() -> UILabel { let label = ARSansSerifLabelWithChevron() label.tintColor = .black label.text = "MORE INFO" return label } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Observable+JSONAble.swift ================================================ import Foundation import Moya import RxSwift enum EidolonError: String { case couldNotParseJSON case notLoggedIn case missingData } extension EidolonError: Swift.Error { } extension Observable { typealias Dictionary = [String: AnyObject] /// Get given JSONified data, pass back objects func mapTo(object classType: B.Type) -> Observable { return self.map { json in guard let dict = json as? Dictionary else { throw EidolonError.couldNotParseJSON } return B.fromJSON(dict) } } /// Get given JSONified data, pass back objects as an array func mapTo(arrayOf classType: B.Type) -> Observable<[B]> { return self.map { json in guard let array = json as? [AnyObject] else { throw EidolonError.couldNotParseJSON } guard let dicts = array as? [Dictionary] else { throw EidolonError.couldNotParseJSON } return dicts.map { B.fromJSON($0) } } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Observable+Logging.swift ================================================ import RxSwift extension Observable { func logError(prefix: String = "Error: ") -> Observable { return self.do(onError: { error in print("\(prefix)\(error)") }) } func logServerError(message: String) -> Observable { return self.do(onError: { e in let error = e as NSError logger.log(message) logger.log("Error: \(error.localizedDescription). \n \(error.artsyServerError())") }) } func logNext() -> Observable { return self.do(onNext: { element in print("\(element)") }) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Observable+Operators.swift ================================================ import RxSwift extension Observable where Element: Equatable { func ignore(value: Element) -> Observable { return filter { (e) -> Bool in return value != e } } } extension Observable { // OK, so the idea is that I have a Variable that exposes an Observable and I want // to switch to the latest without mapping. // // viewModel.flatMap { saleArtworkViewModel in return saleArtworkViewModel.lotNumber } // // Becomes... // // viewModel.flatMapTo(SaleArtworkViewModel.lotNumber) // // Still not sure if this is a good idea. func flatMapTo(_ selector: @escaping (Element) -> () -> Observable) -> Observable { return self.map { (s) -> Observable in return selector(s)() }.switchLatest() } } protocol OptionalType { associatedtype Wrapped var value: Wrapped? { get } } extension Optional: OptionalType { var value: Wrapped? { return self } } extension Observable where Element: OptionalType { func filterNil() -> Observable { return flatMap { (element) -> Observable in if let value = element.value { return .just(value) } else { return .empty() } } } func filterNilKeepOptional() -> Observable { return self.filter { (element) -> Bool in return element.value != nil } } func replaceNil(with nilValue: Element.Wrapped) -> Observable { return flatMap { (element) -> Observable in if let value = element.value { return .just(value) } else { return .just(nilValue) } } } } // TODO: Added in new RxSwift? extension Observable { func doOnNext(_ closure: @escaping (Element) -> Void) -> Observable { return self.do(onNext: { (element) in closure(element) }) } func doOnCompleted(_ closure: @escaping () -> Void) -> Observable { return self.do(onCompleted: { closure() }) } func doOnError(_ closure: @escaping (Error) -> Void) -> Observable { return self.do(onError: { (error) in closure(error) }) } } private let backgroundScheduler = SerialDispatchQueueScheduler(qos: .default) extension Observable { func mapReplace(with value: T) -> Observable { return map { _ -> T in return value } } func dispatchAsyncMainScheduler() -> Observable { return self.observeOn(backgroundScheduler).observeOn(MainScheduler.instance) } } protocol BooleanType { var boolValue: Bool { get } } extension Bool: BooleanType { var boolValue: Bool { return self } } // Maps true to false and vice versa extension Observable where Element: BooleanType { func not() -> Observable { return self.map { input in return !input.boolValue } } } extension Collection where Iterator.Element: ObservableType, Iterator.Element.E: BooleanType { func combineLatestAnd() -> Observable { return Observable.combineLatest(self) { bools -> Bool in return bools.reduce(true, { (memo, element) in return memo && element.boolValue }) } } func combineLatestOr() -> Observable { return Observable.combineLatest(self) { bools in bools.reduce(false, { (memo, element) in return memo || element.boolValue }) } } } extension ObservableType { func then(_ closure: @escaping () -> Observable?) -> Observable { return then(closure() ?? .empty()) } func then( _ closure: @autoclosure @escaping () -> Observable) -> Observable { let next = Observable.deferred { return closure() } return self .ignoreElements() .concat(next) } } extension Observable { func mapToOptional() -> Observable> { return map { Optional($0) } } } func sendDispatchCompleted(to observer: AnyObserver) { DispatchQueue.main.async { observer.onCompleted() } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Sale Artwork Details/ImageTiledDataSource.swift ================================================ import Foundation import ARTiledImageView class TiledImageDataSourceWithImage: ARWebTiledImageDataSource { let image: Image init(image: Image) { self.image = image super.init() tileFormat = "jpg" tileBaseURL = URL(string: image.baseURL) tileSize = image.tileSize maxTiledHeight = image.maxTiledHeight maxTiledWidth = image.maxTiledWidth maxTileLevel = image.maxLevel minTileLevel = 11 } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Sale Artwork Details/SaleArtworkDetailsViewController.swift ================================================ import UIKit import ORStackView import Artsy_UILabels import Artsy_UIFonts import RxSwift import Artsy_UIButtons import SDWebImage import Action class SaleArtworkDetailsViewController: UIViewController { var allowAnimations = true var auctionID = AppSetup.sharedState.auctionID var saleArtwork: SaleArtwork! var provider: Networking! var showBuyersPremiumCommand = { () -> CocoaAction in appDelegate().showBuyersPremiumCommand() } class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> SaleArtworkDetailsViewController { return storyboard.viewController(withID: .SaleArtworkDetail) as! SaleArtworkDetailsViewController } lazy var artistInfo: Observable = { let artistInfo = self.provider.request(.artwork(id: self.saleArtwork.artwork.id)).filterSuccessfulStatusCodes().mapJSON() return artistInfo.shareReplay(1) }() @IBOutlet weak var metadataStackView: ORTagBasedAutoStackView! @IBOutlet weak var additionalDetailScrollView: ORStackScrollView! var buyersPremium: () -> (BuyersPremium?) = { appDelegate().sale.buyersPremium } let layoutSubviews = PublishSubject() let viewWillAppear = PublishSubject() override func viewDidLoad() { super.viewDidLoad() setupMetadataView() setupAdditionalDetailStackView() } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // OK, so this is pretty weird, eh? So basically we need to be notified of layout changes _just after_ the layout // is actually done. For whatever reason, the UIKit hack to get the labels to adhere to their proper width only // works if we defer recalculating their geometry to the next runloop. // This wasn't an issue with RAC's rac_signalForSelector because that invoked the signal _after_ this method completed. // So that's what I've done here. DispatchQueue.main.async { self.layoutSubviews.onNext() } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) viewWillAppear.onCompleted() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue == .ZoomIntoArtwork { let nextViewController = segue.destination as! SaleArtworkZoomViewController nextViewController.saleArtwork = saleArtwork } } enum MetadataStackViewTag: Int { case lotNumberLabel = 1 case artistNameLabel case artworkNameLabel case artworkMediumLabel case artworkDimensionsLabel case imageRightsLabel case estimateTopBorder case estimateLabel case estimateBottomBorder case currentBidLabel case currentBidValueLabel case numberOfBidsPlacedLabel case bidButton case buyersPremium } @IBAction func backWasPressed(_ sender: AnyObject) { _ = navigationController?.popViewController(animated: true) } fileprivate func setupMetadataView() { enum LabelType { case serif case sansSerif case italicsSerif case bold } func label(_ type: LabelType, tag: MetadataStackViewTag, fontSize: CGFloat = 16.0) -> UILabel { let label: UILabel = { () -> UILabel in switch type { case .serif: return ARSerifLabel() case .sansSerif: return ARSansSerifLabel() case .italicsSerif: return ARItalicsSerifLabel() case .bold: let label = ARSerifLabel() label.font = UIFont.sansSerifFont(withSize: label.font.pointSize) return label } }() label.lineBreakMode = .byWordWrapping label.font = label.font.withSize(fontSize) label.tag = tag.rawValue label.preferredMaxLayoutWidth = 276 return label } let hasLotNumber = (saleArtwork.lotNumber != nil) if let _ = saleArtwork.lotNumber { let lotNumberLabel = label(.sansSerif, tag: .lotNumberLabel) lotNumberLabel.font = lotNumberLabel.font.withSize(12) metadataStackView.addSubview(lotNumberLabel, withTopMargin: "0", sideMargin: "0") saleArtwork .viewModel .lotNumber() .filterNil() .mapToOptional() .bindTo(lotNumberLabel.rx.text) .addDisposableTo(rx_disposeBag) } if let artist = artist() { let artistNameLabel = label(.sansSerif, tag: .artistNameLabel) artistNameLabel.text = artist.name metadataStackView.addSubview(artistNameLabel, withTopMargin: hasLotNumber ? "10" : "0", sideMargin: "0") } let artworkNameLabel = label(.italicsSerif, tag: .artworkNameLabel) artworkNameLabel.text = "\(saleArtwork.artwork.title), \(saleArtwork.artwork.date)" metadataStackView.addSubview(artworkNameLabel, withTopMargin: "10", sideMargin: "0") if let medium = saleArtwork.artwork.medium { if medium.isNotEmpty { let mediumLabel = label(.serif, tag: .artworkMediumLabel) mediumLabel.text = medium metadataStackView.addSubview(mediumLabel, withTopMargin: "22", sideMargin: "0") } } if saleArtwork.artwork.dimensions.count > 0 { let dimensionsLabel = label(.serif, tag: .artworkDimensionsLabel) dimensionsLabel.text = (saleArtwork.artwork.dimensions as NSArray).componentsJoined(by: "\n") metadataStackView.addSubview(dimensionsLabel, withTopMargin: "5", sideMargin: "0") } retrieveImageRights() .filter { imageRights -> Bool in return imageRights.isNotEmpty }.subscribe(onNext: { [weak self] imageRights in let rightsLabel = label(.serif, tag: .imageRightsLabel) rightsLabel.text = imageRights self?.metadataStackView.addSubview(rightsLabel, withTopMargin: "22", sideMargin: "0") }) .addDisposableTo(rx_disposeBag) let estimateTopBorder = UIView() estimateTopBorder.constrainHeight("1") estimateTopBorder.tag = MetadataStackViewTag.estimateTopBorder.rawValue metadataStackView.addSubview(estimateTopBorder, withTopMargin: "22", sideMargin: "0") var estimateBottomBorder: UIView? let estimateString = saleArtwork.viewModel.estimateString if estimateString.isNotEmpty { let estimateLabel = label(.serif, tag: .estimateLabel) estimateLabel.text = estimateString metadataStackView.addSubview(estimateLabel, withTopMargin: "15", sideMargin: "0") estimateBottomBorder = UIView() _ = estimateBottomBorder?.constrainHeight("1") estimateBottomBorder?.tag = MetadataStackViewTag.estimateBottomBorder.rawValue metadataStackView.addSubview(estimateBottomBorder, withTopMargin: "10", sideMargin: "0") } viewWillAppear .subscribe(onCompleted: { [weak estimateTopBorder, weak estimateBottomBorder] in estimateTopBorder?.drawDottedBorders() estimateBottomBorder?.drawDottedBorders() }) .addDisposableTo(rx_disposeBag) let hasBids = saleArtwork .rx.observe(NSNumber.self, "highestBidCents") .map { observeredCents -> Bool in guard let cents = observeredCents else { return false } return (cents as Int) > 0 } let currentBidLabel = label(.serif, tag: .currentBidLabel) hasBids .flatMap { hasBids -> Observable in if hasBids { return .just("Current Bid:") } else { return .just("Starting Bid:") } } .mapToOptional() .bindTo(currentBidLabel.rx.text) .addDisposableTo(rx_disposeBag) metadataStackView.addSubview(currentBidLabel, withTopMargin: "22", sideMargin: "0") let currentBidValueLabel = label(.bold, tag: .currentBidValueLabel, fontSize: 27) saleArtwork .viewModel .currentBid() .mapToOptional() .bindTo(currentBidValueLabel.rx.text) .addDisposableTo(rx_disposeBag) metadataStackView.addSubview(currentBidValueLabel, withTopMargin: "10", sideMargin: "0") let numberOfBidsPlacedLabel = label(.serif, tag: .numberOfBidsPlacedLabel) saleArtwork .viewModel .numberOfBidsWithReserve .mapToOptional() .bindTo(numberOfBidsPlacedLabel.rx.text) .addDisposableTo(rx_disposeBag) metadataStackView.addSubview(numberOfBidsPlacedLabel, withTopMargin: "10", sideMargin: "0") let bidButton = ActionButton() bidButton .rx.tap .asObservable() .subscribe(onNext: { [weak self] _ in guard let me = self else { return } me.bid(auctionID: me.auctionID, saleArtwork: me.saleArtwork, allowAnimations: me.allowAnimations, provider: me.provider) }) .addDisposableTo(rx_disposeBag) saleArtwork .viewModel .forSale() .subscribe(onNext: { [weak bidButton] forSale in let forSale = forSale let title = forSale ? "BID" : "SOLD" bidButton?.setTitle(title, for: .normal) }) .addDisposableTo(rx_disposeBag) saleArtwork .viewModel .forSale() .bindTo(bidButton.rx.isEnabled) .addDisposableTo(rx_disposeBag) bidButton.tag = MetadataStackViewTag.bidButton.rawValue metadataStackView.addSubview(bidButton, withTopMargin: "40", sideMargin: "0") if let _ = buyersPremium() { let buyersPremiumView = UIView() buyersPremiumView.tag = MetadataStackViewTag.buyersPremium.rawValue let buyersPremiumLabel = ARSerifLabel() buyersPremiumLabel.font = buyersPremiumLabel.font.withSize(16) buyersPremiumLabel.text = "This work has a " buyersPremiumLabel.textColor = .artsyGrayBold() var buyersPremiumButton = ARButton() let title = "buyers premium" let attributes: [String: AnyObject] = [ NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue as AnyObject, NSFontAttributeName: buyersPremiumLabel.font ] let attributedTitle = NSAttributedString(string: title, attributes: attributes) buyersPremiumButton.setTitle(title, for: .normal) buyersPremiumButton.titleLabel?.attributedText = attributedTitle buyersPremiumButton.setTitleColor(.artsyGrayBold(), for: .normal) buyersPremiumButton.rx.action = showBuyersPremiumCommand() buyersPremiumView.addSubview(buyersPremiumLabel) buyersPremiumView.addSubview(buyersPremiumButton) buyersPremiumLabel.alignTop("0", leading: "0", bottom: "0", trailing: nil, to: buyersPremiumView) buyersPremiumLabel.alignBaseline(with: buyersPremiumButton, predicate: nil) buyersPremiumButton.alignAttribute(.left, to: .right, of: buyersPremiumLabel, predicate: "0") metadataStackView.addSubview(buyersPremiumView, withTopMargin: "30", sideMargin: "0") } metadataStackView.bottomMarginHeight = CGFloat(NSNotFound) } fileprivate func setupImageView(_ imageView: UIImageView) { if let image = saleArtwork.artwork.defaultImage { // We'll try to retrieve the thumbnail image from the cache. If we don't have it, we'll set the background colour to grey to indicate that we're downloading it. let key = SDWebImageManager.shared().cacheKey(for: image.thumbnailURL() as URL!) let thumbnailImage = SDImageCache.shared().imageFromDiskCache(forKey: key) if thumbnailImage == nil { imageView.backgroundColor = .artsyGrayLight() } imageView.sd_setImage(with: image.fullsizeURL(), placeholderImage: thumbnailImage, options: [], completed: { (image, _, _, _) in // If the image was successfully downloaded, make sure we aren't still displaying grey. if image != nil { imageView.backgroundColor = .clear } }) let heightConstraintNumber = { () -> CGFloat in if let aspectRatio = image.aspectRatio { if aspectRatio != 0 { return min(400, CGFloat(538) / aspectRatio) } } return 400 }() imageView.constrainHeight( "\(heightConstraintNumber)" ) imageView.contentMode = .scaleAspectFit imageView.isUserInteractionEnabled = true let recognizer = UITapGestureRecognizer() imageView.addGestureRecognizer(recognizer) recognizer .rx.event .asObservable() .subscribe(onNext: { [weak self] _ in self?.performSegue(.ZoomIntoArtwork) }) .addDisposableTo(rx_disposeBag) } } fileprivate func setupAdditionalDetailStackView() { enum LabelType { case header case body } func label(_ type: LabelType, layout: Observable? = nil) -> UILabel { let (label, fontSize) = { () -> (UILabel, CGFloat) in switch type { case .header: return (ARSansSerifLabel(), 14) case .body: return (ARSerifLabel(), 16) } }() label.font = label.font.withSize(fontSize) label.lineBreakMode = .byWordWrapping layout? .take(1) .subscribe(onNext: { [weak label] (_) in if let label = label { label.preferredMaxLayoutWidth = label.frame.width } }) .addDisposableTo(rx_disposeBag) return label } additionalDetailScrollView.stackView.bottomMarginHeight = 40 let imageView = UIImageView() additionalDetailScrollView.stackView.addSubview(imageView, withTopMargin: "0", sideMargin: "40") setupImageView(imageView) let additionalInfoHeaderLabel = label(.header) additionalInfoHeaderLabel.text = "Additional Information" additionalDetailScrollView.stackView.addSubview(additionalInfoHeaderLabel, withTopMargin: "20", sideMargin: "40") if let blurb = saleArtwork.artwork.blurb { let blurbLabel = label(.body, layout: layoutSubviews) blurbLabel.attributedText = MarkdownParser().attributedString( fromMarkdownString: blurb ) additionalDetailScrollView.stackView.addSubview(blurbLabel, withTopMargin: "22", sideMargin: "40") } let additionalInfoLabel = label(.body, layout: layoutSubviews) additionalInfoLabel.attributedText = MarkdownParser().attributedString( fromMarkdownString: saleArtwork.artwork.additionalInfo ) additionalDetailScrollView.stackView.addSubview(additionalInfoLabel, withTopMargin: "22", sideMargin: "40") retrieveAdditionalInfo() .filter { info in return info.isNotEmpty }.subscribe(onNext: { [weak self] info in additionalInfoLabel.attributedText = MarkdownParser().attributedString(fromMarkdownString: info) self?.view.setNeedsLayout() self?.view.layoutIfNeeded() }) .addDisposableTo(rx_disposeBag) if let artist = artist() { retrieveArtistBlurb() .filter { blurb in return blurb.isNotEmpty } .subscribe(onNext: { [weak self] blurb in guard let me = self else { return } let aboutArtistHeaderLabel = label(.header) aboutArtistHeaderLabel.text = "About \(artist.name)" me.additionalDetailScrollView.stackView.addSubview(aboutArtistHeaderLabel, withTopMargin: "22", sideMargin: "40") let aboutAristLabel = label(.body, layout: me.layoutSubviews) aboutAristLabel.attributedText = MarkdownParser().attributedString(fromMarkdownString: blurb) me.additionalDetailScrollView.stackView.addSubview(aboutAristLabel, withTopMargin: "22", sideMargin: "40") }) .addDisposableTo(rx_disposeBag) } } fileprivate func artist() -> Artist? { return saleArtwork.artwork.artists?.first } fileprivate func retrieveImageRights() -> Observable { let artwork = saleArtwork.artwork if let imageRights = artwork.imageRights { return .just(imageRights) } else { return artistInfo.map { json in return (json as AnyObject)["image_rights"] as? String } .filterNil() .doOnNext { imageRights in artwork.imageRights = imageRights } } } fileprivate func retrieveAdditionalInfo() -> Observable { let artwork = saleArtwork.artwork if let additionalInfo = artwork.additionalInfo { return .just(additionalInfo) } else { return artistInfo.map { json in return (json as AnyObject)["additional_information"] as? String } .filterNil() .doOnNext { info in artwork.additionalInfo = info } } } fileprivate func retrieveArtistBlurb() -> Observable { guard let artist = artist() else { return .empty() } if let blurb = artist.blurb { return .just(blurb) } else { let retrieveArtist = provider.request(.artist(id: artist.id)) .filterSuccessfulStatusCodes() .mapJSON() return retrieveArtist.map { json in return (json as AnyObject)["blurb"] as? String } .filterNil() .doOnNext { blurb in artist.blurb = blurb } } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Sale Artwork Details/SaleArtworkZoomViewController.swift ================================================ import Foundation import ARTiledImageView class SaleArtworkZoomViewController: UIViewController { var dataSource: TiledImageDataSourceWithImage! var saleArtwork: SaleArtwork! var tiledImageView: ARTiledImageScrollView! override func viewDidLoad() { super.viewDidLoad() let image = saleArtwork.artwork.defaultImage! dataSource = TiledImageDataSourceWithImage(image:image) let tiledView = ARTiledImageScrollView(frame:view.bounds) tiledView.decelerationRate = UIScrollViewDecelerationRateFast tiledView.showsHorizontalScrollIndicator = false tiledView.showsVerticalScrollIndicator = false tiledView.contentMode = .scaleAspectFit tiledView.dataSource = dataSource tiledView.backgroundImageURL = image.fullsizeURL() as URL! view.insertSubview(tiledView, at:0) tiledImageView = tiledView } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) tiledImageView.zoom(toFit: false) } @IBAction func backButtonTapped(_ sender: AnyObject) { _ = self.navigationController?.popViewController(animated: true) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/Sale Artwork Details/WhitespaceGobbler.swift ================================================ import UIKit class WhitespaceGobbler: UIView { override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } convenience init() { self.init(frame: CGRect.zero) setContentHuggingPriority(50, for: .vertical) setContentHuggingPriority(50, for: .horizontal) backgroundColor = .clear } override var intrinsicContentSize: CGSize { return CGSize.zero } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/UIKit+Rx.swift ================================================ import UIKit import RxSwift import RxCocoa extension UIView { public var rx_hidden: AnyObserver { return AnyObserver { [weak self] event in MainScheduler.ensureExecutingOnScheduler() switch event { case .next(let value): self?.isHidden = value case .error(let error): bindingErrorToInterface(error) break case .completed: break } } } } extension UITextField { var rx_returnKey: Observable { return self.rx.controlEvent(.editingDidEndOnExit).takeUntil(rx.deallocated) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/UILabel+Fonts.swift ================================================ import UIKit extension UILabel { func makeSubstringsBold(_ text: [String]) { text.forEach { self.makeSubstringBold($0) } } func makeSubstringBold(_ boldText: String) { let attributedText = self.attributedText!.mutableCopy() as! NSMutableAttributedString let range = ((self.text ?? "") as NSString).range(of: boldText) if range.location != NSNotFound { attributedText.setAttributes([NSFontAttributeName: UIFont.serifSemiBoldFont(withSize: self.font.pointSize)], range: range) } self.attributedText = attributedText } func makeSubstringsItalic(_ text: [String]) { text.forEach { self.makeSubstringItalic($0) } } func makeSubstringItalic(_ italicText: String) { let attributedText = self.attributedText!.mutableCopy() as! NSMutableAttributedString let range = ((self.text ?? "") as NSString).range(of: italicText) if range.location != NSNotFound { attributedText.setAttributes([NSFontAttributeName: UIFont.serifItalicFont(withSize: self.font.pointSize)], range: range) } self.attributedText = attributedText } func setLineHeight(_ lineHeight: Int) { let displayText = text ?? "" let attributedString = self.attributedText!.mutableCopy() as! NSMutableAttributedString let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = CGFloat(lineHeight) paragraphStyle.alignment = textAlignment attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, displayText.count)) attributedText = attributedString } func makeTransparent() { isOpaque = false backgroundColor = .clear } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/UIView+LongPressDisplayMessage.swift ================================================ import UIKit import RxSwift private func alertController(_ message: String, title: String) -> UIAlertController { let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) return alertController } extension UIView { typealias PresentAlertClosure = (_ alertController: UIAlertController) -> Void func presentOnLongPress(_ message: String, title: String, closure: @escaping PresentAlertClosure) { let recognizer = UILongPressGestureRecognizer() recognizer .rx.event .subscribe(onNext: { _ in closure(alertController(message, title: title)) }) .addDisposableTo(rx_disposeBag) isUserInteractionEnabled = true addGestureRecognizer(recognizer) } } ================================================ FILE: SourceryTests/Stub/Performance-Code/Kiosk/UIViewController+Bidding.swift ================================================ import UIKit import ARAnalytics extension UIViewController { func bid(auctionID: String, saleArtwork: SaleArtwork, allowAnimations: Bool, provider: Networking) { ARAnalytics.event("Bid Button Tapped", withProperties: ["id": saleArtwork.artwork.id]) let storyboard = UIStoryboard.fulfillment() let containerController = storyboard.instantiateInitialViewController() as! FulfillmentContainerViewController containerController.allowAnimations = allowAnimations if let internalNav: FulfillmentNavigationController = containerController.internalNavigationController() { internalNav.auctionID = auctionID internalNav.bidDetails.saleArtwork = saleArtwork internalNav.provider = provider } // Present the VC, then once it's ready trigger it's own showing animations appDelegate().appViewController.present(containerController, animated: false) { containerController.viewDidAppearAnimation(containerController.allowAnimations) } } } ================================================ FILE: SourceryTests/Stub/Performance-Code/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Artsy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: SourceryTests/Stub/Result/AllTypealiases.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT struct AnyBarAlias: HasBar { var bar: BarBaz } struct AnyFooAlias: HasFoo { var foo: FooBarBaz } ================================================ FILE: SourceryTests/Stub/Result/Basic+Other+SourceryTemplates.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension BarBaz: Equatable {} // BarBaz has Annotations func == (lhs: BarBaz, rhs: BarBaz) -> Bool { if lhs.parent != rhs.parent { return false } if lhs.otherVariable != rhs.otherVariable { return false } return true } extension FooBarBaz: Equatable {} func == (lhs: FooBarBaz, rhs: FooBarBaz) -> Bool { if lhs.name != rhs.name { return false } if lhs.value != rhs.value { return false } return true } extension FooSubclass: Equatable {} func == (lhs: FooSubclass, rhs: FooSubclass) -> Bool { if lhs.other != rhs.other { return false } return true } // Found 3 types // SourceryTemplateEJS Found 3 types // SourceryTemplateStencil found 3 types ================================================ FILE: SourceryTests/Stub/Result/Basic+Other+SourceryTemplates_Linux.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension BarBaz: Equatable {} // BarBaz has Annotations func == (lhs: BarBaz, rhs: BarBaz) -> Bool { if lhs.parent != rhs.parent { return false } if lhs.otherVariable != rhs.otherVariable { return false } return true } extension FooBarBaz: Equatable {} func == (lhs: FooBarBaz, rhs: FooBarBaz) -> Bool { if lhs.name != rhs.name { return false } if lhs.value != rhs.value { return false } return true } extension FooSubclass: Equatable {} func == (lhs: FooSubclass, rhs: FooSubclass) -> Bool { if lhs.other != rhs.other { return false } return true } // Found 3 types // SourceryTemplateStencil found 3 types ================================================ FILE: SourceryTests/Stub/Result/Basic+Other.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension BarBaz: Equatable {} // BarBaz has Annotations func == (lhs: BarBaz, rhs: BarBaz) -> Bool { if lhs.parent != rhs.parent { return false } if lhs.otherVariable != rhs.otherVariable { return false } return true } extension FooBarBaz: Equatable {} func == (lhs: FooBarBaz, rhs: FooBarBaz) -> Bool { if lhs.name != rhs.name { return false } if lhs.value != rhs.value { return false } return true } extension FooSubclass: Equatable {} func == (lhs: FooSubclass, rhs: FooSubclass) -> Bool { if lhs.other != rhs.other { return false } return true } // Found 3 types ================================================ FILE: SourceryTests/Stub/Result/Basic.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension BarBaz: Equatable {} // BarBaz has Annotations func == (lhs: BarBaz, rhs: BarBaz) -> Bool { if lhs.parent != rhs.parent { return false } if lhs.otherVariable != rhs.otherVariable { return false } return true } extension FooBarBaz: Equatable {} func == (lhs: FooBarBaz, rhs: FooBarBaz) -> Bool { if lhs.name != rhs.name { return false } if lhs.value != rhs.value { return false } return true } extension FooSubclass: Equatable {} func == (lhs: FooSubclass, rhs: FooSubclass) -> Bool { if lhs.other != rhs.other { return false } return true } ================================================ FILE: SourceryTests/Stub/Result/BasicFooExcluded.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension BarBaz: Equatable {} // BarBaz has Annotations func == (lhs: BarBaz, rhs: BarBaz) -> Bool { if lhs.parent != rhs.parent { return false } if lhs.otherVariable != rhs.otherVariable { return false } return true } ================================================ FILE: SourceryTests/Stub/Result/Function.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT func wrappedPerformFoo(value: FooBarBaz) { performFoo(value: value) } ================================================ FILE: SourceryTests/Stub/Result/Other.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Found 3 types ================================================ FILE: SourceryTests/Stub/Result/ProtocolCompositions.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT struct AnyFooBar: FooBar { // MARK: HasFoo properties var foo: FooBarBaz // MARK: HasBar properties var bar: BarBaz } ================================================ FILE: SourceryTests/Stub/Result/Typealiases.swift ================================================ // Generated using Sourcery Major.Minor.Patch — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // Typealiases in BarBaz // - name 'List', type '[FooBarBaz]' // Typealiases in FooBarBaz // - name 'Name', type '[String: String]' // Typealiases in FooSubclass ================================================ FILE: SourceryTests/Stub/Source/Bar.swift ================================================ import Foundation // sourcery: this will not appear under FooBarBaz /// Documentation for bar // sourcery: showComment /// other documentation class BarBaz: FooBarBaz, AutoEquatable { typealias List = [FooBarBaz] var parent: FooBarBaz? = nil var otherVariable: Int = 0 } ================================================ FILE: SourceryTests/Stub/Source/Foo.swift ================================================ import Foundation class FooBarBaz { typealias Name = [String: String] var name: String = "" var value: Int = 0 } protocol AutoEquatable {} class FooSubclass: FooBarBaz, AutoEquatable { var other: String = "" } func performFoo(value: FooBarBaz) { } ================================================ FILE: SourceryTests/Stub/Source/FooBar.swift ================================================ import Foundation protocol HasFoo { var foo: FooBarBaz { get } } protocol HasBar { var bar: BarBaz { get } } // sourcery: AutoStruct typealias FooBar = HasFoo & HasBar // sourcery: AutoStruct typealias FooAlias = HasFoo // sourcery: AutoStruct typealias BarAlias = HasBar ================================================ FILE: SourceryTests/Stub/Source/TestProject/TestProject/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: SourceryTests/Stub/Source/TestProject/TestProject.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 48; objects = { /* Begin PBXBuildFile section */ 6396C56D202B236B00BC2767 /* Bar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6396C56B202B236B00BC2767 /* Bar.swift */; }; 6396C56E202B236B00BC2767 /* Foo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6396C56C202B236B00BC2767 /* Foo.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 6396C556202B234E00BC2767 /* TestProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6396C565202B234E00BC2767 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6396C56B202B236B00BC2767 /* Bar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bar.swift; path = ../../Bar.swift; sourceTree = ""; }; 6396C56C202B236B00BC2767 /* Foo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Foo.swift; path = ../../Foo.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 6396C553202B234E00BC2767 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 6396C54D202B234E00BC2767 = { isa = PBXGroup; children = ( 6396C558202B234E00BC2767 /* TestProject */, 6396C557202B234E00BC2767 /* Products */, ); sourceTree = ""; }; 6396C557202B234E00BC2767 /* Products */ = { isa = PBXGroup; children = ( 6396C556202B234E00BC2767 /* TestProject.app */, ); name = Products; sourceTree = ""; }; 6396C558202B234E00BC2767 /* TestProject */ = { isa = PBXGroup; children = ( 6396C565202B234E00BC2767 /* Info.plist */, 6396C56B202B236B00BC2767 /* Bar.swift */, 6396C56C202B236B00BC2767 /* Foo.swift */, ); path = TestProject; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 6396C555202B234E00BC2767 /* TestProject */ = { isa = PBXNativeTarget; buildConfigurationList = 6396C568202B234E00BC2767 /* Build configuration list for PBXNativeTarget "TestProject" */; buildPhases = ( 6396C552202B234E00BC2767 /* Sources */, 6396C553202B234E00BC2767 /* Frameworks */, 6396C554202B234E00BC2767 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = TestProject; productName = TestProject; productReference = 6396C556202B234E00BC2767 /* TestProject.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 6396C54E202B234E00BC2767 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 0920; ORGANIZATIONNAME = Pixle; TargetAttributes = { 6396C555202B234E00BC2767 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 0920; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 6396C551202B234E00BC2767 /* Build configuration list for PBXProject "TestProject" */; compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 6396C54D202B234E00BC2767; productRefGroup = 6396C557202B234E00BC2767 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 6396C555202B234E00BC2767 /* TestProject */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 6396C554202B234E00BC2767 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 6396C552202B234E00BC2767 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 6396C56E202B236B00BC2767 /* Foo.swift in Sources */, 6396C56D202B236B00BC2767 /* Bar.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 6396C566202B234E00BC2767 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 6396C567202B234E00BC2767 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; }; 6396C569202B234E00BC2767 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = TestProject/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.TestProject; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 6396C56A202B234E00BC2767 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = TestProject/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.TestProject; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 6396C551202B234E00BC2767 /* Build configuration list for PBXProject "TestProject" */ = { isa = XCConfigurationList; buildConfigurations = ( 6396C566202B234E00BC2767 /* Debug */, 6396C567202B234E00BC2767 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 6396C568202B234E00BC2767 /* Build configuration list for PBXNativeTarget "TestProject" */ = { isa = XCConfigurationList; buildConfigurations = ( 6396C569202B234E00BC2767 /* Debug */, 6396C56A202B234E00BC2767 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 6396C54E202B234E00BC2767 /* Project object */; } ================================================ FILE: SourceryTests/Stub/Source/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: SourceryTests/Stub/Source_Linux/Bar.swift ================================================ import Foundation // sourcery: this will not appear under FooBarBaz /// Documentation for bar // sourcery: showComment /// other documentation class BarBaz: FooBarBaz, AutoEquatable { // Note: when Swift Linux doesn't bug out on [String: String], add a test back for it // See https://github.com/krzysztofzablocki/Sourcery/pull/1208#issuecomment-1752185381 // typealias List = [FooBarBaz] var parent: FooBarBaz? = nil var otherVariable: Int = 0 } ================================================ FILE: SourceryTests/Stub/Source_Linux/Foo.swift ================================================ import Foundation class FooBarBaz { // Note: when Swift Linux doesn't bug out on [String: String], add a test back for it // See https://github.com/krzysztofzablocki/Sourcery/pull/1208#issuecomment-1752185381 // typealias Name = String var name: String = "" var value: Int = 0 } protocol AutoEquatable {} class FooSubclass: FooBarBaz, AutoEquatable { var other: String = "" } func performFoo(value: FooBarBaz) { } ================================================ FILE: SourceryTests/Stub/Source_Linux/FooBar.swift ================================================ import Foundation protocol HasFoo { var foo: FooBarBaz { get } } protocol HasBar { var bar: BarBaz { get } } // sourcery: AutoStruct typealias FooBar = HasFoo & HasBar ================================================ FILE: SourceryTests/Stub/Source_Linux/TestProject/TestProject/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: SourceryTests/Stub/Source_Linux/TestProject/TestProject.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 48; objects = { /* Begin PBXBuildFile section */ 6396C56D202B236B00BC2767 /* Bar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6396C56B202B236B00BC2767 /* Bar.swift */; }; 6396C56E202B236B00BC2767 /* Foo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6396C56C202B236B00BC2767 /* Foo.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 6396C556202B234E00BC2767 /* TestProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6396C565202B234E00BC2767 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6396C56B202B236B00BC2767 /* Bar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bar.swift; path = ../../Bar.swift; sourceTree = ""; }; 6396C56C202B236B00BC2767 /* Foo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Foo.swift; path = ../../Foo.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 6396C553202B234E00BC2767 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 6396C54D202B234E00BC2767 = { isa = PBXGroup; children = ( 6396C558202B234E00BC2767 /* TestProject */, 6396C557202B234E00BC2767 /* Products */, ); sourceTree = ""; }; 6396C557202B234E00BC2767 /* Products */ = { isa = PBXGroup; children = ( 6396C556202B234E00BC2767 /* TestProject.app */, ); name = Products; sourceTree = ""; }; 6396C558202B234E00BC2767 /* TestProject */ = { isa = PBXGroup; children = ( 6396C565202B234E00BC2767 /* Info.plist */, 6396C56B202B236B00BC2767 /* Bar.swift */, 6396C56C202B236B00BC2767 /* Foo.swift */, ); path = TestProject; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 6396C555202B234E00BC2767 /* TestProject */ = { isa = PBXNativeTarget; buildConfigurationList = 6396C568202B234E00BC2767 /* Build configuration list for PBXNativeTarget "TestProject" */; buildPhases = ( 6396C552202B234E00BC2767 /* Sources */, 6396C553202B234E00BC2767 /* Frameworks */, 6396C554202B234E00BC2767 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = TestProject; productName = TestProject; productReference = 6396C556202B234E00BC2767 /* TestProject.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 6396C54E202B234E00BC2767 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 0920; ORGANIZATIONNAME = Pixle; TargetAttributes = { 6396C555202B234E00BC2767 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 0920; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 6396C551202B234E00BC2767 /* Build configuration list for PBXProject "TestProject" */; compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 6396C54D202B234E00BC2767; productRefGroup = 6396C557202B234E00BC2767 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 6396C555202B234E00BC2767 /* TestProject */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 6396C554202B234E00BC2767 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 6396C552202B234E00BC2767 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 6396C56E202B236B00BC2767 /* Foo.swift in Sources */, 6396C56D202B236B00BC2767 /* Bar.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 6396C566202B234E00BC2767 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 6396C567202B234E00BC2767 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; }; 6396C569202B234E00BC2767 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = TestProject/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.TestProject; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 6396C56A202B234E00BC2767 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = TestProject/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.TestProject; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 6396C551202B234E00BC2767 /* Build configuration list for PBXProject "TestProject" */ = { isa = XCConfigurationList; buildConfigurations = ( 6396C566202B234E00BC2767 /* Debug */, 6396C567202B234E00BC2767 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 6396C568202B234E00BC2767 /* Build configuration list for PBXNativeTarget "TestProject" */ = { isa = XCConfigurationList; buildConfigurations = ( 6396C569202B234E00BC2767 /* Debug */, 6396C56A202B234E00BC2767 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 6396C54E202B234E00BC2767 /* Project object */; } ================================================ FILE: SourceryTests/Stub/Source_Linux/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: SourceryTests/Stub/Stubs.swift ================================================ // // Created by Krzysztof Zablocki on 13/12/2016. // Copyright (c) 2016 Pixle. All rights reserved. // import Foundation import PathKit import Quick #if SWIFT_PACKAGE @testable import SourceryLib #else @testable import Sourcery #endif private class Reference {} enum Stubs { #if SWIFT_PACKAGE static let bundle = Bundle.module #else static let bundle = Bundle(for: Reference.self) #endif private static let basePath = bundle.resourcePath.flatMap { Path($0) }! static let swiftTemplates = basePath + Path("SwiftTemplates/") static let jsTemplates = basePath + Path("JavaScriptTemplates/") #if canImport(ObjectiveC) static let sourceDirectory = basePath + Path("Source/") #else static let sourceDirectory = basePath + Path("Source_Linux/") #endif static let sourceForPerformance = basePath + Path("Performance-Code/") static let sourceForDryRun = basePath + Path("DryRun-Code/") static let resultDirectory = basePath + Path("Result/") static let templateDirectory = basePath + Path("Templates") static let errorsDirectory = basePath + Path("Errors/") static let configs = basePath + Path("Configs/") static func cleanTemporarySourceryDir() -> Path { return Path.cleanTemporaryDir(name: "Sourcery") } } ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Equality.swift ================================================ import SourceryRuntime enum EqualityGenerator { static func generate(for types: Types) -> String { return types.classes.map { $0.generateEquality() }.joined(separator: "\n") } } extension Class { func generateEquality() -> String { let propertyComparisons = variables.map { $0.generateEquality() }.joined(separator: "\n ") return """ extension \(name): Equatable {} \(hasAnnotations()) func == (lhs: \(name), rhs: \(name)) -> Bool { \(propertyComparisons) return true } """ } func hasAnnotations() -> String { guard annotations["showComment"] != nil else { return "" } return """ // \(name) has Annotations """ } } extension Variable { func generateEquality() -> String { return "if lhs.\(name) != rhs.\(name) { return false }" } } ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Equality.swifttemplate ================================================ <% for type in types.classes { -%> <%_ %><%# this is a comment -%> extension <%= type.name %>: Equatable {} <%_ if type.annotations["showComment"] != nil { -%> <% _%> // <%= type.name %> has Annotations <% } -%> func == (lhs: <%= type.name %>, rhs: <%= type.name %>) -> Bool { <%_ for variable in type.variables { -%> if lhs.<%= variable.name %> != rhs.<%= variable.name %> { return false } <%_ } %> return true } <% } -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Function.swifttemplate ================================================ <%_ for function in functions { let functionName = String(function.name.split(separator: "(")[0]) let capitalizedName = functionName.prefix(1).uppercased() + functionName.dropFirst() -%> func wrapped<%= capitalizedName %>(<%= function.parameters.map { "\($0.name): \($0.typeName.name)" }.joined(separator: ", ") %>) { <%= functionName %>(<%= function.parameters.map { "\($0.name): \($0.name)" }.joined(separator: ", ") %>) } <%_ } -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/IncludeCycle.swifttemplate ================================================ <%- include("includeCycle/One.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/IncludeFile.swifttemplate ================================================ <%- includeFile("Equality.swift") -%><%= EqualityGenerator.generate(for: types) %> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/IncludeFileNoExtension.swifttemplate ================================================ <%- includeFile("Equality") -%><%= EqualityGenerator.generate(for: types) %> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Includes.swifttemplate ================================================ <%- include("Equality.swifttemplate") -%><%- include("Other.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/IncludesNoExtension.swifttemplate ================================================ <%- include("Equality") -%><%- include("Other") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Invalid.swifttemplate ================================================ <%= %> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/InvalidTag.swifttemplate ================================================ <% for type in types.all {%> extension <%= type.name > { } <%}%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Other.swifttemplate ================================================ // Found <%= types.all.count %> types ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Runtime.swifttemplate ================================================ <%= types.implementing["Some"] %> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/SelfIncludeCycle.swifttemplate ================================================ <%- include("SelfIncludeCycle.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/SubfolderFileIncludes.swifttemplate ================================================ <%- includeFile("lib/Equality.swift") -%><%= EqualityGenerator.generate(for: types) %> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/SubfolderIncludes.swifttemplate ================================================ <%- include("lib/One.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/Throws.swifttemplate ================================================ <% fatalError("Template not implemented") %> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/includeCycle/One.swifttemplate ================================================ <%- include("Two.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/includeCycle/Two.swifttemplate ================================================ <%- include("One.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/lib/Equality.swift ================================================ import SourceryRuntime enum EqualityGenerator { static func generate(for types: Types) -> String { return types.classes.map { $0.generateEquality() }.joined(separator: "\n") } } extension Class { func generateEquality() -> String { let propertyComparisons = variables.map { $0.generateEquality() }.joined(separator: "\n ") return """ extension \(name): Equatable {} \(hasAnnotations()) func == (lhs: \(name), rhs: \(name)) -> Bool { \(propertyComparisons) return true } """ } func hasAnnotations() -> String { guard annotations["showComment"] != nil else { return "" } return """ // \(name) has Annotations """ } } extension Variable { func generateEquality() -> String { return "if lhs.\(name) != rhs.\(name) { return false }" } } ================================================ FILE: SourceryTests/Stub/SwiftTemplates/lib/One.swifttemplate ================================================ <%- include("Two.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/SwiftTemplates/lib/Two.swifttemplate ================================================ <%- include("../Equality.swifttemplate") -%> ================================================ FILE: SourceryTests/Stub/Templates/Basic.stencil ================================================ {% for type in types.classes %} extension {{ type.name }}: Equatable {} {% if type.annotations.showComment %} // {{ type.name }} has Annotations {% endif %} func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool { {% for variable in type.variables %} if lhs.{{ variable.name }} != rhs.{{ variable.name }} { return false } {% endfor %} return true } {% endfor %} ================================================ FILE: SourceryTests/Stub/Templates/GenerationWays.stencil ================================================ // swiftlint:disable file_length fileprivate func compareOptionals(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { switch (lhs, rhs) { case let (lValue?, rValue?): return compare(lValue, rValue) case (nil, nil): return true default: return false } } fileprivate func compareArrays(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { guard lhs.count == rhs.count else { return false } for (idx, lhsItem) in lhs.enumerated() { guard compare(lhsItem, rhs[idx]) else { return false } } return true } {% macro compareVariables variables %} {% for variable in variables where variable.readAccess != "private" and variable.readAccess != "fileprivate" %}{% if not variable.annotations.skipEquality %}guard {% if not variable.isOptional %}{% if not variable.annotations.arrayEquality %}lhs.{{ variable.name }} == rhs.{{ variable.name }}{% else %}compareArrays(lhs: lhs.{{ variable.name }}, rhs: rhs.{{ variable.name }}, compare: ==){% endif %}{% else %}compareOptionals(lhs: lhs.{{ variable.name }}, rhs: rhs.{{ variable.name }}, compare: ==){% endif %} else { return false }{% endif %} {% endfor %} {% endmacro %} // MARK: - AutoEquatable for classes, protocols, structs {% for type in types.types|!enum where type.implements.AutoEquatable or type|annotated:"AutoEquatable" %} // sourcery:inline:{{ type.name }}.AutoEquatable // MARK: - {{ type.name }} AutoEquatable {% if not type.kind == "protocol" and not type.based.NSObject %}extension {{ type.name }}: Equatable {}{% endif %} {% if type.supertype.based.Equatable or type.supertype.implements.AutoEquatable or type.supertype|annotated:"AutoEquatable" %}THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable{% endif %} {{ type.accessLevel }} func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool { {% if not type.kind == "protocol" %} {% call compareVariables type.storedVariables %} {% else %} {% call compareVariables type.allVariables %} {% endif %} return true } // sourcery:end {% endfor %} // MARK: - AutoEquatable for Enums {% for type in types.enums where type.implements.AutoEquatable or type|annotated:"AutoEquatable" %} // sourcery:file:Generated/{{ type.name }}+TemplateName // MARK: - {{ type.name }} AutoEquatable extension {{ type.name }}: Equatable {} {{ type.accessLevel }} func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool { switch (lhs, rhs) { {% for case in type.cases %} {% if case.hasAssociatedValue %} {% if case.associatedValues.count == 1 %} case let (.{{ case.name }}(lhs), .{{ case.name }}(rhs)): {% else %} {% map case.associatedValues into lhsValues using associated %}lhs{{ associated.externalName|upperFirstLetter }}{% endmap %} {% map case.associatedValues into rhsValues using associated %}rhs{{ associated.externalName|upperFirstLetter }}{% endmap %} case let (.{{ case.name }}({{ lhsValues|join: ", " }}), .{{ case.name }}({{ rhsValues|join: ", " }})): {% endif %} {% else %} case (.{{ case.name }}, .{{ case.name }}): {% endif %} {% if not case.hasAssociatedValue %}return true{% else %} {% if case.associatedValues.count == 1 %} return lhs == rhs {% else %} {% for associated in case.associatedValues %}if lhs{{ associated.externalName|upperFirstLetter }} != rhs{{ associated.externalName|upperFirstLetter }} { return false } {% endfor %}return true {% endif %} {% endif %} {% endfor %} {{ 'default: return false' if type.cases.count > 1 }} } } // sourcery:end {% endfor %} ================================================ FILE: SourceryTests/Stub/Templates/Include.stencil ================================================ {% include "Partial.stencil" %} ================================================ FILE: SourceryTests/Stub/Templates/Other.stencil ================================================ // Found {{ types.all.count }} types ================================================ FILE: SourceryTests/Stub/Templates/Partial.stencil ================================================ partial template content ================================================ FILE: SourceryTests/Stub/Templates/SourceryTemplateEJS.sourcerytemplate ================================================ {"version":2,"instance":"eyJpZCI6IkNFOEJDQkQyLTFBODItNDQyNy1CN0M4LTM5NzVFMDRFOEUwNCIsImRlc2NyaXB0aW9uIjoiIiwiY29udGVudCI6IlwvXC8gU291cmNlcnlUZW1wbGF0ZUVKUyBGb3VuZCA8JS0gdHlwZXMuYWxsLmxlbmd0aCAlPiB0eXBlcyIsInZlcnNpb24iOjIsImZhdm9yaXRlIjp0cnVlLCJhdXRob3IiOiIiLCJ1cmwiOiIiLCJyZWdlbmVyYXRpb25Db3VudGVyIjoxLCJmaWxlVVJMIjoiZmlsZTpcL1wvXC9Vc2Vyc1wvbWVyb3dpbmdcL3dvcmtcL3ByaXZhdGVcL1NvdXJjZXJ5XC9Tb3VyY2VyeVRlc3RzXC9TdHViXC9UZW1wbGF0ZXNcL1NvdXJjZXJ5VGVtcGxhdGVFSlMuc291cmNlcnl0ZW1wbGF0ZSIsInJ1bkNvbmZpZ3VyYXRpb24iOiJzZWxlY3Rpb24iLCJzYW1wbGVDb2RlIjoic3RydWN0IEZvbyB7XG4gICAgdmFyIG51bWJlcjogSW50ID0gMlxuICAgIHZhciBuYW1lOiBTdHJpbmcgPSBcIlwiXG59XG5jbGFzcyBCb28ge30iLCJpc0xvY2tlZCI6ZmFsc2UsImtpbmQiOiJlanMiLCJ0cmltV2hpdGVzcGFjZXMiOnRydWUsIm5hbWUiOiJJbXBvcnRlZCBTb3VyY2VyeVRlc3RFSlMgMSIsImluc2VydGlvbk1vZGUiOiJlbmRPZkZpbGUifQ=="} ================================================ FILE: SourceryTests/Stub/Templates/SourceryTemplateStencil.sourcerytemplate ================================================ {"version":2,"instance":"eyJpZCI6IkU2RUVGOTZBLUY5QTktNEU4NC1CNUJGLTlCNkNFRkRFNTA1RSIsImRlc2NyaXB0aW9uIjoiIiwiY29udGVudCI6IlwvXC8gU291cmNlcnlUZW1wbGF0ZVN0ZW5jaWwgZm91bmQge3sgdHlwZXMuYWxsLmNvdW50IH19IHR5cGVzIiwidmVyc2lvbiI6MiwiZmF2b3JpdGUiOnRydWUsImF1dGhvciI6IiIsInVybCI6IiIsInJlZ2VuZXJhdGlvbkNvdW50ZXIiOjAsImZpbGVVUkwiOiJmaWxlOlwvXC9cL1VzZXJzXC9tZXJvd2luZ1wvd29ya1wvcHJpdmF0ZVwvU291cmNlcnlcL1NvdXJjZXJ5VGVzdHNcL1N0dWJcL1RlbXBsYXRlc1wvU291cmNlcnlUZW1wbGF0ZVN0ZW5jaWwuc291cmNlcnl0ZW1wbGF0ZSIsInJ1bkNvbmZpZ3VyYXRpb24iOiJzZWxlY3Rpb24iLCJzYW1wbGVDb2RlIjoic3RydWN0IEZvbyB7XG4gICAgdmFyIG51bWJlcjogSW50ID0gMlxuICAgIHZhciBuYW1lOiBTdHJpbmcgPSBcIlwiXG59XG5jbGFzcyBCb28ge30iLCJpc0xvY2tlZCI6ZmFsc2UsImtpbmQiOiJzdGVuY2lsIiwidHJpbVdoaXRlc3BhY2VzIjp0cnVlLCJuYW1lIjoiSW1wb3J0ZWQgU291cmNlcnlUZXN0IDEiLCJpbnNlcnRpb25Nb2RlIjoiZW5kT2ZGaWxlIn0="} ================================================ FILE: SourceryUtils/Sources/Path+Extensions.swift ================================================ // // Path+Extensions.swift // Sourcery // // Created by Krunoslav Zaher on 1/6/17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation import PathKit public typealias Path = PathKit.Path extension Path { public var modifiedDate: Date? { (try? FileManager.default.attributesOfItem(atPath: string)[.modificationDate]) as? Date } public static func cleanTemporaryDir(name: String) -> Path { guard let tempDirURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Sourcery.\(name)") else { fatalError("Unable to get temporary path") } _ = try? FileManager.default.removeItem(at: tempDirURL) // swiftlint:disable:next force_try try! FileManager.default.createDirectory(at: tempDirURL, withIntermediateDirectories: true, attributes: nil) return Path(tempDirURL.path) } /// - returns: The `.cachesDirectory` search path in the user domain, as a `Path`. public static var defaultBaseCachePath: Path { let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true) as [String] let path = paths[0] return Path(path) } /// - parameter _basePath: The value of the `--cachePath` command line parameter, if any. /// - note: This function does not consider the `--disableCache` command line parameter. /// It is considered programmer error to call this function when `--disableCache` is specified. public static func cachesDir(sourcePath: Path, basePath _basePath: Path?, createIfMissing: Bool = true) -> Path { let basePath = _basePath ?? defaultBaseCachePath let path = basePath + "Sourcery" + sourcePath.lastComponent if !path.exists && createIfMissing { // swiftlint:disable:next force_try try! FileManager.default.createDirectory(at: path.url, withIntermediateDirectories: true, attributes: nil) } return path } public var isTemplateFile: Bool { return self.extension == "stencil" || self.extension == "swifttemplate" || self.extension == "ejs" || self.extension == "sourcerytemplate" } public var isSwiftSourceFile: Bool { return !self.isDirectory && (self.extension == "swift" || self.extension == "swiftinterface") } public func hasExtension(as string: String) -> Bool { let extensionString = ".\(string)." return self.string.contains(extensionString) } public init(_ string: String, relativeTo relativePath: Path) { var path = Path(string) if !path.isAbsolute { path = (relativePath + path).absolute() } self.init(path.string) } public var allPaths: [Path] { if isDirectory { return (try? recursiveChildren()) ?? [] } else { return [self] } } } ================================================ FILE: SourceryUtils/Sources/Sha.swift ================================================ // // Created by Krzysztof Zablocki on 10/01/2017. // Copyright (c) 2017 Pixle. All rights reserved. // import Foundation #if canImport(ObjectiveC) import CommonCrypto #else import Crypto #endif extension Data { public func sha256() -> Data { #if canImport(ObjectiveC) var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) self.withUnsafeBytes { (pointer) -> Void in _ = CC_SHA256(pointer.baseAddress, CC_LONG(pointer.count), &hash) } return Data(hash) #else let digest = SHA256.hash(data: self) return Data(digest) #endif } } extension String { public func sha256() -> String? { guard let data = data(using: String.Encoding.utf8) else { return nil } let rc = data.sha256().base64EncodedString(options: []) return rc } } ================================================ FILE: SourceryUtils/Sources/Time.swift ================================================ // // Time.swift // SourceryFramework // // Created by merowing on 03/09/2019. // Copyright © 2019 Pixle. All rights reserved. // import Foundation /// Returns current timestamp interval public func currentTimestamp() -> TimeInterval { return Date().timeIntervalSince1970 } ================================================ FILE: SourceryUtils/Sources/Version.swift ================================================ // // Version.swift // Sourcery // // Created by Anton Domashnev on 15.06.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation public struct SourceryVersion { public let value: String public static let current = SourceryVersion(value: inUnitTests ? "Major.Minor.Patch" : "2.3.0") } #if canImport(ObjectiveC) public let inUnitTests: Bool = NSClassFromString("XCTest") != nil #else public let inUnitTests: Bool = ProcessInfo.processInfo.processName.hasSuffix("xctest") #endif ================================================ FILE: SourceryUtils/Supporting Files/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2018 Pixle. All rights reserved. ================================================ FILE: SourceryUtils/Supporting Files/SourceryUtils.h ================================================ // // Copyright © 2018 Pixle. All rights reserved. // #import //! Project version number for SourceryUtils. FOUNDATION_EXPORT double SourceryUtilsVersionNumber; //! Project version string for SourceryUtils. FOUNDATION_EXPORT const unsigned char SourceryUtilsVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: SourceryUtils.podspec ================================================ Pod::Spec.new do |s| s.name = "SourceryUtils" s.version = "2.3.0" s.summary = "A tool that brings meta-programming to Swift, allowing you to code generate Swift code." s.platform = :osx, '10.15' s.description = <<-DESC A tool that brings meta-programming to Swift, allowing you to code generate Swift code. * Featuring daemon mode that allows you to write templates side-by-side with generated code. * Using SourceKit so you can scan your regular code. DESC s.homepage = "https://github.com/krzysztofzablocki/Sourcery" s.license = 'MIT' s.author = { "Krzysztof Zabłocki" => "krzysztof.zablocki@pixle.pl" } s.social_media_url = "https://twitter.com/merowing_" s.source = { :http => "https://github.com/krzysztofzablocki/Sourcery/releases/download/#{s.version}/sourcery-#{s.version}.zip" } s.source_files = "SourceryUtils/Sources/**/*.swift" s.osx.deployment_target = '10.15' s.dependency 'PathKit' end ================================================ FILE: Templates/.swiftlint.yml ================================================ excluded: # paths to ignore during linting. Takes precedence over `included`. - Tests/Generated - Tests/Expected ================================================ FILE: Templates/CodableContext/CodableContext.h ================================================ // // CodableContext.h // CodableContext // // Created by Ilya Puchka on 29/04/2018. // Copyright © 2018 Pixle. All rights reserved. // #import //! Project version number for CodableContext. FOUNDATION_EXPORT double CodableContextVersionNumber; //! Project version string for CodableContext. FOUNDATION_EXPORT const unsigned char CodableContextVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: Templates/CodableContext/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2018 Pixle. All rights reserved. NSPrincipalClass ================================================ FILE: Templates/CodableContextTests/CodableContextTests.swift ================================================ import Foundation import Quick import Nimble @testable import CodableContext class CodableContextTests: QuickSpec { override func spec() { #if canImport(ObjectiveC) let encoder: JSONEncoder = { let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted, .sortedKeys] return encoder }() let decoder = JSONDecoder() describe("enum") { context("with enum case key") { it("codes value with associated values") { let value = AssociatedValuesEnum.someCase(id: 0, name: "a") let encoded = try! encoder.encode(value) expect(String(data: encoded, encoding: .utf8)).to(equal(""" { "id" : 0, "name" : "a", "type" : "someCase" } """ )) let decoded = try! decoder.decode(AssociatedValuesEnum.self, from: encoded) expect(decoded).to(equal(value)) } it("can't use value with unnamed associated values") { let value = AssociatedValuesEnum.unnamedCase(0, "a") let encoded = "{\"type\" : \"unnamedCase\"}".data(using: .utf8)! expect { try encoder.encode(value) }.to(throwError()) expect { try decoder.decode(AssociatedValuesEnum.self, from: encoded) }.to(throwError()) } it("can't use value with mixed associated values") { let value = AssociatedValuesEnum.mixCase(0, name: "a") let encoded = "{\"type\" : \"mixCase\"}".data(using: .utf8)! expect { try encoder.encode(value) }.to(throwError()) expect { try decoder.decode(AssociatedValuesEnum.self, from: encoded) }.to(throwError()) } it("codes value without associated values") { let value = AssociatedValuesEnum.anotherCase let encoded = try! encoder.encode(value) expect(String(data: encoded, encoding: .utf8)).to(equal(""" { "type" : "anotherCase" } """ )) let decoded = try! decoder.decode(AssociatedValuesEnum.self, from: encoded) expect(decoded).to(equal(value)) } } context("without enum case key") { it("codes value with associated values") { let value = AssociatedValuesEnumNoCaseKey.someCase(id: 0, name: "a") let encoded = try! encoder.encode(value) expect(String(data: encoded, encoding: .utf8)).to(equal( """ { "someCase" : { "id" : 0, "name" : "a" } } """ )) let decoded = try! decoder.decode(AssociatedValuesEnumNoCaseKey.self, from: encoded) expect(decoded).to(equal(value)) } it("codes value with unnamed associated values") { let value = AssociatedValuesEnumNoCaseKey.unnamedCase(0, "a") let encoded = try! encoder.encode(value) expect(String(data: encoded, encoding: .utf8)).to(equal(""" { "unnamedCase" : [ 0, "a" ] } """ )) let decoded = try! decoder.decode(AssociatedValuesEnumNoCaseKey.self, from: encoded) expect(decoded).to(equal(value)) } it("can't use value with mixed associated values") { let value = AssociatedValuesEnumNoCaseKey.mixCase(0, name: "a") let encoded = "{\"type\" : \"mixCase\"}".data(using: .utf8)! expect { try encoder.encode(value) }.to(throwError()) expect { try decoder.decode(AssociatedValuesEnumNoCaseKey.self, from: encoded) }.to(throwError()) } it("codes value without assoicated values") { let value = AssociatedValuesEnumNoCaseKey.anotherCase let encoded = try! encoder.encode(value) expect(String(data: encoded, encoding: .utf8)).to(equal(""" { "anotherCase" : { } } """ )) let decoded = try! decoder.decode(AssociatedValuesEnumNoCaseKey.self, from: encoded) expect(decoded).to(equal(value)) } } } #endif } } ================================================ FILE: Templates/CodableContextTests/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: Templates/Templates/AutoCases.stencil ================================================ {% for enum in types.implementing.AutoCases|enum %} {{ enum.accessLevel }} extension {{ enum.name }} { static let count: Int = {{ enum.cases.count }} {% if not enum.hasAssociatedValues %} static let allCases: [{{ enum.name }}] = [ {% for case in enum.cases %} .{{ case.name }}{{ ',' if not forloop.last }} {% endfor %}] {% endif %} } {% endfor %} ================================================ FILE: Templates/Templates/AutoCodable.swifttemplate ================================================ <% func capitalizedName(for variable: Variable) -> String { return "\(String(variable.name.first!).capitalized)\(String(variable.name.dropFirst()))" } func customDecodingMethod(for variable: Variable, of type: Type) -> SourceryMethod? { return type.staticMethods.first { $0.selectorName == "decode\(capitalizedName(for: variable))(from:)" } } func defaultDecodingValue(for variable: Variable, of type: Type) -> Variable? { return type.staticVariables.first { $0.name == "default\(capitalizedName(for: variable))" } } func decodingContainerMethod(for type: Type) -> SourceryMethod? { if let enumType = type as? Enum, !enumType.hasAssociatedValues { return SourceryMethod(name: "singleValueContainer", throws: true) } return type.staticMethods.first { $0.selectorName == "decodingContainer(_:)" } } func customEncodingMethod(for variable: Variable, of type: Type) -> SourceryMethod? { return type.instanceMethods.first { $0.selectorName == "encode\(capitalizedName(for: variable))(to:)" } } func encodeAdditionalVariablesMethod(for type: Type) -> SourceryMethod? { return type.instanceMethods.first { $0.selectorName == "encodeAdditionalValues(to:)" } } func encodingContainerMethod(for type: Type) -> SourceryMethod? { if let enumType = type as? Enum, !enumType.hasAssociatedValues { return SourceryMethod(name: "singleValueContainer") } return type.instanceMethods.first { $0.selectorName == "encodingContainer(_:)" } } func typeHasMoreCodingKeysThanStoredProperties(_ type: Type, codingKeys: [String]) -> Bool { let allKeysSet = Set(codingKeys) let allStoredPropertiesNames = Set(type.storedVariables.map({ $0.name })) let hasMoreKeys = allKeysSet.subtracting(allStoredPropertiesNames).count > 0 return hasMoreKeys } func needsDecodableImplementation(for type: Type, codingKeys: (generated: [String], all: [String])) -> Bool { guard type.implements["AutoDecodable"] != nil else { return false } if let enumType = type as? Enum, enumType.rawTypeName == nil { return true } if type.storedVariables.contains(where: { customDecodingMethod(for: $0, of: type) != nil }) { return true } if type.storedVariables.contains(where: { defaultDecodingValue(for: $0, of: type) != nil }) { return true } if decodingContainerMethod(for: type) != nil { return true } if typeHasMoreCodingKeysThanStoredProperties(type, codingKeys: codingKeys.all) { return true } return false } func needsEncodableImplementation(for type: Type, codingKeys: (generated: [String], all: [String])) -> Bool { guard type.implements["AutoEncodable"] != nil else { return false } if let enumType = type as? Enum, enumType.rawTypeName == nil { return true } if type.variables.contains(where: { customEncodingMethod(for: $0, of: type) != nil }) { return true } if encodeAdditionalVariablesMethod(for: type) != nil { return true } if decodingContainerMethod(for: type) != nil { return true } if typeHasMoreCodingKeysThanStoredProperties(type, codingKeys: codingKeys.all) { return true } if ((type.containedType["SkipEncodingKeys"] as? Enum)?.cases.count ?? 0) > 0 { return true } return false } func codingKeysFor(_ type: Type) -> (generated: [String], all: [String]) { var generatedKeys = [String]() var allCodingKeys = [String]() if type is Struct { if let codingKeysType = type.containedType["CodingKeys"] as? Enum { allCodingKeys = codingKeysType.cases.map({ $0.name }) let definedKeys = Set(allCodingKeys) let storedVariablesKeys = type.storedVariables.filter({ $0.defaultValue == nil }).map({ $0.name }) let computedVariablesKeys = type.computedVariables.filter({ customEncodingMethod(for: $0, of: type) != nil }).map({ $0.name }) if (storedVariablesKeys.count + computedVariablesKeys.count) > definedKeys.count { for key in storedVariablesKeys where !definedKeys.contains(key) { generatedKeys.append(key) allCodingKeys.append(key) } for key in computedVariablesKeys where !definedKeys.contains(key) { generatedKeys.append(key) allCodingKeys.append(key) } } } else { for variable in type.storedVariables { generatedKeys.append(variable.name) allCodingKeys.append(variable.name) } for variable in type.computedVariables { guard customEncodingMethod(for: variable, of: type) != nil else { continue } generatedKeys.append(variable.name) allCodingKeys.append(variable.name) } } } else if let enumType = type as? Enum { var casesKeys: [String] = enumType.cases.map({ $0.name }) if enumType.hasAssociatedValues { enumType.cases .flatMap({ $0.associatedValues }) .compactMap({ $0.localName }) .forEach({ if !casesKeys.contains($0) { casesKeys.append($0) } }) } if let codingKeysType = type.containedType["CodingKeys"] as? Enum { allCodingKeys = codingKeysType.cases.map({ $0.name }) let definedKeys = Set(allCodingKeys) if casesKeys.count > definedKeys.count { for key in casesKeys where !definedKeys.contains(key) { generatedKeys.append(key) allCodingKeys.append(key) } } } else { allCodingKeys = casesKeys generatedKeys = allCodingKeys } } return (generated: generatedKeys, all: allCodingKeys) } -%> <%_ for type in types.all where (type is Struct || type is Enum) && (type.implements["AutoDecodable"] != nil || type.implements["AutoEncodable"] != nil) { -%> <%_ let codingKeys = codingKeysFor(type) -%> <%_ if let codingKeysType = type.containedType["CodingKeys"] as? Enum, codingKeys.generated.count > 0 { -%> // sourcery:inline:auto:<%= codingKeysType.name %>.AutoCodable <%_ for key in codingKeys.generated { -%> case <%= key %> <%_ } -%> // sourcery:end <%_ } -%> <%_ let typeNeedsDecodableImplementation = needsDecodableImplementation(for: type, codingKeys: codingKeys) -%> <%_ let typeNeedsEncodableImplementation = needsEncodableImplementation(for: type, codingKeys: codingKeys) -%> <%_ guard typeNeedsDecodableImplementation || typeNeedsEncodableImplementation else { continue } -%> extension <%= type.name %> { <%_ if type.containedType["CodingKeys"] as? Enum == nil { -%> enum CodingKeys: String, CodingKey { <%_ for key in codingKeys.generated { -%> case <%= key %> <%_ } -%> } <%_ }-%> <%_ if typeNeedsDecodableImplementation { -%> <%= type.accessLevel %> init(from decoder: Decoder) throws { <%_ if let containerMethod = decodingContainerMethod(for: type) { -%> let container = <% if containerMethod.throws { %>try <% } -%> <%_ if containerMethod.callName == "singleValueContainer" { %>decoder<% } else { -%><%= type.name %><% } -%> <%_ %>.<%= containerMethod.callName %>(<% if !containerMethod.parameters.isEmpty { %>decoder<% } %>) <%_ } else { -%> let container = try decoder.container(keyedBy: CodingKeys.self) <%_ } -%> <%_ if let enumType = type as? Enum { -%> <%_ if enumType.hasAssociatedValues { -%> <%_ if codingKeys.all.contains("enumCaseKey") { -%> let enumCase = try container.decode(String.self, forKey: .enumCaseKey) switch enumCase { <%_ for enumCase in enumType.cases { -%> case CodingKeys.<%= enumCase.name %>.rawValue: <%_ if enumCase.associatedValues.isEmpty { -%> self = .<%= enumCase.name %> <%_ } else if enumCase.associatedValues.filter({ $0.localName == nil }).count == enumCase.associatedValues.count { -%> // Enum cases with unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Can't decode '\(enumCase)'") <%_ } else if enumCase.associatedValues.filter({ $0.localName != nil }).count == enumCase.associatedValues.count { -%> <%_ for associatedValue in enumCase.associatedValues { -%> let <%= associatedValue.localName! %> = try container.decode(<%= associatedValue.typeName %>.self, forKey: .<%= associatedValue.localName! %>) <%_ } -%> self = .<%= enumCase.name %>(<% -%> <%_ %><%= enumCase.associatedValues.map({ "\($0.localName!): \($0.localName!)" }).joined(separator: ", ") %>) <%_ } else { -%> // Enum cases with mixed named and unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Can't decode '\(enumCase)'") <%_ } -%> <%_ } -%> default: throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Unknown enum case '\(enumCase)'") } <%_ } else { -%> <%_ for enumCase in enumType.cases { -%> if container.allKeys.contains(.<%= enumCase.name %>), try container.decodeNil(forKey: .<%= enumCase.name %>) == false { <%_ if enumCase.associatedValues.isEmpty { -%> self = .<%= enumCase.name %> return <%_ } else if enumCase.associatedValues.filter({ $0.localName == nil }).count == enumCase.associatedValues.count { -%> var associatedValues = try container.nestedUnkeyedContainer(forKey: .<%= enumCase.name %>) <%_ for (index, associatedValue) in enumCase.associatedValues.enumerated() { -%> let associatedValue<%= index %> = try associatedValues.decode(<%= associatedValue.typeName %>.self) <%_ } -%> self = .<%= enumCase.name %>(<% -%> <%_ %><%= enumCase.associatedValues.indices.map({ "associatedValue\($0)" }).joined(separator: ", ") %>) return <%_ } else if enumCase.associatedValues.filter({ $0.localName != nil }).count == enumCase.associatedValues.count { -%> let associatedValues = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .<%= enumCase.name %>) <%_ for associatedValue in enumCase.associatedValues { -%> let <%= associatedValue.localName! %> = try associatedValues.decode(<%= associatedValue.typeName %>.self, forKey: .<%= associatedValue.localName! %>) <%_ } -%> self = .<%= enumCase.name %>(<% -%> <%_ %><%= enumCase.associatedValues.map({ "\($0.localName!): \($0.localName!)" }).joined(separator: ", ") %>) return <%_ } else { -%> // Enum cases with mixed named and unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .<%= enumCase.name %>, in: container, debugDescription: "Can't decode `.<%= enumCase.name %>`") <%_ } -%> } <%_ } -%> throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case")) <%_ } -%> <%_ } else { -%> let enumCase = try container.decode(String.self) switch enumCase { <%_ for enumCase in enumType.cases { -%> case CodingKeys.<%= enumCase.name %>.rawValue: self = .<%= enumCase.name %> <%_ } -%> default: throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case '\(enumCase)'")) } <%_ } -%> <%_ } else { -%> <%_ for key in codingKeys.all { -%> <%_ guard let variable = type.instanceVariables.first(where: { $0.name == key && !$0.isComputed }) else { continue } -%> <%_ let defaultValue = defaultDecodingValue(for: variable, of: type) -%> <%_ let customMethod = customDecodingMethod(for: variable, of: type) -%> <%_ let shouldTry = customMethod?.throws == true || customMethod == nil -%> <%_ let shouldWrapTry = shouldTry && defaultValue != nil -%> <%= variable.name %> = <% if shouldWrapTry { %>(try? <% } else if shouldTry { %>try <% } -%> <%_ if let customMethod = customMethod { -%> <%_ %><%= type.name %>.<%= customMethod.callName %>(from: <% if customMethod.parameters.first?.name == "decoder" { %>decoder<% } else { %>container<% } %>)<% -%> <%_ } else { -%> <%_ %>container.decode<% if variable.isOptional { %>IfPresent<% } %>(<%= variable.unwrappedTypeName %>.self, forKey: .<%= variable.name %>)<% -%> <%_ } -%> <%_ %><% if shouldWrapTry { %>)<% } -%> <%_ if let defaultValue = defaultValue { %> ?? <%= type.name %>.<%= defaultValue.name -%><%_ } %> <%_ } -%> <%_ } -%> } <%_ } -%> <%_ if typeNeedsEncodableImplementation { -%> <%= type.accessLevel %> func encode(to encoder: Encoder) throws { <%_ if let containerMethod = encodingContainerMethod(for: type) { -%> var container = <% if containerMethod.callName == "singleValueContainer" { %>encoder.<% } %><%= containerMethod.callName %>(<% if !containerMethod.parameters.isEmpty { %>encoder<% } %>) <%_ } else { -%> var container = encoder.container(keyedBy: CodingKeys.self) <%_ } -%> <%_ if let enumType = type as? Enum { -%> <%_ if enumType.hasAssociatedValues { -%> <%_ if codingKeys.all.contains("enumCaseKey") { -%> switch self { <%_ for enumCase in enumType.cases { -%> <%_ if enumCase.associatedValues.isEmpty { -%> case .<%= enumCase.name %>: try container.encode(CodingKeys.<%= enumCase.name %>.rawValue, forKey: .enumCaseKey) <%_ } else if enumCase.associatedValues.filter({ $0.localName == nil }).count == enumCase.associatedValues.count { -%> case .<%= enumCase.name %>: // Enum cases with unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) <%_ } else if enumCase.associatedValues.filter({ $0.localName != nil }).count == enumCase.associatedValues.count { -%> case let .<%= enumCase.name %>(<%= enumCase.associatedValues.map({ "\($0.localName!)" }).joined(separator: ", ") %>): try container.encode(CodingKeys.<%= enumCase.name %>.rawValue, forKey: .enumCaseKey) <%_ for accociatedValue in enumCase.associatedValues { -%> try container.encode(<%= accociatedValue.localName! %>, forKey: .<%= accociatedValue.localName! %>) <%_ } -%> <%_ } else { -%> case .<%= enumCase.name %>: // Enum cases with mixed named and unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) <%_ } -%> <%_ } -%> } <%_ } else { -%> switch self { <%_ for enumCase in enumType.cases { -%> <%_ if enumCase.associatedValues.isEmpty { -%> case .<%= enumCase.name %>: _ = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .<%= enumCase.name %>) <%_ } else if enumCase.associatedValues.filter({ $0.localName == nil }).count == enumCase.associatedValues.count { -%> case let .<%= enumCase.name %>(<%= enumCase.associatedValues.indices.map({ "associatedValue\($0)" }).joined(separator: ", ") %>): var associatedValues = container.nestedUnkeyedContainer(forKey: .<%= enumCase.name %>) <%_ for (index, associatedValue) in enumCase.associatedValues.enumerated() { -%> try associatedValues.encode(associatedValue<%= index %>) <%_ } -%> <%_ } else if enumCase.associatedValues.filter({ $0.localName != nil }).count == enumCase.associatedValues.count { -%> case let .<%= enumCase.name %>(<%= enumCase.associatedValues.map({ "\($0.localName!)" }).joined(separator: ", ") %>): var associatedValues = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .<%= enumCase.name %>) <%_ for accociatedValue in enumCase.associatedValues { -%> try associatedValues.encode(<%= accociatedValue.localName! %>, forKey: .<%= accociatedValue.localName! %>) <%_ } -%> <%_ } else { -%> case .<%= enumCase.name %>: // Enum cases with mixed named and unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) <%_ } -%> <%_ } -%> } <%_ } -%> <%_ } else { -%> switch self { <%_ for enumCase in enumType.cases { -%> case .<%= enumCase.name %>: try container.encode(CodingKeys.<%= enumCase.name %>.rawValue) <%_ } -%> } <%_ } -%> <%_ } else { -%> <%_ let skipKeys = type.containedType["SkipEncodingKeys"] as? Enum -%> <%_ for key in codingKeys.all { -%> <%_ if let skipKeys = skipKeys, skipKeys.cases.contains(where: { $0.name == key }) { continue } -%> <%_ guard let variable = type.instanceVariables.first(where: { $0.name == key }) ?? type.computedVariables.first(where: { $0.name == key }) else { continue } -%> <%_ let customMethod = customEncodingMethod(for: variable, of: type) -%> <%_ if let customMethod = customMethod { -%> <% if customMethod.throws { %>try <% } %><%= customMethod.callName %>(to: <% if customMethod.parameters.first?.name == "encoder" { %>encoder<% } else { %>&container<% } %>) <%_ } else { -%> try container.encode<% if variable.isOptional { %>IfPresent<% } %>(<%= variable.name %>, forKey: .<%= variable.name %>) <%_ } -%> <%_ } -%> <%_ if let encodeAdditional = encodeAdditionalVariablesMethod(for: type) { -%> <% if encodeAdditional.throws { %>try <% } %><%= encodeAdditional.callName %>(to: <% if encodeAdditional.parameters.first?.name == "encoder" { %>encoder<% } else { %>&container<% } %>) <%_ } -%> <%_ } -%> } <%_ } -%> } <% } -%> ================================================ FILE: Templates/Templates/AutoEquatable.stencil ================================================ // swiftlint:disable file_length fileprivate func compareOptionals(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { switch (lhs, rhs) { case let (lValue?, rValue?): return compare(lValue, rValue) case (nil, nil): return true default: return false } } fileprivate func compareArrays(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { guard lhs.count == rhs.count else { return false } for (idx, lhsItem) in lhs.enumerated() { guard compare(lhsItem, rhs[idx]) else { return false } } return true } {% macro compareVariables variables %} {% for variable in variables where variable.readAccess != "private" and variable.readAccess != "fileprivate" %}{% if not variable.annotations.skipEquality %}guard {% if not variable.isOptional %}{% if not variable.annotations.arrayEquality %}lhs.{{ variable.name }} == rhs.{{ variable.name }}{% else %}compareArrays(lhs: lhs.{{ variable.name }}, rhs: rhs.{{ variable.name }}, compare: ==){% endif %}{% else %}compareOptionals(lhs: lhs.{{ variable.name }}, rhs: rhs.{{ variable.name }}, compare: ==){% endif %} else { return false }{% endif %} {% endfor %} {% endmacro %} // MARK: - AutoEquatable for classes, protocols, structs {% for type in types.types|!enum where type.implements.AutoEquatable or type|annotated:"AutoEquatable" %} // MARK: - {{ type.name }} AutoEquatable {% if not type.kind == "protocol" and not type.based.NSObject %}extension {{ type.name }}: Equatable {}{% endif %} {% if type.supertype.based.Equatable or type.supertype.implements.AutoEquatable or type.supertype|annotated:"AutoEquatable" %}THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable{% endif %} {{ type.accessLevel }} func == (lhs:{% if type.kind == "protocol" %} any{% endif %} {{ type.name }}, rhs:{% if type.kind == "protocol" %} any{% endif %} {{ type.name }}) -> Bool { {% if not type.kind == "protocol" %} {% call compareVariables type.storedVariables %} {% else %} {% call compareVariables type.allVariables %} {% endif %} return true } {% endfor %} // MARK: - AutoEquatable for Enums {% for type in types.enums where type.implements.AutoEquatable or type|annotated:"AutoEquatable" %} // MARK: - {{ type.name }} AutoEquatable extension {{ type.name }}: Equatable {} {{ type.accessLevel }} func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool { switch (lhs, rhs) { {% for case in type.cases %} {% if case.hasAssociatedValue %} {% if case.associatedValues.count == 1 %} case let (.{{ case.name }}(lhs), .{{ case.name }}(rhs)): {% else %} {% map case.associatedValues into lhsValues using associated %}lhs{{ associated.externalName|upperFirstLetter }}{% endmap %} {% map case.associatedValues into rhsValues using associated %}rhs{{ associated.externalName|upperFirstLetter }}{% endmap %} case let (.{{ case.name }}({{ lhsValues|join: ", " }}), .{{ case.name }}({{ rhsValues|join: ", " }})): {% endif %} {% else %} case (.{{ case.name }}, .{{ case.name }}): {% endif %} {% if not case.hasAssociatedValue %}return true{% else %} {% if case.associatedValues.count == 1 %} return lhs == rhs {% else %} {% for associated in case.associatedValues %}if lhs{{ associated.externalName|upperFirstLetter }} != rhs{{ associated.externalName|upperFirstLetter }} { return false } {% endfor %}return true {% endif %} {% endif %} {% endfor %} {{ 'default: return false' if type.cases.count > 1 }} } } {% endfor %} ================================================ FILE: Templates/Templates/AutoHashable.stencil ================================================ // swiftlint:disable all {% macro combineVariableHashes variables %} {% for variable in variables where variable.readAccess != "private" and variable.readAccess != "fileprivate" %} {% if not variable.annotations.skipHashing %} {% if variable.isStatic %}type(of: self).{% endif %}{{ variable.name }}.hash(into: &hasher) {% endif %} {% endfor %} {% endmacro %} // MARK: - AutoHashable for classes, protocols, structs {% for type in types.types|!enum where type.implements.AutoHashable or type|annotated:"AutoHashable" %} // MARK: - {{ type.name }} AutoHashable extension {{ type.name }}{% if not type.kind == "protocol" and not type.based.NSObject %}: Hashable{% endif %} { {{ type.accessLevel }}{% if type.based.NSObject or type.supertype.implements.AutoHashable or type.supertype|annotated:"AutoHashable" or type.supertype.based.Hashable %} override{% endif %} func hash(into hasher: inout Hasher) { {% if type.based.NSObject or type.supertype.implements.AutoHashable or type.supertype|annotated:"AutoHashable" or type.supertype.based.Hashable %} super.hash(into: hasher) {% endif %} {% if not type.kind == "protocol" %} {% call combineVariableHashes type.storedVariables %} {% else %} {% call combineVariableHashes type.allVariables %} {% endif %} } } {% endfor %} // MARK: - AutoHashable for Enums {% for type in types.enums where type.implements.AutoHashable or type|annotated:"AutoHashable" %} // MARK: - {{ type.name }} AutoHashable extension {{ type.name }}: Hashable { {{ type.accessLevel }} func hash(into hasher: inout Hasher) { switch self { {% for case in type.cases %} {% if case.hasAssociatedValue %} {% if case.associatedValues.count == 1 %} case let .{{ case.name }}(data): {% else %} {% map case.associatedValues into associatedValues using associated %}{{ associated.externalName }}{% endmap %} case let .{{ case.name }}({{ associatedValues|join: ", " }}): {% endif %} {% else %} case .{{ case.name }}: {% endif %} {{ forloop.counter }}.hash(into: &hasher) {% if type.computedVariables.count > 0 %} {% for variable in type.computedVariables %} {% if not variable.annotations.skipHashing %}{{ variable.name }}.hash(into: &hasher) {% endif %} {% endfor %} {% endif %} {% if case.hasAssociatedValue %} {% if case.associatedValues.count == 1 %} data.hash(into: &hasher) {% else %} {% for associated in case.associatedValues %}{{ associated.externalName }}.hash(into: &hasher) {% endfor %} {% endif %} {% endif %} {% endfor %} } } } {% endfor %} ================================================ FILE: Templates/Templates/AutoLenses.stencil ================================================ // swiftlint:disable variable_name infix operator *~: MultiplicationPrecedence infix operator |>: AdditionPrecedence struct Lens { let get: (Whole) -> Part let set: (Part, Whole) -> Whole } func * (lhs: Lens, rhs: Lens) -> Lens { return Lens( get: { a in rhs.get(lhs.get(a)) }, set: { (c, a) in lhs.set(rhs.set(c, lhs.get(a)), a) } ) } func *~ (lhs: Lens, rhs: B) -> (A) -> A { return { a in lhs.set(rhs, a) } } func |> (x: A, f: (A) -> B) -> B { return f(x) } func |> (f: @escaping (A) -> B, g: @escaping (B) -> C) -> (A) -> C { return { g(f($0)) } } {% for type in types.implementing.AutoLenses|struct %} extension {{ type.name }} { {% for variable in type.storedVariables %} static let {{ variable.name }}Lens = Lens<{{type.name}}, {{variable.typeName}}>( get: { $0.{{variable.name}} }, set: { {{variable.name}}, {{type.name|lowercase}} in {{type.name}}({% for argument in type.storedVariables %}{{argument.name}}: {% if variable.name == argument.name %}{{variable.name}}{% else %}{{type.name|lowercase}}.{{argument.name}}{% endif %}{{ ', ' if not forloop.last }}{% endfor %}) } ){% endfor %} } {% endfor %} ================================================ FILE: Templates/Templates/AutoMockable.stencil ================================================ // swiftlint:disable line_length // swiftlint:disable variable_name import Foundation #if os(iOS) || os(tvOS) || os(watchOS) import UIKit #elseif os(OSX) import AppKit #endif {% for import in argument.autoMockableImports %} import {{ import }} {% endfor %} {% for import in argument.autoMockableTestableImports %} @testable import {{ import }} {% endfor %} {% macro cleanString string %}{{ string | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | replace:" ","_" | replace:"?","_" | replace:"!","_" | replace:",","_" | replace:"->","_" | replace:"@","_" | replace:".","_" | replace:"[","" | replace:"]","" | replace:"<","" | replace:">","" | replace:"&","" | snakeToCamelCase }}{% endmacro %} {%- macro swiftifyMethodName method -%} {%- set cleanMethodName %}{% call cleanString method.name %}{% endset %} {%- set cleanMethodReturnTypeName %}{% call cleanString method.actualReturnTypeName.name %}{% endset -%} {{ cleanMethodName | lowerFirstLetter }}{{ cleanMethodReturnTypeName | upperFirstLetter }} {%- endmacro -%} {% macro accessLevel level %}{% if level != 'internal' %}{{ level }} {% endif %}{% endmacro %} {% macro staticSpecifier method %}{% if method.isStatic and not method.isInitializer %}static {% endif %}{% endmacro %} {% macro methodThrowableErrorDeclaration method %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}ThrowableError: {% if method.throwsTypeName %}({% call getTypeName method.throwsTypeName %})?{% else %}(any Error)?{% endif %} {% endmacro %} {% macro methodThrowableErrorUsage method %} if let error = {% call swiftifyMethodName method %}ThrowableError { throw error } {% endmacro %} {% macro methodReceivedParameters method %} {% set hasNonEscapingClosures %} {%- for param in method.parameters where param.isClosure and not param.typeAttributes.escaping and not param.isOptional %} {{ true }} {% endfor -%} {% endset %} {% if method.parameters.count == 1 and not hasNonEscapingClosures %} {% call swiftifyMethodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }} = {% if not param.name == "" %}{{ param.name }}{% else %}arg{{ param.index }}{% endif %}{% endfor %} {% call swiftifyMethodName method %}ReceivedInvocations.append({% for param in method.parameters %}{% if not param.name == "" %}{{ param.name }}{% else %}arg{{ param.index }}{% endif %}){% endfor %} {% else %} {% if not method.parameters.count == 0 and not hasNonEscapingClosures %} {% call swiftifyMethodName method %}ReceivedArguments = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %}) {% call swiftifyMethodName method %}ReceivedInvocations.append(({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %})) {% endif %} {% endif %} {% endmacro %} {% macro methodClosureName method %}{% call swiftifyMethodName method %}Closure{% endmacro %} {% macro closureReturnTypeName method %}{% if method.isOptionalReturnType %}{{ method.unwrappedReturnTypeName }}?{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %} {% macro getTypeName type %}{% if type.actualTypeName %}{{ type.actualTypeName }}{% else %}{{ type.name }}{% endif %}{% endmacro -%} {% macro throwsSpecifier throwable %}{% if throwable.throws %}throws{% if throwable.throwsTypeName %}({% call getTypeName throwable.throwsTypeName %}){% endif %}{% endif %}{% endmacro -%} {% macro methodClosureDeclaration method %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call methodClosureName method %}: (({% for param in method.parameters %}{% call existentialClosureVariableTypeName param.typeName param.isVariadic true %}{% if not forloop.last %}, {% elif param.typeName.isClosure and param.typeName.closure.returnTypeName.name|contains:"any " %}{% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% call throwsSpecifier method %}{{ ' ' if method.throws }}-> {% if method.isInitializer %}Void{% else %}{% call existentialVariableTypeName method.returnTypeName true %}{% endif %})? {% endmacro %} {% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ '&' if param.typeName.name | hasPrefix:"inout " }}{% if not param.name == "" %}{{ param.name }}{% else %}arg{{ param.index }}{% endif %}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %} {% macro mockMethod method %} //MARK: - {{ method.shortName }} {% if not method.isThrowsTypeGeneric %} {% if method.throws %} {% call methodThrowableErrorDeclaration method %} {% endif %} {% if not method.isInitializer %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}CallsCount = 0 {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}Called: Bool { return {% call swiftifyMethodName method %}CallsCount > 0 } {% endif %} {% set hasNonEscapingClosures %} {%- for param in method.parameters where param.isClosure and not param.typeAttributes.escaping and not param.isOptional %} {{ true }} {% endfor -%} {% endset %} {% if method.parameters.count == 1 and not hasNonEscapingClosures %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {{ '(' if param.isClosure }}({% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName param.isVariadic false %}{{ ')' if param.isClosure }})?{% endfor %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}ReceivedInvocations{% for param in method.parameters %}: [{{ '(' if param.isClosure }}({% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName param.isVariadic false %}){{ ')' if param.isClosure }}{%if param.typeName.isOptional%}?{%endif%}]{% endfor %} = [] {% elif not method.parameters.count == 0 and not hasNonEscapingClosures %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call existentialClosureTupleVariableTypeName param.typeName.unwrappedTypeName param.isVariadic false %}{% else %}{% call existentialClosureTupleVariableTypeName param.typeName param.isVariadic false %}{% endif %}{{ ', ' if not forloop.last }}{% endfor %})? {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}ReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call existentialClosureTupleVariableTypeName param.typeName.unwrappedTypeName param.isVariadic false %}{% else %}{% call existentialClosureTupleVariableTypeName param.typeName param.isVariadic false %}{% endif %}{{ ', ' if not forloop.last }}{% endfor %})] = [] {% endif %} {% if not method.returnTypeName.isVoid and not method.isInitializer %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method %}ReturnValue: {{ '(' if method.returnTypeName.isClosure and not method.isOptionalReturnType or method.returnTypeName|contains:"any "}}{% call existentialVariableTypeName method.returnTypeName false %}{{ ')' if method.returnTypeName.isClosure and not method.isOptionalReturnType or method.returnTypeName|contains:"any " }}{{ '!' if not method.isOptionalReturnType }} {% endif %} {% call methodClosureDeclaration method %} {% endif %} {% if method.isInitializer %} {% call accessLevel method.accessLevel %}required {{ method.name }} { {% if method.isThrowsTypeGeneric %} fatalError("Generic typed throws in inits are not fully supported yet") {% else %} {% call methodReceivedParameters method %} {% call methodClosureName method %}?({% call methodClosureCallParameters method %}) {% endif %} } {% else %} {% for name, attribute in method.attributes %} {% for value in attribute %} {{ value }} {% endfor %} {% endfor %} {% call accessLevel method.accessLevel %}{% call staticSpecifier method %}{% call methodName method %}{{ ' async' if method.isAsync }}{{ ' ' if method.throws }}{% call throwsSpecifier method %}{% if not method.returnTypeName.isVoid %} -> {% call existentialVariableTypeName method.returnTypeName false %}{% endif %} { {% if method.isThrowsTypeGeneric %} fatalError("Generic typed throws are not fully supported yet") {% else %} {% call swiftifyMethodName method %}CallsCount += 1 {% call methodReceivedParameters method %} {% if method.throws %} {% call methodThrowableErrorUsage method %} {% endif %} {% if method.returnTypeName.isVoid %} {% if method.throws %}try {% endif %}{% if method.isAsync %}await {% endif %}{% call methodClosureName method %}?({% call methodClosureCallParameters method %}) {% else %} if let {% call methodClosureName method %} = {% call methodClosureName method %} { return {{ 'try ' if method.throws }}{{ 'await ' if method.isAsync }}{% call methodClosureName method %}({% call methodClosureCallParameters method %}) } else { return {% call swiftifyMethodName method %}ReturnValue } {% endif %} {% endif %} } {% endif %} {% endmacro %} {% macro mockSubscript subscript index %} //MARK: - Subscript #{{ index }} {% call accessLevel subscript.readAccess %}subscript{% if subscript.isGeneric %}<{% for genericParameter in subscript.genericParameters %}{{ genericParameter.name }}{% if genericParameter.inheritedTypeName %}: {{ genericParameter.inheritedTypeName.name }}{% endif %}{{ ', ' if not forloop.last }}{% endfor %}>{% endif %}({% for parameter in subscript.parameters %}{{ parameter.asSource }}{{ ', ' if not forloop.last }}{% endfor %}) -> {{ subscript.returnTypeName.name }}{% if subscript.genericRequirements|count != 0 %} where {% for requirement in subscript.genericRequirements %}{{ requirement.leftType.name }} {{ requirement.relationshipSyntax }} {{ requirement.rightType.typeName.name }}{{ ', ' if not forloop.last }}{% endfor %}{% endif %} { {% if subscript.readAccess %}get{% if subscript.isAsync %} async{% endif %}{% if subscript.throws %} {% call throwsSpecifier subscript %}{% endif %} { fatalError("Subscripts are not fully supported yet") }{% endif %} {% if subscript.writeAccess %}set { fatalError("Subscripts are not fully supported yet") }{% endif %} } {% endmacro %} {% macro resetMethod method %} {# for type method which are mocked, a way to reset the invocation, argument, etc #} {% if method.isStatic and not method.isInitializer %} //MARK: - {{ method.shortName }} {% if not method.isInitializer %} {% call swiftifyMethodName method %}CallsCount = 0 {% endif %} {% if method.parameters.count == 1 %} {% call swiftifyMethodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}{% endfor %} = nil {% call swiftifyMethodName method %}ReceivedInvocations = [] {% elif not method.parameters.count == 0 %} {% call swiftifyMethodName method %}ReceivedArguments = nil {% call swiftifyMethodName method %}ReceivedInvocations = [] {% endif %} {% call methodClosureName method %} = nil {% if method.throws %} {% call swiftifyMethodName method %}ThrowableError = nil {% endif %} {% endif %} {% endmacro %} {% macro mockOptionalVariable variable %} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {% call existentialVariableTypeName variable.typeName false %} {% endmacro %} {% macro mockNonOptionalArrayOrDictionaryVariable variable %} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {% call existentialVariableTypeName variable.typeName false %} = {% if variable.isArray %}[]{% elif variable.isDictionary %}[:]{% endif %} {% endmacro %} {% macro mockNonOptionalVariable variable %} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {% call existentialVariableTypeName variable.typeName false %} { get { return {% call underlyingMockedVariableName variable %} } set(value) { {% call underlyingMockedVariableName variable %} = value } } {% set wrappedTypeName %}{% if variable.typeName.isProtocolComposition %}({% call existentialVariableTypeName variable.typeName false %}){% else %}{% call existentialVariableTypeName variable.typeName false %}{% endif %}{% endset %} {% call accessLevel variable.readAccess %}var {% call underlyingMockedVariableName variable %}: ({% call existentialVariableTypeName wrappedTypeName false %})! {% endmacro %} {% macro variableThrowableErrorDeclaration variable %} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}ThrowableError: {% if variable.throwsTypeName %}({% call getTypeName variable.throwsTypeName %})?{% else %}Error?{% endif %} {% endmacro %} {% macro variableThrowableErrorUsage variable %} if let error = {% call mockedVariableName variable %}ThrowableError { throw error } {% endmacro %} {% macro variableClosureDeclaration variable %} {% call accessLevel variable.readAccess %}var {% call variableClosureName variable %}: (() {% if variable.isAsync %}async {% endif %}{% if variable.throws %}{% call throwsSpecifier variable %} {% endif %}-> {% call existentialVariableTypeName variable.typeName true %})? {% endmacro %} {% macro variableClosureName variable %}{% call mockedVariableName variable %}Closure{% endmacro %} {% macro mockAsyncOrThrowingVariable variable %} {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}CallsCount = 0 {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}Called: Bool { return {% call mockedVariableName variable %}CallsCount > 0 } {% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {% call existentialVariableTypeName variable.typeName false %} { get {% if variable.isAsync %}async {% endif %}{% if variable.throws %}{% call throwsSpecifier variable %} {% endif %}{ {% call mockedVariableName variable %}CallsCount += 1 {% if variable.throws %} {% call variableThrowableErrorUsage variable %} {% endif %} if let {% call variableClosureName variable %} = {% call variableClosureName variable %} { return {{ 'try ' if variable.throws }}{{ 'await ' if variable.isAsync }}{% call variableClosureName variable %}() } else { return {% call underlyingMockedVariableName variable %} } } } {% call accessLevel variable.readAccess %}var {% call underlyingMockedVariableName variable %}: {% call existentialVariableTypeName variable.typeName false %}{{ '!' if not variable.isOptional }} {% if variable.throws %} {% call variableThrowableErrorDeclaration variable %} {% endif %} {% call variableClosureDeclaration method %} {% endmacro %} {% macro underlyingMockedVariableName variable %}underlying{{ variable.name|upperFirstLetter }}{% endmacro %} {% macro mockedVariableName variable %}{{ variable.name }}{% endmacro %} {# Swift does not support closures with implicitly unwrapped optional return value type. That is why existentialVariableTypeName.isNotAllowedToBeImplicitlyUnwrappedOptional should be true in such case #} {% macro existentialVariableTypeName typeName isNotAllowedToBeImplicitlyUnwrappedOptional -%} {%- if typeName|contains:"<" and typeName|contains:">" -%} {{ typeName }} {%- elif typeName|contains:"[" and typeName|contains:"]" -%} {{ typeName }} {%- elif typeName|contains:"any " and typeName|contains:"!" -%} {{ typeName | replace:"any","(any" | replace:"!",")!" }} {%- elif typeName|contains:"any " and typeName.isOptional and not typeName|contains:"(" -%} {{ typeName | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"any " and typeName.isClosure and typeName|contains:"?" -%} ({{ typeName | replace:"any","(any" | replace:"?",")?" }}) {%- elif typeName|contains:"some " and typeName|contains:"!" -%} {{ typeName | replace:"some","(some" | replace:"!",")!" }} {%- elif typeName|contains:"some " and typeName.isOptional -%} {{ typeName | replace:"some","(some" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName.isClosure and typeName|contains:"?" -%} ({{ typeName | replace:"some","(some" | replace:"?",")?" }}) {%- elif typeName.isClosure -%} ({{ typeName }}) {%- elif isNotAllowedToBeImplicitlyUnwrappedOptional -%} {{ typeName | replace:"!","" }} {%- else -%} {{ typeName }} {%- endif -%} {%- endmacro %} {# Swift does not support closures with variadic parameters of existential types as arguments. That is why existentialClosureVariableTypeName.isVariadic should be false when typeName is a closure #} {% macro existentialClosureVariableTypeName typeName isVariadic keepInout -%} {% set name %} {%- if keepInout -%} {{ typeName }} {%- else -%} {{ typeName | replace:"inout ","" }} {%- endif -%} {% endset %} {%- if typeName|contains:"[" and typeName|contains:"]" -%} {{ name }} {%- elif typeName|contains:"any " and typeName|contains:"!" -%} {{ name | replace:"any","(any" | replace:"!",")?" }} {%- elif typeName|contains:"any " and typeName.isOptional and typeName.isClosure -%} ({{ typeName.unwrappedTypeName| replace:"inout ","" | replace:"any","(any" | replace:"?",")?" }})? {%- elif typeName|contains:"any " and typeName.isClosure and typeName|contains:"?" and typeName.closure.parameters.count > 1 -%} {{ name | replace:"any","(any" | replace:"?",")?" | replace:") ->",")) ->" }} {%- elif typeName|contains:"any " and typeName.isClosure and typeName|contains:"?" and typeName.closure.parameters.count > 1 -%} {{ name | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"any " and typeName|contains:"?" -%} {{ name | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName|contains:"!" -%} {{ name | replace:"some","(any" | replace:"!",")?" }} {%- elif typeName|contains:"some " and typeName.isClosure and typeName|contains:"?" -%} {{ name | replace:"some","(any" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName|contains:"?" -%} {{ name | replace:"some","(any" | replace:"?",")?" }} {%- elif isVariadic and typeName|contains:"any " -%} [({{ name }})] {%- elif isVariadic -%} {{ name }}... {%- else -%} {{ name|replace:"some ","any " }} {%- endif -%} {%- endmacro %} {# Swift does not support tuples with variadic parameters. That is why existentialClosureVariableTypeName.isVariadic should be false when typeName is a closure #} {% macro existentialClosureTupleVariableTypeName typeName isVariadic keepInout -%} {% set name %} {%- if keepInout -%} {{ typeName }} {%- else -%} {{ typeName | replace:"inout ","" }} {%- endif -%} {% endset %} {%- if typeName|contains:"[" and typeName|contains:"]" -%} {{ name }} {%- elif typeName|contains:"any " and typeName|contains:"!" -%} {{ name | replace:"any","(any" | replace:"!",")?" }} {%- elif typeName|contains:"any " and typeName.isOptional and typeName.isClosure -%} ({{ typeName.unwrappedTypeName| replace:"inout ","" | replace:"any","(any" | replace:"?",")?" }})? {%- elif typeName|contains:"any " and typeName.isClosure and typeName|contains:"?" -%} {{ name | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"any " and typeName|contains:"?" -%} {{ name | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName|contains:"!" -%} {{ name | replace:"some","(any" | replace:"!",")?" }} {%- elif typeName|contains:"some " and typeName.isClosure and typeName|contains:"?" -%} {{ name | replace:"some","(any" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName|contains:"?" -%} {{ name | replace:"some","(any" | replace:"?",")?" }} {%- elif isVariadic -%} [{{ name }}] {%- else -%} {{ name|replace:"some ","any " }} {%- endif -%} {%- endmacro %} {% macro existentialParameterTypeName typeName isVariadic -%} {%- if typeName|contains:"[" and typeName|contains:"]" -%} {{ typeName }} {%- elif typeName|contains:"any " and typeName|contains:"?," and typeName|contains:">?" -%} {{ typeName | replace:"any","(any" | replace:"?,",")?," }} {%- elif typeName|contains:"any " and typeName|contains:"!" -%} {{ typeName | replace:"any","(any" | replace:"!",")!" }} {%- elif typeName|contains:"any " and typeName.isOptional and typeName.isClosure -%} ({{ typeName.unwrappedTypeName | replace:"any","(any" | replace:"?",")?" }})? {%- elif typeName|contains:"any " and typeName.isClosure and typeName.closure.parameters.count > 1 and typeName.closure.returnTypeName.name|contains:"any " and typeName|contains:"?" -%} {{ typeName | replace:"any","(any" | replace:"?",")?" | replace:") ->",")) ->" }}) {%- elif typeName|contains:"any " and typeName.isClosure and typeName.closure.returnTypeName.name|contains:"any " and typeName|contains:"?" -%} {{ typeName | replace:"any","(any" | replace:"?",")?" }}) {%- elif typeName|contains:"any " and typeName.isClosure and typeName|contains:"?" -%} {{ typeName | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"any " and typeName.isOptional -%} {{ typeName | replace:"any","(any" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName|contains:"!" -%} {{ typeName | replace:"some","(some" | replace:"!",")!" }} {%- elif typeName|contains:"some " and typeName.isClosure and typeName|contains:"?" -%} {{ typeName | replace:"some","(some" | replace:"?",")?" }} {%- elif typeName|contains:"some " and typeName.isOptional -%} {{ typeName | replace:"some","(some" | replace:"?",")?" }} {%- elif isVariadic -%} {{ typeName }}... {%- else -%} {{ typeName }} {%- endif -%} {%- endmacro %} {% macro methodName method %}func {{ method.shortName}}({%- for param in method.parameters %}{% if param.argumentLabel == nil %}_ {% if not param.name == "" %}{{ param.name }}{% else %}arg{{ param.index }}{% endif %}{%elif param.argumentLabel == param.name%}{{ param.name }}{%else%}{{ param.argumentLabel }} {{ param.name }}{% endif %}: {% if param.typeName.isClosure and param.typeName.closure.parameters.count > 1 %}({% endif %}{% call existentialParameterTypeName param.typeName param.isVariadic %}{% if param.typeName.isClosure and param.typeName.closure.parameters.count > 1 and not (param.typeName|contains:"any " and param.typeName.closure.returnTypeName.name|contains:"any " and param.typeName|contains:"?") %}){% endif %}{% if not forloop.last %}, {% endif %}{% endfor -%}){% endmacro %} {% macro extractProtocolCompositionFromAssociatedTypes type -%} {%- if type.associatedTypes|sortedValuesByKeys|count > 0 -%} < {%- for associatedType in type.associatedTypes|sortedValuesByKeys -%} {% if associatedType.type.kind != nil and associatedType.type.kind|contains:"protocol" %} {{ associatedType.name }}: {{ associatedType.typeName }}, {%- endif -%} {%- endfor -%} > {%- endif -%} {%- endmacro %} {%- macro extractProtocolRequirementsFromAssociatedTypes associatedTypes -%} {%- for associatedType in associatedTypes -%} {%- if associatedType.type.kind != nil and associatedType.type.kind|contains:"protocol" -%} {%- for requirement in associatedType.type.genericRequirements -%} {%- set requirementString -%} {{ requirement.leftType.name }} {{ requirement.relationshipSyntax }} {{ requirement.rightType.typeName.name }} {%- endset -%} {{ requirementString }}, {%- endfor -%} {%- endif -%} {%- endfor -%} {%- endmacro -%} {% macro extractProtocolRequirementsFromType type -%} {%- set requirements -%} {% call extractProtocolRequirementsFromAssociatedTypes type.associatedTypes|sortedValuesByKeys %} {%- endset -%} {% if requirements|isEmpty == false %} where {{ requirements }}{ {%- else -%} { {% endif %} {%- endmacro %} {% macro extractRequiredProtocolConformance type -%} {% if type.based.Sendable %}, @unchecked Sendable{% endif %} {%- endmacro %} {% for type in types.protocols where type.based.AutoMockable or type|annotated:"AutoMockable" %}{% if type.name != "AutoMockable" %} {% call accessLevel type.accessLevel %}class {{ type.name }}Mock{% set generics %}{% call extractProtocolCompositionFromAssociatedTypes type %}{% endset %}{{ generics | replace:",>",">"}}: {{ type.name }}{% call extractRequiredProtocolConformance type %} {%- set requirements -%}{% call extractProtocolRequirementsFromType type %}{%- endset -%} {{ requirements|replace:",{","{"|replace:"{"," {" }} {% for associatedType in type.associatedTypes|sortedValuesByKeys %} {% if associatedType.type.kind == nil or not associatedType.type.kind|contains:"protocol" %} typealias {{ associatedType.name }} = {% if associatedType.type != nil %}{{ associatedType.type.name }}{% elif associatedType.typeName != nil %}{{ associatedType.typeName.name }}{% else %}Any{% endif %} {% endif %} {% endfor %} {% if type.accessLevel == "public" %}public init() {}{% endif %} {% for variable in type.allVariables|!definedInExtension %} {% if variable.isAsync or variable.throws %}{% call mockAsyncOrThrowingVariable variable %}{% elif variable.isOptional %}{% call mockOptionalVariable variable %}{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}{% else %}{% call mockNonOptionalVariable variable %}{% endif %} {% endfor %} {% if type.allMethods|static|count != 0 and type.allMethods|initializer|count != type.allMethods|static|count %} {% call accessLevel type.accessLevel %}static func reset() { {% for method in type.allMethods|static|!definedInExtension %} {% call resetMethod method %} {% endfor %} } {% endif %} {% for method in type.allMethods|!definedInExtension %} {% call mockMethod method %} {% endfor %} {% for subscript in type.allSubscripts|!definedInExtension %} {% call mockSubscript subscript forloop.counter %} {% endfor %} } {% endif %}{% endfor %} ================================================ FILE: Templates/Templates/Decorator.swifttemplate ================================================ <%# Constructs full method declaration string -%> <% func methodDeclaration(_ method: SourceryRuntime.Method) -> String { var result = method.name if method.throws { result = result + " throws" } else if method.rethrows { result = result + " rethrows" } return result + " -> \(method.returnTypeName)" } -%> <%# Constructs method call string passing in parameters with their local names -%> <% func methodCall(_ method: SourceryRuntime.Method) -> String { let params = method.parameters.map({ if let label = $0.argumentLabel { return "\(label): \($0.name)" } else { return $0.name } }).joined(separator: ", ") var result = "decorated.\(method.callName)(\(params))" if method.throws { result = "try " + result } if !method.returnTypeName.isVoid { result = "return " + result } return result } -%> <% for type in types.all { guard let protocolToDecorate = type.annotations["decorate"] as? String else { continue } if let aProtocol = types.protocols.first(where: { $0.name == protocolToDecorate }) { -%> // sourcery:inline:auto:<%= type.name %>.autoDecorated <%= type.accessLevel %> private(set) var decorated: <%= aProtocol.name %> <%= type.accessLevel %> init(decorated: <%= aProtocol.name %>) { self.decorated = decorated } <%_ for property in aProtocol.variables { -%> <%= type.accessLevel %> var <%= property.name %>: <%= property.typeName %> { <%_ if property.writeAccess != "" { -%> get { <% if let decorateGet = type.annotations["decorateGet"] { %><%= decorateGet %> <%_ } -%> return decorated.<%= property.name %> } set { <% if let decorateSet = type.annotations["decorateSet"] { %><%= decorateSet %> <%_ } -%> decorated.<%= property.name %> = newValue } <%_ } else { -%> <% if let decorateGet = type.annotations["decorateGet"] { %><%= decorateGet %> <%_ } -%> return decorated.<%= property.name %> <%_ } -%> } <%_ } -%> <%_ -%> <%_ for method in aProtocol.methods { let implements = type.methods.contains(where: { $0.name == method.name && $0.returnTypeName.name == method.returnTypeName.name }) guard !implements else { continue } -%> <%= type.accessLevel %> func <%= methodDeclaration(method) %> { <% if let decorateMethod = type.annotations["decorateMethod"] { %><%= decorateMethod %> <%_ } -%> <%= methodCall(method) %> } <% } %> // sourcery:end <% } } %> ================================================ FILE: Templates/Templates/LinuxMain.stencil ================================================ import XCTest {{ argument.testimports }} {% for type in types.classes|based:"XCTestCase" %} {% if not type.annotations.disableTests %}extension {{ type.name }} { static var allTests: [(String, ({{ type.name }}) -> () throws -> Void)] = [ {% for method in type.methods %}{% if method.parameters.count == 0 and method.shortName|hasPrefix:"test" %} ("{{ method.shortName }}", {{ method.shortName }}){{ ',' if not forloop.last }} {% endif %}{% endfor %}] } {% endif %}{% endfor %} // swiftlint:disable trailing_comma XCTMain([ {% for type in types.classes|based:"XCTestCase" %}{% if not type.annotations.disableTests %} testCase({{ type.name }}.allTests), {% endif %}{% endfor %}]) // swiftlint:enable trailing_comma ================================================ FILE: Templates/Templates.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 328D9E935602E7E23C76D3C3 /* Pods_CodableContextTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 433370DB5CFA428C5E58DD79 /* Pods_CodableContextTests.framework */; }; 636D78572081781E00160CC4 /* AutoCodable.swifttemplate in Resources */ = {isa = PBXBuildFile; fileRef = 636D78472080251800160CC4 /* AutoCodable.swifttemplate */; }; 63A4F4D120964FB3000F8CDF /* CodableContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 63A4F4CF20964FB3000F8CDF /* CodableContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; 63A4F4D520964FBE000F8CDF /* AutoCodable.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636D784C208169E100160CC4 /* AutoCodable.generated.swift */; }; 63A4F4D620964FC5000F8CDF /* AutoCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636D78492080256500160CC4 /* AutoCodable.swift */; }; 63A4F4E02096509A000F8CDF /* CodableContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63A4F4DF2096509A000F8CDF /* CodableContextTests.swift */; }; 63A4F4E22096509A000F8CDF /* CodableContext.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63A4F4CD20964FB3000F8CDF /* CodableContext.framework */; }; 63A4F4E820965AD5000F8CDF /* AutoCodable.generated.swift in CopyFiles */ = {isa = PBXBuildFile; fileRef = 636D784C208169E100160CC4 /* AutoCodable.generated.swift */; }; 6D037EA11EC26E6300FA6C91 /* AutoEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D037EA01EC26E6300FA6C91 /* AutoEquatable.swift */; }; 6D037EA31EC26E6A00FA6C91 /* AutoEquatable.expected in Resources */ = {isa = PBXBuildFile; fileRef = 6D037EA21EC26E6A00FA6C91 /* AutoEquatable.expected */; }; 6D0AF6BC1EC5EDD100F9A410 /* AutoHashable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D0AF6BB1EC5EDD100F9A410 /* AutoHashable.swift */; }; 6D130B791ECACCDF00E9642A /* AutoLenses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D130B781ECACCDF00E9642A /* AutoLenses.swift */; }; 6D130B7B1ECACD0F00E9642A /* AutoLenses.expected in Resources */ = {isa = PBXBuildFile; fileRef = 6D130B7A1ECACD0F00E9642A /* AutoLenses.expected */; }; 6D130B7C1ECACEB800E9642A /* AutoLenses.generated.swift in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C9A1EBA3156006EEBEC /* AutoLenses.generated.swift */; }; 6D342C831EBA13DF006EEBEC /* AutoCases.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C7C1EBA13DF006EEBEC /* AutoCases.stencil */; }; 6D342C841EBA13DF006EEBEC /* AutoEquatable.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C7D1EBA13DF006EEBEC /* AutoEquatable.stencil */; }; 6D342C851EBA13DF006EEBEC /* AutoHashable.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C7E1EBA13DF006EEBEC /* AutoHashable.stencil */; }; 6D342C861EBA13DF006EEBEC /* AutoLenses.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C7F1EBA13DF006EEBEC /* AutoLenses.stencil */; }; 6D342C871EBA13DF006EEBEC /* AutoMockable.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C801EBA13DF006EEBEC /* AutoMockable.stencil */; }; 6D342C891EBA13DF006EEBEC /* LinuxMain.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C821EBA13DF006EEBEC /* LinuxMain.stencil */; }; 6D342C911EBA146F006EEBEC /* TemplatesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D342C8F1EBA146F006EEBEC /* TemplatesTests.swift */; }; 6D342C941EBA155A006EEBEC /* AutoCases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D342C931EBA155A006EEBEC /* AutoCases.swift */; }; 6D342CA31EBA5415006EEBEC /* AutoCases.expected in Resources */ = {isa = PBXBuildFile; fileRef = 6D342CA11EBA35E9006EEBEC /* AutoCases.expected */; }; 6D342CA41EBA54DF006EEBEC /* AutoCases.generated.swift in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C971EBA3156006EEBEC /* AutoCases.generated.swift */; }; 6D4D84481EC667630005932D /* AutoEquatable.generated.swift in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C981EBA3156006EEBEC /* AutoEquatable.generated.swift */; }; 6D4D84491EC667650005932D /* AutoHashable.generated.swift in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C991EBA3156006EEBEC /* AutoHashable.generated.swift */; }; 6D6645C31ECC1824004C1948 /* AutoMockable.expected in Resources */ = {isa = PBXBuildFile; fileRef = 6D6645C21ECC1824004C1948 /* AutoMockable.expected */; }; 6D6645C51ECC184A004C1948 /* AutoMockable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6645C41ECC184A004C1948 /* AutoMockable.swift */; }; 6D6645C61ECC1CAA004C1948 /* AutoMockable.generated.swift in Resources */ = {isa = PBXBuildFile; fileRef = 6D6645C01ECC181A004C1948 /* AutoMockable.generated.swift */; }; 6D6645C81ECC2187004C1948 /* LinuxMain.expected in Resources */ = {isa = PBXBuildFile; fileRef = 6D6645C71ECC2187004C1948 /* LinuxMain.expected */; }; 6D6645CA1ECC219C004C1948 /* LinuxMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6645C91ECC219C004C1948 /* LinuxMain.swift */; }; 6D6645CB1ECC22A3004C1948 /* LinuxMain.generated.swift in Resources */ = {isa = PBXBuildFile; fileRef = 6D342C9B1EBA3156006EEBEC /* LinuxMain.generated.swift */; }; 6D6C19261FC4CE7900CD2A34 /* Decorator.swifttemplate in Resources */ = {isa = PBXBuildFile; fileRef = 6D6C19251FC4CE7900CD2A34 /* Decorator.swifttemplate */; }; 6DC27BD81EC6592700B73CAF /* AutoHashable.expected in Resources */ = {isa = PBXBuildFile; fileRef = 6DC27BD71EC6592700B73CAF /* AutoHashable.expected */; }; B50435DF2157222E00F120DF /* AutoCodable.expected in Resources */ = {isa = PBXBuildFile; fileRef = 636D786B2083B8D700160CC4 /* AutoCodable.expected */; }; C03FD2E6F7645376C192094D /* Pods_TemplatesTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26AD1250F60484521E03C14A /* Pods_TemplatesTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 63A4F4E32096509A000F8CDF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 6D6A24911EB79E8900C1FB1A /* Project object */; proxyType = 1; remoteGlobalIDString = 63A4F4CC20964FB3000F8CDF; remoteInfo = CodableContext; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 63A4F4C420964E7B000F8CDF /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 7; files = ( 63A4F4E820965AD5000F8CDF /* AutoCodable.generated.swift in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 26AD1250F60484521E03C14A /* Pods_TemplatesTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TemplatesTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 433370DB5CFA428C5E58DD79 /* Pods_CodableContextTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CodableContextTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 636D78472080251800160CC4 /* AutoCodable.swifttemplate */ = {isa = PBXFileReference; explicitFileType = text; path = AutoCodable.swifttemplate; sourceTree = ""; }; 636D78492080256500160CC4 /* AutoCodable.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = AutoCodable.swift; sourceTree = ""; }; 636D784C208169E100160CC4 /* AutoCodable.generated.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; path = AutoCodable.generated.swift; sourceTree = ""; }; 636D786B2083B8D700160CC4 /* AutoCodable.expected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoCodable.expected; sourceTree = ""; }; 63A4F4CD20964FB3000F8CDF /* CodableContext.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CodableContext.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 63A4F4CF20964FB3000F8CDF /* CodableContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CodableContext.h; sourceTree = ""; }; 63A4F4D020964FB3000F8CDF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63A4F4DD2096509A000F8CDF /* CodableContextTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodableContextTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63A4F4DF2096509A000F8CDF /* CodableContextTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableContextTests.swift; sourceTree = ""; }; 63A4F4E12096509A000F8CDF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6D037EA01EC26E6300FA6C91 /* AutoEquatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoEquatable.swift; sourceTree = ""; }; 6D037EA21EC26E6A00FA6C91 /* AutoEquatable.expected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoEquatable.expected; sourceTree = ""; }; 6D0AF6BB1EC5EDD100F9A410 /* AutoHashable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoHashable.swift; sourceTree = ""; }; 6D130B781ECACCDF00E9642A /* AutoLenses.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoLenses.swift; sourceTree = ""; }; 6D130B7A1ECACD0F00E9642A /* AutoLenses.expected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoLenses.expected; sourceTree = ""; }; 6D342C7C1EBA13DF006EEBEC /* AutoCases.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoCases.stencil; sourceTree = ""; }; 6D342C7D1EBA13DF006EEBEC /* AutoEquatable.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoEquatable.stencil; sourceTree = ""; }; 6D342C7E1EBA13DF006EEBEC /* AutoHashable.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoHashable.stencil; sourceTree = ""; }; 6D342C7F1EBA13DF006EEBEC /* AutoLenses.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoLenses.stencil; sourceTree = ""; }; 6D342C801EBA13DF006EEBEC /* AutoMockable.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoMockable.stencil; sourceTree = ""; }; 6D342C821EBA13DF006EEBEC /* LinuxMain.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LinuxMain.stencil; sourceTree = ""; }; 6D342C8E1EBA146F006EEBEC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6D342C8F1EBA146F006EEBEC /* TemplatesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplatesTests.swift; sourceTree = ""; }; 6D342C931EBA155A006EEBEC /* AutoCases.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoCases.swift; sourceTree = ""; }; 6D342C971EBA3156006EEBEC /* AutoCases.generated.swift */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = AutoCases.generated.swift; sourceTree = ""; }; 6D342C981EBA3156006EEBEC /* AutoEquatable.generated.swift */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = AutoEquatable.generated.swift; sourceTree = ""; }; 6D342C991EBA3156006EEBEC /* AutoHashable.generated.swift */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = AutoHashable.generated.swift; sourceTree = ""; }; 6D342C9A1EBA3156006EEBEC /* AutoLenses.generated.swift */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = AutoLenses.generated.swift; sourceTree = ""; }; 6D342C9B1EBA3156006EEBEC /* LinuxMain.generated.swift */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = LinuxMain.generated.swift; sourceTree = ""; }; 6D342CA11EBA35E9006EEBEC /* AutoCases.expected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoCases.expected; sourceTree = ""; }; 6D6645C01ECC181A004C1948 /* AutoMockable.generated.swift */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = AutoMockable.generated.swift; sourceTree = ""; }; 6D6645C21ECC1824004C1948 /* AutoMockable.expected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AutoMockable.expected; sourceTree = ""; }; 6D6645C41ECC184A004C1948 /* AutoMockable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoMockable.swift; sourceTree = ""; }; 6D6645C71ECC2187004C1948 /* LinuxMain.expected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LinuxMain.expected; sourceTree = ""; }; 6D6645C91ECC219C004C1948 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; 6D6A24AA1EB79E8900C1FB1A /* TemplatesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TemplatesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 6D6C19251FC4CE7900CD2A34 /* Decorator.swifttemplate */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Decorator.swifttemplate; sourceTree = ""; }; 6DC27BD71EC6592700B73CAF /* AutoHashable.expected */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = AutoHashable.expected; sourceTree = ""; }; 8BC863822106BD763A8B145B /* Pods-TemplatesTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TemplatesTests.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-TemplatesTests/Pods-TemplatesTests.debug.xcconfig"; sourceTree = ""; }; A4E640041AB8FBF997174F87 /* Pods-CodableContextTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CodableContextTests.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-CodableContextTests/Pods-CodableContextTests.debug.xcconfig"; sourceTree = ""; }; AD6C4A9866B1F8FDB6B02DA5 /* Pods-TemplatesTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TemplatesTests.release.xcconfig"; path = "../Pods/Target Support Files/Pods-TemplatesTests/Pods-TemplatesTests.release.xcconfig"; sourceTree = ""; }; E0F526BDFB067A8F16ACE2F6 /* Pods-CodableContextTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CodableContextTests.release.xcconfig"; path = "../Pods/Target Support Files/Pods-CodableContextTests/Pods-CodableContextTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 63A4F4C920964FB3000F8CDF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 63A4F4DA2096509A000F8CDF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 63A4F4E22096509A000F8CDF /* CodableContext.framework in Frameworks */, 328D9E935602E7E23C76D3C3 /* Pods_CodableContextTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 6D6A24A71EB79E8900C1FB1A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( C03FD2E6F7645376C192094D /* Pods_TemplatesTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 63A4F4CE20964FB3000F8CDF /* CodableContext */ = { isa = PBXGroup; children = ( 63A4F4CF20964FB3000F8CDF /* CodableContext.h */, 63A4F4D020964FB3000F8CDF /* Info.plist */, ); path = CodableContext; sourceTree = ""; }; 63A4F4DE2096509A000F8CDF /* CodableContextTests */ = { isa = PBXGroup; children = ( 63A4F4DF2096509A000F8CDF /* CodableContextTests.swift */, 63A4F4E12096509A000F8CDF /* Info.plist */, ); path = CodableContextTests; sourceTree = ""; }; 6D342C8C1EBA146F006EEBEC /* Tests */ = { isa = PBXGroup; children = ( 6D342C961EBA18F6006EEBEC /* Generated */, 6D342C921EBA1481006EEBEC /* Expected */, 6D342C8D1EBA146F006EEBEC /* Context */, 6D342C8E1EBA146F006EEBEC /* Info.plist */, 6D342C8F1EBA146F006EEBEC /* TemplatesTests.swift */, ); path = Tests; sourceTree = ""; }; 6D342C8D1EBA146F006EEBEC /* Context */ = { isa = PBXGroup; children = ( 6D342C931EBA155A006EEBEC /* AutoCases.swift */, 6D037EA01EC26E6300FA6C91 /* AutoEquatable.swift */, 6D0AF6BB1EC5EDD100F9A410 /* AutoHashable.swift */, 6D130B781ECACCDF00E9642A /* AutoLenses.swift */, 6D6645C41ECC184A004C1948 /* AutoMockable.swift */, 6D6645C91ECC219C004C1948 /* LinuxMain.swift */, 636D78492080256500160CC4 /* AutoCodable.swift */, ); path = Context; sourceTree = ""; }; 6D342C921EBA1481006EEBEC /* Expected */ = { isa = PBXGroup; children = ( 6DC27BD71EC6592700B73CAF /* AutoHashable.expected */, 6D037EA21EC26E6A00FA6C91 /* AutoEquatable.expected */, 6D342CA11EBA35E9006EEBEC /* AutoCases.expected */, 6D130B7A1ECACD0F00E9642A /* AutoLenses.expected */, 6D6645C21ECC1824004C1948 /* AutoMockable.expected */, 6D6645C71ECC2187004C1948 /* LinuxMain.expected */, 636D786B2083B8D700160CC4 /* AutoCodable.expected */, ); path = Expected; sourceTree = ""; }; 6D342C961EBA18F6006EEBEC /* Generated */ = { isa = PBXGroup; children = ( 6D6645C01ECC181A004C1948 /* AutoMockable.generated.swift */, 6D342C971EBA3156006EEBEC /* AutoCases.generated.swift */, 6D342C981EBA3156006EEBEC /* AutoEquatable.generated.swift */, 6D342C991EBA3156006EEBEC /* AutoHashable.generated.swift */, 6D342C9A1EBA3156006EEBEC /* AutoLenses.generated.swift */, 6D342C9B1EBA3156006EEBEC /* LinuxMain.generated.swift */, 636D784C208169E100160CC4 /* AutoCodable.generated.swift */, ); path = Generated; sourceTree = ""; }; 6D6A24901EB79E8900C1FB1A = { isa = PBXGroup; children = ( 6D342C8C1EBA146F006EEBEC /* Tests */, 6D6A249B1EB79E8900C1FB1A /* Templates */, 63A4F4CE20964FB3000F8CDF /* CodableContext */, 63A4F4DE2096509A000F8CDF /* CodableContextTests */, 6D6A249A1EB79E8900C1FB1A /* Products */, CA94A66439D4310F095D40C2 /* Pods */, 72FF6DD085C4C67695145997 /* Frameworks */, ); sourceTree = ""; }; 6D6A249A1EB79E8900C1FB1A /* Products */ = { isa = PBXGroup; children = ( 6D6A24AA1EB79E8900C1FB1A /* TemplatesTests.xctest */, 63A4F4CD20964FB3000F8CDF /* CodableContext.framework */, 63A4F4DD2096509A000F8CDF /* CodableContextTests.xctest */, ); name = Products; sourceTree = ""; }; 6D6A249B1EB79E8900C1FB1A /* Templates */ = { isa = PBXGroup; children = ( 6D6C19251FC4CE7900CD2A34 /* Decorator.swifttemplate */, 6D342C7C1EBA13DF006EEBEC /* AutoCases.stencil */, 6D342C7D1EBA13DF006EEBEC /* AutoEquatable.stencil */, 6D342C7E1EBA13DF006EEBEC /* AutoHashable.stencil */, 6D342C7F1EBA13DF006EEBEC /* AutoLenses.stencil */, 6D342C801EBA13DF006EEBEC /* AutoMockable.stencil */, 6D342C821EBA13DF006EEBEC /* LinuxMain.stencil */, 636D78472080251800160CC4 /* AutoCodable.swifttemplate */, ); path = Templates; sourceTree = ""; }; 72FF6DD085C4C67695145997 /* Frameworks */ = { isa = PBXGroup; children = ( 26AD1250F60484521E03C14A /* Pods_TemplatesTests.framework */, 433370DB5CFA428C5E58DD79 /* Pods_CodableContextTests.framework */, ); name = Frameworks; sourceTree = ""; }; CA94A66439D4310F095D40C2 /* Pods */ = { isa = PBXGroup; children = ( 8BC863822106BD763A8B145B /* Pods-TemplatesTests.debug.xcconfig */, AD6C4A9866B1F8FDB6B02DA5 /* Pods-TemplatesTests.release.xcconfig */, A4E640041AB8FBF997174F87 /* Pods-CodableContextTests.debug.xcconfig */, E0F526BDFB067A8F16ACE2F6 /* Pods-CodableContextTests.release.xcconfig */, ); name = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 63A4F4CA20964FB3000F8CDF /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 63A4F4D120964FB3000F8CDF /* CodableContext.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 63A4F4CC20964FB3000F8CDF /* CodableContext */ = { isa = PBXNativeTarget; buildConfigurationList = 63A4F4D220964FB3000F8CDF /* Build configuration list for PBXNativeTarget "CodableContext" */; buildPhases = ( 63A4F4C820964FB3000F8CDF /* Sources */, 63A4F4C920964FB3000F8CDF /* Frameworks */, 63A4F4CA20964FB3000F8CDF /* Headers */, 63A4F4CB20964FB3000F8CDF /* Resources */, ); buildRules = ( ); dependencies = ( ); name = CodableContext; productName = CodableContext; productReference = 63A4F4CD20964FB3000F8CDF /* CodableContext.framework */; productType = "com.apple.product-type.framework"; }; 63A4F4DC2096509A000F8CDF /* CodableContextTests */ = { isa = PBXNativeTarget; buildConfigurationList = 63A4F4E52096509A000F8CDF /* Build configuration list for PBXNativeTarget "CodableContextTests" */; buildPhases = ( FFEF5D0C986086E8F28D9EC4 /* [CP] Check Pods Manifest.lock */, 63A4F4D92096509A000F8CDF /* Sources */, 63A4F4DA2096509A000F8CDF /* Frameworks */, 63A4F4DB2096509A000F8CDF /* Resources */, 22DA36BA830521DB8295746C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 63A4F4E42096509A000F8CDF /* PBXTargetDependency */, ); name = CodableContextTests; productName = CodableContextTests; productReference = 63A4F4DD2096509A000F8CDF /* CodableContextTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 6D6A24A91EB79E8900C1FB1A /* TemplatesTests */ = { isa = PBXNativeTarget; buildConfigurationList = 6D6A24B61EB79E8900C1FB1A /* Build configuration list for PBXNativeTarget "TemplatesTests" */; buildPhases = ( D775B999DCC76F43E995E441 /* [CP] Check Pods Manifest.lock */, 6D342C951EBA1881006EEBEC /* Sourcery */, 6D6A24A61EB79E8900C1FB1A /* Sources */, 6D6A24A71EB79E8900C1FB1A /* Frameworks */, 6D6A24A81EB79E8900C1FB1A /* Resources */, 7139144942C834B5880D5184 /* [CP] Embed Pods Frameworks */, 63A4F4C420964E7B000F8CDF /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = TemplatesTests; productName = TemplatesTests; productReference = 6D6A24AA1EB79E8900C1FB1A /* TemplatesTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 6D6A24911EB79E8900C1FB1A /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0930; LastUpgradeCheck = 1210; ORGANIZATIONNAME = Pixle; TargetAttributes = { 63A4F4CC20964FB3000F8CDF = { CreatedOnToolsVersion = 9.3; ProvisioningStyle = Automatic; }; 63A4F4DC2096509A000F8CDF = { CreatedOnToolsVersion = 9.3; ProvisioningStyle = Automatic; }; 6D6A24A91EB79E8900C1FB1A = { CreatedOnToolsVersion = 8.3.2; LastSwiftMigration = 1000; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 6D6A24941EB79E8900C1FB1A /* Build configuration list for PBXProject "Templates" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, en, Base, ); mainGroup = 6D6A24901EB79E8900C1FB1A; productRefGroup = 6D6A249A1EB79E8900C1FB1A /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 6D6A24A91EB79E8900C1FB1A /* TemplatesTests */, 63A4F4CC20964FB3000F8CDF /* CodableContext */, 63A4F4DC2096509A000F8CDF /* CodableContextTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 63A4F4CB20964FB3000F8CDF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 63A4F4DB2096509A000F8CDF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 6D6A24A81EB79E8900C1FB1A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 6D4D84481EC667630005932D /* AutoEquatable.generated.swift in Resources */, 6D6645C61ECC1CAA004C1948 /* AutoMockable.generated.swift in Resources */, 6D6645C31ECC1824004C1948 /* AutoMockable.expected in Resources */, 6D6645CB1ECC22A3004C1948 /* LinuxMain.generated.swift in Resources */, 6D6645C81ECC2187004C1948 /* LinuxMain.expected in Resources */, 6D130B7B1ECACD0F00E9642A /* AutoLenses.expected in Resources */, 6D342C841EBA13DF006EEBEC /* AutoEquatable.stencil in Resources */, 6D6C19261FC4CE7900CD2A34 /* Decorator.swifttemplate in Resources */, B50435DF2157222E00F120DF /* AutoCodable.expected in Resources */, 6D342C891EBA13DF006EEBEC /* LinuxMain.stencil in Resources */, 6D130B7C1ECACEB800E9642A /* AutoLenses.generated.swift in Resources */, 6D342C871EBA13DF006EEBEC /* AutoMockable.stencil in Resources */, 6D4D84491EC667650005932D /* AutoHashable.generated.swift in Resources */, 6D342C861EBA13DF006EEBEC /* AutoLenses.stencil in Resources */, 6D342C851EBA13DF006EEBEC /* AutoHashable.stencil in Resources */, 6DC27BD81EC6592700B73CAF /* AutoHashable.expected in Resources */, 6D342C831EBA13DF006EEBEC /* AutoCases.stencil in Resources */, 636D78572081781E00160CC4 /* AutoCodable.swifttemplate in Resources */, 6D342CA31EBA5415006EEBEC /* AutoCases.expected in Resources */, 6D342CA41EBA54DF006EEBEC /* AutoCases.generated.swift in Resources */, 6D037EA31EC26E6A00FA6C91 /* AutoEquatable.expected in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 22DA36BA830521DB8295746C /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-CodableContextTests/Pods-CodableContextTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework", "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CodableContextTests/Pods-CodableContextTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 6D342C951EBA1881006EEBEC /* Sourcery */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = Sourcery; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${BUILD_DIR}/Debug/Sourcery.app/Contents/MacOS/Sourcery\" --sources \"${SRCROOT}/Tests/Context\" --templates \"${SRCROOT}/Templates\" --output \"${SRCROOT}/Tests/Generated\" --disableCache --verbose\n"; }; 7139144942C834B5880D5184 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-TemplatesTests/Pods-TemplatesTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework", "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TemplatesTests/Pods-TemplatesTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; D775B999DCC76F43E995E441 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-TemplatesTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; FFEF5D0C986086E8F28D9EC4 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-CodableContextTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 63A4F4C820964FB3000F8CDF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 63A4F4D520964FBE000F8CDF /* AutoCodable.generated.swift in Sources */, 63A4F4D620964FC5000F8CDF /* AutoCodable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 63A4F4D92096509A000F8CDF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 63A4F4E02096509A000F8CDF /* CodableContextTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 6D6A24A61EB79E8900C1FB1A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 6D037EA11EC26E6300FA6C91 /* AutoEquatable.swift in Sources */, 6D130B791ECACCDF00E9642A /* AutoLenses.swift in Sources */, 6D342C941EBA155A006EEBEC /* AutoCases.swift in Sources */, 6D6645C51ECC184A004C1948 /* AutoMockable.swift in Sources */, 6D0AF6BC1EC5EDD100F9A410 /* AutoHashable.swift in Sources */, 6D342C911EBA146F006EEBEC /* TemplatesTests.swift in Sources */, 6D6645CA1ECC219C004C1948 /* LinuxMain.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 63A4F4E42096509A000F8CDF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 63A4F4CC20964FB3000F8CDF /* CodableContext */; targetProxy = 63A4F4E32096509A000F8CDF /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 63A4F4D320964FB3000F8CDF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CodableContext/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.CodableContext; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 63A4F4D420964FB3000F8CDF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CodableContext/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.CodableContext; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 63A4F4E62096509A000F8CDF /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = A4E640041AB8FBF997174F87 /* Pods-CodableContextTests.debug.xcconfig */; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CodableContextTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = Pixle.CodableContextTests; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 63A4F4E72096509A000F8CDF /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = E0F526BDFB067A8F16ACE2F6 /* Pods-CodableContextTests.release.xcconfig */; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CodableContextTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = Pixle.CodableContextTests; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 6D6A24B11EB79E8900C1FB1A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 6D6A24B21EB79E8900C1FB1A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; }; name = Release; }; 6D6A24B71EB79E8900C1FB1A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 8BC863822106BD763A8B145B /* Pods-TemplatesTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.Sourcery.TemplatesTests; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 6D6A24B81EB79E8900C1FB1A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = AD6C4A9866B1F8FDB6B02DA5 /* Pods-TemplatesTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = Pixle.Sourcery.TemplatesTests; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 63A4F4D220964FB3000F8CDF /* Build configuration list for PBXNativeTarget "CodableContext" */ = { isa = XCConfigurationList; buildConfigurations = ( 63A4F4D320964FB3000F8CDF /* Debug */, 63A4F4D420964FB3000F8CDF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 63A4F4E52096509A000F8CDF /* Build configuration list for PBXNativeTarget "CodableContextTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 63A4F4E62096509A000F8CDF /* Debug */, 63A4F4E72096509A000F8CDF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 6D6A24941EB79E8900C1FB1A /* Build configuration list for PBXProject "Templates" */ = { isa = XCConfigurationList; buildConfigurations = ( 6D6A24B11EB79E8900C1FB1A /* Debug */, 6D6A24B21EB79E8900C1FB1A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 6D6A24B61EB79E8900C1FB1A /* Build configuration list for PBXNativeTarget "TemplatesTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 6D6A24B71EB79E8900C1FB1A /* Debug */, 6D6A24B81EB79E8900C1FB1A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 6D6A24911EB79E8900C1FB1A /* Project object */; } ================================================ FILE: Templates/Templates.xcodeproj/xcshareddata/xcschemes/TemplatesTests.xcscheme ================================================ ================================================ FILE: Templates/Tests/Context/AutoCases.swift ================================================ // // AutoCases.swift // Templates // // Created by Anton Domashnev on 03.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation protocol AutoCases {} enum AutoCasesEnum: AutoCases { case north case south case east case west } enum AutoCasesOneValueEnum: AutoCases { case one } public enum AutoCasesHasAssociatedValuesEnum: AutoCases { case foo(test: String) case bar(number: Int) } ================================================ FILE: Templates/Tests/Context/AutoCodable.swift ================================================ // // AutoCodable.swift // TemplatesTests // // Created by Ilya Puchka on 13/04/2018. // Copyright © 2018 Pixle. All rights reserved. // #if canImport(ObjectiveC) import Foundation protocol AutoDecodable: Swift.Decodable {} protocol AutoEncodable: Swift.Encodable {} protocol AutoCodable: AutoDecodable, AutoEncodable {} public struct CustomKeyDecodable: AutoDecodable { let stringValue: String let boolValue: Bool let intValue: Int enum CodingKeys: String, CodingKey { case intValue = "integer" // sourcery:inline:auto:CustomKeyDecodable.CodingKeys.AutoCodable case stringValue case boolValue // sourcery:end } } public struct CustomMethodsCodable: AutoCodable { let boolValue: Bool let intValue: Int? let optionalString: String? let requiredString: String let requiredStringWithDefault: String var computedPropertyToEncode: Int { return 0 } static let defaultIntValue: Int = 0 static let defaultRequiredStringWithDefault: String = "" static func decodeIntValue(from container: KeyedDecodingContainer) -> Int? { return (try? container.decode(String.self, forKey: .intValue)).flatMap(Int.init) } static func decodeBoolValue(from decoder: Decoder) throws -> Bool { return try decoder.container(keyedBy: CodingKeys.self).decode(Bool.self, forKey: .boolValue) } func encodeIntValue(to container: inout KeyedEncodingContainer) { try? container.encode(String(intValue ?? 0), forKey: .intValue) } func encodeBoolValue(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(boolValue, forKey: .boolValue) } func encodeComputedPropertyToEncode(to container: inout KeyedEncodingContainer) { try? container.encode(computedPropertyToEncode, forKey: .computedPropertyToEncode) } func encodeAdditionalValues(to encoder: Encoder) throws { } } public struct CustomContainerCodable: AutoCodable { let value: Int enum CodingKeys: String, CodingKey { case nested case value } static func decodingContainer(_ decoder: Decoder) throws -> KeyedDecodingContainer { return try decoder.container(keyedBy: CodingKeys.self) .nestedContainer(keyedBy: CodingKeys.self, forKey: .nested) } func encodingContainer(_ encoder: Encoder) -> KeyedEncodingContainer { var container = encoder.container(keyedBy: CodingKeys.self) return container.nestedContainer(keyedBy: CodingKeys.self, forKey: .nested) } } struct CustomCodingWithNotAllDefinedKeys: AutoCodable { let value: Int var computedValue: Int { return 0 } enum CodingKeys: String, CodingKey { case value // sourcery:inline:auto:CustomCodingWithNotAllDefinedKeys.CodingKeys.AutoCodable case computedValue // sourcery:end } func encodeComputedValue(to container: inout KeyedEncodingContainer) { try? container.encode(computedValue, forKey: .computedValue) } } struct SkipDecodingWithDefaultValueOrComputedProperty: AutoCodable { let value: Int let skipValue: Int = 0 var computedValue: Int { return 0 } enum CodingKeys: String, CodingKey { case value case computedValue } } struct SkipEncodingKeys: AutoCodable { let value: Int let skipValue: Int enum SkipEncodingKeys { case skipValue } } enum SimpleEnum: AutoCodable { case someCase case anotherCase } enum AssociatedValuesEnum: AutoCodable, Equatable { case someCase(id: Int, name: String) case unnamedCase(Int, String) case mixCase(Int, name: String) case anotherCase enum CodingKeys: String, CodingKey { case enumCaseKey = "type" // sourcery:inline:auto:AssociatedValuesEnum.CodingKeys.AutoCodable case someCase case unnamedCase case mixCase case anotherCase case id case name // sourcery:end } } enum AssociatedValuesEnumNoCaseKey: AutoCodable, Equatable { case someCase(id: Int, name: String) case unnamedCase(Int, String) case mixCase(Int, name: String) case anotherCase } #endif ================================================ FILE: Templates/Tests/Context/AutoEquatable.swift ================================================ // // AutoCases.swift // Templates // // Created by Anton Domashnev on 03.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation protocol AutoEquatable {} protocol Parent { var name: String { get } } /// General protocol protocol AutoEquatableProtocol: AutoEquatable { var width: Double { get } var height: Double { get} static var name: String { get } } /// General enum enum AutoEquatableEnum: AutoEquatable { case one case two(first: String, second: String) case three(bar: Int) func allValue() -> [AutoEquatableEnum] { return [.one, .two(first: "a", second: "b"), .three(bar: 42)] } } /// Sourcery should not generate a default case for enum with only one case enum AutoEquatableEnumWithOneCase: AutoEquatable { case one } /// Sourcery should generate correct code for struct struct AutoEquatableStruct: AutoEquatable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel } // Arrays // sourcery: arrayEquality let parents: [Parent] // Variable var moneyInThePocket: Double = 0 // Optional variable var friends: [String]? /// Forced unwrapped variable var age: Int! // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } /// It should generate correct code for general class class AutoEquatableClass: AutoEquatable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel } // Arrays // sourcery: arrayEquality let parents: [Parent] /// Forced unwrapped variable var age: Int! // Variable var moneyInThePocket: Double = 0 // Optional variable var friends: [String]? // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } /// Sourcery doesn't support inheritance for AutoEqualtable class AutoEquatableClassInherited: AutoEquatableClass { // Optional constants let middleName: String? init(middleName: String?) { self.middleName = middleName super.init(firstName: "", lastName: "", parents: [], laptopModel: "", phoneModel: "") } } /// Should not add Equatable conformance class AutoEquatableNSObject: NSObject, AutoEquatable { let firstName: String init(firstName: String) { self.firstName = firstName } } /// It should generate correct code for general class /// sourcery: AutoEquatable class AutoEquatableAnnotatedClass { // Variable var moneyInThePocket: Double = 0 } // It won't be generated class AutoEquatableAnnotatedClassInherited: AutoEquatableAnnotatedClass { // Variable var middleName: String = "Poor" } // Sourcery doesn't support inheritance for AutoEqualtable so it won't be generated /// sourcery: AutoEquatable class AutoEquatableAnnotatedClassAnnotatedInherited: AutoEquatableAnnotatedClass { // Variable var middleName: String = "Poor" } ================================================ FILE: Templates/Tests/Context/AutoHashable.swift ================================================ import Foundation protocol AutoHashable {} /// General protocol protocol AutoHashableProtocol: AutoHashable { var width: Double { get } var height: Double { get} static var name: String { get } } /// General enum enum AutoHashableEnum: AutoHashable { case one case two(first: String, second: String) case three(bar: Int) func allValue() -> [AutoHashableEnum] { return [.one, .two(first: "a", second: "b"), .three(bar: 42)] } } /// Sourcery should generate correct code for struct struct AutoHashableStruct: AutoHashable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Static constant static let structName: String = "AutoHashableStruct" // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel self.universityGrades = ["Math": 5, "Geometry": 3] } // Arrays let parents: [Parent] // Dictionary let universityGrades: [String: Int] // Variable var moneyInThePocket: Double = 0 // Forced unwrapped variable var age: Int! // Optional variable var friends: [String]? // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } /// It should generate correct code for general class class AutoHashableClass: AutoHashable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Static constant static let className: String = "AutoHashableClass" // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel self.universityGrades = ["Math": 5, "Geometry": 3] } // Arrays let parents: [Parent] // Dictionary let universityGrades: [String: Int] // Variable var moneyInThePocket: Double = 0 // Forced unwrapped variable var age: Int! // Optional variable var friends: [String]? // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } class AutoHashableClassInherited: AutoHashableClass { // Optional constants let middleName: String? init(middleName: String?) { self.middleName = middleName super.init(firstName: "", lastName: "", parents: [], laptopModel: "", phoneModel: "") } } class AutoHashableClassInheritedInherited: AutoHashableClassInherited { // Optional constants let prefix: String? init(prefix: String?) { self.prefix = prefix super.init(middleName: "") } } class NonHashableClass { let firstName: String init(firstName: String) { self.firstName = firstName } } // Should not add super call class AutoHashableClassFromNonHashableInherited: NonHashableClass, AutoHashable { let lastName: String? init(lastName: String?) { self.lastName = lastName super.init(firstName: "") } } // Should add super call class AutoHashableClassFromNonHashableInheritedInherited: AutoHashableClassFromNonHashableInherited { let prefix: String? init(prefix: String?) { self.prefix = prefix super.init(lastName: "") } } class HashableClass: Hashable { let firstName: String init(firstName: String) { self.firstName = firstName } static func == (lhs: HashableClass, rhs: HashableClass) -> Bool { return lhs.firstName == rhs.firstName } func hash(into hasher: inout Hasher) { self.firstName.hash(into: &hasher) } } // Should add super class AutoHashableFromHashableInherited: HashableClass, AutoHashable { let lastName: String? init(lastName: String?) { self.lastName = lastName super.init(firstName: "") } } /// Should not add Hashable conformance class AutoHashableNSObject: NSObject, AutoHashable { let firstName: String init(firstName: String) { self.firstName = firstName } } // Should add super call class AutoHashableNSObjectInherited: AutoHashableNSObject { let lastName: String init(lastName: String) { self.lastName = lastName super.init(firstName: "") } } ================================================ FILE: Templates/Tests/Context/AutoLenses.swift ================================================ // // AutoLenses.swift // Templates // // Created by Anton Domashnev on 16.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation protocol AutoLenses {} struct House: AutoLenses { let rooms: Room let address: String let size: Int } struct Room: AutoLenses { let people: [Person] let name: String } struct Person: AutoLenses { let name: String } // swiftlint:disable identifier_name struct Rectangle: AutoLenses { let x: Int let y: Int var area: Int { return x*y } } ================================================ FILE: Templates/Tests/Context/AutoMockable.swift ================================================ // // AutoMockable.swift // Templates // // Created by Anton Domashnev on 17.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation public protocol AutoMockable {} protocol StubProtocol {} protocol StubWithAnyNameProtocol {} protocol StubWithSomeNameProtocol {} protocol PersonProtocol {} protocol BasicProtocol: AutoMockable { func loadConfiguration() -> String? /// Asks a Duck to quack /// /// - Parameter times: How many times the Duck will quack func save(configuration: String) } protocol ImplicitlyUnwrappedOptionalReturnValueProtocol: AutoMockable { func implicitReturn() -> String! } protocol InitializationProtocol: AutoMockable { init(intParameter: Int, stringParameter: String, optionalParameter: String?) func start() func stop() } protocol VariablesProtocol: AutoMockable { var company: String? { get set } var name: String { get } var age: Int { get } var kids: [String] { get } var universityMarks: [String: Int] { get } } protocol SameShortMethodNamesProtocol: AutoMockable { func start(car: String, of model: String) func start(plane: String, of model: String) } protocol ExtendableProtocol: AutoMockable { var canReport: Bool { get } func report(message: String) } protocol ReservedWordsProtocol: AutoMockable { func `continue`(with message: String) -> String } protocol ThrowableProtocol: AutoMockable { func doOrThrow() throws -> String func doOrThrowVoid() throws } protocol TypedThrowableProtocol: AutoMockable { init() throws(CustomError) init(init2: Void) throws(E) where E: Error var value: Int { get throws(CustomError) } var valueAnyError: Int { get throws(any Error) } var valueThrowsNever: Int { get throws(Never) } func doOrThrow() throws(CustomError) -> String // func doOrThrowVoid() throws(CustomErrorNameSpace.Error) func doOrThrowAnyError() throws(any Error) func doOrThrowNever() throws(Never) func doOrRethrows(_ block: () throws(E) -> Void) throws(E) -> Int where E: Error } struct CustomError: Error {} // Nested types does not work on Linux, but works on macOS so this cannot be used in this test //enum CustomErrorNameSpace { // struct Error: Swift.Error {} //} protocol CurrencyPresenter: AutoMockable { func showSourceCurrency(_ currency: String) } extension ExtendableProtocol { var canReport: Bool { return true } func report(message: String = "Test") { print(message) } } protocol ClosureProtocol: AutoMockable { func setClosure(_ closure: @escaping () -> Void) } protocol NullableClosureProtocol: AutoMockable { func setClosure(_ closure: (() -> Void)?) } protocol MultiClosureProtocol: AutoMockable { func setClosure(name: String, _ closure: @escaping () -> Void) } protocol MultiNullableClosureProtocol: AutoMockable { func setClosure(name: String, _ closure: (() -> Void)?) } protocol NonEscapingClosureProtocol: AutoMockable { func executeClosure(_ closure: () -> Void) } protocol MultiNonEscapingClosureProtocol: AutoMockable { func executeClosure(name: String, _ closure: () -> Void) } protocol MultiExistentialArgumentsClosureProtocol: AutoMockable { func execute(completion: ((any StubWithSomeNameProtocol)?, any StubWithSomeNameProtocol) -> (any StubWithSomeNameProtocol)?) } protocol ClosureWithTwoParametersProtocol: AutoMockable { func setClosure(closure: @escaping (String, Int) -> Void) } /// sourcery: AutoMockable protocol AnnotatedProtocol { func sayHelloWith(name: String) } protocol SingleOptionalParameterFunction: AutoMockable { func send(message: String?) } protocol FunctionWithClosureReturnType: AutoMockable { func get() -> () -> Void func getOptional() -> (() -> Void)? } protocol FunctionWithMultilineDeclaration: AutoMockable { func start(car: String, of model: String) } protocol ThrowingVariablesProtocol: AutoMockable { var title: String? { get throws } var firstName: String { get throws } } protocol AsyncVariablesProtocol: AutoMockable { var title: String? { get async } var firstName: String { get async } } protocol AsyncThrowingVariablesProtocol: AutoMockable { var title: String? { get async throws } var firstName: String { get async throws } } protocol AsyncProtocol: AutoMockable { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func callAsync(parameter: Int) async -> String func callAsyncAndThrow(parameter: Int) async throws -> String func callAsyncVoid(parameter: Int) async -> Void func callAsyncAndThrowVoid(parameter: Int) async throws -> Void } protocol FunctionWithAttributes: AutoMockable { @discardableResult func callOneAttribute() -> String @discardableResult @available(macOS 10.15, *) func callTwoAttributes() -> Int @discardableResult @available(iOS 13.0, *) @available(macOS 10.15, *) func callRepeatedAttributes() -> Bool } public protocol AccessLevelProtocol: AutoMockable { var company: String? { get set } var name: String { get } func loadConfiguration() -> String? } protocol StaticMethodProtocol: AutoMockable { static func staticFunction(_: String) -> String } protocol AnyProtocol: AutoMockable { var a: any StubProtocol { get } var b: (any StubProtocol)? { get } var c: (any StubProtocol)! { get } var d: (((any StubProtocol)?) -> Void) { get } var e: [(any StubProtocol)?] { get } func f(_ x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) var g: any StubProtocol { get } var h: (any StubProtocol)? { get } var i: (any StubProtocol)! { get } func j(x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) async -> String func k(x: ((any StubProtocol)?) -> Void, y: (any StubProtocol) -> Void) func l(x: (((any StubProtocol)?) -> Void), y: ((any StubProtocol) -> Void)) var anyConfusingPropertyName: any StubProtocol { get } func m(anyConfusingArgumentName: any StubProtocol) func n(x: @escaping ((any StubProtocol)?) -> Void) var o: any StubWithAnyNameProtocol { get } func p(_ x: (any StubWithAnyNameProtocol)?) func q() -> any StubProtocol func r() -> (any StubProtocol)? func s() -> () -> any StubProtocol func t() -> () -> (any StubProtocol)? func u() -> (Int, () -> (any StubProtocol)?) func v() -> (Int, (() -> any StubProtocol)?) func w() -> [(any StubProtocol)?] func x() -> [String: (any StubProtocol)?] func y() -> (any StubProtocol, (any StubProtocol)?) func z() -> any StubProtocol & CustomStringConvertible } protocol AnyProtocolWithOptionals: AutoMockable { var a: [any StubProtocol]? { get } var b: [Result] { get } var c: (Int, [(any StubProtocol)?])? { get } var d: (Int, (any StubProtocol)?) { get } var e: (Int, (any StubProtocol)?)? { get } var f: (Int, [any StubProtocol]?)? { get } func g(_ g: String, handler: @escaping ([any StubProtocol]?) -> Void) -> Bool func h(_ h: String, handler: @escaping ([StubProtocol]) -> Void) -> Bool func i(_ i: String, handler: @escaping ([(any StubProtocol)?]) -> Void) -> Bool var j: (anyInteger: Int, anyArray: [any StubProtocol]?)? { get } } protocol SomeProtocol: AutoMockable { func a(_ x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) func b(x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) async -> String func someConfusingFuncName(x: some StubProtocol) func c(someConfusingArgumentName: some StubProtocol) func d(_ x: (some StubWithSomeNameProtocol)?) } class GenericType{} protocol HouseProtocol: AutoMockable { var aPublisher: AnyPublisher? { get } var bPublisher: AnyPublisher<(any PersonProtocol)?, Never>? { get } var cPublisher: CurrentValueSubject<(any PersonProtocol)?, Never>? { get } var dPublisher: PassthroughSubject<(any PersonProtocol)?, Never>? { get } var e1Publisher: GenericType<(any PersonProtocol)?, Never, Never>? { get } var e2Publisher: GenericType? { get } var e3Publisher: GenericType? { get } var e4Publisher: GenericType<(any PersonProtocol)?, (any PersonProtocol)?, (any PersonProtocol)?>? { get } var f1Publisher: GenericType? { get } var f2Publisher: GenericType? { get } var f3Publisher: GenericType? { get } var f4Publisher: GenericType? { get } } protocol FunctionWithNullableCompletionThatHasNullableAnyParameterProtocol: AutoMockable { func add( _ request: Int, withCompletionHandler completionHandler: (((any Error)?) -> Void)? ) } // sourcery: AutoMockable protocol ExampleVararg { func string(key: String, args: CVarArg...) -> String } // sourcery: AutoMockable protocol ExampleVarargTwo { func toto(args: any StubWithSomeNameProtocol...) } // sourcery: AutoMockable protocol ExampleVarargThree { func toto(arg: ((String, any Collection...) -> any Collection)) } // sourcery: AutoMockable protocol ExampleVarargFour { func toto(arg: ((String, any Collection...) -> Void)) } // sourcery: AutoMockable public protocol ProtocolWithOverrides { func doSomething(_ data: Int) -> [String] func doSomething(_ data: String) -> [String] func doSomething(_ data: String) -> [Int] func doSomething(_ data: String) -> ([Int], [String]) func doSomething(_ data: String) throws -> ([Int], [Any]) func doSomething(_ data: String) -> (([Int], [String]) -> Void) func doSomething(_ data: String) throws -> (([Int], [Any]) -> Void) } // sourcery: AutoMockable protocol SubscriptProtocol { subscript(arg: Int) -> String { get set } subscript(arg: T) -> Int { get } subscript(arg: T) -> String { get async } subscript(arg: T) -> T? { get set } subscript(arg: String) -> T? where T: Cancellable { get throws } subscript(arg2: String) -> T { get throws(CustomError) } } // sourcery: AutoMockable public protocol ProtocolWithMethodWithGenericParameters { func execute(param: Result) -> Result } // sourcery: AutoMockable public protocol ProtocolWithMethodWithInoutParameter { func execute(param: inout String) func execute(param: inout String, bar: Int) } //sourcery:AutoMockable protocol TestProtocol { associatedtype Value: Sequence where Value.Element: Collection, Value.Element: Hashable, Value.Element: Comparable func getValue() -> Value associatedtype Value2 = Int func getValue2() -> Value2 associatedtype Value3: Collection where Value3.Element == String func getValue3() -> Value3 associatedtype Value5: Sequence where Value5.Element == Int func getValue5() -> Value5 associatedtype Value6: Sequence where Value6.Element == Int, Value6.Element: Hashable, Value6.Element: Comparable func getValue6() -> Value6 } // sourcery: AutoMockable protocol SendableProtocol: Sendable { var value: Any { get } } protocol NotMockedSendableProtocol: Sendable {} // sourcery: AutoMockable protocol SendableSendableProtocol: NotMockedSendableProtocol { var value: Any { get } } ================================================ FILE: Templates/Tests/Context/LinuxMain.swift ================================================ // // LinuxMain.swift // Templates // // Created by Anton Domashnev on 17.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation import XCTest class AutoInjectionTests: XCTestCase { func testThatItResolvesAutoInjectedDependencies() { XCTAssertTrue(true) } func testThatItDoesntResolveAutoInjectedDependencies() { XCTAssertTrue(true) } } class AutoWiringTests: XCTestCase { func testThatItCanResolveWithAutoWiring() { XCTAssertTrue(true) } func testThatItCanNotResolveWithAutoWiring() { XCTAssertTrue(true) } } // sourcery: disableTests class DisabledTests: XCTestCase { func testThatItResolvesDisabledTestsAnnotation() { XCTAssertTrue(true) } } ================================================ FILE: Templates/Tests/Context_Linux/AutoCases.swift ================================================ // // AutoCases.swift // Templates // // Created by Anton Domashnev on 03.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation protocol AutoCases {} enum AutoCasesEnum: AutoCases { case north case south case east case west } enum AutoCasesOneValueEnum: AutoCases { case one } public enum AutoCasesHasAssociatedValuesEnum: AutoCases { case foo(test: String) case bar(number: Int) } ================================================ FILE: Templates/Tests/Context_Linux/AutoEquatable.swift ================================================ // // AutoCases.swift // Templates // // Created by Anton Domashnev on 03.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation protocol AutoEquatable {} protocol Parent { var name: String { get } } /// General protocol protocol AutoEquatableProtocol: AutoEquatable { var width: Double { get } var height: Double { get} static var name: String { get } } /// General enum enum AutoEquatableEnum: AutoEquatable { case one case two(first: String, second: String) case three(bar: Int) func allValue() -> [AutoEquatableEnum] { return [.one, .two(first: "a", second: "b"), .three(bar: 42)] } } /// Sourcery should not generate a default case for enum with only one case enum AutoEquatableEnumWithOneCase: AutoEquatable { case one } /// Sourcery should generate correct code for struct struct AutoEquatableStruct: AutoEquatable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel } // Arrays // sourcery: arrayEquality let parents: [Parent] // Variable var moneyInThePocket: Double = 0 // Optional variable var friends: [String]? /// Forced unwrapped variable var age: Int! // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } /// It should generate correct code for general class class AutoEquatableClass: AutoEquatable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel } // Arrays // sourcery: arrayEquality let parents: [Parent] /// Forced unwrapped variable var age: Int! // Variable var moneyInThePocket: Double = 0 // Optional variable var friends: [String]? // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } /// Sourcery doesn't support inheritance for AutoEqualtable class AutoEquatableClassInherited: AutoEquatableClass { // Optional constants let middleName: String? init(middleName: String?) { self.middleName = middleName super.init(firstName: "", lastName: "", parents: [], laptopModel: "", phoneModel: "") } } /// Should not add Equatable conformance class AutoEquatableNSObject: NSObject, AutoEquatable { let firstName: String init(firstName: String) { self.firstName = firstName } } /// It should generate correct code for general class /// sourcery: AutoEquatable class AutoEquatableAnnotatedClass { // Variable var moneyInThePocket: Double = 0 } // It won't be generated class AutoEquatableAnnotatedClassInherited: AutoEquatableAnnotatedClass { // Variable var middleName: String = "Poor" } // Sourcery doesn't support inheritance for AutoEqualtable so it won't be generated /// sourcery: AutoEquatable class AutoEquatableAnnotatedClassAnnotatedInherited: AutoEquatableAnnotatedClass { // Variable var middleName: String = "Poor" } ================================================ FILE: Templates/Tests/Context_Linux/AutoHashable.swift ================================================ import Foundation protocol AutoHashable {} /// General protocol protocol AutoHashableProtocol: AutoHashable { var width: Double { get } var height: Double { get} static var name: String { get } } /// General enum enum AutoHashableEnum: AutoHashable { case one case two(first: String, second: String) case three(bar: Int) func allValue() -> [AutoHashableEnum] { return [.one, .two(first: "a", second: "b"), .three(bar: 42)] } } /// Sourcery should generate correct code for struct struct AutoHashableStruct: AutoHashable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Static constant static let structName: String = "AutoHashableStruct" // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel self.universityGrades = ["Math": 5, "Geometry": 3] } // Arrays let parents: [Parent] // Dictionary let universityGrades: [String: Int] // Variable var moneyInThePocket: Double = 0 // Forced unwrapped variable var age: Int! // Optional variable var friends: [String]? // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } /// It should generate correct code for general class class AutoHashableClass: AutoHashable { // Private Constants private let laptopModel: String // Fileprivate Constants fileprivate let phoneModel: String // Static constant static let className: String = "AutoHashableClass" // Internal Constants let firstName: String // Public Constans public let lastName: String init(firstName: String, lastName: String, parents: [Parent], laptopModel: String, phoneModel: String) { self.firstName = firstName self.lastName = lastName self.parents = parents self.laptopModel = laptopModel self.phoneModel = phoneModel self.universityGrades = ["Math": 5, "Geometry": 3] } // Arrays let parents: [Parent] // Dictionary let universityGrades: [String: Int] // Variable var moneyInThePocket: Double = 0 // Forced unwrapped variable var age: Int! // Optional variable var friends: [String]? // Void method func walk() { print("I'm going") } // Method with return value func greeting(for name: String) -> String { return "Hi \(name)" } // Method with optional return value func books(sharedWith name: String) -> String? { return nil } } class AutoHashableClassInherited: AutoHashableClass { // Optional constants let middleName: String? init(middleName: String?) { self.middleName = middleName super.init(firstName: "", lastName: "", parents: [], laptopModel: "", phoneModel: "") } } class AutoHashableClassInheritedInherited: AutoHashableClassInherited { // Optional constants let prefix: String? init(prefix: String?) { self.prefix = prefix super.init(middleName: "") } } class NonHashableClass { let firstName: String init(firstName: String) { self.firstName = firstName } } // Should not add super call class AutoHashableClassFromNonHashableInherited: NonHashableClass, AutoHashable { let lastName: String? init(lastName: String?) { self.lastName = lastName super.init(firstName: "") } } // Should add super call class AutoHashableClassFromNonHashableInheritedInherited: AutoHashableClassFromNonHashableInherited { let prefix: String? init(prefix: String?) { self.prefix = prefix super.init(lastName: "") } } class HashableClass: Hashable { let firstName: String init(firstName: String) { self.firstName = firstName } static func == (lhs: HashableClass, rhs: HashableClass) -> Bool { return lhs.firstName == rhs.firstName } func hash(into hasher: inout Hasher) { self.firstName.hash(into: &hasher) } } // Should add super class AutoHashableFromHashableInherited: HashableClass, AutoHashable { let lastName: String? init(lastName: String?) { self.lastName = lastName super.init(firstName: "") } } /// Should not add Hashable conformance class AutoHashableNSObject: NSObject, AutoHashable { let firstName: String init(firstName: String) { self.firstName = firstName } } // Should add super call class AutoHashableNSObjectInherited: AutoHashableNSObject { let lastName: String init(lastName: String) { self.lastName = lastName super.init(firstName: "") } } ================================================ FILE: Templates/Tests/Context_Linux/AutoLenses.swift ================================================ // // AutoLenses.swift // Templates // // Created by Anton Domashnev on 16.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation protocol AutoLenses {} struct House: AutoLenses { let rooms: Room let address: String let size: Int } struct Room: AutoLenses { let people: [Person] let name: String } struct Person: AutoLenses { let name: String } // swiftlint:disable identifier_name struct Rectangle: AutoLenses { let x: Int let y: Int var area: Int { return x*y } } ================================================ FILE: Templates/Tests/Context_Linux/AutoMockable.swift ================================================ // // AutoMockable.swift // Templates // // Created by Anton Domashnev on 17.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation public protocol AutoMockable {} protocol StubProtocol {} protocol StubWithAnyNameProtocol {} protocol StubWithSomeNameProtocol {} protocol PersonProtocol {} protocol BasicProtocol: AutoMockable { func loadConfiguration() -> String? /// Asks a Duck to quack /// /// - Parameter times: How many times the Duck will quack func save(configuration: String) } protocol ImplicitlyUnwrappedOptionalReturnValueProtocol: AutoMockable { func implicitReturn() -> String! } protocol InitializationProtocol: AutoMockable { init(intParameter: Int, stringParameter: String, optionalParameter: String?) func start() func stop() } protocol VariablesProtocol: AutoMockable { var company: String? { get set } var name: String { get } var age: Int { get } var kids: [String] { get } var universityMarks: [String: Int] { get } } protocol SameShortMethodNamesProtocol: AutoMockable { func start(car: String, of model: String) func start(plane: String, of model: String) } protocol ExtendableProtocol: AutoMockable { var canReport: Bool { get } func report(message: String) } protocol ReservedWordsProtocol: AutoMockable { func `continue`(with message: String) -> String } protocol ThrowableProtocol: AutoMockable { func doOrThrow() throws -> String func doOrThrowVoid() throws } protocol TypedThrowableProtocol: AutoMockable { init() throws(CustomError) init(init2: Void) throws(E) where E: Error var value: Int { get throws(CustomError) } var valueAnyError: Int { get throws(any Error) } var valueThrowsNever: Int { get throws(Never) } func doOrThrow() throws(CustomError) -> String // func doOrThrowVoid() throws(CustomErrorNameSpace.Error) func doOrThrowAnyError() throws(any Error) func doOrThrowNever() throws(Never) func doOrRethrows(_ block: () throws(E) -> Void) throws(E) -> Int where E: Error } struct CustomError: Error {} // This seems to not be supported on linux, as it cause a crash when running Sourcery // because of the cycle in Type (with Type and Typealias), causing a crash during NSArchive decoding // enum CustomErrorNameSpace { // struct Error: Swift.Error {} // } protocol CurrencyPresenter: AutoMockable { func showSourceCurrency(_ currency: String) } extension ExtendableProtocol { var canReport: Bool { return true } func report(message: String = "Test") { print(message) } } protocol ClosureProtocol: AutoMockable { func setClosure(_ closure: @escaping () -> Void) } protocol NullableClosureProtocol: AutoMockable { func setClosure(_ closure: (() -> Void)?) } protocol MultiClosureProtocol: AutoMockable { func setClosure(name: String, _ closure: @escaping () -> Void) } protocol MultiNullableClosureProtocol: AutoMockable { func setClosure(name: String, _ closure: (() -> Void)?) } protocol NonEscapingClosureProtocol: AutoMockable { func executeClosure(_ closure: () -> Void) } protocol MultiNonEscapingClosureProtocol: AutoMockable { func executeClosure(name: String, _ closure: () -> Void) } protocol MultiExistentialArgumentsClosureProtocol: AutoMockable { func execute(completion: ((any StubWithSomeNameProtocol)?, any StubWithSomeNameProtocol) -> (any StubWithSomeNameProtocol)?) } protocol ClosureWithTwoParametersProtocol: AutoMockable { func setClosure(closure: @escaping (String, Int) -> Void) } /// sourcery: AutoMockable protocol AnnotatedProtocol { func sayHelloWith(name: String) } protocol SingleOptionalParameterFunction: AutoMockable { func send(message: String?) } protocol FunctionWithClosureReturnType: AutoMockable { func get() -> () -> Void func getOptional() -> (() -> Void)? } protocol FunctionWithMultilineDeclaration: AutoMockable { func start(car: String, of model: String) } protocol ThrowingVariablesProtocol: AutoMockable { var title: String? { get throws } var firstName: String { get throws } } protocol AsyncVariablesProtocol: AutoMockable { var title: String? { get async } var firstName: String { get async } } protocol AsyncThrowingVariablesProtocol: AutoMockable { var title: String? { get async throws } var firstName: String { get async throws } } protocol AsyncProtocol: AutoMockable { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func callAsync(parameter: Int) async -> String func callAsyncAndThrow(parameter: Int) async throws -> String func callAsyncVoid(parameter: Int) async -> Void func callAsyncAndThrowVoid(parameter: Int) async throws -> Void } protocol FunctionWithAttributes: AutoMockable { @discardableResult func callOneAttribute() -> String @discardableResult @available(macOS 10.15, *) func callTwoAttributes() -> Int @discardableResult @available(iOS 13.0, *) @available(macOS 10.15, *) func callRepeatedAttributes() -> Bool } public protocol AccessLevelProtocol: AutoMockable { var company: String? { get set } var name: String { get } func loadConfiguration() -> String? } protocol StaticMethodProtocol: AutoMockable { static func staticFunction(_: String) -> String } protocol AnyProtocol: AutoMockable { var a: any StubProtocol { get } var b: (any StubProtocol)? { get } var c: (any StubProtocol)! { get } var d: (((any StubProtocol)?) -> Void) { get } var e: [(any StubProtocol)?] { get } func f(_ x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) var g: any StubProtocol { get } var h: (any StubProtocol)? { get } var i: (any StubProtocol)! { get } func j(x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) async -> String func k(x: ((any StubProtocol)?) -> Void, y: (any StubProtocol) -> Void) func l(x: (((any StubProtocol)?) -> Void), y: ((any StubProtocol) -> Void)) var anyConfusingPropertyName: any StubProtocol { get } func m(anyConfusingArgumentName: any StubProtocol) func n(x: @escaping ((any StubProtocol)?) -> Void) var o: any StubWithAnyNameProtocol { get } func p(_ x: (any StubWithAnyNameProtocol)?) func q() -> any StubProtocol func r() -> (any StubProtocol)? func s() -> () -> any StubProtocol func t() -> () -> (any StubProtocol)? func u() -> (Int, () -> (any StubProtocol)?) func v() -> (Int, (() -> any StubProtocol)?) func w() -> [(any StubProtocol)?] func x() -> [String: (any StubProtocol)?] func y() -> (any StubProtocol, (any StubProtocol)?) func z() -> any StubProtocol & CustomStringConvertible } protocol AnyProtocolWithOptionals: AutoMockable { var a: [any StubProtocol]? { get } var b: [Result] { get } var c: (Int, [(any StubProtocol)?])? { get } var d: (Int, (any StubProtocol)?) { get } var e: (Int, (any StubProtocol)?)? { get } var f: (Int, [any StubProtocol]?)? { get } func g(_ g: String, handler: @escaping ([any StubProtocol]?) -> Void) -> Bool func h(_ h: String, handler: @escaping ([StubProtocol]) -> Void) -> Bool func i(_ i: String, handler: @escaping ([(any StubProtocol)?]) -> Void) -> Bool var j: (anyInteger: Int, anyArray: [any StubProtocol]?)? { get } } protocol SomeProtocol: AutoMockable { func a(_ x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) func b(x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) async -> String func someConfusingFuncName(x: some StubProtocol) func c(someConfusingArgumentName: some StubProtocol) func d(_ x: (some StubWithSomeNameProtocol)?) } class GenericType{} protocol HouseProtocol: AutoMockable { var aPublisher: AnyPublisher? { get } var bPublisher: AnyPublisher<(any PersonProtocol)?, Never>? { get } var cPublisher: CurrentValueSubject<(any PersonProtocol)?, Never>? { get } var dPublisher: PassthroughSubject<(any PersonProtocol)?, Never>? { get } var e1Publisher: GenericType<(any PersonProtocol)?, Never, Never>? { get } var e2Publisher: GenericType? { get } var e3Publisher: GenericType? { get } var e4Publisher: GenericType<(any PersonProtocol)?, (any PersonProtocol)?, (any PersonProtocol)?>? { get } var f1Publisher: GenericType? { get } var f2Publisher: GenericType? { get } var f3Publisher: GenericType? { get } var f4Publisher: GenericType? { get } } protocol FunctionWithNullableCompletionThatHasNullableAnyParameterProtocol: AutoMockable { func add( _ request: Int, withCompletionHandler completionHandler: (((any Error)?) -> Void)? ) } // sourcery: AutoMockable protocol ExampleVararg { func string(key: String, args: CVarArg...) -> String } // sourcery: AutoMockable protocol ExampleVarargTwo { func toto(args: any StubWithSomeNameProtocol...) } // sourcery: AutoMockable protocol ExampleVarargThree { func toto(arg: ((String, any Collection...) -> any Collection)) } // sourcery: AutoMockable protocol ExampleVarargFour { func toto(arg: ((String, any Collection...) -> Void)) } // sourcery: AutoMockable public protocol ProtocolWithOverrides { func doSomething(_ data: Int) -> [String] func doSomething(_ data: String) -> [String] func doSomething(_ data: String) -> [Int] func doSomething(_ data: String) -> ([Int], [String]) func doSomething(_ data: String) throws -> ([Int], [Any]) func doSomething(_ data: String) -> (([Int], [String]) -> Void) func doSomething(_ data: String) throws -> (([Int], [Any]) -> Void) } // sourcery: AutoMockable protocol SubscriptProtocol { subscript(arg: Int) -> String { get set } subscript(arg: T) -> Int { get } subscript(arg: T) -> String { get async } subscript(arg: T) -> T? { get set } subscript(arg: String) -> T? where T: Cancellable { get throws } subscript(arg2: String) -> T { get throws(CustomError) } } // sourcery: AutoMockable public protocol ProtocolWithMethodWithGenericParameters { func execute(param: Result) -> Result } // sourcery: AutoMockable public protocol ProtocolWithMethodWithInoutParameter { func execute(param: inout String) func execute(param: inout String, bar: Int) } //sourcery:AutoMockable protocol TestProtocol { associatedtype Value: Sequence where Value.Element: Collection, Value.Element: Hashable, Value.Element: Comparable func getValue() -> Value associatedtype Value2 = Int func getValue2() -> Value2 associatedtype Value3: Collection where Value3.Element == String func getValue3() -> Value3 associatedtype Value5: Sequence where Value5.Element == Int func getValue5() -> Value5 associatedtype Value6: Sequence where Value6.Element == Int, Value6.Element: Hashable, Value6.Element: Comparable func getValue6() -> Value6 } // sourcery: AutoMockable protocol SendableProtocol: Sendable { var value: Any { get } } protocol NotMockedSendableProtocol: Sendable {} // sourcery: AutoMockable protocol SendableSendableProtocol: NotMockedSendableProtocol { var value: Any { get } } ================================================ FILE: Templates/Tests/Context_Linux/LinuxMain.swift ================================================ // // LinuxMain.swift // Templates // // Created by Anton Domashnev on 17.05.17. // Copyright © 2017 Pixle. All rights reserved. // import Foundation import XCTest class AutoInjectionTests: XCTestCase { func testThatItResolvesAutoInjectedDependencies() { XCTAssertTrue(true) } func testThatItDoesntResolveAutoInjectedDependencies() { XCTAssertTrue(true) } } class AutoWiringTests: XCTestCase { func testThatItCanResolveWithAutoWiring() { XCTAssertTrue(true) } func testThatItCanNotResolveWithAutoWiring() { XCTAssertTrue(true) } } // sourcery: disableTests class DisabledTests: XCTestCase { func testThatItResolvesDisabledTestsAnnotation() { XCTAssertTrue(true) } } ================================================ FILE: Templates/Tests/Expected/AutoCases.expected ================================================ internal extension AutoCasesEnum { static let count: Int = 4 static let allCases: [AutoCasesEnum] = [ .north, .south, .east, .west ] } public extension AutoCasesHasAssociatedValuesEnum { static let count: Int = 2 } internal extension AutoCasesOneValueEnum { static let count: Int = 1 static let allCases: [AutoCasesOneValueEnum] = [ .one ] } ================================================ FILE: Templates/Tests/Expected/AutoCodable.expected ================================================ // Generated using Sourcery 0.12.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT extension AssociatedValuesEnum { internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let enumCase = try container.decode(String.self, forKey: .enumCaseKey) switch enumCase { case CodingKeys.someCase.rawValue: let id = try container.decode(Int.self, forKey: .id) let name = try container.decode(String.self, forKey: .name) self = .someCase(id: id, name: name) case CodingKeys.unnamedCase.rawValue: // Enum cases with unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Can't decode '\(enumCase)'") case CodingKeys.mixCase.rawValue: // Enum cases with mixed named and unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Can't decode '\(enumCase)'") case CodingKeys.anotherCase.rawValue: self = .anotherCase default: throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Unknown enum case '\(enumCase)'") } } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case let .someCase(id, name): try container.encode(CodingKeys.someCase.rawValue, forKey: .enumCaseKey) try container.encode(id, forKey: .id) try container.encode(name, forKey: .name) case .unnamedCase: // Enum cases with unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) case .mixCase: // Enum cases with mixed named and unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) case .anotherCase: try container.encode(CodingKeys.anotherCase.rawValue, forKey: .enumCaseKey) } } } extension AssociatedValuesEnumNoCaseKey { enum CodingKeys: String, CodingKey { case someCase case unnamedCase case mixCase case anotherCase case id case name } internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.contains(.someCase), try container.decodeNil(forKey: .someCase) == false { let associatedValues = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .someCase) let id = try associatedValues.decode(Int.self, forKey: .id) let name = try associatedValues.decode(String.self, forKey: .name) self = .someCase(id: id, name: name) return } if container.allKeys.contains(.unnamedCase), try container.decodeNil(forKey: .unnamedCase) == false { var associatedValues = try container.nestedUnkeyedContainer(forKey: .unnamedCase) let associatedValue0 = try associatedValues.decode(Int.self) let associatedValue1 = try associatedValues.decode(String.self) self = .unnamedCase(associatedValue0, associatedValue1) return } if container.allKeys.contains(.mixCase), try container.decodeNil(forKey: .mixCase) == false { // Enum cases with mixed named and unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .mixCase, in: container, debugDescription: "Can't decode `.mixCase`") } if container.allKeys.contains(.anotherCase), try container.decodeNil(forKey: .anotherCase) == false { self = .anotherCase return } throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case")) } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case let .someCase(id, name): var associatedValues = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .someCase) try associatedValues.encode(id, forKey: .id) try associatedValues.encode(name, forKey: .name) case let .unnamedCase(associatedValue0, associatedValue1): var associatedValues = container.nestedUnkeyedContainer(forKey: .unnamedCase) try associatedValues.encode(associatedValue0) try associatedValues.encode(associatedValue1) case .mixCase: // Enum cases with mixed named and unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) case .anotherCase: _ = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .anotherCase) } } } extension CustomCodingWithNotAllDefinedKeys { internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) value = try container.decode(Int.self, forKey: .value) } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) encodeComputedValue(to: &container) } } extension CustomContainerCodable { public init(from decoder: Decoder) throws { let container = try CustomContainerCodable.decodingContainer(decoder) value = try container.decode(Int.self, forKey: .value) } public func encode(to encoder: Encoder) throws { var container = encodingContainer(encoder) try container.encode(value, forKey: .value) } } extension CustomMethodsCodable { enum CodingKeys: String, CodingKey { case boolValue case intValue case optionalString case requiredString case requiredStringWithDefault case computedPropertyToEncode } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) boolValue = try CustomMethodsCodable.decodeBoolValue(from: decoder) intValue = CustomMethodsCodable.decodeIntValue(from: container) ?? CustomMethodsCodable.defaultIntValue optionalString = try container.decodeIfPresent(String.self, forKey: .optionalString) requiredString = try container.decode(String.self, forKey: .requiredString) requiredStringWithDefault = (try? container.decode(String.self, forKey: .requiredStringWithDefault)) ?? CustomMethodsCodable.defaultRequiredStringWithDefault } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try encodeBoolValue(to: encoder) encodeIntValue(to: &container) try container.encodeIfPresent(optionalString, forKey: .optionalString) try container.encode(requiredString, forKey: .requiredString) try container.encode(requiredStringWithDefault, forKey: .requiredStringWithDefault) encodeComputedPropertyToEncode(to: &container) try encodeAdditionalValues(to: encoder) } } extension SimpleEnum { enum CodingKeys: String, CodingKey { case someCase case anotherCase } internal init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let enumCase = try container.decode(String.self) switch enumCase { case CodingKeys.someCase.rawValue: self = .someCase case CodingKeys.anotherCase.rawValue: self = .anotherCase default: throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case '\(enumCase)'")) } } internal func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .someCase: try container.encode(CodingKeys.someCase.rawValue) case .anotherCase: try container.encode(CodingKeys.anotherCase.rawValue) } } } extension SkipDecodingWithDefaultValueOrComputedProperty { internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) value = try container.decode(Int.self, forKey: .value) } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) try container.encode(computedValue, forKey: .computedValue) } } extension SkipEncodingKeys { enum CodingKeys: String, CodingKey { case value case skipValue } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } ================================================ FILE: Templates/Tests/Expected/AutoEquatable.expected ================================================ // swiftlint:disable file_length fileprivate func compareOptionals(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { switch (lhs, rhs) { case let (lValue?, rValue?): return compare(lValue, rValue) case (nil, nil): return true default: return false } } fileprivate func compareArrays(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { guard lhs.count == rhs.count else { return false } for (idx, lhsItem) in lhs.enumerated() { guard compare(lhsItem, rhs[idx]) else { return false } } return true } // MARK: - AutoEquatable for classes, protocols, structs // MARK: - AutoEquatableAnnotatedClass AutoEquatable extension AutoEquatableAnnotatedClass: Equatable {} internal func == (lhs: AutoEquatableAnnotatedClass, rhs: AutoEquatableAnnotatedClass) -> Bool { guard lhs.moneyInThePocket == rhs.moneyInThePocket else { return false } return true } // MARK: - AutoEquatableAnnotatedClassAnnotatedInherited AutoEquatable extension AutoEquatableAnnotatedClassAnnotatedInherited: Equatable {} THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable internal func == (lhs: AutoEquatableAnnotatedClassAnnotatedInherited, rhs: AutoEquatableAnnotatedClassAnnotatedInherited) -> Bool { guard lhs.middleName == rhs.middleName else { return false } return true } // MARK: - AutoEquatableClass AutoEquatable extension AutoEquatableClass: Equatable {} internal func == (lhs: AutoEquatableClass, rhs: AutoEquatableClass) -> Bool { guard lhs.firstName == rhs.firstName else { return false } guard lhs.lastName == rhs.lastName else { return false } guard compareArrays(lhs: lhs.parents, rhs: rhs.parents, compare: ==) else { return false } guard compareOptionals(lhs: lhs.age, rhs: rhs.age, compare: ==) else { return false } guard lhs.moneyInThePocket == rhs.moneyInThePocket else { return false } guard compareOptionals(lhs: lhs.friends, rhs: rhs.friends, compare: ==) else { return false } return true } // MARK: - AutoEquatableClassInherited AutoEquatable extension AutoEquatableClassInherited: Equatable {} THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable internal func == (lhs: AutoEquatableClassInherited, rhs: AutoEquatableClassInherited) -> Bool { guard compareOptionals(lhs: lhs.middleName, rhs: rhs.middleName, compare: ==) else { return false } return true } // MARK: - AutoEquatableNSObject AutoEquatable internal func == (lhs: AutoEquatableNSObject, rhs: AutoEquatableNSObject) -> Bool { guard lhs.firstName == rhs.firstName else { return false } return true } // MARK: - AutoEquatableProtocol AutoEquatable internal func == (lhs: any AutoEquatableProtocol, rhs: any AutoEquatableProtocol) -> Bool { guard lhs.width == rhs.width else { return false } guard lhs.height == rhs.height else { return false } guard lhs.name == rhs.name else { return false } return true } // MARK: - AutoEquatableStruct AutoEquatable extension AutoEquatableStruct: Equatable {} internal func == (lhs: AutoEquatableStruct, rhs: AutoEquatableStruct) -> Bool { guard lhs.firstName == rhs.firstName else { return false } guard lhs.lastName == rhs.lastName else { return false } guard compareArrays(lhs: lhs.parents, rhs: rhs.parents, compare: ==) else { return false } guard lhs.moneyInThePocket == rhs.moneyInThePocket else { return false } guard compareOptionals(lhs: lhs.friends, rhs: rhs.friends, compare: ==) else { return false } guard compareOptionals(lhs: lhs.age, rhs: rhs.age, compare: ==) else { return false } return true } // MARK: - AutoEquatable for Enums // MARK: - AutoEquatableEnum AutoEquatable extension AutoEquatableEnum: Equatable {} internal func == (lhs: AutoEquatableEnum, rhs: AutoEquatableEnum) -> Bool { switch (lhs, rhs) { case (.one, .one): return true case let (.two(lhsFirst, lhsSecond), .two(rhsFirst, rhsSecond)): if lhsFirst != rhsFirst { return false } if lhsSecond != rhsSecond { return false } return true case let (.three(lhs), .three(rhs)): return lhs == rhs default: return false } } // MARK: - AutoEquatableEnumWithOneCase AutoEquatable extension AutoEquatableEnumWithOneCase: Equatable {} internal func == (lhs: AutoEquatableEnumWithOneCase, rhs: AutoEquatableEnumWithOneCase) -> Bool { switch (lhs, rhs) { case (.one, .one): return true } } ================================================ FILE: Templates/Tests/Expected/AutoHashable.expected ================================================ // swiftlint:disable all // MARK: - AutoHashable for classes, protocols, structs // MARK: - AutoHashableClass AutoHashable extension AutoHashableClass: Hashable { internal func hash(into hasher: inout Hasher) { firstName.hash(into: &hasher) lastName.hash(into: &hasher) parents.hash(into: &hasher) universityGrades.hash(into: &hasher) moneyInThePocket.hash(into: &hasher) age.hash(into: &hasher) friends.hash(into: &hasher) } } // MARK: - AutoHashableClassFromNonHashableInherited AutoHashable extension AutoHashableClassFromNonHashableInherited: Hashable { internal func hash(into hasher: inout Hasher) { lastName.hash(into: &hasher) } } // MARK: - AutoHashableClassFromNonHashableInheritedInherited AutoHashable extension AutoHashableClassFromNonHashableInheritedInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) prefix.hash(into: &hasher) } } // MARK: - AutoHashableClassInherited AutoHashable extension AutoHashableClassInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) middleName.hash(into: &hasher) } } // MARK: - AutoHashableClassInheritedInherited AutoHashable extension AutoHashableClassInheritedInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) prefix.hash(into: &hasher) } } // MARK: - AutoHashableFromHashableInherited AutoHashable extension AutoHashableFromHashableInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) lastName.hash(into: &hasher) } } // MARK: - AutoHashableNSObject AutoHashable extension AutoHashableNSObject { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) firstName.hash(into: &hasher) } } // MARK: - AutoHashableNSObjectInherited AutoHashable extension AutoHashableNSObjectInherited { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) lastName.hash(into: &hasher) } } // MARK: - AutoHashableProtocol AutoHashable extension AutoHashableProtocol { internal func hash(into hasher: inout Hasher) { width.hash(into: &hasher) height.hash(into: &hasher) type(of: self).name.hash(into: &hasher) } } // MARK: - AutoHashableStruct AutoHashable extension AutoHashableStruct: Hashable { internal func hash(into hasher: inout Hasher) { firstName.hash(into: &hasher) lastName.hash(into: &hasher) parents.hash(into: &hasher) universityGrades.hash(into: &hasher) moneyInThePocket.hash(into: &hasher) age.hash(into: &hasher) friends.hash(into: &hasher) } } // MARK: - AutoHashable for Enums // MARK: - AutoHashableEnum AutoHashable extension AutoHashableEnum: Hashable { internal func hash(into hasher: inout Hasher) { switch self { case .one: 1.hash(into: &hasher) case let .two(first, second): 2.hash(into: &hasher) first.hash(into: &hasher) second.hash(into: &hasher) case let .three(data): 3.hash(into: &hasher) data.hash(into: &hasher) } } } ================================================ FILE: Templates/Tests/Expected/AutoLenses.expected ================================================ // swiftlint:disable variable_name infix operator *~: MultiplicationPrecedence infix operator |>: AdditionPrecedence struct Lens { let get: (Whole) -> Part let set: (Part, Whole) -> Whole } func * (lhs: Lens, rhs: Lens) -> Lens { return Lens( get: { a in rhs.get(lhs.get(a)) }, set: { (c, a) in lhs.set(rhs.set(c, lhs.get(a)), a) } ) } func *~ (lhs: Lens, rhs: B) -> (A) -> A { return { a in lhs.set(rhs, a) } } func |> (x: A, f: (A) -> B) -> B { return f(x) } func |> (f: @escaping (A) -> B, g: @escaping (B) -> C) -> (A) -> C { return { g(f($0)) } } extension House { static let roomsLens = Lens( get: { $0.rooms }, set: { rooms, house in House(rooms: rooms, address: house.address, size: house.size) } ) static let addressLens = Lens( get: { $0.address }, set: { address, house in House(rooms: house.rooms, address: address, size: house.size) } ) static let sizeLens = Lens( get: { $0.size }, set: { size, house in House(rooms: house.rooms, address: house.address, size: size) } ) } extension Person { static let nameLens = Lens( get: { $0.name }, set: { name, person in Person(name: name) } ) } extension Rectangle { static let xLens = Lens( get: { $0.x }, set: { x, rectangle in Rectangle(x: x, y: rectangle.y) } ) static let yLens = Lens( get: { $0.y }, set: { y, rectangle in Rectangle(x: rectangle.x, y: y) } ) } extension Room { static let peopleLens = Lens( get: { $0.people }, set: { people, room in Room(people: people, name: room.name) } ) static let nameLens = Lens( get: { $0.name }, set: { name, room in Room(people: room.people, name: name) } ) } ================================================ FILE: Templates/Tests/Expected/AutoMockable.expected ================================================ // Generated using Sourcery 2.2.7 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable line_length // swiftlint:disable variable_name import Foundation #if os(iOS) || os(tvOS) || os(watchOS) import UIKit #elseif os(OSX) import AppKit #endif public class AccessLevelProtocolMock: AccessLevelProtocol { public init() {} public var company: String? public var name: String { get { return underlyingName } set(value) { underlyingName = value } } public var underlyingName: (String)! //MARK: - loadConfiguration public var loadConfigurationStringCallsCount = 0 public var loadConfigurationStringCalled: Bool { return loadConfigurationStringCallsCount > 0 } public var loadConfigurationStringReturnValue: String? public var loadConfigurationStringClosure: (() -> String?)? public func loadConfiguration() -> String? { loadConfigurationStringCallsCount += 1 if let loadConfigurationStringClosure = loadConfigurationStringClosure { return loadConfigurationStringClosure() } else { return loadConfigurationStringReturnValue } } } class AnnotatedProtocolMock: AnnotatedProtocol { //MARK: - sayHelloWith var sayHelloWithNameStringVoidCallsCount = 0 var sayHelloWithNameStringVoidCalled: Bool { return sayHelloWithNameStringVoidCallsCount > 0 } var sayHelloWithNameStringVoidReceivedName: (String)? var sayHelloWithNameStringVoidReceivedInvocations: [(String)] = [] var sayHelloWithNameStringVoidClosure: ((String) -> Void)? func sayHelloWith(name: String) { sayHelloWithNameStringVoidCallsCount += 1 sayHelloWithNameStringVoidReceivedName = name sayHelloWithNameStringVoidReceivedInvocations.append(name) sayHelloWithNameStringVoidClosure?(name) } } class AnyProtocolMock: AnyProtocol { var a: any StubProtocol { get { return underlyingA } set(value) { underlyingA = value } } var underlyingA: (any StubProtocol)! var b: (any StubProtocol)? var c: (any StubProtocol)! var d: (((any StubProtocol)?) -> Void) { get { return underlyingD } set(value) { underlyingD = value } } var underlyingD: ((((any StubProtocol)?) -> Void))! var e: [(any StubProtocol)?] = [] var g: any StubProtocol { get { return underlyingG } set(value) { underlyingG = value } } var underlyingG: (any StubProtocol)! var h: (any StubProtocol)? var i: (any StubProtocol)! var anyConfusingPropertyName: any StubProtocol { get { return underlyingAnyConfusingPropertyName } set(value) { underlyingAnyConfusingPropertyName = value } } var underlyingAnyConfusingPropertyName: (any StubProtocol)! var o: any StubWithAnyNameProtocol { get { return underlyingO } set(value) { underlyingO = value } } var underlyingO: (any StubWithAnyNameProtocol)! //MARK: - f var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCallsCount = 0 var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCalled: Bool { return fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCallsCount > 0 } var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) -> Void)? func f(_ x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) { fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCallsCount += 1 fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedArguments = (x: x, y: y, z: z) fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedInvocations.append((x: x, y: y, z: z)) fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidClosure?(x, y, z) } //MARK: - j var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCallsCount = 0 var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCalled: Bool { return jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCallsCount > 0 } var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReturnValue: String! var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) async -> String)? func j(x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) async -> String { jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCallsCount += 1 jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedArguments = (x: x, y: y, z: z) jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedInvocations.append((x: x, y: y, z: z)) if let jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure = jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure { return await jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure(x, y, z) } else { return jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReturnValue } } //MARK: - k var kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount = 0 var kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCalled: Bool { return kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount > 0 } var kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure: ((((any StubProtocol)?) -> Void, (any StubProtocol) -> Void) -> Void)? func k(x: ((any StubProtocol)?) -> Void, y: (any StubProtocol) -> Void) { kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount += 1 kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure?(x, y) } //MARK: - l var lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount = 0 var lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCalled: Bool { return lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount > 0 } var lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure: ((((any StubProtocol)?) -> Void, (any StubProtocol) -> Void) -> Void)? func l(x: ((any StubProtocol)?) -> Void, y: (any StubProtocol) -> Void) { lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount += 1 lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure?(x, y) } //MARK: - m var mAnyConfusingArgumentNameAnyStubProtocolVoidCallsCount = 0 var mAnyConfusingArgumentNameAnyStubProtocolVoidCalled: Bool { return mAnyConfusingArgumentNameAnyStubProtocolVoidCallsCount > 0 } var mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedAnyConfusingArgumentName: (any StubProtocol)? var mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedInvocations: [(any StubProtocol)] = [] var mAnyConfusingArgumentNameAnyStubProtocolVoidClosure: ((any StubProtocol) -> Void)? func m(anyConfusingArgumentName: any StubProtocol) { mAnyConfusingArgumentNameAnyStubProtocolVoidCallsCount += 1 mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedAnyConfusingArgumentName = anyConfusingArgumentName mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedInvocations.append(anyConfusingArgumentName) mAnyConfusingArgumentNameAnyStubProtocolVoidClosure?(anyConfusingArgumentName) } //MARK: - n var nXEscapingAnyStubProtocolVoidVoidCallsCount = 0 var nXEscapingAnyStubProtocolVoidVoidCalled: Bool { return nXEscapingAnyStubProtocolVoidVoidCallsCount > 0 } var nXEscapingAnyStubProtocolVoidVoidReceivedX: ((((any StubProtocol)?) -> Void))? var nXEscapingAnyStubProtocolVoidVoidReceivedInvocations: [((((any StubProtocol)?) -> Void))] = [] var nXEscapingAnyStubProtocolVoidVoidClosure: ((@escaping ((any StubProtocol)?) -> Void) -> Void)? func n(x: @escaping ((any StubProtocol)?) -> Void) { nXEscapingAnyStubProtocolVoidVoidCallsCount += 1 nXEscapingAnyStubProtocolVoidVoidReceivedX = x nXEscapingAnyStubProtocolVoidVoidReceivedInvocations.append(x) nXEscapingAnyStubProtocolVoidVoidClosure?(x) } //MARK: - p var pXAnyStubWithAnyNameProtocolVoidCallsCount = 0 var pXAnyStubWithAnyNameProtocolVoidCalled: Bool { return pXAnyStubWithAnyNameProtocolVoidCallsCount > 0 } var pXAnyStubWithAnyNameProtocolVoidReceivedX: (any StubWithAnyNameProtocol)? var pXAnyStubWithAnyNameProtocolVoidReceivedInvocations: [(any StubWithAnyNameProtocol)?] = [] var pXAnyStubWithAnyNameProtocolVoidClosure: (((any StubWithAnyNameProtocol)?) -> Void)? func p(_ x: (any StubWithAnyNameProtocol)?) { pXAnyStubWithAnyNameProtocolVoidCallsCount += 1 pXAnyStubWithAnyNameProtocolVoidReceivedX = x pXAnyStubWithAnyNameProtocolVoidReceivedInvocations.append(x) pXAnyStubWithAnyNameProtocolVoidClosure?(x) } //MARK: - q var qAnyStubProtocolCallsCount = 0 var qAnyStubProtocolCalled: Bool { return qAnyStubProtocolCallsCount > 0 } var qAnyStubProtocolReturnValue: (any StubProtocol)! var qAnyStubProtocolClosure: (() -> any StubProtocol)? func q() -> any StubProtocol { qAnyStubProtocolCallsCount += 1 if let qAnyStubProtocolClosure = qAnyStubProtocolClosure { return qAnyStubProtocolClosure() } else { return qAnyStubProtocolReturnValue } } //MARK: - r var rAnyStubProtocolCallsCount = 0 var rAnyStubProtocolCalled: Bool { return rAnyStubProtocolCallsCount > 0 } var rAnyStubProtocolReturnValue: ((any StubProtocol)?) var rAnyStubProtocolClosure: (() -> (any StubProtocol)?)? func r() -> (any StubProtocol)? { rAnyStubProtocolCallsCount += 1 if let rAnyStubProtocolClosure = rAnyStubProtocolClosure { return rAnyStubProtocolClosure() } else { return rAnyStubProtocolReturnValue } } //MARK: - s var s____AnyStubProtocolCallsCount = 0 var s____AnyStubProtocolCalled: Bool { return s____AnyStubProtocolCallsCount > 0 } var s____AnyStubProtocolReturnValue: ((() -> any StubProtocol))! var s____AnyStubProtocolClosure: (() -> (() -> any StubProtocol))? func s() -> (() -> any StubProtocol) { s____AnyStubProtocolCallsCount += 1 if let s____AnyStubProtocolClosure = s____AnyStubProtocolClosure { return s____AnyStubProtocolClosure() } else { return s____AnyStubProtocolReturnValue } } //MARK: - t var t____AnyStubProtocolCallsCount = 0 var t____AnyStubProtocolCalled: Bool { return t____AnyStubProtocolCallsCount > 0 } var t____AnyStubProtocolReturnValue: ((() -> (any StubProtocol)?))! var t____AnyStubProtocolClosure: (() -> (() -> (any StubProtocol)?))? func t() -> (() -> (any StubProtocol)?) { t____AnyStubProtocolCallsCount += 1 if let t____AnyStubProtocolClosure = t____AnyStubProtocolClosure { return t____AnyStubProtocolClosure() } else { return t____AnyStubProtocolReturnValue } } //MARK: - u var u_IntAnyStubProtocolCallsCount = 0 var u_IntAnyStubProtocolCalled: Bool { return u_IntAnyStubProtocolCallsCount > 0 } var u_IntAnyStubProtocolReturnValue: ((Int, () -> (any StubProtocol)?))! var u_IntAnyStubProtocolClosure: (() -> (Int, () -> (any StubProtocol)?))? func u() -> (Int, () -> (any StubProtocol)?) { u_IntAnyStubProtocolCallsCount += 1 if let u_IntAnyStubProtocolClosure = u_IntAnyStubProtocolClosure { return u_IntAnyStubProtocolClosure() } else { return u_IntAnyStubProtocolReturnValue } } //MARK: - v var v_IntAnyStubProtocolCallsCount = 0 var v_IntAnyStubProtocolCalled: Bool { return v_IntAnyStubProtocolCallsCount > 0 } var v_IntAnyStubProtocolReturnValue: ((Int, (() -> any StubProtocol)?))! var v_IntAnyStubProtocolClosure: (() -> (Int, (() -> any StubProtocol)?))? func v() -> (Int, (() -> any StubProtocol)?) { v_IntAnyStubProtocolCallsCount += 1 if let v_IntAnyStubProtocolClosure = v_IntAnyStubProtocolClosure { return v_IntAnyStubProtocolClosure() } else { return v_IntAnyStubProtocolReturnValue } } //MARK: - w var w_AnyStubProtocolCallsCount = 0 var w_AnyStubProtocolCalled: Bool { return w_AnyStubProtocolCallsCount > 0 } var w_AnyStubProtocolReturnValue: ([(any StubProtocol)?])! var w_AnyStubProtocolClosure: (() -> [(any StubProtocol)?])? func w() -> [(any StubProtocol)?] { w_AnyStubProtocolCallsCount += 1 if let w_AnyStubProtocolClosure = w_AnyStubProtocolClosure { return w_AnyStubProtocolClosure() } else { return w_AnyStubProtocolReturnValue } } //MARK: - x var xStringAnyStubProtocolCallsCount = 0 var xStringAnyStubProtocolCalled: Bool { return xStringAnyStubProtocolCallsCount > 0 } var xStringAnyStubProtocolReturnValue: ([String: (any StubProtocol)?])! var xStringAnyStubProtocolClosure: (() -> [String: (any StubProtocol)?])? func x() -> [String: (any StubProtocol)?] { xStringAnyStubProtocolCallsCount += 1 if let xStringAnyStubProtocolClosure = xStringAnyStubProtocolClosure { return xStringAnyStubProtocolClosure() } else { return xStringAnyStubProtocolReturnValue } } //MARK: - y var y_AnyStubProtocolAnyStubProtocolCallsCount = 0 var y_AnyStubProtocolAnyStubProtocolCalled: Bool { return y_AnyStubProtocolAnyStubProtocolCallsCount > 0 } var y_AnyStubProtocolAnyStubProtocolReturnValue: ((any StubProtocol, (any StubProtocol)?))! var y_AnyStubProtocolAnyStubProtocolClosure: (() -> (any StubProtocol, (any StubProtocol)?))? func y() -> (any StubProtocol, (any StubProtocol)?) { y_AnyStubProtocolAnyStubProtocolCallsCount += 1 if let y_AnyStubProtocolAnyStubProtocolClosure = y_AnyStubProtocolAnyStubProtocolClosure { return y_AnyStubProtocolAnyStubProtocolClosure() } else { return y_AnyStubProtocolAnyStubProtocolReturnValue } } //MARK: - z var zAnyStubProtocolCustomStringConvertibleCallsCount = 0 var zAnyStubProtocolCustomStringConvertibleCalled: Bool { return zAnyStubProtocolCustomStringConvertibleCallsCount > 0 } var zAnyStubProtocolCustomStringConvertibleReturnValue: (any StubProtocol & CustomStringConvertible)! var zAnyStubProtocolCustomStringConvertibleClosure: (() -> any StubProtocol & CustomStringConvertible)? func z() -> any StubProtocol & CustomStringConvertible { zAnyStubProtocolCustomStringConvertibleCallsCount += 1 if let zAnyStubProtocolCustomStringConvertibleClosure = zAnyStubProtocolCustomStringConvertibleClosure { return zAnyStubProtocolCustomStringConvertibleClosure() } else { return zAnyStubProtocolCustomStringConvertibleReturnValue } } } class AnyProtocolWithOptionalsMock: AnyProtocolWithOptionals { var a: [any StubProtocol]? var b: [Result] = [] var c: (Int, [(any StubProtocol)?])? var d: (Int, (any StubProtocol)?) { get { return underlyingD } set(value) { underlyingD = value } } var underlyingD: ((Int, (any StubProtocol)?))! var e: (Int, (any StubProtocol)?)? var f: (Int, [any StubProtocol]?)? var j: (anyInteger: Int, anyArray: [any StubProtocol]?)? //MARK: - g var gGStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount = 0 var gGStringHandlerEscapingAnyStubProtocolVoidBoolCalled: Bool { return gGStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount > 0 } var gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments: (g: String, handler: ([any StubProtocol]?) -> Void)? var gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations: [(g: String, handler: ([any StubProtocol]?) -> Void)] = [] var gGStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue: Bool! var gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure: ((String, @escaping ([any StubProtocol]?) -> Void) -> Bool)? func g(_ g: String, handler: @escaping ([any StubProtocol]?) -> Void) -> Bool { gGStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount += 1 gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments = (g: g, handler: handler) gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations.append((g: g, handler: handler)) if let gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure = gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure { return gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure(g, handler) } else { return gGStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue } } //MARK: - h var hHStringHandlerEscapingStubProtocolVoidBoolCallsCount = 0 var hHStringHandlerEscapingStubProtocolVoidBoolCalled: Bool { return hHStringHandlerEscapingStubProtocolVoidBoolCallsCount > 0 } var hHStringHandlerEscapingStubProtocolVoidBoolReceivedArguments: (h: String, handler: ([StubProtocol]) -> Void)? var hHStringHandlerEscapingStubProtocolVoidBoolReceivedInvocations: [(h: String, handler: ([StubProtocol]) -> Void)] = [] var hHStringHandlerEscapingStubProtocolVoidBoolReturnValue: Bool! var hHStringHandlerEscapingStubProtocolVoidBoolClosure: ((String, @escaping ([StubProtocol]) -> Void) -> Bool)? func h(_ h: String, handler: @escaping ([StubProtocol]) -> Void) -> Bool { hHStringHandlerEscapingStubProtocolVoidBoolCallsCount += 1 hHStringHandlerEscapingStubProtocolVoidBoolReceivedArguments = (h: h, handler: handler) hHStringHandlerEscapingStubProtocolVoidBoolReceivedInvocations.append((h: h, handler: handler)) if let hHStringHandlerEscapingStubProtocolVoidBoolClosure = hHStringHandlerEscapingStubProtocolVoidBoolClosure { return hHStringHandlerEscapingStubProtocolVoidBoolClosure(h, handler) } else { return hHStringHandlerEscapingStubProtocolVoidBoolReturnValue } } //MARK: - i var iIStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount = 0 var iIStringHandlerEscapingAnyStubProtocolVoidBoolCalled: Bool { return iIStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount > 0 } var iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments: (i: String, handler: ([(any StubProtocol)?]) -> Void)? var iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations: [(i: String, handler: ([(any StubProtocol)?]) -> Void)] = [] var iIStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue: Bool! var iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure: ((String, @escaping ([(any StubProtocol)?]) -> Void) -> Bool)? func i(_ i: String, handler: @escaping ([(any StubProtocol)?]) -> Void) -> Bool { iIStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount += 1 iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments = (i: i, handler: handler) iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations.append((i: i, handler: handler)) if let iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure = iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure { return iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure(i, handler) } else { return iIStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue } } } class AsyncProtocolMock: AsyncProtocol { //MARK: - callAsync var callAsyncParameterIntStringCallsCount = 0 var callAsyncParameterIntStringCalled: Bool { return callAsyncParameterIntStringCallsCount > 0 } var callAsyncParameterIntStringReceivedParameter: (Int)? var callAsyncParameterIntStringReceivedInvocations: [(Int)] = [] var callAsyncParameterIntStringReturnValue: String! var callAsyncParameterIntStringClosure: ((Int) async -> String)? @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func callAsync(parameter: Int) async -> String { callAsyncParameterIntStringCallsCount += 1 callAsyncParameterIntStringReceivedParameter = parameter callAsyncParameterIntStringReceivedInvocations.append(parameter) if let callAsyncParameterIntStringClosure = callAsyncParameterIntStringClosure { return await callAsyncParameterIntStringClosure(parameter) } else { return callAsyncParameterIntStringReturnValue } } //MARK: - callAsyncAndThrow var callAsyncAndThrowParameterIntStringThrowableError: (any Error)? var callAsyncAndThrowParameterIntStringCallsCount = 0 var callAsyncAndThrowParameterIntStringCalled: Bool { return callAsyncAndThrowParameterIntStringCallsCount > 0 } var callAsyncAndThrowParameterIntStringReceivedParameter: (Int)? var callAsyncAndThrowParameterIntStringReceivedInvocations: [(Int)] = [] var callAsyncAndThrowParameterIntStringReturnValue: String! var callAsyncAndThrowParameterIntStringClosure: ((Int) async throws -> String)? func callAsyncAndThrow(parameter: Int) async throws -> String { callAsyncAndThrowParameterIntStringCallsCount += 1 callAsyncAndThrowParameterIntStringReceivedParameter = parameter callAsyncAndThrowParameterIntStringReceivedInvocations.append(parameter) if let error = callAsyncAndThrowParameterIntStringThrowableError { throw error } if let callAsyncAndThrowParameterIntStringClosure = callAsyncAndThrowParameterIntStringClosure { return try await callAsyncAndThrowParameterIntStringClosure(parameter) } else { return callAsyncAndThrowParameterIntStringReturnValue } } //MARK: - callAsyncVoid var callAsyncVoidParameterIntVoidCallsCount = 0 var callAsyncVoidParameterIntVoidCalled: Bool { return callAsyncVoidParameterIntVoidCallsCount > 0 } var callAsyncVoidParameterIntVoidReceivedParameter: (Int)? var callAsyncVoidParameterIntVoidReceivedInvocations: [(Int)] = [] var callAsyncVoidParameterIntVoidClosure: ((Int) async -> Void)? func callAsyncVoid(parameter: Int) async { callAsyncVoidParameterIntVoidCallsCount += 1 callAsyncVoidParameterIntVoidReceivedParameter = parameter callAsyncVoidParameterIntVoidReceivedInvocations.append(parameter) await callAsyncVoidParameterIntVoidClosure?(parameter) } //MARK: - callAsyncAndThrowVoid var callAsyncAndThrowVoidParameterIntVoidThrowableError: (any Error)? var callAsyncAndThrowVoidParameterIntVoidCallsCount = 0 var callAsyncAndThrowVoidParameterIntVoidCalled: Bool { return callAsyncAndThrowVoidParameterIntVoidCallsCount > 0 } var callAsyncAndThrowVoidParameterIntVoidReceivedParameter: (Int)? var callAsyncAndThrowVoidParameterIntVoidReceivedInvocations: [(Int)] = [] var callAsyncAndThrowVoidParameterIntVoidClosure: ((Int) async throws -> Void)? func callAsyncAndThrowVoid(parameter: Int) async throws { callAsyncAndThrowVoidParameterIntVoidCallsCount += 1 callAsyncAndThrowVoidParameterIntVoidReceivedParameter = parameter callAsyncAndThrowVoidParameterIntVoidReceivedInvocations.append(parameter) if let error = callAsyncAndThrowVoidParameterIntVoidThrowableError { throw error } try await callAsyncAndThrowVoidParameterIntVoidClosure?(parameter) } } class AsyncThrowingVariablesProtocolMock: AsyncThrowingVariablesProtocol { var titleCallsCount = 0 var titleCalled: Bool { return titleCallsCount > 0 } var title: String? { get async throws { titleCallsCount += 1 if let error = titleThrowableError { throw error } if let titleClosure = titleClosure { return try await titleClosure() } else { return underlyingTitle } } } var underlyingTitle: String? var titleThrowableError: Error? var titleClosure: (() async throws -> String?)? var firstNameCallsCount = 0 var firstNameCalled: Bool { return firstNameCallsCount > 0 } var firstName: String { get async throws { firstNameCallsCount += 1 if let error = firstNameThrowableError { throw error } if let firstNameClosure = firstNameClosure { return try await firstNameClosure() } else { return underlyingFirstName } } } var underlyingFirstName: String! var firstNameThrowableError: Error? var firstNameClosure: (() async throws -> String)? } class AsyncVariablesProtocolMock: AsyncVariablesProtocol { var titleCallsCount = 0 var titleCalled: Bool { return titleCallsCount > 0 } var title: String? { get async { titleCallsCount += 1 if let titleClosure = titleClosure { return await titleClosure() } else { return underlyingTitle } } } var underlyingTitle: String? var titleClosure: (() async -> String?)? var firstNameCallsCount = 0 var firstNameCalled: Bool { return firstNameCallsCount > 0 } var firstName: String { get async { firstNameCallsCount += 1 if let firstNameClosure = firstNameClosure { return await firstNameClosure() } else { return underlyingFirstName } } } var underlyingFirstName: String! var firstNameClosure: (() async -> String)? } class BasicProtocolMock: BasicProtocol { //MARK: - loadConfiguration var loadConfigurationStringCallsCount = 0 var loadConfigurationStringCalled: Bool { return loadConfigurationStringCallsCount > 0 } var loadConfigurationStringReturnValue: String? var loadConfigurationStringClosure: (() -> String?)? func loadConfiguration() -> String? { loadConfigurationStringCallsCount += 1 if let loadConfigurationStringClosure = loadConfigurationStringClosure { return loadConfigurationStringClosure() } else { return loadConfigurationStringReturnValue } } //MARK: - save var saveConfigurationStringVoidCallsCount = 0 var saveConfigurationStringVoidCalled: Bool { return saveConfigurationStringVoidCallsCount > 0 } var saveConfigurationStringVoidReceivedConfiguration: (String)? var saveConfigurationStringVoidReceivedInvocations: [(String)] = [] var saveConfigurationStringVoidClosure: ((String) -> Void)? func save(configuration: String) { saveConfigurationStringVoidCallsCount += 1 saveConfigurationStringVoidReceivedConfiguration = configuration saveConfigurationStringVoidReceivedInvocations.append(configuration) saveConfigurationStringVoidClosure?(configuration) } } class ClosureProtocolMock: ClosureProtocol { //MARK: - setClosure var setClosureClosureEscapingVoidVoidCallsCount = 0 var setClosureClosureEscapingVoidVoidCalled: Bool { return setClosureClosureEscapingVoidVoidCallsCount > 0 } var setClosureClosureEscapingVoidVoidReceivedClosure: ((() -> Void))? var setClosureClosureEscapingVoidVoidReceivedInvocations: [((() -> Void))] = [] var setClosureClosureEscapingVoidVoidClosure: ((@escaping () -> Void) -> Void)? func setClosure(_ closure: @escaping () -> Void) { setClosureClosureEscapingVoidVoidCallsCount += 1 setClosureClosureEscapingVoidVoidReceivedClosure = closure setClosureClosureEscapingVoidVoidReceivedInvocations.append(closure) setClosureClosureEscapingVoidVoidClosure?(closure) } } class ClosureWithTwoParametersProtocolMock: ClosureWithTwoParametersProtocol { //MARK: - setClosure var setClosureClosureEscapingStringIntVoidVoidCallsCount = 0 var setClosureClosureEscapingStringIntVoidVoidCalled: Bool { return setClosureClosureEscapingStringIntVoidVoidCallsCount > 0 } var setClosureClosureEscapingStringIntVoidVoidReceivedClosure: (((String, Int) -> Void))? var setClosureClosureEscapingStringIntVoidVoidReceivedInvocations: [(((String, Int) -> Void))] = [] var setClosureClosureEscapingStringIntVoidVoidClosure: ((@escaping (String, Int) -> Void) -> Void)? func setClosure(closure: (@escaping (String, Int) -> Void)) { setClosureClosureEscapingStringIntVoidVoidCallsCount += 1 setClosureClosureEscapingStringIntVoidVoidReceivedClosure = closure setClosureClosureEscapingStringIntVoidVoidReceivedInvocations.append(closure) setClosureClosureEscapingStringIntVoidVoidClosure?(closure) } } class CurrencyPresenterMock: CurrencyPresenter { //MARK: - showSourceCurrency var showSourceCurrencyCurrencyStringVoidCallsCount = 0 var showSourceCurrencyCurrencyStringVoidCalled: Bool { return showSourceCurrencyCurrencyStringVoidCallsCount > 0 } var showSourceCurrencyCurrencyStringVoidReceivedCurrency: (String)? var showSourceCurrencyCurrencyStringVoidReceivedInvocations: [(String)] = [] var showSourceCurrencyCurrencyStringVoidClosure: ((String) -> Void)? func showSourceCurrency(_ currency: String) { showSourceCurrencyCurrencyStringVoidCallsCount += 1 showSourceCurrencyCurrencyStringVoidReceivedCurrency = currency showSourceCurrencyCurrencyStringVoidReceivedInvocations.append(currency) showSourceCurrencyCurrencyStringVoidClosure?(currency) } } class ExampleVarargMock: ExampleVararg { //MARK: - string var stringKeyStringArgsCVarArgStringCallsCount = 0 var stringKeyStringArgsCVarArgStringCalled: Bool { return stringKeyStringArgsCVarArgStringCallsCount > 0 } var stringKeyStringArgsCVarArgStringReceivedArguments: (key: String, args: [CVarArg])? var stringKeyStringArgsCVarArgStringReceivedInvocations: [(key: String, args: [CVarArg])] = [] var stringKeyStringArgsCVarArgStringReturnValue: String! var stringKeyStringArgsCVarArgStringClosure: ((String, CVarArg...) -> String)? func string(key: String, args: CVarArg...) -> String { stringKeyStringArgsCVarArgStringCallsCount += 1 stringKeyStringArgsCVarArgStringReceivedArguments = (key: key, args: args) stringKeyStringArgsCVarArgStringReceivedInvocations.append((key: key, args: args)) if let stringKeyStringArgsCVarArgStringClosure = stringKeyStringArgsCVarArgStringClosure { return stringKeyStringArgsCVarArgStringClosure(key, args) } else { return stringKeyStringArgsCVarArgStringReturnValue } } } class ExampleVarargFourMock: ExampleVarargFour { //MARK: - toto var totoArgStringAnyCollectionVoidVoidCallsCount = 0 var totoArgStringAnyCollectionVoidVoidCalled: Bool { return totoArgStringAnyCollectionVoidVoidCallsCount > 0 } var totoArgStringAnyCollectionVoidVoidClosure: (((String, any Collection...) -> Void) -> Void)? func toto(arg: ((String, any Collection...) -> Void)) { totoArgStringAnyCollectionVoidVoidCallsCount += 1 totoArgStringAnyCollectionVoidVoidClosure?(arg) } } class ExampleVarargThreeMock: ExampleVarargThree { //MARK: - toto var totoArgStringAnyCollectionAnyCollectionVoidCallsCount = 0 var totoArgStringAnyCollectionAnyCollectionVoidCalled: Bool { return totoArgStringAnyCollectionAnyCollectionVoidCallsCount > 0 } var totoArgStringAnyCollectionAnyCollectionVoidClosure: (((String, any Collection...) -> any Collection) -> Void)? func toto(arg: ((String, any Collection...) -> any Collection)) { totoArgStringAnyCollectionAnyCollectionVoidCallsCount += 1 totoArgStringAnyCollectionAnyCollectionVoidClosure?(arg) } } class ExampleVarargTwoMock: ExampleVarargTwo { //MARK: - toto var totoArgsAnyStubWithSomeNameProtocolVoidCallsCount = 0 var totoArgsAnyStubWithSomeNameProtocolVoidCalled: Bool { return totoArgsAnyStubWithSomeNameProtocolVoidCallsCount > 0 } var totoArgsAnyStubWithSomeNameProtocolVoidReceivedArgs: ([(any StubWithSomeNameProtocol)])? var totoArgsAnyStubWithSomeNameProtocolVoidReceivedInvocations: [([(any StubWithSomeNameProtocol)])] = [] var totoArgsAnyStubWithSomeNameProtocolVoidClosure: (([(any StubWithSomeNameProtocol)]) -> Void)? func toto(args: any StubWithSomeNameProtocol...) { totoArgsAnyStubWithSomeNameProtocolVoidCallsCount += 1 totoArgsAnyStubWithSomeNameProtocolVoidReceivedArgs = args totoArgsAnyStubWithSomeNameProtocolVoidReceivedInvocations.append(args) totoArgsAnyStubWithSomeNameProtocolVoidClosure?(args) } } class ExtendableProtocolMock: ExtendableProtocol { var canReport: Bool { get { return underlyingCanReport } set(value) { underlyingCanReport = value } } var underlyingCanReport: (Bool)! //MARK: - report var reportMessageStringVoidCallsCount = 0 var reportMessageStringVoidCalled: Bool { return reportMessageStringVoidCallsCount > 0 } var reportMessageStringVoidReceivedMessage: (String)? var reportMessageStringVoidReceivedInvocations: [(String)] = [] var reportMessageStringVoidClosure: ((String) -> Void)? func report(message: String) { reportMessageStringVoidCallsCount += 1 reportMessageStringVoidReceivedMessage = message reportMessageStringVoidReceivedInvocations.append(message) reportMessageStringVoidClosure?(message) } } class FunctionWithAttributesMock: FunctionWithAttributes { //MARK: - callOneAttribute var callOneAttributeStringCallsCount = 0 var callOneAttributeStringCalled: Bool { return callOneAttributeStringCallsCount > 0 } var callOneAttributeStringReturnValue: String! var callOneAttributeStringClosure: (() -> String)? @discardableResult func callOneAttribute() -> String { callOneAttributeStringCallsCount += 1 if let callOneAttributeStringClosure = callOneAttributeStringClosure { return callOneAttributeStringClosure() } else { return callOneAttributeStringReturnValue } } //MARK: - callTwoAttributes var callTwoAttributesIntCallsCount = 0 var callTwoAttributesIntCalled: Bool { return callTwoAttributesIntCallsCount > 0 } var callTwoAttributesIntReturnValue: Int! var callTwoAttributesIntClosure: (() -> Int)? @available(macOS 10.15, *) @discardableResult func callTwoAttributes() -> Int { callTwoAttributesIntCallsCount += 1 if let callTwoAttributesIntClosure = callTwoAttributesIntClosure { return callTwoAttributesIntClosure() } else { return callTwoAttributesIntReturnValue } } //MARK: - callRepeatedAttributes var callRepeatedAttributesBoolCallsCount = 0 var callRepeatedAttributesBoolCalled: Bool { return callRepeatedAttributesBoolCallsCount > 0 } var callRepeatedAttributesBoolReturnValue: Bool! var callRepeatedAttributesBoolClosure: (() -> Bool)? @available(iOS 13.0, *) @available(macOS 10.15, *) @discardableResult func callRepeatedAttributes() -> Bool { callRepeatedAttributesBoolCallsCount += 1 if let callRepeatedAttributesBoolClosure = callRepeatedAttributesBoolClosure { return callRepeatedAttributesBoolClosure() } else { return callRepeatedAttributesBoolReturnValue } } } class FunctionWithClosureReturnTypeMock: FunctionWithClosureReturnType { //MARK: - get var get____VoidCallsCount = 0 var get____VoidCalled: Bool { return get____VoidCallsCount > 0 } var get____VoidReturnValue: ((() -> Void))! var get____VoidClosure: (() -> (() -> Void))? func get() -> (() -> Void) { get____VoidCallsCount += 1 if let get____VoidClosure = get____VoidClosure { return get____VoidClosure() } else { return get____VoidReturnValue } } //MARK: - getOptional var getOptional_____VoidCallsCount = 0 var getOptional_____VoidCalled: Bool { return getOptional_____VoidCallsCount > 0 } var getOptional_____VoidReturnValue: ((() -> Void)?) var getOptional_____VoidClosure: (() -> ((() -> Void)?))? func getOptional() -> ((() -> Void)?) { getOptional_____VoidCallsCount += 1 if let getOptional_____VoidClosure = getOptional_____VoidClosure { return getOptional_____VoidClosure() } else { return getOptional_____VoidReturnValue } } } class FunctionWithMultilineDeclarationMock: FunctionWithMultilineDeclaration { //MARK: - start var startCarStringOfModelStringVoidCallsCount = 0 var startCarStringOfModelStringVoidCalled: Bool { return startCarStringOfModelStringVoidCallsCount > 0 } var startCarStringOfModelStringVoidReceivedArguments: (car: String, model: String)? var startCarStringOfModelStringVoidReceivedInvocations: [(car: String, model: String)] = [] var startCarStringOfModelStringVoidClosure: ((String, String) -> Void)? func start(car: String, of model: String) { startCarStringOfModelStringVoidCallsCount += 1 startCarStringOfModelStringVoidReceivedArguments = (car: car, model: model) startCarStringOfModelStringVoidReceivedInvocations.append((car: car, model: model)) startCarStringOfModelStringVoidClosure?(car, model) } } class FunctionWithNullableCompletionThatHasNullableAnyParameterProtocolMock: FunctionWithNullableCompletionThatHasNullableAnyParameterProtocol { //MARK: - add var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCallsCount = 0 var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCalled: Bool { return addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCallsCount > 0 } var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedArguments: (request: Int, completionHandler: ((((any Error)?) -> Void))?)? var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedInvocations: [(request: Int, completionHandler: ((((any Error)?) -> Void))?)] = [] var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidClosure: ((Int, ((((any Error)?) -> Void))?) -> Void)? func add(_ request: Int, withCompletionHandler completionHandler: ((((any Error)?) -> Void))?) { addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCallsCount += 1 addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedArguments = (request: request, completionHandler: completionHandler) addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedInvocations.append((request: request, completionHandler: completionHandler)) addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidClosure?(request, completionHandler) } } class HouseProtocolMock: HouseProtocol { var aPublisher: AnyPublisher? var bPublisher: AnyPublisher<(any PersonProtocol)?, Never>? var cPublisher: CurrentValueSubject<(any PersonProtocol)?, Never>? var dPublisher: PassthroughSubject<(any PersonProtocol)?, Never>? var e1Publisher: GenericType<(any PersonProtocol)?, Never, Never>? var e2Publisher: GenericType? var e3Publisher: GenericType? var e4Publisher: GenericType<(any PersonProtocol)?, (any PersonProtocol)?, (any PersonProtocol)?>? var f1Publisher: GenericType? var f2Publisher: GenericType? var f3Publisher: GenericType? var f4Publisher: GenericType? } class ImplicitlyUnwrappedOptionalReturnValueProtocolMock: ImplicitlyUnwrappedOptionalReturnValueProtocol { //MARK: - implicitReturn var implicitReturnStringCallsCount = 0 var implicitReturnStringCalled: Bool { return implicitReturnStringCallsCount > 0 } var implicitReturnStringReturnValue: String! var implicitReturnStringClosure: (() -> String)? func implicitReturn() -> String! { implicitReturnStringCallsCount += 1 if let implicitReturnStringClosure = implicitReturnStringClosure { return implicitReturnStringClosure() } else { return implicitReturnStringReturnValue } } } class InitializationProtocolMock: InitializationProtocol { //MARK: - init var initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedArguments: (intParameter: Int, stringParameter: String, optionalParameter: String?)? var initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedInvocations: [(intParameter: Int, stringParameter: String, optionalParameter: String?)] = [] var initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolClosure: ((Int, String, String?) -> Void)? required init(intParameter: Int, stringParameter: String, optionalParameter: String?) { initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedArguments = (intParameter: intParameter, stringParameter: stringParameter, optionalParameter: optionalParameter) initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedInvocations.append((intParameter: intParameter, stringParameter: stringParameter, optionalParameter: optionalParameter)) initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolClosure?(intParameter, stringParameter, optionalParameter) } //MARK: - start var startVoidCallsCount = 0 var startVoidCalled: Bool { return startVoidCallsCount > 0 } var startVoidClosure: (() -> Void)? func start() { startVoidCallsCount += 1 startVoidClosure?() } //MARK: - stop var stopVoidCallsCount = 0 var stopVoidCalled: Bool { return stopVoidCallsCount > 0 } var stopVoidClosure: (() -> Void)? func stop() { stopVoidCallsCount += 1 stopVoidClosure?() } } class MultiClosureProtocolMock: MultiClosureProtocol { //MARK: - setClosure var setClosureNameStringClosureEscapingVoidVoidCallsCount = 0 var setClosureNameStringClosureEscapingVoidVoidCalled: Bool { return setClosureNameStringClosureEscapingVoidVoidCallsCount > 0 } var setClosureNameStringClosureEscapingVoidVoidReceivedArguments: (name: String, closure: () -> Void)? var setClosureNameStringClosureEscapingVoidVoidReceivedInvocations: [(name: String, closure: () -> Void)] = [] var setClosureNameStringClosureEscapingVoidVoidClosure: ((String, @escaping () -> Void) -> Void)? func setClosure(name: String, _ closure: @escaping () -> Void) { setClosureNameStringClosureEscapingVoidVoidCallsCount += 1 setClosureNameStringClosureEscapingVoidVoidReceivedArguments = (name: name, closure: closure) setClosureNameStringClosureEscapingVoidVoidReceivedInvocations.append((name: name, closure: closure)) setClosureNameStringClosureEscapingVoidVoidClosure?(name, closure) } } class MultiExistentialArgumentsClosureProtocolMock: MultiExistentialArgumentsClosureProtocol { //MARK: - execute var executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCallsCount = 0 var executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCalled: Bool { return executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCallsCount > 0 } var executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidClosure: ((((any StubWithSomeNameProtocol)?, (any StubWithSomeNameProtocol)) -> (any StubWithSomeNameProtocol)?) -> Void)? func execute(completion: (((any StubWithSomeNameProtocol)?, (any StubWithSomeNameProtocol)) -> (any StubWithSomeNameProtocol)?)) { executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCallsCount += 1 executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidClosure?(completion) } } class MultiNonEscapingClosureProtocolMock: MultiNonEscapingClosureProtocol { //MARK: - executeClosure var executeClosureNameStringClosureVoidVoidCallsCount = 0 var executeClosureNameStringClosureVoidVoidCalled: Bool { return executeClosureNameStringClosureVoidVoidCallsCount > 0 } var executeClosureNameStringClosureVoidVoidClosure: ((String, () -> Void) -> Void)? func executeClosure(name: String, _ closure: () -> Void) { executeClosureNameStringClosureVoidVoidCallsCount += 1 executeClosureNameStringClosureVoidVoidClosure?(name, closure) } } class MultiNullableClosureProtocolMock: MultiNullableClosureProtocol { //MARK: - setClosure var setClosureNameStringClosureVoidVoidCallsCount = 0 var setClosureNameStringClosureVoidVoidCalled: Bool { return setClosureNameStringClosureVoidVoidCallsCount > 0 } var setClosureNameStringClosureVoidVoidReceivedArguments: (name: String, closure: (() -> Void)?)? var setClosureNameStringClosureVoidVoidReceivedInvocations: [(name: String, closure: (() -> Void)?)] = [] var setClosureNameStringClosureVoidVoidClosure: ((String, (() -> Void)?) -> Void)? func setClosure(name: String, _ closure: (() -> Void)?) { setClosureNameStringClosureVoidVoidCallsCount += 1 setClosureNameStringClosureVoidVoidReceivedArguments = (name: name, closure: closure) setClosureNameStringClosureVoidVoidReceivedInvocations.append((name: name, closure: closure)) setClosureNameStringClosureVoidVoidClosure?(name, closure) } } class NonEscapingClosureProtocolMock: NonEscapingClosureProtocol { //MARK: - executeClosure var executeClosureClosureVoidVoidCallsCount = 0 var executeClosureClosureVoidVoidCalled: Bool { return executeClosureClosureVoidVoidCallsCount > 0 } var executeClosureClosureVoidVoidClosure: ((() -> Void) -> Void)? func executeClosure(_ closure: () -> Void) { executeClosureClosureVoidVoidCallsCount += 1 executeClosureClosureVoidVoidClosure?(closure) } } class NullableClosureProtocolMock: NullableClosureProtocol { //MARK: - setClosure var setClosureClosureVoidVoidCallsCount = 0 var setClosureClosureVoidVoidCalled: Bool { return setClosureClosureVoidVoidCallsCount > 0 } var setClosureClosureVoidVoidReceivedClosure: (((() -> Void)))? var setClosureClosureVoidVoidReceivedInvocations: [(((() -> Void)))?] = [] var setClosureClosureVoidVoidClosure: (((() -> Void)?) -> Void)? func setClosure(_ closure: (() -> Void)?) { setClosureClosureVoidVoidCallsCount += 1 setClosureClosureVoidVoidReceivedClosure = closure setClosureClosureVoidVoidReceivedInvocations.append(closure) setClosureClosureVoidVoidClosure?(closure) } } public class ProtocolWithMethodWithGenericParametersMock: ProtocolWithMethodWithGenericParameters { public init() {} //MARK: - execute public var executeParamResultIntErrorResultStringErrorCallsCount = 0 public var executeParamResultIntErrorResultStringErrorCalled: Bool { return executeParamResultIntErrorResultStringErrorCallsCount > 0 } public var executeParamResultIntErrorResultStringErrorReceivedParam: (Result)? public var executeParamResultIntErrorResultStringErrorReceivedInvocations: [(Result)] = [] public var executeParamResultIntErrorResultStringErrorReturnValue: Result! public var executeParamResultIntErrorResultStringErrorClosure: ((Result) -> Result)? public func execute(param: Result) -> Result { executeParamResultIntErrorResultStringErrorCallsCount += 1 executeParamResultIntErrorResultStringErrorReceivedParam = param executeParamResultIntErrorResultStringErrorReceivedInvocations.append(param) if let executeParamResultIntErrorResultStringErrorClosure = executeParamResultIntErrorResultStringErrorClosure { return executeParamResultIntErrorResultStringErrorClosure(param) } else { return executeParamResultIntErrorResultStringErrorReturnValue } } } public class ProtocolWithMethodWithInoutParameterMock: ProtocolWithMethodWithInoutParameter { public init() {} //MARK: - execute public var executeParamInoutStringVoidCallsCount = 0 public var executeParamInoutStringVoidCalled: Bool { return executeParamInoutStringVoidCallsCount > 0 } public var executeParamInoutStringVoidReceivedParam: (String)? public var executeParamInoutStringVoidReceivedInvocations: [(String)] = [] public var executeParamInoutStringVoidClosure: ((inout String) -> Void)? public func execute(param: inout String) { executeParamInoutStringVoidCallsCount += 1 executeParamInoutStringVoidReceivedParam = param executeParamInoutStringVoidReceivedInvocations.append(param) executeParamInoutStringVoidClosure?(¶m) } //MARK: - execute public var executeParamInoutStringBarIntVoidCallsCount = 0 public var executeParamInoutStringBarIntVoidCalled: Bool { return executeParamInoutStringBarIntVoidCallsCount > 0 } public var executeParamInoutStringBarIntVoidReceivedArguments: (param: String, bar: Int)? public var executeParamInoutStringBarIntVoidReceivedInvocations: [(param: String, bar: Int)] = [] public var executeParamInoutStringBarIntVoidClosure: ((inout String, Int) -> Void)? public func execute(param: inout String, bar: Int) { executeParamInoutStringBarIntVoidCallsCount += 1 executeParamInoutStringBarIntVoidReceivedArguments = (param: param, bar: bar) executeParamInoutStringBarIntVoidReceivedInvocations.append((param: param, bar: bar)) executeParamInoutStringBarIntVoidClosure?(¶m, bar) } } public class ProtocolWithOverridesMock: ProtocolWithOverrides { public init() {} //MARK: - doSomething public var doSomethingDataIntStringCallsCount = 0 public var doSomethingDataIntStringCalled: Bool { return doSomethingDataIntStringCallsCount > 0 } public var doSomethingDataIntStringReceivedData: (Int)? public var doSomethingDataIntStringReceivedInvocations: [(Int)] = [] public var doSomethingDataIntStringReturnValue: [String]! public var doSomethingDataIntStringClosure: ((Int) -> [String])? public func doSomething(_ data: Int) -> [String] { doSomethingDataIntStringCallsCount += 1 doSomethingDataIntStringReceivedData = data doSomethingDataIntStringReceivedInvocations.append(data) if let doSomethingDataIntStringClosure = doSomethingDataIntStringClosure { return doSomethingDataIntStringClosure(data) } else { return doSomethingDataIntStringReturnValue } } //MARK: - doSomething public var doSomethingDataStringStringCallsCount = 0 public var doSomethingDataStringStringCalled: Bool { return doSomethingDataStringStringCallsCount > 0 } public var doSomethingDataStringStringReceivedData: (String)? public var doSomethingDataStringStringReceivedInvocations: [(String)] = [] public var doSomethingDataStringStringReturnValue: [String]! public var doSomethingDataStringStringClosure: ((String) -> [String])? public func doSomething(_ data: String) -> [String] { doSomethingDataStringStringCallsCount += 1 doSomethingDataStringStringReceivedData = data doSomethingDataStringStringReceivedInvocations.append(data) if let doSomethingDataStringStringClosure = doSomethingDataStringStringClosure { return doSomethingDataStringStringClosure(data) } else { return doSomethingDataStringStringReturnValue } } //MARK: - doSomething public var doSomethingDataStringIntCallsCount = 0 public var doSomethingDataStringIntCalled: Bool { return doSomethingDataStringIntCallsCount > 0 } public var doSomethingDataStringIntReceivedData: (String)? public var doSomethingDataStringIntReceivedInvocations: [(String)] = [] public var doSomethingDataStringIntReturnValue: [Int]! public var doSomethingDataStringIntClosure: ((String) -> [Int])? public func doSomething(_ data: String) -> [Int] { doSomethingDataStringIntCallsCount += 1 doSomethingDataStringIntReceivedData = data doSomethingDataStringIntReceivedInvocations.append(data) if let doSomethingDataStringIntClosure = doSomethingDataStringIntClosure { return doSomethingDataStringIntClosure(data) } else { return doSomethingDataStringIntReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntStringCallsCount = 0 public var doSomethingDataString_IntStringCalled: Bool { return doSomethingDataString_IntStringCallsCount > 0 } public var doSomethingDataString_IntStringReceivedData: (String)? public var doSomethingDataString_IntStringReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntStringReturnValue: ([Int], [String])! public var doSomethingDataString_IntStringClosure: ((String) -> ([Int], [String]))? public func doSomething(_ data: String) -> ([Int], [String]) { doSomethingDataString_IntStringCallsCount += 1 doSomethingDataString_IntStringReceivedData = data doSomethingDataString_IntStringReceivedInvocations.append(data) if let doSomethingDataString_IntStringClosure = doSomethingDataString_IntStringClosure { return doSomethingDataString_IntStringClosure(data) } else { return doSomethingDataString_IntStringReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntAnyThrowableError: (any Error)? public var doSomethingDataString_IntAnyCallsCount = 0 public var doSomethingDataString_IntAnyCalled: Bool { return doSomethingDataString_IntAnyCallsCount > 0 } public var doSomethingDataString_IntAnyReceivedData: (String)? public var doSomethingDataString_IntAnyReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntAnyReturnValue: ([Int], [Any])! public var doSomethingDataString_IntAnyClosure: ((String) throws -> ([Int], [Any]))? public func doSomething(_ data: String) throws -> ([Int], [Any]) { doSomethingDataString_IntAnyCallsCount += 1 doSomethingDataString_IntAnyReceivedData = data doSomethingDataString_IntAnyReceivedInvocations.append(data) if let error = doSomethingDataString_IntAnyThrowableError { throw error } if let doSomethingDataString_IntAnyClosure = doSomethingDataString_IntAnyClosure { return try doSomethingDataString_IntAnyClosure(data) } else { return doSomethingDataString_IntAnyReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntStringVoidCallsCount = 0 public var doSomethingDataString_IntStringVoidCalled: Bool { return doSomethingDataString_IntStringVoidCallsCount > 0 } public var doSomethingDataString_IntStringVoidReceivedData: (String)? public var doSomethingDataString_IntStringVoidReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntStringVoidReturnValue: (([Int], [String]) -> Void)! public var doSomethingDataString_IntStringVoidClosure: ((String) -> ([Int], [String]) -> Void)? public func doSomething(_ data: String) -> ([Int], [String]) -> Void { doSomethingDataString_IntStringVoidCallsCount += 1 doSomethingDataString_IntStringVoidReceivedData = data doSomethingDataString_IntStringVoidReceivedInvocations.append(data) if let doSomethingDataString_IntStringVoidClosure = doSomethingDataString_IntStringVoidClosure { return doSomethingDataString_IntStringVoidClosure(data) } else { return doSomethingDataString_IntStringVoidReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntAnyVoidThrowableError: (any Error)? public var doSomethingDataString_IntAnyVoidCallsCount = 0 public var doSomethingDataString_IntAnyVoidCalled: Bool { return doSomethingDataString_IntAnyVoidCallsCount > 0 } public var doSomethingDataString_IntAnyVoidReceivedData: (String)? public var doSomethingDataString_IntAnyVoidReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntAnyVoidReturnValue: (([Int], [Any]) -> Void)! public var doSomethingDataString_IntAnyVoidClosure: ((String) throws -> ([Int], [Any]) -> Void)? public func doSomething(_ data: String) throws -> ([Int], [Any]) -> Void { doSomethingDataString_IntAnyVoidCallsCount += 1 doSomethingDataString_IntAnyVoidReceivedData = data doSomethingDataString_IntAnyVoidReceivedInvocations.append(data) if let error = doSomethingDataString_IntAnyVoidThrowableError { throw error } if let doSomethingDataString_IntAnyVoidClosure = doSomethingDataString_IntAnyVoidClosure { return try doSomethingDataString_IntAnyVoidClosure(data) } else { return doSomethingDataString_IntAnyVoidReturnValue } } } class ReservedWordsProtocolMock: ReservedWordsProtocol { //MARK: - `continue` var continueWithMessageStringStringCallsCount = 0 var continueWithMessageStringStringCalled: Bool { return continueWithMessageStringStringCallsCount > 0 } var continueWithMessageStringStringReceivedMessage: (String)? var continueWithMessageStringStringReceivedInvocations: [(String)] = [] var continueWithMessageStringStringReturnValue: String! var continueWithMessageStringStringClosure: ((String) -> String)? func `continue`(with message: String) -> String { continueWithMessageStringStringCallsCount += 1 continueWithMessageStringStringReceivedMessage = message continueWithMessageStringStringReceivedInvocations.append(message) if let continueWithMessageStringStringClosure = continueWithMessageStringStringClosure { return continueWithMessageStringStringClosure(message) } else { return continueWithMessageStringStringReturnValue } } } class SameShortMethodNamesProtocolMock: SameShortMethodNamesProtocol { //MARK: - start var startCarStringOfModelStringVoidCallsCount = 0 var startCarStringOfModelStringVoidCalled: Bool { return startCarStringOfModelStringVoidCallsCount > 0 } var startCarStringOfModelStringVoidReceivedArguments: (car: String, model: String)? var startCarStringOfModelStringVoidReceivedInvocations: [(car: String, model: String)] = [] var startCarStringOfModelStringVoidClosure: ((String, String) -> Void)? func start(car: String, of model: String) { startCarStringOfModelStringVoidCallsCount += 1 startCarStringOfModelStringVoidReceivedArguments = (car: car, model: model) startCarStringOfModelStringVoidReceivedInvocations.append((car: car, model: model)) startCarStringOfModelStringVoidClosure?(car, model) } //MARK: - start var startPlaneStringOfModelStringVoidCallsCount = 0 var startPlaneStringOfModelStringVoidCalled: Bool { return startPlaneStringOfModelStringVoidCallsCount > 0 } var startPlaneStringOfModelStringVoidReceivedArguments: (plane: String, model: String)? var startPlaneStringOfModelStringVoidReceivedInvocations: [(plane: String, model: String)] = [] var startPlaneStringOfModelStringVoidClosure: ((String, String) -> Void)? func start(plane: String, of model: String) { startPlaneStringOfModelStringVoidCallsCount += 1 startPlaneStringOfModelStringVoidReceivedArguments = (plane: plane, model: model) startPlaneStringOfModelStringVoidReceivedInvocations.append((plane: plane, model: model)) startPlaneStringOfModelStringVoidClosure?(plane, model) } } class SendableProtocolMock: SendableProtocol, @unchecked Sendable { var value: Any { get { return underlyingValue } set(value) { underlyingValue = value } } var underlyingValue: (Any)! } class SendableSendableProtocolMock: SendableSendableProtocol, @unchecked Sendable { var value: Any { get { return underlyingValue } set(value) { underlyingValue = value } } var underlyingValue: (Any)! } class SingleOptionalParameterFunctionMock: SingleOptionalParameterFunction { //MARK: - send var sendMessageStringVoidCallsCount = 0 var sendMessageStringVoidCalled: Bool { return sendMessageStringVoidCallsCount > 0 } var sendMessageStringVoidReceivedMessage: (String)? var sendMessageStringVoidReceivedInvocations: [(String)?] = [] var sendMessageStringVoidClosure: ((String?) -> Void)? func send(message: String?) { sendMessageStringVoidCallsCount += 1 sendMessageStringVoidReceivedMessage = message sendMessageStringVoidReceivedInvocations.append(message) sendMessageStringVoidClosure?(message) } } class SomeProtocolMock: SomeProtocol { //MARK: - a var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCallsCount = 0 var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCalled: Bool { return aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCallsCount > 0 } var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) -> Void)? func a(_ x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) { aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCallsCount += 1 aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedArguments = (x: x, y: y, z: z) aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedInvocations.append((x: x, y: y, z: z)) aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidClosure?(x, y, z) } //MARK: - b var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCallsCount = 0 var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCalled: Bool { return bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCallsCount > 0 } var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReturnValue: String! var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) async -> String)? func b(x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) async -> String { bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCallsCount += 1 bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedArguments = (x: x, y: y, z: z) bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedInvocations.append((x: x, y: y, z: z)) if let bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure = bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure { return await bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure(x, y, z) } else { return bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReturnValue } } //MARK: - someConfusingFuncName var someConfusingFuncNameXSomeStubProtocolVoidCallsCount = 0 var someConfusingFuncNameXSomeStubProtocolVoidCalled: Bool { return someConfusingFuncNameXSomeStubProtocolVoidCallsCount > 0 } var someConfusingFuncNameXSomeStubProtocolVoidReceivedX: (any StubProtocol)? var someConfusingFuncNameXSomeStubProtocolVoidReceivedInvocations: [(any StubProtocol)] = [] var someConfusingFuncNameXSomeStubProtocolVoidClosure: ((any StubProtocol) -> Void)? func someConfusingFuncName(x: some StubProtocol) { someConfusingFuncNameXSomeStubProtocolVoidCallsCount += 1 someConfusingFuncNameXSomeStubProtocolVoidReceivedX = x someConfusingFuncNameXSomeStubProtocolVoidReceivedInvocations.append(x) someConfusingFuncNameXSomeStubProtocolVoidClosure?(x) } //MARK: - c var cSomeConfusingArgumentNameSomeStubProtocolVoidCallsCount = 0 var cSomeConfusingArgumentNameSomeStubProtocolVoidCalled: Bool { return cSomeConfusingArgumentNameSomeStubProtocolVoidCallsCount > 0 } var cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedSomeConfusingArgumentName: (any StubProtocol)? var cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedInvocations: [(any StubProtocol)] = [] var cSomeConfusingArgumentNameSomeStubProtocolVoidClosure: ((any StubProtocol) -> Void)? func c(someConfusingArgumentName: some StubProtocol) { cSomeConfusingArgumentNameSomeStubProtocolVoidCallsCount += 1 cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedSomeConfusingArgumentName = someConfusingArgumentName cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedInvocations.append(someConfusingArgumentName) cSomeConfusingArgumentNameSomeStubProtocolVoidClosure?(someConfusingArgumentName) } //MARK: - d var dXSomeStubWithSomeNameProtocolVoidCallsCount = 0 var dXSomeStubWithSomeNameProtocolVoidCalled: Bool { return dXSomeStubWithSomeNameProtocolVoidCallsCount > 0 } var dXSomeStubWithSomeNameProtocolVoidReceivedX: (any StubWithSomeNameProtocol)? var dXSomeStubWithSomeNameProtocolVoidReceivedInvocations: [(any StubWithSomeNameProtocol)?] = [] var dXSomeStubWithSomeNameProtocolVoidClosure: (((any StubWithSomeNameProtocol)?) -> Void)? func d(_ x: (some StubWithSomeNameProtocol)?) { dXSomeStubWithSomeNameProtocolVoidCallsCount += 1 dXSomeStubWithSomeNameProtocolVoidReceivedX = x dXSomeStubWithSomeNameProtocolVoidReceivedInvocations.append(x) dXSomeStubWithSomeNameProtocolVoidClosure?(x) } } class StaticMethodProtocolMock: StaticMethodProtocol { static func reset() { //MARK: - staticFunction staticFunctionStringStringCallsCount = 0 staticFunctionStringStringReceived = nil staticFunctionStringStringReceivedInvocations = [] staticFunctionStringStringClosure = nil } //MARK: - staticFunction static var staticFunctionStringStringCallsCount = 0 static var staticFunctionStringStringCalled: Bool { return staticFunctionStringStringCallsCount > 0 } static var staticFunctionStringStringReceived: (String)? static var staticFunctionStringStringReceivedInvocations: [(String)] = [] static var staticFunctionStringStringReturnValue: String! static var staticFunctionStringStringClosure: ((String) -> String)? static func staticFunction(_ arg0: String) -> String { staticFunctionStringStringCallsCount += 1 staticFunctionStringStringReceived = arg0 staticFunctionStringStringReceivedInvocations.append(arg0) if let staticFunctionStringStringClosure = staticFunctionStringStringClosure { return staticFunctionStringStringClosure(arg0) } else { return staticFunctionStringStringReturnValue } } } class SubscriptProtocolMock: SubscriptProtocol { //MARK: - Subscript #1 subscript(arg: Int) -> String { get { fatalError("Subscripts are not fully supported yet") } set { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #2 subscript(arg: T) -> Int { get { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #3 subscript(arg: T) -> String { get async { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #4 subscript(arg: T) -> T? { get { fatalError("Subscripts are not fully supported yet") } set { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #5 subscript(arg: String) -> T? where T : Cancellable { get throws { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #6 subscript(arg2: String) -> T { get throws(CustomError) { fatalError("Subscripts are not fully supported yet") } } } class TestProtocolMock< Value: Sequence, Value3: Collection, Value5: Sequence, Value6: Sequence>: TestProtocol where Value.Element : Collection,Value.Element : Hashable,Value.Element : Comparable,Value3.Element == String,Value5.Element == Int,Value6.Element == Int,Value6.Element : Hashable,Value6.Element : Comparable { typealias Value2 = Int //MARK: - getValue var getValueSequenceCallsCount = 0 var getValueSequenceCalled: Bool { return getValueSequenceCallsCount > 0 } var getValueSequenceReturnValue: Value! var getValueSequenceClosure: (() -> Value)? func getValue() -> Value { getValueSequenceCallsCount += 1 if let getValueSequenceClosure = getValueSequenceClosure { return getValueSequenceClosure() } else { return getValueSequenceReturnValue } } //MARK: - getValue2 var getValue2Value2CallsCount = 0 var getValue2Value2Called: Bool { return getValue2Value2CallsCount > 0 } var getValue2Value2ReturnValue: Value2! var getValue2Value2Closure: (() -> Value2)? func getValue2() -> Value2 { getValue2Value2CallsCount += 1 if let getValue2Value2Closure = getValue2Value2Closure { return getValue2Value2Closure() } else { return getValue2Value2ReturnValue } } //MARK: - getValue3 var getValue3CollectionCallsCount = 0 var getValue3CollectionCalled: Bool { return getValue3CollectionCallsCount > 0 } var getValue3CollectionReturnValue: Value3! var getValue3CollectionClosure: (() -> Value3)? func getValue3() -> Value3 { getValue3CollectionCallsCount += 1 if let getValue3CollectionClosure = getValue3CollectionClosure { return getValue3CollectionClosure() } else { return getValue3CollectionReturnValue } } //MARK: - getValue5 var getValue5SequenceCallsCount = 0 var getValue5SequenceCalled: Bool { return getValue5SequenceCallsCount > 0 } var getValue5SequenceReturnValue: Value5! var getValue5SequenceClosure: (() -> Value5)? func getValue5() -> Value5 { getValue5SequenceCallsCount += 1 if let getValue5SequenceClosure = getValue5SequenceClosure { return getValue5SequenceClosure() } else { return getValue5SequenceReturnValue } } //MARK: - getValue6 var getValue6SequenceCallsCount = 0 var getValue6SequenceCalled: Bool { return getValue6SequenceCallsCount > 0 } var getValue6SequenceReturnValue: Value6! var getValue6SequenceClosure: (() -> Value6)? func getValue6() -> Value6 { getValue6SequenceCallsCount += 1 if let getValue6SequenceClosure = getValue6SequenceClosure { return getValue6SequenceClosure() } else { return getValue6SequenceReturnValue } } } class ThrowableProtocolMock: ThrowableProtocol { //MARK: - doOrThrow var doOrThrowStringThrowableError: (any Error)? var doOrThrowStringCallsCount = 0 var doOrThrowStringCalled: Bool { return doOrThrowStringCallsCount > 0 } var doOrThrowStringReturnValue: String! var doOrThrowStringClosure: (() throws -> String)? func doOrThrow() throws -> String { doOrThrowStringCallsCount += 1 if let error = doOrThrowStringThrowableError { throw error } if let doOrThrowStringClosure = doOrThrowStringClosure { return try doOrThrowStringClosure() } else { return doOrThrowStringReturnValue } } //MARK: - doOrThrowVoid var doOrThrowVoidVoidThrowableError: (any Error)? var doOrThrowVoidVoidCallsCount = 0 var doOrThrowVoidVoidCalled: Bool { return doOrThrowVoidVoidCallsCount > 0 } var doOrThrowVoidVoidClosure: (() throws -> Void)? func doOrThrowVoid() throws { doOrThrowVoidVoidCallsCount += 1 if let error = doOrThrowVoidVoidThrowableError { throw error } try doOrThrowVoidVoidClosure?() } } class ThrowingVariablesProtocolMock: ThrowingVariablesProtocol { var titleCallsCount = 0 var titleCalled: Bool { return titleCallsCount > 0 } var title: String? { get throws { titleCallsCount += 1 if let error = titleThrowableError { throw error } if let titleClosure = titleClosure { return try titleClosure() } else { return underlyingTitle } } } var underlyingTitle: String? var titleThrowableError: Error? var titleClosure: (() throws -> String?)? var firstNameCallsCount = 0 var firstNameCalled: Bool { return firstNameCallsCount > 0 } var firstName: String { get throws { firstNameCallsCount += 1 if let error = firstNameThrowableError { throw error } if let firstNameClosure = firstNameClosure { return try firstNameClosure() } else { return underlyingFirstName } } } var underlyingFirstName: String! var firstNameThrowableError: Error? var firstNameClosure: (() throws -> String)? } class TypedThrowableProtocolMock: TypedThrowableProtocol { var valueCallsCount = 0 var valueCalled: Bool { return valueCallsCount > 0 } var value: Int { get throws(CustomError) { valueCallsCount += 1 if let error = valueThrowableError { throw error } if let valueClosure = valueClosure { return try valueClosure() } else { return underlyingValue } } } var underlyingValue: Int! var valueThrowableError: (CustomError)? var valueClosure: (() throws(CustomError) -> Int)? var valueAnyErrorCallsCount = 0 var valueAnyErrorCalled: Bool { return valueAnyErrorCallsCount > 0 } var valueAnyError: Int { get throws(any Error) { valueAnyErrorCallsCount += 1 if let error = valueAnyErrorThrowableError { throw error } if let valueAnyErrorClosure = valueAnyErrorClosure { return try valueAnyErrorClosure() } else { return underlyingValueAnyError } } } var underlyingValueAnyError: Int! var valueAnyErrorThrowableError: (any Error)? var valueAnyErrorClosure: (() throws(any Error) -> Int)? var valueThrowsNever: Int { get { return underlyingValueThrowsNever } set(value) { underlyingValueThrowsNever = value } } var underlyingValueThrowsNever: (Int)! //MARK: - init var initTypedThrowableProtocolThrowableError: (CustomError)? var initTypedThrowableProtocolClosure: (() throws(CustomError) -> Void)? required init() { initTypedThrowableProtocolClosure?() } //MARK: - init required init(init2: Void) { fatalError("Generic typed throws in inits are not fully supported yet") } //MARK: - doOrThrow var doOrThrowStringThrowableError: (CustomError)? var doOrThrowStringCallsCount = 0 var doOrThrowStringCalled: Bool { return doOrThrowStringCallsCount > 0 } var doOrThrowStringReturnValue: String! var doOrThrowStringClosure: (() throws(CustomError) -> String)? func doOrThrow() throws(CustomError) -> String { doOrThrowStringCallsCount += 1 if let error = doOrThrowStringThrowableError { throw error } if let doOrThrowStringClosure = doOrThrowStringClosure { return try doOrThrowStringClosure() } else { return doOrThrowStringReturnValue } } //MARK: - doOrThrowAnyError var doOrThrowAnyErrorVoidThrowableError: (any Error)? var doOrThrowAnyErrorVoidCallsCount = 0 var doOrThrowAnyErrorVoidCalled: Bool { return doOrThrowAnyErrorVoidCallsCount > 0 } var doOrThrowAnyErrorVoidClosure: (() throws(any Error) -> Void)? func doOrThrowAnyError() throws(any Error) { doOrThrowAnyErrorVoidCallsCount += 1 if let error = doOrThrowAnyErrorVoidThrowableError { throw error } try doOrThrowAnyErrorVoidClosure?() } //MARK: - doOrThrowNever var doOrThrowNeverVoidCallsCount = 0 var doOrThrowNeverVoidCalled: Bool { return doOrThrowNeverVoidCallsCount > 0 } var doOrThrowNeverVoidClosure: (() -> Void)? func doOrThrowNever() { doOrThrowNeverVoidCallsCount += 1 doOrThrowNeverVoidClosure?() } //MARK: - doOrRethrows func doOrRethrows(_ block: () throws(E) -> Void) throws(E) -> Int where E: Error { fatalError("Generic typed throws are not fully supported yet") } } class VariablesProtocolMock: VariablesProtocol { var company: String? var name: String { get { return underlyingName } set(value) { underlyingName = value } } var underlyingName: (String)! var age: Int { get { return underlyingAge } set(value) { underlyingAge = value } } var underlyingAge: (Int)! var kids: [String] = [] var universityMarks: [String: Int] = [:] } ================================================ FILE: Templates/Tests/Expected/LinuxMain.expected ================================================ import XCTest extension AutoInjectionTests { static var allTests: [(String, (AutoInjectionTests) -> () throws -> Void)] = [ ("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies), ("testThatItDoesntResolveAutoInjectedDependencies", testThatItDoesntResolveAutoInjectedDependencies) ] } extension AutoWiringTests { static var allTests: [(String, (AutoWiringTests) -> () throws -> Void)] = [ ("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring), ("testThatItCanNotResolveWithAutoWiring", testThatItCanNotResolveWithAutoWiring) ] } // swiftlint:disable trailing_comma XCTMain([ testCase(AutoInjectionTests.allTests), testCase(AutoWiringTests.allTests), ]) // swiftlint:enable trailing_comma ================================================ FILE: Templates/Tests/Generated/AutoCases.generated.swift ================================================ // Generated using Sourcery 1.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT internal extension AutoCasesEnum { static let count: Int = 4 static let allCases: [AutoCasesEnum] = [ .north, .south, .east, .west ] } public extension AutoCasesHasAssociatedValuesEnum { static let count: Int = 2 } internal extension AutoCasesOneValueEnum { static let count: Int = 1 static let allCases: [AutoCasesOneValueEnum] = [ .one ] } ================================================ FILE: Templates/Tests/Generated/AutoCodable.generated.swift ================================================ // Generated using Sourcery 1.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT #if canImport(ObjectiveC) extension AssociatedValuesEnum { internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let enumCase = try container.decode(String.self, forKey: .enumCaseKey) switch enumCase { case CodingKeys.someCase.rawValue: let id = try container.decode(Int.self, forKey: .id) let name = try container.decode(String.self, forKey: .name) self = .someCase(id: id, name: name) case CodingKeys.unnamedCase.rawValue: // Enum cases with unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Can't decode '\(enumCase)'") case CodingKeys.mixCase.rawValue: // Enum cases with mixed named and unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Can't decode '\(enumCase)'") case CodingKeys.anotherCase.rawValue: self = .anotherCase default: throw DecodingError.dataCorruptedError(forKey: .enumCaseKey, in: container, debugDescription: "Unknown enum case '\(enumCase)'") } } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case let .someCase(id, name): try container.encode(CodingKeys.someCase.rawValue, forKey: .enumCaseKey) try container.encode(id, forKey: .id) try container.encode(name, forKey: .name) case .unnamedCase: // Enum cases with unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) case .mixCase: // Enum cases with mixed named and unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) case .anotherCase: try container.encode(CodingKeys.anotherCase.rawValue, forKey: .enumCaseKey) } } } extension AssociatedValuesEnumNoCaseKey { enum CodingKeys: String, CodingKey { case someCase case unnamedCase case mixCase case anotherCase case id case name } internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.contains(.someCase), try container.decodeNil(forKey: .someCase) == false { let associatedValues = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .someCase) let id = try associatedValues.decode(Int.self, forKey: .id) let name = try associatedValues.decode(String.self, forKey: .name) self = .someCase(id: id, name: name) return } if container.allKeys.contains(.unnamedCase), try container.decodeNil(forKey: .unnamedCase) == false { var associatedValues = try container.nestedUnkeyedContainer(forKey: .unnamedCase) let associatedValue0 = try associatedValues.decode(Int.self) let associatedValue1 = try associatedValues.decode(String.self) self = .unnamedCase(associatedValue0, associatedValue1) return } if container.allKeys.contains(.mixCase), try container.decodeNil(forKey: .mixCase) == false { // Enum cases with mixed named and unnamed associated values can't be decoded throw DecodingError.dataCorruptedError(forKey: .mixCase, in: container, debugDescription: "Can't decode `.mixCase`") } if container.allKeys.contains(.anotherCase), try container.decodeNil(forKey: .anotherCase) == false { self = .anotherCase return } throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case")) } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case let .someCase(id, name): var associatedValues = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .someCase) try associatedValues.encode(id, forKey: .id) try associatedValues.encode(name, forKey: .name) case let .unnamedCase(associatedValue0, associatedValue1): var associatedValues = container.nestedUnkeyedContainer(forKey: .unnamedCase) try associatedValues.encode(associatedValue0) try associatedValues.encode(associatedValue1) case .mixCase: // Enum cases with mixed named and unnamed associated values can't be encoded throw EncodingError.invalidValue(self, .init(codingPath: encoder.codingPath, debugDescription: "Can't encode '\(self)'")) case .anotherCase: _ = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .anotherCase) } } } extension CustomCodingWithNotAllDefinedKeys { internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) value = try container.decode(Int.self, forKey: .value) } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) encodeComputedValue(to: &container) } } extension CustomContainerCodable { public init(from decoder: Decoder) throws { let container = try CustomContainerCodable.decodingContainer(decoder) value = try container.decode(Int.self, forKey: .value) } public func encode(to encoder: Encoder) throws { var container = encodingContainer(encoder) try container.encode(value, forKey: .value) } } extension CustomMethodsCodable { enum CodingKeys: String, CodingKey { case boolValue case intValue case optionalString case requiredString case requiredStringWithDefault case computedPropertyToEncode } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) boolValue = try CustomMethodsCodable.decodeBoolValue(from: decoder) intValue = CustomMethodsCodable.decodeIntValue(from: container) ?? CustomMethodsCodable.defaultIntValue optionalString = try container.decodeIfPresent(String.self, forKey: .optionalString) requiredString = try container.decode(String.self, forKey: .requiredString) requiredStringWithDefault = (try? container.decode(String.self, forKey: .requiredStringWithDefault)) ?? CustomMethodsCodable.defaultRequiredStringWithDefault } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try encodeBoolValue(to: encoder) encodeIntValue(to: &container) try container.encodeIfPresent(optionalString, forKey: .optionalString) try container.encode(requiredString, forKey: .requiredString) try container.encode(requiredStringWithDefault, forKey: .requiredStringWithDefault) encodeComputedPropertyToEncode(to: &container) try encodeAdditionalValues(to: encoder) } } extension SimpleEnum { enum CodingKeys: String, CodingKey { case someCase case anotherCase } internal init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let enumCase = try container.decode(String.self) switch enumCase { case CodingKeys.someCase.rawValue: self = .someCase case CodingKeys.anotherCase.rawValue: self = .anotherCase default: throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case '\(enumCase)'")) } } internal func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .someCase: try container.encode(CodingKeys.someCase.rawValue) case .anotherCase: try container.encode(CodingKeys.anotherCase.rawValue) } } } extension SkipDecodingWithDefaultValueOrComputedProperty { internal init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) value = try container.decode(Int.self, forKey: .value) } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) try container.encode(computedValue, forKey: .computedValue) } } extension SkipEncodingKeys { enum CodingKeys: String, CodingKey { case value case skipValue } internal func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } #endif ================================================ FILE: Templates/Tests/Generated/AutoEquatable.generated.swift ================================================ // Generated using Sourcery 1.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable file_length fileprivate func compareOptionals(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { switch (lhs, rhs) { case let (lValue?, rValue?): return compare(lValue, rValue) case (nil, nil): return true default: return false } } fileprivate func compareArrays(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool { guard lhs.count == rhs.count else { return false } for (idx, lhsItem) in lhs.enumerated() { guard compare(lhsItem, rhs[idx]) else { return false } } return true } // MARK: - AutoEquatable for classes, protocols, structs // MARK: - AutoEquatableAnnotatedClass AutoEquatable extension AutoEquatableAnnotatedClass: Equatable {} internal func == (lhs: AutoEquatableAnnotatedClass, rhs: AutoEquatableAnnotatedClass) -> Bool { guard lhs.moneyInThePocket == rhs.moneyInThePocket else { return false } return true } // MARK: - AutoEquatableAnnotatedClassAnnotatedInherited AutoEquatable extension AutoEquatableAnnotatedClassAnnotatedInherited: Equatable {} THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable internal func == (lhs: AutoEquatableAnnotatedClassAnnotatedInherited, rhs: AutoEquatableAnnotatedClassAnnotatedInherited) -> Bool { guard lhs.middleName == rhs.middleName else { return false } return true } // MARK: - AutoEquatableClass AutoEquatable extension AutoEquatableClass: Equatable {} internal func == (lhs: AutoEquatableClass, rhs: AutoEquatableClass) -> Bool { guard lhs.firstName == rhs.firstName else { return false } guard lhs.lastName == rhs.lastName else { return false } guard compareArrays(lhs: lhs.parents, rhs: rhs.parents, compare: ==) else { return false } guard compareOptionals(lhs: lhs.age, rhs: rhs.age, compare: ==) else { return false } guard lhs.moneyInThePocket == rhs.moneyInThePocket else { return false } guard compareOptionals(lhs: lhs.friends, rhs: rhs.friends, compare: ==) else { return false } return true } // MARK: - AutoEquatableClassInherited AutoEquatable extension AutoEquatableClassInherited: Equatable {} THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable internal func == (lhs: AutoEquatableClassInherited, rhs: AutoEquatableClassInherited) -> Bool { guard compareOptionals(lhs: lhs.middleName, rhs: rhs.middleName, compare: ==) else { return false } return true } // MARK: - AutoEquatableNSObject AutoEquatable internal func == (lhs: AutoEquatableNSObject, rhs: AutoEquatableNSObject) -> Bool { guard lhs.firstName == rhs.firstName else { return false } return true } // MARK: - AutoEquatableProtocol AutoEquatable internal func == (lhs: AutoEquatableProtocol, rhs: AutoEquatableProtocol) -> Bool { guard lhs.width == rhs.width else { return false } guard lhs.height == rhs.height else { return false } guard lhs.name == rhs.name else { return false } return true } // MARK: - AutoEquatableStruct AutoEquatable extension AutoEquatableStruct: Equatable {} internal func == (lhs: AutoEquatableStruct, rhs: AutoEquatableStruct) -> Bool { guard lhs.firstName == rhs.firstName else { return false } guard lhs.lastName == rhs.lastName else { return false } guard compareArrays(lhs: lhs.parents, rhs: rhs.parents, compare: ==) else { return false } guard lhs.moneyInThePocket == rhs.moneyInThePocket else { return false } guard compareOptionals(lhs: lhs.friends, rhs: rhs.friends, compare: ==) else { return false } guard compareOptionals(lhs: lhs.age, rhs: rhs.age, compare: ==) else { return false } return true } // MARK: - AutoEquatable for Enums // MARK: - AutoEquatableEnum AutoEquatable extension AutoEquatableEnum: Equatable {} internal func == (lhs: AutoEquatableEnum, rhs: AutoEquatableEnum) -> Bool { switch (lhs, rhs) { case (.one, .one): return true case let (.two(lhsFirst, lhsSecond), .two(rhsFirst, rhsSecond)): if lhsFirst != rhsFirst { return false } if lhsSecond != rhsSecond { return false } return true case let (.three(lhs), .three(rhs)): return lhs == rhs default: return false } } // MARK: - AutoEquatableEnumWithOneCase AutoEquatable extension AutoEquatableEnumWithOneCase: Equatable {} internal func == (lhs: AutoEquatableEnumWithOneCase, rhs: AutoEquatableEnumWithOneCase) -> Bool { switch (lhs, rhs) { case (.one, .one): return true } } ================================================ FILE: Templates/Tests/Generated/AutoHashable.generated.swift ================================================ // Generated using Sourcery 1.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable all // MARK: - AutoHashable for classes, protocols, structs // MARK: - AutoHashableClass AutoHashable extension AutoHashableClass: Hashable { internal func hash(into hasher: inout Hasher) { firstName.hash(into: &hasher) lastName.hash(into: &hasher) parents.hash(into: &hasher) universityGrades.hash(into: &hasher) moneyInThePocket.hash(into: &hasher) age.hash(into: &hasher) friends.hash(into: &hasher) } } // MARK: - AutoHashableClassFromNonHashableInherited AutoHashable extension AutoHashableClassFromNonHashableInherited: Hashable { internal func hash(into hasher: inout Hasher) { lastName.hash(into: &hasher) } } // MARK: - AutoHashableClassFromNonHashableInheritedInherited AutoHashable extension AutoHashableClassFromNonHashableInheritedInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) prefix.hash(into: &hasher) } } // MARK: - AutoHashableClassInherited AutoHashable extension AutoHashableClassInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) middleName.hash(into: &hasher) } } // MARK: - AutoHashableClassInheritedInherited AutoHashable extension AutoHashableClassInheritedInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) prefix.hash(into: &hasher) } } // MARK: - AutoHashableFromHashableInherited AutoHashable extension AutoHashableFromHashableInherited: Hashable { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) lastName.hash(into: &hasher) } } // MARK: - AutoHashableNSObject AutoHashable extension AutoHashableNSObject { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) firstName.hash(into: &hasher) } } // MARK: - AutoHashableNSObjectInherited AutoHashable extension AutoHashableNSObjectInherited { internal override func hash(into hasher: inout Hasher) { super.hash(into: hasher) lastName.hash(into: &hasher) } } // MARK: - AutoHashableProtocol AutoHashable extension AutoHashableProtocol { internal func hash(into hasher: inout Hasher) { width.hash(into: &hasher) height.hash(into: &hasher) type(of: self).name.hash(into: &hasher) } } // MARK: - AutoHashableStruct AutoHashable extension AutoHashableStruct: Hashable { internal func hash(into hasher: inout Hasher) { firstName.hash(into: &hasher) lastName.hash(into: &hasher) parents.hash(into: &hasher) universityGrades.hash(into: &hasher) moneyInThePocket.hash(into: &hasher) age.hash(into: &hasher) friends.hash(into: &hasher) } } // MARK: - AutoHashable for Enums // MARK: - AutoHashableEnum AutoHashable extension AutoHashableEnum: Hashable { internal func hash(into hasher: inout Hasher) { switch self { case .one: 1.hash(into: &hasher) case let .two(first, second): 2.hash(into: &hasher) first.hash(into: &hasher) second.hash(into: &hasher) case let .three(data): 3.hash(into: &hasher) data.hash(into: &hasher) } } } ================================================ FILE: Templates/Tests/Generated/AutoLenses.generated.swift ================================================ // Generated using Sourcery 1.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable variable_name infix operator *~: MultiplicationPrecedence infix operator |>: AdditionPrecedence struct Lens { let get: (Whole) -> Part let set: (Part, Whole) -> Whole } func * (lhs: Lens, rhs: Lens) -> Lens { return Lens( get: { a in rhs.get(lhs.get(a)) }, set: { (c, a) in lhs.set(rhs.set(c, lhs.get(a)), a) } ) } func *~ (lhs: Lens, rhs: B) -> (A) -> A { return { a in lhs.set(rhs, a) } } func |> (x: A, f: (A) -> B) -> B { return f(x) } func |> (f: @escaping (A) -> B, g: @escaping (B) -> C) -> (A) -> C { return { g(f($0)) } } extension House { static let roomsLens = Lens( get: { $0.rooms }, set: { rooms, house in House(rooms: rooms, address: house.address, size: house.size) } ) static let addressLens = Lens( get: { $0.address }, set: { address, house in House(rooms: house.rooms, address: address, size: house.size) } ) static let sizeLens = Lens( get: { $0.size }, set: { size, house in House(rooms: house.rooms, address: house.address, size: size) } ) } extension Person { static let nameLens = Lens( get: { $0.name }, set: { name, person in Person(name: name) } ) } extension Rectangle { static let xLens = Lens( get: { $0.x }, set: { x, rectangle in Rectangle(x: x, y: rectangle.y) } ) static let yLens = Lens( get: { $0.y }, set: { y, rectangle in Rectangle(x: rectangle.x, y: y) } ) } extension Room { static let peopleLens = Lens( get: { $0.people }, set: { people, room in Room(people: people, name: room.name) } ) static let nameLens = Lens( get: { $0.name }, set: { name, room in Room(people: room.people, name: name) } ) } ================================================ FILE: Templates/Tests/Generated/AutoMockable.generated.swift ================================================ // Generated using Sourcery 2.2.7 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable line_length // swiftlint:disable variable_name import Foundation #if os(iOS) || os(tvOS) || os(watchOS) import UIKit #elseif os(OSX) import AppKit #endif public class AccessLevelProtocolMock: AccessLevelProtocol { public init() {} public var company: String? public var name: String { get { return underlyingName } set(value) { underlyingName = value } } public var underlyingName: (String)! //MARK: - loadConfiguration public var loadConfigurationStringCallsCount = 0 public var loadConfigurationStringCalled: Bool { return loadConfigurationStringCallsCount > 0 } public var loadConfigurationStringReturnValue: String? public var loadConfigurationStringClosure: (() -> String?)? public func loadConfiguration() -> String? { loadConfigurationStringCallsCount += 1 if let loadConfigurationStringClosure = loadConfigurationStringClosure { return loadConfigurationStringClosure() } else { return loadConfigurationStringReturnValue } } } class AnnotatedProtocolMock: AnnotatedProtocol { //MARK: - sayHelloWith var sayHelloWithNameStringVoidCallsCount = 0 var sayHelloWithNameStringVoidCalled: Bool { return sayHelloWithNameStringVoidCallsCount > 0 } var sayHelloWithNameStringVoidReceivedName: (String)? var sayHelloWithNameStringVoidReceivedInvocations: [(String)] = [] var sayHelloWithNameStringVoidClosure: ((String) -> Void)? func sayHelloWith(name: String) { sayHelloWithNameStringVoidCallsCount += 1 sayHelloWithNameStringVoidReceivedName = name sayHelloWithNameStringVoidReceivedInvocations.append(name) sayHelloWithNameStringVoidClosure?(name) } } class AnyProtocolMock: AnyProtocol { var a: any StubProtocol { get { return underlyingA } set(value) { underlyingA = value } } var underlyingA: (any StubProtocol)! var b: (any StubProtocol)? var c: (any StubProtocol)! var d: (((any StubProtocol)?) -> Void) { get { return underlyingD } set(value) { underlyingD = value } } var underlyingD: ((((any StubProtocol)?) -> Void))! var e: [(any StubProtocol)?] = [] var g: any StubProtocol { get { return underlyingG } set(value) { underlyingG = value } } var underlyingG: (any StubProtocol)! var h: (any StubProtocol)? var i: (any StubProtocol)! var anyConfusingPropertyName: any StubProtocol { get { return underlyingAnyConfusingPropertyName } set(value) { underlyingAnyConfusingPropertyName = value } } var underlyingAnyConfusingPropertyName: (any StubProtocol)! var o: any StubWithAnyNameProtocol { get { return underlyingO } set(value) { underlyingO = value } } var underlyingO: (any StubWithAnyNameProtocol)! //MARK: - f var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCallsCount = 0 var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCalled: Bool { return fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCallsCount > 0 } var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) -> Void)? func f(_ x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) { fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidCallsCount += 1 fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedArguments = (x: x, y: y, z: z) fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidReceivedInvocations.append((x: x, y: y, z: z)) fXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolVoidClosure?(x, y, z) } //MARK: - j var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCallsCount = 0 var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCalled: Bool { return jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCallsCount > 0 } var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReturnValue: String! var jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) async -> String)? func j(x: (any StubProtocol)?, y: (any StubProtocol)!, z: any StubProtocol) async -> String { jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringCallsCount += 1 jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedArguments = (x: x, y: y, z: z) jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReceivedInvocations.append((x: x, y: y, z: z)) if let jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure = jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure { return await jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringClosure(x, y, z) } else { return jXAnyStubProtocolYAnyStubProtocolZAnyStubProtocolStringReturnValue } } //MARK: - k var kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount = 0 var kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCalled: Bool { return kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount > 0 } var kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure: ((((any StubProtocol)?) -> Void, (any StubProtocol) -> Void) -> Void)? func k(x: ((any StubProtocol)?) -> Void, y: (any StubProtocol) -> Void) { kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount += 1 kXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure?(x, y) } //MARK: - l var lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount = 0 var lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCalled: Bool { return lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount > 0 } var lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure: ((((any StubProtocol)?) -> Void, (any StubProtocol) -> Void) -> Void)? func l(x: ((any StubProtocol)?) -> Void, y: (any StubProtocol) -> Void) { lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidCallsCount += 1 lXAnyStubProtocolVoidYAnyStubProtocolVoidVoidClosure?(x, y) } //MARK: - m var mAnyConfusingArgumentNameAnyStubProtocolVoidCallsCount = 0 var mAnyConfusingArgumentNameAnyStubProtocolVoidCalled: Bool { return mAnyConfusingArgumentNameAnyStubProtocolVoidCallsCount > 0 } var mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedAnyConfusingArgumentName: (any StubProtocol)? var mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedInvocations: [(any StubProtocol)] = [] var mAnyConfusingArgumentNameAnyStubProtocolVoidClosure: ((any StubProtocol) -> Void)? func m(anyConfusingArgumentName: any StubProtocol) { mAnyConfusingArgumentNameAnyStubProtocolVoidCallsCount += 1 mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedAnyConfusingArgumentName = anyConfusingArgumentName mAnyConfusingArgumentNameAnyStubProtocolVoidReceivedInvocations.append(anyConfusingArgumentName) mAnyConfusingArgumentNameAnyStubProtocolVoidClosure?(anyConfusingArgumentName) } //MARK: - n var nXEscapingAnyStubProtocolVoidVoidCallsCount = 0 var nXEscapingAnyStubProtocolVoidVoidCalled: Bool { return nXEscapingAnyStubProtocolVoidVoidCallsCount > 0 } var nXEscapingAnyStubProtocolVoidVoidReceivedX: ((((any StubProtocol)?) -> Void))? var nXEscapingAnyStubProtocolVoidVoidReceivedInvocations: [((((any StubProtocol)?) -> Void))] = [] var nXEscapingAnyStubProtocolVoidVoidClosure: ((@escaping ((any StubProtocol)?) -> Void) -> Void)? func n(x: @escaping ((any StubProtocol)?) -> Void) { nXEscapingAnyStubProtocolVoidVoidCallsCount += 1 nXEscapingAnyStubProtocolVoidVoidReceivedX = x nXEscapingAnyStubProtocolVoidVoidReceivedInvocations.append(x) nXEscapingAnyStubProtocolVoidVoidClosure?(x) } //MARK: - p var pXAnyStubWithAnyNameProtocolVoidCallsCount = 0 var pXAnyStubWithAnyNameProtocolVoidCalled: Bool { return pXAnyStubWithAnyNameProtocolVoidCallsCount > 0 } var pXAnyStubWithAnyNameProtocolVoidReceivedX: (any StubWithAnyNameProtocol)? var pXAnyStubWithAnyNameProtocolVoidReceivedInvocations: [(any StubWithAnyNameProtocol)?] = [] var pXAnyStubWithAnyNameProtocolVoidClosure: (((any StubWithAnyNameProtocol)?) -> Void)? func p(_ x: (any StubWithAnyNameProtocol)?) { pXAnyStubWithAnyNameProtocolVoidCallsCount += 1 pXAnyStubWithAnyNameProtocolVoidReceivedX = x pXAnyStubWithAnyNameProtocolVoidReceivedInvocations.append(x) pXAnyStubWithAnyNameProtocolVoidClosure?(x) } //MARK: - q var qAnyStubProtocolCallsCount = 0 var qAnyStubProtocolCalled: Bool { return qAnyStubProtocolCallsCount > 0 } var qAnyStubProtocolReturnValue: (any StubProtocol)! var qAnyStubProtocolClosure: (() -> any StubProtocol)? func q() -> any StubProtocol { qAnyStubProtocolCallsCount += 1 if let qAnyStubProtocolClosure = qAnyStubProtocolClosure { return qAnyStubProtocolClosure() } else { return qAnyStubProtocolReturnValue } } //MARK: - r var rAnyStubProtocolCallsCount = 0 var rAnyStubProtocolCalled: Bool { return rAnyStubProtocolCallsCount > 0 } var rAnyStubProtocolReturnValue: ((any StubProtocol)?) var rAnyStubProtocolClosure: (() -> (any StubProtocol)?)? func r() -> (any StubProtocol)? { rAnyStubProtocolCallsCount += 1 if let rAnyStubProtocolClosure = rAnyStubProtocolClosure { return rAnyStubProtocolClosure() } else { return rAnyStubProtocolReturnValue } } //MARK: - s var s____AnyStubProtocolCallsCount = 0 var s____AnyStubProtocolCalled: Bool { return s____AnyStubProtocolCallsCount > 0 } var s____AnyStubProtocolReturnValue: ((() -> any StubProtocol))! var s____AnyStubProtocolClosure: (() -> (() -> any StubProtocol))? func s() -> (() -> any StubProtocol) { s____AnyStubProtocolCallsCount += 1 if let s____AnyStubProtocolClosure = s____AnyStubProtocolClosure { return s____AnyStubProtocolClosure() } else { return s____AnyStubProtocolReturnValue } } //MARK: - t var t____AnyStubProtocolCallsCount = 0 var t____AnyStubProtocolCalled: Bool { return t____AnyStubProtocolCallsCount > 0 } var t____AnyStubProtocolReturnValue: ((() -> (any StubProtocol)?))! var t____AnyStubProtocolClosure: (() -> (() -> (any StubProtocol)?))? func t() -> (() -> (any StubProtocol)?) { t____AnyStubProtocolCallsCount += 1 if let t____AnyStubProtocolClosure = t____AnyStubProtocolClosure { return t____AnyStubProtocolClosure() } else { return t____AnyStubProtocolReturnValue } } //MARK: - u var u_IntAnyStubProtocolCallsCount = 0 var u_IntAnyStubProtocolCalled: Bool { return u_IntAnyStubProtocolCallsCount > 0 } var u_IntAnyStubProtocolReturnValue: ((Int, () -> (any StubProtocol)?))! var u_IntAnyStubProtocolClosure: (() -> (Int, () -> (any StubProtocol)?))? func u() -> (Int, () -> (any StubProtocol)?) { u_IntAnyStubProtocolCallsCount += 1 if let u_IntAnyStubProtocolClosure = u_IntAnyStubProtocolClosure { return u_IntAnyStubProtocolClosure() } else { return u_IntAnyStubProtocolReturnValue } } //MARK: - v var v_IntAnyStubProtocolCallsCount = 0 var v_IntAnyStubProtocolCalled: Bool { return v_IntAnyStubProtocolCallsCount > 0 } var v_IntAnyStubProtocolReturnValue: ((Int, (() -> any StubProtocol)?))! var v_IntAnyStubProtocolClosure: (() -> (Int, (() -> any StubProtocol)?))? func v() -> (Int, (() -> any StubProtocol)?) { v_IntAnyStubProtocolCallsCount += 1 if let v_IntAnyStubProtocolClosure = v_IntAnyStubProtocolClosure { return v_IntAnyStubProtocolClosure() } else { return v_IntAnyStubProtocolReturnValue } } //MARK: - w var w_AnyStubProtocolCallsCount = 0 var w_AnyStubProtocolCalled: Bool { return w_AnyStubProtocolCallsCount > 0 } var w_AnyStubProtocolReturnValue: ([(any StubProtocol)?])! var w_AnyStubProtocolClosure: (() -> [(any StubProtocol)?])? func w() -> [(any StubProtocol)?] { w_AnyStubProtocolCallsCount += 1 if let w_AnyStubProtocolClosure = w_AnyStubProtocolClosure { return w_AnyStubProtocolClosure() } else { return w_AnyStubProtocolReturnValue } } //MARK: - x var xStringAnyStubProtocolCallsCount = 0 var xStringAnyStubProtocolCalled: Bool { return xStringAnyStubProtocolCallsCount > 0 } var xStringAnyStubProtocolReturnValue: ([String: (any StubProtocol)?])! var xStringAnyStubProtocolClosure: (() -> [String: (any StubProtocol)?])? func x() -> [String: (any StubProtocol)?] { xStringAnyStubProtocolCallsCount += 1 if let xStringAnyStubProtocolClosure = xStringAnyStubProtocolClosure { return xStringAnyStubProtocolClosure() } else { return xStringAnyStubProtocolReturnValue } } //MARK: - y var y_AnyStubProtocolAnyStubProtocolCallsCount = 0 var y_AnyStubProtocolAnyStubProtocolCalled: Bool { return y_AnyStubProtocolAnyStubProtocolCallsCount > 0 } var y_AnyStubProtocolAnyStubProtocolReturnValue: ((any StubProtocol, (any StubProtocol)?))! var y_AnyStubProtocolAnyStubProtocolClosure: (() -> (any StubProtocol, (any StubProtocol)?))? func y() -> (any StubProtocol, (any StubProtocol)?) { y_AnyStubProtocolAnyStubProtocolCallsCount += 1 if let y_AnyStubProtocolAnyStubProtocolClosure = y_AnyStubProtocolAnyStubProtocolClosure { return y_AnyStubProtocolAnyStubProtocolClosure() } else { return y_AnyStubProtocolAnyStubProtocolReturnValue } } //MARK: - z var zAnyStubProtocolCustomStringConvertibleCallsCount = 0 var zAnyStubProtocolCustomStringConvertibleCalled: Bool { return zAnyStubProtocolCustomStringConvertibleCallsCount > 0 } var zAnyStubProtocolCustomStringConvertibleReturnValue: (any StubProtocol & CustomStringConvertible)! var zAnyStubProtocolCustomStringConvertibleClosure: (() -> any StubProtocol & CustomStringConvertible)? func z() -> any StubProtocol & CustomStringConvertible { zAnyStubProtocolCustomStringConvertibleCallsCount += 1 if let zAnyStubProtocolCustomStringConvertibleClosure = zAnyStubProtocolCustomStringConvertibleClosure { return zAnyStubProtocolCustomStringConvertibleClosure() } else { return zAnyStubProtocolCustomStringConvertibleReturnValue } } } class AnyProtocolWithOptionalsMock: AnyProtocolWithOptionals { var a: [any StubProtocol]? var b: [Result] = [] var c: (Int, [(any StubProtocol)?])? var d: (Int, (any StubProtocol)?) { get { return underlyingD } set(value) { underlyingD = value } } var underlyingD: ((Int, (any StubProtocol)?))! var e: (Int, (any StubProtocol)?)? var f: (Int, [any StubProtocol]?)? var j: (anyInteger: Int, anyArray: [any StubProtocol]?)? //MARK: - g var gGStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount = 0 var gGStringHandlerEscapingAnyStubProtocolVoidBoolCalled: Bool { return gGStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount > 0 } var gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments: (g: String, handler: ([any StubProtocol]?) -> Void)? var gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations: [(g: String, handler: ([any StubProtocol]?) -> Void)] = [] var gGStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue: Bool! var gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure: ((String, @escaping ([any StubProtocol]?) -> Void) -> Bool)? func g(_ g: String, handler: @escaping ([any StubProtocol]?) -> Void) -> Bool { gGStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount += 1 gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments = (g: g, handler: handler) gGStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations.append((g: g, handler: handler)) if let gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure = gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure { return gGStringHandlerEscapingAnyStubProtocolVoidBoolClosure(g, handler) } else { return gGStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue } } //MARK: - h var hHStringHandlerEscapingStubProtocolVoidBoolCallsCount = 0 var hHStringHandlerEscapingStubProtocolVoidBoolCalled: Bool { return hHStringHandlerEscapingStubProtocolVoidBoolCallsCount > 0 } var hHStringHandlerEscapingStubProtocolVoidBoolReceivedArguments: (h: String, handler: ([StubProtocol]) -> Void)? var hHStringHandlerEscapingStubProtocolVoidBoolReceivedInvocations: [(h: String, handler: ([StubProtocol]) -> Void)] = [] var hHStringHandlerEscapingStubProtocolVoidBoolReturnValue: Bool! var hHStringHandlerEscapingStubProtocolVoidBoolClosure: ((String, @escaping ([StubProtocol]) -> Void) -> Bool)? func h(_ h: String, handler: @escaping ([StubProtocol]) -> Void) -> Bool { hHStringHandlerEscapingStubProtocolVoidBoolCallsCount += 1 hHStringHandlerEscapingStubProtocolVoidBoolReceivedArguments = (h: h, handler: handler) hHStringHandlerEscapingStubProtocolVoidBoolReceivedInvocations.append((h: h, handler: handler)) if let hHStringHandlerEscapingStubProtocolVoidBoolClosure = hHStringHandlerEscapingStubProtocolVoidBoolClosure { return hHStringHandlerEscapingStubProtocolVoidBoolClosure(h, handler) } else { return hHStringHandlerEscapingStubProtocolVoidBoolReturnValue } } //MARK: - i var iIStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount = 0 var iIStringHandlerEscapingAnyStubProtocolVoidBoolCalled: Bool { return iIStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount > 0 } var iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments: (i: String, handler: ([(any StubProtocol)?]) -> Void)? var iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations: [(i: String, handler: ([(any StubProtocol)?]) -> Void)] = [] var iIStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue: Bool! var iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure: ((String, @escaping ([(any StubProtocol)?]) -> Void) -> Bool)? func i(_ i: String, handler: @escaping ([(any StubProtocol)?]) -> Void) -> Bool { iIStringHandlerEscapingAnyStubProtocolVoidBoolCallsCount += 1 iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedArguments = (i: i, handler: handler) iIStringHandlerEscapingAnyStubProtocolVoidBoolReceivedInvocations.append((i: i, handler: handler)) if let iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure = iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure { return iIStringHandlerEscapingAnyStubProtocolVoidBoolClosure(i, handler) } else { return iIStringHandlerEscapingAnyStubProtocolVoidBoolReturnValue } } } class AsyncProtocolMock: AsyncProtocol { //MARK: - callAsync var callAsyncParameterIntStringCallsCount = 0 var callAsyncParameterIntStringCalled: Bool { return callAsyncParameterIntStringCallsCount > 0 } var callAsyncParameterIntStringReceivedParameter: (Int)? var callAsyncParameterIntStringReceivedInvocations: [(Int)] = [] var callAsyncParameterIntStringReturnValue: String! var callAsyncParameterIntStringClosure: ((Int) async -> String)? @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func callAsync(parameter: Int) async -> String { callAsyncParameterIntStringCallsCount += 1 callAsyncParameterIntStringReceivedParameter = parameter callAsyncParameterIntStringReceivedInvocations.append(parameter) if let callAsyncParameterIntStringClosure = callAsyncParameterIntStringClosure { return await callAsyncParameterIntStringClosure(parameter) } else { return callAsyncParameterIntStringReturnValue } } //MARK: - callAsyncAndThrow var callAsyncAndThrowParameterIntStringThrowableError: (any Error)? var callAsyncAndThrowParameterIntStringCallsCount = 0 var callAsyncAndThrowParameterIntStringCalled: Bool { return callAsyncAndThrowParameterIntStringCallsCount > 0 } var callAsyncAndThrowParameterIntStringReceivedParameter: (Int)? var callAsyncAndThrowParameterIntStringReceivedInvocations: [(Int)] = [] var callAsyncAndThrowParameterIntStringReturnValue: String! var callAsyncAndThrowParameterIntStringClosure: ((Int) async throws -> String)? func callAsyncAndThrow(parameter: Int) async throws -> String { callAsyncAndThrowParameterIntStringCallsCount += 1 callAsyncAndThrowParameterIntStringReceivedParameter = parameter callAsyncAndThrowParameterIntStringReceivedInvocations.append(parameter) if let error = callAsyncAndThrowParameterIntStringThrowableError { throw error } if let callAsyncAndThrowParameterIntStringClosure = callAsyncAndThrowParameterIntStringClosure { return try await callAsyncAndThrowParameterIntStringClosure(parameter) } else { return callAsyncAndThrowParameterIntStringReturnValue } } //MARK: - callAsyncVoid var callAsyncVoidParameterIntVoidCallsCount = 0 var callAsyncVoidParameterIntVoidCalled: Bool { return callAsyncVoidParameterIntVoidCallsCount > 0 } var callAsyncVoidParameterIntVoidReceivedParameter: (Int)? var callAsyncVoidParameterIntVoidReceivedInvocations: [(Int)] = [] var callAsyncVoidParameterIntVoidClosure: ((Int) async -> Void)? func callAsyncVoid(parameter: Int) async { callAsyncVoidParameterIntVoidCallsCount += 1 callAsyncVoidParameterIntVoidReceivedParameter = parameter callAsyncVoidParameterIntVoidReceivedInvocations.append(parameter) await callAsyncVoidParameterIntVoidClosure?(parameter) } //MARK: - callAsyncAndThrowVoid var callAsyncAndThrowVoidParameterIntVoidThrowableError: (any Error)? var callAsyncAndThrowVoidParameterIntVoidCallsCount = 0 var callAsyncAndThrowVoidParameterIntVoidCalled: Bool { return callAsyncAndThrowVoidParameterIntVoidCallsCount > 0 } var callAsyncAndThrowVoidParameterIntVoidReceivedParameter: (Int)? var callAsyncAndThrowVoidParameterIntVoidReceivedInvocations: [(Int)] = [] var callAsyncAndThrowVoidParameterIntVoidClosure: ((Int) async throws -> Void)? func callAsyncAndThrowVoid(parameter: Int) async throws { callAsyncAndThrowVoidParameterIntVoidCallsCount += 1 callAsyncAndThrowVoidParameterIntVoidReceivedParameter = parameter callAsyncAndThrowVoidParameterIntVoidReceivedInvocations.append(parameter) if let error = callAsyncAndThrowVoidParameterIntVoidThrowableError { throw error } try await callAsyncAndThrowVoidParameterIntVoidClosure?(parameter) } } class AsyncThrowingVariablesProtocolMock: AsyncThrowingVariablesProtocol { var titleCallsCount = 0 var titleCalled: Bool { return titleCallsCount > 0 } var title: String? { get async throws { titleCallsCount += 1 if let error = titleThrowableError { throw error } if let titleClosure = titleClosure { return try await titleClosure() } else { return underlyingTitle } } } var underlyingTitle: String? var titleThrowableError: Error? var titleClosure: (() async throws -> String?)? var firstNameCallsCount = 0 var firstNameCalled: Bool { return firstNameCallsCount > 0 } var firstName: String { get async throws { firstNameCallsCount += 1 if let error = firstNameThrowableError { throw error } if let firstNameClosure = firstNameClosure { return try await firstNameClosure() } else { return underlyingFirstName } } } var underlyingFirstName: String! var firstNameThrowableError: Error? var firstNameClosure: (() async throws -> String)? } class AsyncVariablesProtocolMock: AsyncVariablesProtocol { var titleCallsCount = 0 var titleCalled: Bool { return titleCallsCount > 0 } var title: String? { get async { titleCallsCount += 1 if let titleClosure = titleClosure { return await titleClosure() } else { return underlyingTitle } } } var underlyingTitle: String? var titleClosure: (() async -> String?)? var firstNameCallsCount = 0 var firstNameCalled: Bool { return firstNameCallsCount > 0 } var firstName: String { get async { firstNameCallsCount += 1 if let firstNameClosure = firstNameClosure { return await firstNameClosure() } else { return underlyingFirstName } } } var underlyingFirstName: String! var firstNameClosure: (() async -> String)? } class BasicProtocolMock: BasicProtocol { //MARK: - loadConfiguration var loadConfigurationStringCallsCount = 0 var loadConfigurationStringCalled: Bool { return loadConfigurationStringCallsCount > 0 } var loadConfigurationStringReturnValue: String? var loadConfigurationStringClosure: (() -> String?)? func loadConfiguration() -> String? { loadConfigurationStringCallsCount += 1 if let loadConfigurationStringClosure = loadConfigurationStringClosure { return loadConfigurationStringClosure() } else { return loadConfigurationStringReturnValue } } //MARK: - save var saveConfigurationStringVoidCallsCount = 0 var saveConfigurationStringVoidCalled: Bool { return saveConfigurationStringVoidCallsCount > 0 } var saveConfigurationStringVoidReceivedConfiguration: (String)? var saveConfigurationStringVoidReceivedInvocations: [(String)] = [] var saveConfigurationStringVoidClosure: ((String) -> Void)? func save(configuration: String) { saveConfigurationStringVoidCallsCount += 1 saveConfigurationStringVoidReceivedConfiguration = configuration saveConfigurationStringVoidReceivedInvocations.append(configuration) saveConfigurationStringVoidClosure?(configuration) } } class ClosureProtocolMock: ClosureProtocol { //MARK: - setClosure var setClosureClosureEscapingVoidVoidCallsCount = 0 var setClosureClosureEscapingVoidVoidCalled: Bool { return setClosureClosureEscapingVoidVoidCallsCount > 0 } var setClosureClosureEscapingVoidVoidReceivedClosure: ((() -> Void))? var setClosureClosureEscapingVoidVoidReceivedInvocations: [((() -> Void))] = [] var setClosureClosureEscapingVoidVoidClosure: ((@escaping () -> Void) -> Void)? func setClosure(_ closure: @escaping () -> Void) { setClosureClosureEscapingVoidVoidCallsCount += 1 setClosureClosureEscapingVoidVoidReceivedClosure = closure setClosureClosureEscapingVoidVoidReceivedInvocations.append(closure) setClosureClosureEscapingVoidVoidClosure?(closure) } } class ClosureWithTwoParametersProtocolMock: ClosureWithTwoParametersProtocol { //MARK: - setClosure var setClosureClosureEscapingStringIntVoidVoidCallsCount = 0 var setClosureClosureEscapingStringIntVoidVoidCalled: Bool { return setClosureClosureEscapingStringIntVoidVoidCallsCount > 0 } var setClosureClosureEscapingStringIntVoidVoidReceivedClosure: (((String, Int) -> Void))? var setClosureClosureEscapingStringIntVoidVoidReceivedInvocations: [(((String, Int) -> Void))] = [] var setClosureClosureEscapingStringIntVoidVoidClosure: ((@escaping (String, Int) -> Void) -> Void)? func setClosure(closure: (@escaping (String, Int) -> Void)) { setClosureClosureEscapingStringIntVoidVoidCallsCount += 1 setClosureClosureEscapingStringIntVoidVoidReceivedClosure = closure setClosureClosureEscapingStringIntVoidVoidReceivedInvocations.append(closure) setClosureClosureEscapingStringIntVoidVoidClosure?(closure) } } class CurrencyPresenterMock: CurrencyPresenter { //MARK: - showSourceCurrency var showSourceCurrencyCurrencyStringVoidCallsCount = 0 var showSourceCurrencyCurrencyStringVoidCalled: Bool { return showSourceCurrencyCurrencyStringVoidCallsCount > 0 } var showSourceCurrencyCurrencyStringVoidReceivedCurrency: (String)? var showSourceCurrencyCurrencyStringVoidReceivedInvocations: [(String)] = [] var showSourceCurrencyCurrencyStringVoidClosure: ((String) -> Void)? func showSourceCurrency(_ currency: String) { showSourceCurrencyCurrencyStringVoidCallsCount += 1 showSourceCurrencyCurrencyStringVoidReceivedCurrency = currency showSourceCurrencyCurrencyStringVoidReceivedInvocations.append(currency) showSourceCurrencyCurrencyStringVoidClosure?(currency) } } class ExampleVarargMock: ExampleVararg { //MARK: - string var stringKeyStringArgsCVarArgStringCallsCount = 0 var stringKeyStringArgsCVarArgStringCalled: Bool { return stringKeyStringArgsCVarArgStringCallsCount > 0 } var stringKeyStringArgsCVarArgStringReceivedArguments: (key: String, args: [CVarArg])? var stringKeyStringArgsCVarArgStringReceivedInvocations: [(key: String, args: [CVarArg])] = [] var stringKeyStringArgsCVarArgStringReturnValue: String! var stringKeyStringArgsCVarArgStringClosure: ((String, CVarArg...) -> String)? func string(key: String, args: CVarArg...) -> String { stringKeyStringArgsCVarArgStringCallsCount += 1 stringKeyStringArgsCVarArgStringReceivedArguments = (key: key, args: args) stringKeyStringArgsCVarArgStringReceivedInvocations.append((key: key, args: args)) if let stringKeyStringArgsCVarArgStringClosure = stringKeyStringArgsCVarArgStringClosure { return stringKeyStringArgsCVarArgStringClosure(key, args) } else { return stringKeyStringArgsCVarArgStringReturnValue } } } class ExampleVarargFourMock: ExampleVarargFour { //MARK: - toto var totoArgStringAnyCollectionVoidVoidCallsCount = 0 var totoArgStringAnyCollectionVoidVoidCalled: Bool { return totoArgStringAnyCollectionVoidVoidCallsCount > 0 } var totoArgStringAnyCollectionVoidVoidClosure: (((String, any Collection...) -> Void) -> Void)? func toto(arg: ((String, any Collection...) -> Void)) { totoArgStringAnyCollectionVoidVoidCallsCount += 1 totoArgStringAnyCollectionVoidVoidClosure?(arg) } } class ExampleVarargThreeMock: ExampleVarargThree { //MARK: - toto var totoArgStringAnyCollectionAnyCollectionVoidCallsCount = 0 var totoArgStringAnyCollectionAnyCollectionVoidCalled: Bool { return totoArgStringAnyCollectionAnyCollectionVoidCallsCount > 0 } var totoArgStringAnyCollectionAnyCollectionVoidClosure: (((String, any Collection...) -> any Collection) -> Void)? func toto(arg: ((String, any Collection...) -> any Collection)) { totoArgStringAnyCollectionAnyCollectionVoidCallsCount += 1 totoArgStringAnyCollectionAnyCollectionVoidClosure?(arg) } } class ExampleVarargTwoMock: ExampleVarargTwo { //MARK: - toto var totoArgsAnyStubWithSomeNameProtocolVoidCallsCount = 0 var totoArgsAnyStubWithSomeNameProtocolVoidCalled: Bool { return totoArgsAnyStubWithSomeNameProtocolVoidCallsCount > 0 } var totoArgsAnyStubWithSomeNameProtocolVoidReceivedArgs: ([(any StubWithSomeNameProtocol)])? var totoArgsAnyStubWithSomeNameProtocolVoidReceivedInvocations: [([(any StubWithSomeNameProtocol)])] = [] var totoArgsAnyStubWithSomeNameProtocolVoidClosure: (([(any StubWithSomeNameProtocol)]) -> Void)? func toto(args: any StubWithSomeNameProtocol...) { totoArgsAnyStubWithSomeNameProtocolVoidCallsCount += 1 totoArgsAnyStubWithSomeNameProtocolVoidReceivedArgs = args totoArgsAnyStubWithSomeNameProtocolVoidReceivedInvocations.append(args) totoArgsAnyStubWithSomeNameProtocolVoidClosure?(args) } } class ExtendableProtocolMock: ExtendableProtocol { var canReport: Bool { get { return underlyingCanReport } set(value) { underlyingCanReport = value } } var underlyingCanReport: (Bool)! //MARK: - report var reportMessageStringVoidCallsCount = 0 var reportMessageStringVoidCalled: Bool { return reportMessageStringVoidCallsCount > 0 } var reportMessageStringVoidReceivedMessage: (String)? var reportMessageStringVoidReceivedInvocations: [(String)] = [] var reportMessageStringVoidClosure: ((String) -> Void)? func report(message: String) { reportMessageStringVoidCallsCount += 1 reportMessageStringVoidReceivedMessage = message reportMessageStringVoidReceivedInvocations.append(message) reportMessageStringVoidClosure?(message) } } class FunctionWithAttributesMock: FunctionWithAttributes { //MARK: - callOneAttribute var callOneAttributeStringCallsCount = 0 var callOneAttributeStringCalled: Bool { return callOneAttributeStringCallsCount > 0 } var callOneAttributeStringReturnValue: String! var callOneAttributeStringClosure: (() -> String)? @discardableResult func callOneAttribute() -> String { callOneAttributeStringCallsCount += 1 if let callOneAttributeStringClosure = callOneAttributeStringClosure { return callOneAttributeStringClosure() } else { return callOneAttributeStringReturnValue } } //MARK: - callTwoAttributes var callTwoAttributesIntCallsCount = 0 var callTwoAttributesIntCalled: Bool { return callTwoAttributesIntCallsCount > 0 } var callTwoAttributesIntReturnValue: Int! var callTwoAttributesIntClosure: (() -> Int)? @available(macOS 10.15, *) @discardableResult func callTwoAttributes() -> Int { callTwoAttributesIntCallsCount += 1 if let callTwoAttributesIntClosure = callTwoAttributesIntClosure { return callTwoAttributesIntClosure() } else { return callTwoAttributesIntReturnValue } } //MARK: - callRepeatedAttributes var callRepeatedAttributesBoolCallsCount = 0 var callRepeatedAttributesBoolCalled: Bool { return callRepeatedAttributesBoolCallsCount > 0 } var callRepeatedAttributesBoolReturnValue: Bool! var callRepeatedAttributesBoolClosure: (() -> Bool)? @available(iOS 13.0, *) @available(macOS 10.15, *) @discardableResult func callRepeatedAttributes() -> Bool { callRepeatedAttributesBoolCallsCount += 1 if let callRepeatedAttributesBoolClosure = callRepeatedAttributesBoolClosure { return callRepeatedAttributesBoolClosure() } else { return callRepeatedAttributesBoolReturnValue } } } class FunctionWithClosureReturnTypeMock: FunctionWithClosureReturnType { //MARK: - get var get____VoidCallsCount = 0 var get____VoidCalled: Bool { return get____VoidCallsCount > 0 } var get____VoidReturnValue: ((() -> Void))! var get____VoidClosure: (() -> (() -> Void))? func get() -> (() -> Void) { get____VoidCallsCount += 1 if let get____VoidClosure = get____VoidClosure { return get____VoidClosure() } else { return get____VoidReturnValue } } //MARK: - getOptional var getOptional_____VoidCallsCount = 0 var getOptional_____VoidCalled: Bool { return getOptional_____VoidCallsCount > 0 } var getOptional_____VoidReturnValue: ((() -> Void)?) var getOptional_____VoidClosure: (() -> ((() -> Void)?))? func getOptional() -> ((() -> Void)?) { getOptional_____VoidCallsCount += 1 if let getOptional_____VoidClosure = getOptional_____VoidClosure { return getOptional_____VoidClosure() } else { return getOptional_____VoidReturnValue } } } class FunctionWithMultilineDeclarationMock: FunctionWithMultilineDeclaration { //MARK: - start var startCarStringOfModelStringVoidCallsCount = 0 var startCarStringOfModelStringVoidCalled: Bool { return startCarStringOfModelStringVoidCallsCount > 0 } var startCarStringOfModelStringVoidReceivedArguments: (car: String, model: String)? var startCarStringOfModelStringVoidReceivedInvocations: [(car: String, model: String)] = [] var startCarStringOfModelStringVoidClosure: ((String, String) -> Void)? func start(car: String, of model: String) { startCarStringOfModelStringVoidCallsCount += 1 startCarStringOfModelStringVoidReceivedArguments = (car: car, model: model) startCarStringOfModelStringVoidReceivedInvocations.append((car: car, model: model)) startCarStringOfModelStringVoidClosure?(car, model) } } class FunctionWithNullableCompletionThatHasNullableAnyParameterProtocolMock: FunctionWithNullableCompletionThatHasNullableAnyParameterProtocol { //MARK: - add var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCallsCount = 0 var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCalled: Bool { return addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCallsCount > 0 } var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedArguments: (request: Int, completionHandler: ((((any Error)?) -> Void))?)? var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedInvocations: [(request: Int, completionHandler: ((((any Error)?) -> Void))?)] = [] var addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidClosure: ((Int, ((((any Error)?) -> Void))?) -> Void)? func add(_ request: Int, withCompletionHandler completionHandler: ((((any Error)?) -> Void))?) { addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidCallsCount += 1 addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedArguments = (request: request, completionHandler: completionHandler) addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidReceivedInvocations.append((request: request, completionHandler: completionHandler)) addRequestIntWithCompletionHandlerCompletionHandlerAnyErrorVoidVoidClosure?(request, completionHandler) } } class HouseProtocolMock: HouseProtocol { var aPublisher: AnyPublisher? var bPublisher: AnyPublisher<(any PersonProtocol)?, Never>? var cPublisher: CurrentValueSubject<(any PersonProtocol)?, Never>? var dPublisher: PassthroughSubject<(any PersonProtocol)?, Never>? var e1Publisher: GenericType<(any PersonProtocol)?, Never, Never>? var e2Publisher: GenericType? var e3Publisher: GenericType? var e4Publisher: GenericType<(any PersonProtocol)?, (any PersonProtocol)?, (any PersonProtocol)?>? var f1Publisher: GenericType? var f2Publisher: GenericType? var f3Publisher: GenericType? var f4Publisher: GenericType? } class ImplicitlyUnwrappedOptionalReturnValueProtocolMock: ImplicitlyUnwrappedOptionalReturnValueProtocol { //MARK: - implicitReturn var implicitReturnStringCallsCount = 0 var implicitReturnStringCalled: Bool { return implicitReturnStringCallsCount > 0 } var implicitReturnStringReturnValue: String! var implicitReturnStringClosure: (() -> String)? func implicitReturn() -> String! { implicitReturnStringCallsCount += 1 if let implicitReturnStringClosure = implicitReturnStringClosure { return implicitReturnStringClosure() } else { return implicitReturnStringReturnValue } } } class InitializationProtocolMock: InitializationProtocol { //MARK: - init var initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedArguments: (intParameter: Int, stringParameter: String, optionalParameter: String?)? var initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedInvocations: [(intParameter: Int, stringParameter: String, optionalParameter: String?)] = [] var initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolClosure: ((Int, String, String?) -> Void)? required init(intParameter: Int, stringParameter: String, optionalParameter: String?) { initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedArguments = (intParameter: intParameter, stringParameter: stringParameter, optionalParameter: optionalParameter) initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolReceivedInvocations.append((intParameter: intParameter, stringParameter: stringParameter, optionalParameter: optionalParameter)) initIntParameterIntStringParameterStringOptionalParameterStringInitializationProtocolClosure?(intParameter, stringParameter, optionalParameter) } //MARK: - start var startVoidCallsCount = 0 var startVoidCalled: Bool { return startVoidCallsCount > 0 } var startVoidClosure: (() -> Void)? func start() { startVoidCallsCount += 1 startVoidClosure?() } //MARK: - stop var stopVoidCallsCount = 0 var stopVoidCalled: Bool { return stopVoidCallsCount > 0 } var stopVoidClosure: (() -> Void)? func stop() { stopVoidCallsCount += 1 stopVoidClosure?() } } class MultiClosureProtocolMock: MultiClosureProtocol { //MARK: - setClosure var setClosureNameStringClosureEscapingVoidVoidCallsCount = 0 var setClosureNameStringClosureEscapingVoidVoidCalled: Bool { return setClosureNameStringClosureEscapingVoidVoidCallsCount > 0 } var setClosureNameStringClosureEscapingVoidVoidReceivedArguments: (name: String, closure: () -> Void)? var setClosureNameStringClosureEscapingVoidVoidReceivedInvocations: [(name: String, closure: () -> Void)] = [] var setClosureNameStringClosureEscapingVoidVoidClosure: ((String, @escaping () -> Void) -> Void)? func setClosure(name: String, _ closure: @escaping () -> Void) { setClosureNameStringClosureEscapingVoidVoidCallsCount += 1 setClosureNameStringClosureEscapingVoidVoidReceivedArguments = (name: name, closure: closure) setClosureNameStringClosureEscapingVoidVoidReceivedInvocations.append((name: name, closure: closure)) setClosureNameStringClosureEscapingVoidVoidClosure?(name, closure) } } class MultiExistentialArgumentsClosureProtocolMock: MultiExistentialArgumentsClosureProtocol { //MARK: - execute var executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCallsCount = 0 var executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCalled: Bool { return executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCallsCount > 0 } var executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidClosure: ((((any StubWithSomeNameProtocol)?, (any StubWithSomeNameProtocol)) -> (any StubWithSomeNameProtocol)?) -> Void)? func execute(completion: (((any StubWithSomeNameProtocol)?, (any StubWithSomeNameProtocol)) -> (any StubWithSomeNameProtocol)?)) { executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidCallsCount += 1 executeCompletionAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolAnyStubWithSomeNameProtocolVoidClosure?(completion) } } class MultiNonEscapingClosureProtocolMock: MultiNonEscapingClosureProtocol { //MARK: - executeClosure var executeClosureNameStringClosureVoidVoidCallsCount = 0 var executeClosureNameStringClosureVoidVoidCalled: Bool { return executeClosureNameStringClosureVoidVoidCallsCount > 0 } var executeClosureNameStringClosureVoidVoidClosure: ((String, () -> Void) -> Void)? func executeClosure(name: String, _ closure: () -> Void) { executeClosureNameStringClosureVoidVoidCallsCount += 1 executeClosureNameStringClosureVoidVoidClosure?(name, closure) } } class MultiNullableClosureProtocolMock: MultiNullableClosureProtocol { //MARK: - setClosure var setClosureNameStringClosureVoidVoidCallsCount = 0 var setClosureNameStringClosureVoidVoidCalled: Bool { return setClosureNameStringClosureVoidVoidCallsCount > 0 } var setClosureNameStringClosureVoidVoidReceivedArguments: (name: String, closure: (() -> Void)?)? var setClosureNameStringClosureVoidVoidReceivedInvocations: [(name: String, closure: (() -> Void)?)] = [] var setClosureNameStringClosureVoidVoidClosure: ((String, (() -> Void)?) -> Void)? func setClosure(name: String, _ closure: (() -> Void)?) { setClosureNameStringClosureVoidVoidCallsCount += 1 setClosureNameStringClosureVoidVoidReceivedArguments = (name: name, closure: closure) setClosureNameStringClosureVoidVoidReceivedInvocations.append((name: name, closure: closure)) setClosureNameStringClosureVoidVoidClosure?(name, closure) } } class NonEscapingClosureProtocolMock: NonEscapingClosureProtocol { //MARK: - executeClosure var executeClosureClosureVoidVoidCallsCount = 0 var executeClosureClosureVoidVoidCalled: Bool { return executeClosureClosureVoidVoidCallsCount > 0 } var executeClosureClosureVoidVoidClosure: ((() -> Void) -> Void)? func executeClosure(_ closure: () -> Void) { executeClosureClosureVoidVoidCallsCount += 1 executeClosureClosureVoidVoidClosure?(closure) } } class NullableClosureProtocolMock: NullableClosureProtocol { //MARK: - setClosure var setClosureClosureVoidVoidCallsCount = 0 var setClosureClosureVoidVoidCalled: Bool { return setClosureClosureVoidVoidCallsCount > 0 } var setClosureClosureVoidVoidReceivedClosure: (((() -> Void)))? var setClosureClosureVoidVoidReceivedInvocations: [(((() -> Void)))?] = [] var setClosureClosureVoidVoidClosure: (((() -> Void)?) -> Void)? func setClosure(_ closure: (() -> Void)?) { setClosureClosureVoidVoidCallsCount += 1 setClosureClosureVoidVoidReceivedClosure = closure setClosureClosureVoidVoidReceivedInvocations.append(closure) setClosureClosureVoidVoidClosure?(closure) } } public class ProtocolWithMethodWithGenericParametersMock: ProtocolWithMethodWithGenericParameters { public init() {} //MARK: - execute public var executeParamResultIntErrorResultStringErrorCallsCount = 0 public var executeParamResultIntErrorResultStringErrorCalled: Bool { return executeParamResultIntErrorResultStringErrorCallsCount > 0 } public var executeParamResultIntErrorResultStringErrorReceivedParam: (Result)? public var executeParamResultIntErrorResultStringErrorReceivedInvocations: [(Result)] = [] public var executeParamResultIntErrorResultStringErrorReturnValue: Result! public var executeParamResultIntErrorResultStringErrorClosure: ((Result) -> Result)? public func execute(param: Result) -> Result { executeParamResultIntErrorResultStringErrorCallsCount += 1 executeParamResultIntErrorResultStringErrorReceivedParam = param executeParamResultIntErrorResultStringErrorReceivedInvocations.append(param) if let executeParamResultIntErrorResultStringErrorClosure = executeParamResultIntErrorResultStringErrorClosure { return executeParamResultIntErrorResultStringErrorClosure(param) } else { return executeParamResultIntErrorResultStringErrorReturnValue } } } public class ProtocolWithMethodWithInoutParameterMock: ProtocolWithMethodWithInoutParameter { public init() {} //MARK: - execute public var executeParamInoutStringVoidCallsCount = 0 public var executeParamInoutStringVoidCalled: Bool { return executeParamInoutStringVoidCallsCount > 0 } public var executeParamInoutStringVoidReceivedParam: (String)? public var executeParamInoutStringVoidReceivedInvocations: [(String)] = [] public var executeParamInoutStringVoidClosure: ((inout String) -> Void)? public func execute(param: inout String) { executeParamInoutStringVoidCallsCount += 1 executeParamInoutStringVoidReceivedParam = param executeParamInoutStringVoidReceivedInvocations.append(param) executeParamInoutStringVoidClosure?(¶m) } //MARK: - execute public var executeParamInoutStringBarIntVoidCallsCount = 0 public var executeParamInoutStringBarIntVoidCalled: Bool { return executeParamInoutStringBarIntVoidCallsCount > 0 } public var executeParamInoutStringBarIntVoidReceivedArguments: (param: String, bar: Int)? public var executeParamInoutStringBarIntVoidReceivedInvocations: [(param: String, bar: Int)] = [] public var executeParamInoutStringBarIntVoidClosure: ((inout String, Int) -> Void)? public func execute(param: inout String, bar: Int) { executeParamInoutStringBarIntVoidCallsCount += 1 executeParamInoutStringBarIntVoidReceivedArguments = (param: param, bar: bar) executeParamInoutStringBarIntVoidReceivedInvocations.append((param: param, bar: bar)) executeParamInoutStringBarIntVoidClosure?(¶m, bar) } } public class ProtocolWithOverridesMock: ProtocolWithOverrides { public init() {} //MARK: - doSomething public var doSomethingDataIntStringCallsCount = 0 public var doSomethingDataIntStringCalled: Bool { return doSomethingDataIntStringCallsCount > 0 } public var doSomethingDataIntStringReceivedData: (Int)? public var doSomethingDataIntStringReceivedInvocations: [(Int)] = [] public var doSomethingDataIntStringReturnValue: [String]! public var doSomethingDataIntStringClosure: ((Int) -> [String])? public func doSomething(_ data: Int) -> [String] { doSomethingDataIntStringCallsCount += 1 doSomethingDataIntStringReceivedData = data doSomethingDataIntStringReceivedInvocations.append(data) if let doSomethingDataIntStringClosure = doSomethingDataIntStringClosure { return doSomethingDataIntStringClosure(data) } else { return doSomethingDataIntStringReturnValue } } //MARK: - doSomething public var doSomethingDataStringStringCallsCount = 0 public var doSomethingDataStringStringCalled: Bool { return doSomethingDataStringStringCallsCount > 0 } public var doSomethingDataStringStringReceivedData: (String)? public var doSomethingDataStringStringReceivedInvocations: [(String)] = [] public var doSomethingDataStringStringReturnValue: [String]! public var doSomethingDataStringStringClosure: ((String) -> [String])? public func doSomething(_ data: String) -> [String] { doSomethingDataStringStringCallsCount += 1 doSomethingDataStringStringReceivedData = data doSomethingDataStringStringReceivedInvocations.append(data) if let doSomethingDataStringStringClosure = doSomethingDataStringStringClosure { return doSomethingDataStringStringClosure(data) } else { return doSomethingDataStringStringReturnValue } } //MARK: - doSomething public var doSomethingDataStringIntCallsCount = 0 public var doSomethingDataStringIntCalled: Bool { return doSomethingDataStringIntCallsCount > 0 } public var doSomethingDataStringIntReceivedData: (String)? public var doSomethingDataStringIntReceivedInvocations: [(String)] = [] public var doSomethingDataStringIntReturnValue: [Int]! public var doSomethingDataStringIntClosure: ((String) -> [Int])? public func doSomething(_ data: String) -> [Int] { doSomethingDataStringIntCallsCount += 1 doSomethingDataStringIntReceivedData = data doSomethingDataStringIntReceivedInvocations.append(data) if let doSomethingDataStringIntClosure = doSomethingDataStringIntClosure { return doSomethingDataStringIntClosure(data) } else { return doSomethingDataStringIntReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntStringCallsCount = 0 public var doSomethingDataString_IntStringCalled: Bool { return doSomethingDataString_IntStringCallsCount > 0 } public var doSomethingDataString_IntStringReceivedData: (String)? public var doSomethingDataString_IntStringReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntStringReturnValue: ([Int], [String])! public var doSomethingDataString_IntStringClosure: ((String) -> ([Int], [String]))? public func doSomething(_ data: String) -> ([Int], [String]) { doSomethingDataString_IntStringCallsCount += 1 doSomethingDataString_IntStringReceivedData = data doSomethingDataString_IntStringReceivedInvocations.append(data) if let doSomethingDataString_IntStringClosure = doSomethingDataString_IntStringClosure { return doSomethingDataString_IntStringClosure(data) } else { return doSomethingDataString_IntStringReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntAnyThrowableError: (any Error)? public var doSomethingDataString_IntAnyCallsCount = 0 public var doSomethingDataString_IntAnyCalled: Bool { return doSomethingDataString_IntAnyCallsCount > 0 } public var doSomethingDataString_IntAnyReceivedData: (String)? public var doSomethingDataString_IntAnyReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntAnyReturnValue: ([Int], [Any])! public var doSomethingDataString_IntAnyClosure: ((String) throws -> ([Int], [Any]))? public func doSomething(_ data: String) throws -> ([Int], [Any]) { doSomethingDataString_IntAnyCallsCount += 1 doSomethingDataString_IntAnyReceivedData = data doSomethingDataString_IntAnyReceivedInvocations.append(data) if let error = doSomethingDataString_IntAnyThrowableError { throw error } if let doSomethingDataString_IntAnyClosure = doSomethingDataString_IntAnyClosure { return try doSomethingDataString_IntAnyClosure(data) } else { return doSomethingDataString_IntAnyReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntStringVoidCallsCount = 0 public var doSomethingDataString_IntStringVoidCalled: Bool { return doSomethingDataString_IntStringVoidCallsCount > 0 } public var doSomethingDataString_IntStringVoidReceivedData: (String)? public var doSomethingDataString_IntStringVoidReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntStringVoidReturnValue: (([Int], [String]) -> Void)! public var doSomethingDataString_IntStringVoidClosure: ((String) -> ([Int], [String]) -> Void)? public func doSomething(_ data: String) -> ([Int], [String]) -> Void { doSomethingDataString_IntStringVoidCallsCount += 1 doSomethingDataString_IntStringVoidReceivedData = data doSomethingDataString_IntStringVoidReceivedInvocations.append(data) if let doSomethingDataString_IntStringVoidClosure = doSomethingDataString_IntStringVoidClosure { return doSomethingDataString_IntStringVoidClosure(data) } else { return doSomethingDataString_IntStringVoidReturnValue } } //MARK: - doSomething public var doSomethingDataString_IntAnyVoidThrowableError: (any Error)? public var doSomethingDataString_IntAnyVoidCallsCount = 0 public var doSomethingDataString_IntAnyVoidCalled: Bool { return doSomethingDataString_IntAnyVoidCallsCount > 0 } public var doSomethingDataString_IntAnyVoidReceivedData: (String)? public var doSomethingDataString_IntAnyVoidReceivedInvocations: [(String)] = [] public var doSomethingDataString_IntAnyVoidReturnValue: (([Int], [Any]) -> Void)! public var doSomethingDataString_IntAnyVoidClosure: ((String) throws -> ([Int], [Any]) -> Void)? public func doSomething(_ data: String) throws -> ([Int], [Any]) -> Void { doSomethingDataString_IntAnyVoidCallsCount += 1 doSomethingDataString_IntAnyVoidReceivedData = data doSomethingDataString_IntAnyVoidReceivedInvocations.append(data) if let error = doSomethingDataString_IntAnyVoidThrowableError { throw error } if let doSomethingDataString_IntAnyVoidClosure = doSomethingDataString_IntAnyVoidClosure { return try doSomethingDataString_IntAnyVoidClosure(data) } else { return doSomethingDataString_IntAnyVoidReturnValue } } } class ReservedWordsProtocolMock: ReservedWordsProtocol { //MARK: - `continue` var continueWithMessageStringStringCallsCount = 0 var continueWithMessageStringStringCalled: Bool { return continueWithMessageStringStringCallsCount > 0 } var continueWithMessageStringStringReceivedMessage: (String)? var continueWithMessageStringStringReceivedInvocations: [(String)] = [] var continueWithMessageStringStringReturnValue: String! var continueWithMessageStringStringClosure: ((String) -> String)? func `continue`(with message: String) -> String { continueWithMessageStringStringCallsCount += 1 continueWithMessageStringStringReceivedMessage = message continueWithMessageStringStringReceivedInvocations.append(message) if let continueWithMessageStringStringClosure = continueWithMessageStringStringClosure { return continueWithMessageStringStringClosure(message) } else { return continueWithMessageStringStringReturnValue } } } class SameShortMethodNamesProtocolMock: SameShortMethodNamesProtocol { //MARK: - start var startCarStringOfModelStringVoidCallsCount = 0 var startCarStringOfModelStringVoidCalled: Bool { return startCarStringOfModelStringVoidCallsCount > 0 } var startCarStringOfModelStringVoidReceivedArguments: (car: String, model: String)? var startCarStringOfModelStringVoidReceivedInvocations: [(car: String, model: String)] = [] var startCarStringOfModelStringVoidClosure: ((String, String) -> Void)? func start(car: String, of model: String) { startCarStringOfModelStringVoidCallsCount += 1 startCarStringOfModelStringVoidReceivedArguments = (car: car, model: model) startCarStringOfModelStringVoidReceivedInvocations.append((car: car, model: model)) startCarStringOfModelStringVoidClosure?(car, model) } //MARK: - start var startPlaneStringOfModelStringVoidCallsCount = 0 var startPlaneStringOfModelStringVoidCalled: Bool { return startPlaneStringOfModelStringVoidCallsCount > 0 } var startPlaneStringOfModelStringVoidReceivedArguments: (plane: String, model: String)? var startPlaneStringOfModelStringVoidReceivedInvocations: [(plane: String, model: String)] = [] var startPlaneStringOfModelStringVoidClosure: ((String, String) -> Void)? func start(plane: String, of model: String) { startPlaneStringOfModelStringVoidCallsCount += 1 startPlaneStringOfModelStringVoidReceivedArguments = (plane: plane, model: model) startPlaneStringOfModelStringVoidReceivedInvocations.append((plane: plane, model: model)) startPlaneStringOfModelStringVoidClosure?(plane, model) } } class SendableProtocolMock: SendableProtocol, @unchecked Sendable { var value: Any { get { return underlyingValue } set(value) { underlyingValue = value } } var underlyingValue: (Any)! } class SendableSendableProtocolMock: SendableSendableProtocol, @unchecked Sendable { var value: Any { get { return underlyingValue } set(value) { underlyingValue = value } } var underlyingValue: (Any)! } class SingleOptionalParameterFunctionMock: SingleOptionalParameterFunction { //MARK: - send var sendMessageStringVoidCallsCount = 0 var sendMessageStringVoidCalled: Bool { return sendMessageStringVoidCallsCount > 0 } var sendMessageStringVoidReceivedMessage: (String)? var sendMessageStringVoidReceivedInvocations: [(String)?] = [] var sendMessageStringVoidClosure: ((String?) -> Void)? func send(message: String?) { sendMessageStringVoidCallsCount += 1 sendMessageStringVoidReceivedMessage = message sendMessageStringVoidReceivedInvocations.append(message) sendMessageStringVoidClosure?(message) } } class SomeProtocolMock: SomeProtocol { //MARK: - a var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCallsCount = 0 var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCalled: Bool { return aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCallsCount > 0 } var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) -> Void)? func a(_ x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) { aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidCallsCount += 1 aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedArguments = (x: x, y: y, z: z) aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidReceivedInvocations.append((x: x, y: y, z: z)) aXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolVoidClosure?(x, y, z) } //MARK: - b var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCallsCount = 0 var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCalled: Bool { return bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCallsCount > 0 } var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedArguments: (x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)? var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedInvocations: [(x: (any StubProtocol)?, y: (any StubProtocol)?, z: any StubProtocol)] = [] var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReturnValue: String! var bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure: (((any StubProtocol)?, (any StubProtocol)?, any StubProtocol) async -> String)? func b(x: (some StubProtocol)?, y: (some StubProtocol)!, z: some StubProtocol) async -> String { bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringCallsCount += 1 bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedArguments = (x: x, y: y, z: z) bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReceivedInvocations.append((x: x, y: y, z: z)) if let bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure = bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure { return await bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringClosure(x, y, z) } else { return bXSomeStubProtocolYSomeStubProtocolZSomeStubProtocolStringReturnValue } } //MARK: - someConfusingFuncName var someConfusingFuncNameXSomeStubProtocolVoidCallsCount = 0 var someConfusingFuncNameXSomeStubProtocolVoidCalled: Bool { return someConfusingFuncNameXSomeStubProtocolVoidCallsCount > 0 } var someConfusingFuncNameXSomeStubProtocolVoidReceivedX: (any StubProtocol)? var someConfusingFuncNameXSomeStubProtocolVoidReceivedInvocations: [(any StubProtocol)] = [] var someConfusingFuncNameXSomeStubProtocolVoidClosure: ((any StubProtocol) -> Void)? func someConfusingFuncName(x: some StubProtocol) { someConfusingFuncNameXSomeStubProtocolVoidCallsCount += 1 someConfusingFuncNameXSomeStubProtocolVoidReceivedX = x someConfusingFuncNameXSomeStubProtocolVoidReceivedInvocations.append(x) someConfusingFuncNameXSomeStubProtocolVoidClosure?(x) } //MARK: - c var cSomeConfusingArgumentNameSomeStubProtocolVoidCallsCount = 0 var cSomeConfusingArgumentNameSomeStubProtocolVoidCalled: Bool { return cSomeConfusingArgumentNameSomeStubProtocolVoidCallsCount > 0 } var cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedSomeConfusingArgumentName: (any StubProtocol)? var cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedInvocations: [(any StubProtocol)] = [] var cSomeConfusingArgumentNameSomeStubProtocolVoidClosure: ((any StubProtocol) -> Void)? func c(someConfusingArgumentName: some StubProtocol) { cSomeConfusingArgumentNameSomeStubProtocolVoidCallsCount += 1 cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedSomeConfusingArgumentName = someConfusingArgumentName cSomeConfusingArgumentNameSomeStubProtocolVoidReceivedInvocations.append(someConfusingArgumentName) cSomeConfusingArgumentNameSomeStubProtocolVoidClosure?(someConfusingArgumentName) } //MARK: - d var dXSomeStubWithSomeNameProtocolVoidCallsCount = 0 var dXSomeStubWithSomeNameProtocolVoidCalled: Bool { return dXSomeStubWithSomeNameProtocolVoidCallsCount > 0 } var dXSomeStubWithSomeNameProtocolVoidReceivedX: (any StubWithSomeNameProtocol)? var dXSomeStubWithSomeNameProtocolVoidReceivedInvocations: [(any StubWithSomeNameProtocol)?] = [] var dXSomeStubWithSomeNameProtocolVoidClosure: (((any StubWithSomeNameProtocol)?) -> Void)? func d(_ x: (some StubWithSomeNameProtocol)?) { dXSomeStubWithSomeNameProtocolVoidCallsCount += 1 dXSomeStubWithSomeNameProtocolVoidReceivedX = x dXSomeStubWithSomeNameProtocolVoidReceivedInvocations.append(x) dXSomeStubWithSomeNameProtocolVoidClosure?(x) } } class StaticMethodProtocolMock: StaticMethodProtocol { static func reset() { //MARK: - staticFunction staticFunctionStringStringCallsCount = 0 staticFunctionStringStringReceived = nil staticFunctionStringStringReceivedInvocations = [] staticFunctionStringStringClosure = nil } //MARK: - staticFunction static var staticFunctionStringStringCallsCount = 0 static var staticFunctionStringStringCalled: Bool { return staticFunctionStringStringCallsCount > 0 } static var staticFunctionStringStringReceived: (String)? static var staticFunctionStringStringReceivedInvocations: [(String)] = [] static var staticFunctionStringStringReturnValue: String! static var staticFunctionStringStringClosure: ((String) -> String)? static func staticFunction(_ arg0: String) -> String { staticFunctionStringStringCallsCount += 1 staticFunctionStringStringReceived = arg0 staticFunctionStringStringReceivedInvocations.append(arg0) if let staticFunctionStringStringClosure = staticFunctionStringStringClosure { return staticFunctionStringStringClosure(arg0) } else { return staticFunctionStringStringReturnValue } } } class SubscriptProtocolMock: SubscriptProtocol { //MARK: - Subscript #1 subscript(arg: Int) -> String { get { fatalError("Subscripts are not fully supported yet") } set { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #2 subscript(arg: T) -> Int { get { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #3 subscript(arg: T) -> String { get async { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #4 subscript(arg: T) -> T? { get { fatalError("Subscripts are not fully supported yet") } set { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #5 subscript(arg: String) -> T? where T : Cancellable { get throws { fatalError("Subscripts are not fully supported yet") } } //MARK: - Subscript #6 subscript(arg2: String) -> T { get throws(CustomError) { fatalError("Subscripts are not fully supported yet") } } } class TestProtocolMock< Value: Sequence, Value3: Collection, Value5: Sequence, Value6: Sequence>: TestProtocol where Value.Element : Collection,Value.Element : Hashable,Value.Element : Comparable,Value3.Element == String,Value5.Element == Int,Value6.Element == Int,Value6.Element : Hashable,Value6.Element : Comparable { typealias Value2 = Int //MARK: - getValue var getValueSequenceCallsCount = 0 var getValueSequenceCalled: Bool { return getValueSequenceCallsCount > 0 } var getValueSequenceReturnValue: Value! var getValueSequenceClosure: (() -> Value)? func getValue() -> Value { getValueSequenceCallsCount += 1 if let getValueSequenceClosure = getValueSequenceClosure { return getValueSequenceClosure() } else { return getValueSequenceReturnValue } } //MARK: - getValue2 var getValue2Value2CallsCount = 0 var getValue2Value2Called: Bool { return getValue2Value2CallsCount > 0 } var getValue2Value2ReturnValue: Value2! var getValue2Value2Closure: (() -> Value2)? func getValue2() -> Value2 { getValue2Value2CallsCount += 1 if let getValue2Value2Closure = getValue2Value2Closure { return getValue2Value2Closure() } else { return getValue2Value2ReturnValue } } //MARK: - getValue3 var getValue3CollectionCallsCount = 0 var getValue3CollectionCalled: Bool { return getValue3CollectionCallsCount > 0 } var getValue3CollectionReturnValue: Value3! var getValue3CollectionClosure: (() -> Value3)? func getValue3() -> Value3 { getValue3CollectionCallsCount += 1 if let getValue3CollectionClosure = getValue3CollectionClosure { return getValue3CollectionClosure() } else { return getValue3CollectionReturnValue } } //MARK: - getValue5 var getValue5SequenceCallsCount = 0 var getValue5SequenceCalled: Bool { return getValue5SequenceCallsCount > 0 } var getValue5SequenceReturnValue: Value5! var getValue5SequenceClosure: (() -> Value5)? func getValue5() -> Value5 { getValue5SequenceCallsCount += 1 if let getValue5SequenceClosure = getValue5SequenceClosure { return getValue5SequenceClosure() } else { return getValue5SequenceReturnValue } } //MARK: - getValue6 var getValue6SequenceCallsCount = 0 var getValue6SequenceCalled: Bool { return getValue6SequenceCallsCount > 0 } var getValue6SequenceReturnValue: Value6! var getValue6SequenceClosure: (() -> Value6)? func getValue6() -> Value6 { getValue6SequenceCallsCount += 1 if let getValue6SequenceClosure = getValue6SequenceClosure { return getValue6SequenceClosure() } else { return getValue6SequenceReturnValue } } } class ThrowableProtocolMock: ThrowableProtocol { //MARK: - doOrThrow var doOrThrowStringThrowableError: (any Error)? var doOrThrowStringCallsCount = 0 var doOrThrowStringCalled: Bool { return doOrThrowStringCallsCount > 0 } var doOrThrowStringReturnValue: String! var doOrThrowStringClosure: (() throws -> String)? func doOrThrow() throws -> String { doOrThrowStringCallsCount += 1 if let error = doOrThrowStringThrowableError { throw error } if let doOrThrowStringClosure = doOrThrowStringClosure { return try doOrThrowStringClosure() } else { return doOrThrowStringReturnValue } } //MARK: - doOrThrowVoid var doOrThrowVoidVoidThrowableError: (any Error)? var doOrThrowVoidVoidCallsCount = 0 var doOrThrowVoidVoidCalled: Bool { return doOrThrowVoidVoidCallsCount > 0 } var doOrThrowVoidVoidClosure: (() throws -> Void)? func doOrThrowVoid() throws { doOrThrowVoidVoidCallsCount += 1 if let error = doOrThrowVoidVoidThrowableError { throw error } try doOrThrowVoidVoidClosure?() } } class ThrowingVariablesProtocolMock: ThrowingVariablesProtocol { var titleCallsCount = 0 var titleCalled: Bool { return titleCallsCount > 0 } var title: String? { get throws { titleCallsCount += 1 if let error = titleThrowableError { throw error } if let titleClosure = titleClosure { return try titleClosure() } else { return underlyingTitle } } } var underlyingTitle: String? var titleThrowableError: Error? var titleClosure: (() throws -> String?)? var firstNameCallsCount = 0 var firstNameCalled: Bool { return firstNameCallsCount > 0 } var firstName: String { get throws { firstNameCallsCount += 1 if let error = firstNameThrowableError { throw error } if let firstNameClosure = firstNameClosure { return try firstNameClosure() } else { return underlyingFirstName } } } var underlyingFirstName: String! var firstNameThrowableError: Error? var firstNameClosure: (() throws -> String)? } class TypedThrowableProtocolMock: TypedThrowableProtocol { var valueCallsCount = 0 var valueCalled: Bool { return valueCallsCount > 0 } var value: Int { get throws(CustomError) { valueCallsCount += 1 if let error = valueThrowableError { throw error } if let valueClosure = valueClosure { return try valueClosure() } else { return underlyingValue } } } var underlyingValue: Int! var valueThrowableError: (CustomError)? var valueClosure: (() throws(CustomError) -> Int)? var valueAnyErrorCallsCount = 0 var valueAnyErrorCalled: Bool { return valueAnyErrorCallsCount > 0 } var valueAnyError: Int { get throws(any Error) { valueAnyErrorCallsCount += 1 if let error = valueAnyErrorThrowableError { throw error } if let valueAnyErrorClosure = valueAnyErrorClosure { return try valueAnyErrorClosure() } else { return underlyingValueAnyError } } } var underlyingValueAnyError: Int! var valueAnyErrorThrowableError: (any Error)? var valueAnyErrorClosure: (() throws(any Error) -> Int)? var valueThrowsNever: Int { get { return underlyingValueThrowsNever } set(value) { underlyingValueThrowsNever = value } } var underlyingValueThrowsNever: (Int)! //MARK: - init var initTypedThrowableProtocolThrowableError: (CustomError)? var initTypedThrowableProtocolClosure: (() throws(CustomError) -> Void)? required init() { initTypedThrowableProtocolClosure?() } //MARK: - init required init(init2: Void) { fatalError("Generic typed throws in inits are not fully supported yet") } //MARK: - doOrThrow var doOrThrowStringThrowableError: (CustomError)? var doOrThrowStringCallsCount = 0 var doOrThrowStringCalled: Bool { return doOrThrowStringCallsCount > 0 } var doOrThrowStringReturnValue: String! var doOrThrowStringClosure: (() throws(CustomError) -> String)? func doOrThrow() throws(CustomError) -> String { doOrThrowStringCallsCount += 1 if let error = doOrThrowStringThrowableError { throw error } if let doOrThrowStringClosure = doOrThrowStringClosure { return try doOrThrowStringClosure() } else { return doOrThrowStringReturnValue } } //MARK: - doOrThrowAnyError var doOrThrowAnyErrorVoidThrowableError: (any Error)? var doOrThrowAnyErrorVoidCallsCount = 0 var doOrThrowAnyErrorVoidCalled: Bool { return doOrThrowAnyErrorVoidCallsCount > 0 } var doOrThrowAnyErrorVoidClosure: (() throws(any Error) -> Void)? func doOrThrowAnyError() throws(any Error) { doOrThrowAnyErrorVoidCallsCount += 1 if let error = doOrThrowAnyErrorVoidThrowableError { throw error } try doOrThrowAnyErrorVoidClosure?() } //MARK: - doOrThrowNever var doOrThrowNeverVoidCallsCount = 0 var doOrThrowNeverVoidCalled: Bool { return doOrThrowNeverVoidCallsCount > 0 } var doOrThrowNeverVoidClosure: (() -> Void)? func doOrThrowNever() { doOrThrowNeverVoidCallsCount += 1 doOrThrowNeverVoidClosure?() } //MARK: - doOrRethrows func doOrRethrows(_ block: () throws(E) -> Void) throws(E) -> Int where E: Error { fatalError("Generic typed throws are not fully supported yet") } } class VariablesProtocolMock: VariablesProtocol { var company: String? var name: String { get { return underlyingName } set(value) { underlyingName = value } } var underlyingName: (String)! var age: Int { get { return underlyingAge } set(value) { underlyingAge = value } } var underlyingAge: (Int)! var kids: [String] = [] var universityMarks: [String: Int] = [:] } ================================================ FILE: Templates/Tests/Generated/LinuxMain.generated.swift ================================================ // Generated using Sourcery 1.3.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT import XCTest extension AutoInjectionTests { static var allTests: [(String, (AutoInjectionTests) -> () throws -> Void)] = [ ("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies), ("testThatItDoesntResolveAutoInjectedDependencies", testThatItDoesntResolveAutoInjectedDependencies) ] } extension AutoWiringTests { static var allTests: [(String, (AutoWiringTests) -> () throws -> Void)] = [ ("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring), ("testThatItCanNotResolveWithAutoWiring", testThatItCanNotResolveWithAutoWiring) ] } // swiftlint:disable trailing_comma XCTMain([ testCase(AutoInjectionTests.allTests), testCase(AutoWiringTests.allTests), ]) // swiftlint:enable trailing_comma ================================================ FILE: Templates/Tests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: Templates/Tests/TemplatesTests.swift ================================================ import Foundation import Quick import Nimble #if SWIFT_PACKAGE import PathKit #endif class TemplatesTests: QuickSpec { #if SWIFT_PACKAGE || os(Linux) override class func setUp() { super.setUp() generateFiles() } #endif private static func generateFiles() { print("Generating sources...", terminator: " ") let buildDir: Path // Xcode + SPM if let xcTestBundlePath = ProcessInfo.processInfo.environment["XCTestBundlePath"] { buildDir = Path(xcTestBundlePath).parent() } else { // SPM only buildDir = Path(Bundle.module.bundlePath).parent() } let sourcery = buildDir + "sourcery" let resources = Bundle.module.resourcePath! let outputDirectory = Path(resources) + "Generated" if outputDirectory.exists { do { try outputDirectory.delete() } catch { print(error) } } #if canImport(ObjectiveC) let contextSources = "\(resources)/Context" #else let contextSources = "\(resources)/Context_Linux" #endif var output: String? buildDir.chdir { output = launch( sourceryPath: sourcery, args: [ "--sources", contextSources, "--templates", "\(resources)/Templates", "--output", "\(resources)/Generated", "--disableCache", "--verbose" ] ) } if let output = output { print(output) } else { print("Done!") } } override func spec() { func check(template name: String) { guard let generatedFilePath = path(forResource: "\(name).generated", ofType: "swift", in: "Generated") else { fatalError("Template \(name) can not be checked as the generated file is not presented in the bundle") } guard let expectedFilePath = path(forResource: name, ofType: "expected", in: "Expected") else { fatalError("Template \(name) can not be checked as the expected file is not presented in the bundle") } guard let generatedFileString = try? String(contentsOfFile: generatedFilePath) else { fatalError("Template \(name) can not be checked as the generated file can not be read") } guard let expectedFileString = try? String(contentsOfFile: expectedFilePath) else { fatalError("Template \(name) can not be checked as the expected file can not be read") } let generatedFileLines = generatedFileString.components(separatedBy: .newlines) let expectedFileLines = expectedFileString.components(separatedBy: .newlines) /// String normalization. /// Transformations: /// * Trim all whitespaces, tabs and new lines. /// * If this line is comment (starts with `//`) treat is as an empty line. let normalizeString: (String) -> String = { let string = $0.trimmingCharacters(in: .whitespacesAndNewlines) if string.hasPrefix("//") { return "" } return string } // Allow test to produce all failures. So the diff is clearly visible. self.continueAfterFailure = true // Get the full diff. let diff: CollectionDifference = generatedFileLines.difference(from: expectedFileLines) { normalizeString($0) == normalizeString($1) } let expectedFileName = (expectedFilePath as NSString).lastPathComponent for diffLine in diff { switch diffLine { case let .insert(offset: offset, element: element, associatedWith: _) where !normalizeString(element).isEmpty: fail("Missing line in \(expectedFileName):\(offset):\n\(element)") case let .remove(offset: offset, element: element, associatedWith: _) where !normalizeString(element).isEmpty: fail("Unexpected line in \(expectedFileName):\(offset):\n\(element)") default: continue } } } #if !canImport(ObjectiveC) beforeSuite { TemplatesTests.generateFiles() } #endif describe("AutoCases template") { it("generates expected code") { check(template: "AutoCases") } } describe("AutoEquatable template") { it("generates expected code") { check(template: "AutoEquatable") } } describe("AutoHashable template") { it("generates expected code") { check(template: "AutoHashable") } } describe("AutoLenses template") { it("generates expected code") { check(template: "AutoLenses") } } describe("AutoMockable template") { it("generates expected code") { check(template: "AutoMockable") } } describe("LinuxMain template") { it("generates expected code") { check(template: "LinuxMain") } } #if canImport(ObjectiveC) describe("AutoCodable template") { it("generates expected code") { check(template: "AutoCodable") } } #endif } private func path(forResource name: String, ofType ext: String, in dirName: String) -> String? { #if SWIFT_PACKAGE if let resources = Bundle.module.resourcePath { return resources + "/\(dirName)/\(name).\(ext)" } return nil #else let bundle = Bundle.init(for: type(of: self)) return bundle.path(forResource: name, ofType: ext) #endif } #if SWIFT_PACKAGE private static func launch(sourceryPath: Path, args: [String]) -> String? { let process = Process() let output = Pipe() process.launchPath = sourceryPath.string process.arguments = args process.standardOutput = output do { try process.run() process.waitUntilExit() if process.terminationStatus == 0 { return nil } return String(data: output.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) } catch { return "error: can't run Sourcery from the \(sourceryPath.parent().string)" } } #endif } ================================================ FILE: Templates/artifactbundle.info.json.template ================================================ { "schemaVersion": "1.0", "artifacts": { "sourcery": { "type": "executable", "version": "VERSION", "variants": [ { "path": "sourcery/bin/sourcery", "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] }, ] } } } ================================================ FILE: TryCatch/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2019 Pixle. All rights reserved. ================================================ FILE: TryCatch/TryCatch.m ================================================ // // SwiftTryCatch.h // // Created by William Falcon on 10/10/14. // Copyright (c) 2014 William Falcon. All rights reserved. // /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import "TryCatch.h" @implementation SwiftTryCatch /** Provides try catch functionality for swift by wrapping around Objective-C */ + (void)tryBlock:(void(^)(void))tryBlock catchBlock:(void(^)(NSException*exception))catchBlock finallyBlock:(void(^)(void))finallyBlock { @try { tryBlock ? tryBlock() : nil; } @catch (NSException *exception) { catchBlock ? catchBlock(exception) : nil; } @finally { finallyBlock ? finallyBlock() : nil; } } + (void)throwString:(NSString*)s { @throw [NSException exceptionWithName:s reason:s userInfo:nil]; } + (void)throwException:(NSException*)e { @throw e; } @end ================================================ FILE: TryCatch/include/TryCatch.h ================================================ // // SwiftTryCatch.h // // Created by William Falcon on 10/10/14. // Copyright (c) 2014 William Falcon. All rights reserved. // /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import @interface SwiftTryCatch : NSObject /** Provides try catch functionality for swift by wrapping around Objective-C */ + (void)tryBlock:(void(^)(void))tryBlock catchBlock:(void(^)(NSException*exception))catchBlock finallyBlock:(void(^)(void))finallyBlock; + (void)throwString:(NSString*)s; + (void)throwException:(NSException*)e; @end ================================================ FILE: docs/Classes/Actor.html ================================================ Actor Class Reference

Actor

@objc(SwiftActor)
@objcMembers
public final class Actor : Type

Descibes Swift actor

  • Declaration

    Swift

    public class var kind: String { get }
  • Returns “actor”

    Declaration

    Swift

    public override var kind: String { get }
  • Whether type is final

    Declaration

    Swift

    public var isFinal: Bool { get }
  • Whether method is distributed method

    Declaration

    Swift

    public var isDistributed: Bool { get }
  • Declaration

    Swift

    override public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/ArrayType.html ================================================ ArrayType Class Reference

ArrayType

@objcMembers
public final class ArrayType : NSObject, SourceryModel, Diffable
extension ArrayType: NSCoding

Describes array type

  • Type name used in declaration

    Declaration

    Swift

    public var name: String
  • Array element type name

    Declaration

    Swift

    public var elementTypeName: TypeName
  • Array element type, if known

    Declaration

    Swift

    public var elementType: Type?
  • Returns array as generic type

    Declaration

    Swift

    public var asGeneric: GenericType { get }
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/AssociatedType.html ================================================ AssociatedType Class Reference

AssociatedType

@objcMembers
public final class AssociatedType : NSObject, SourceryModel
extension AssociatedType: NSCoding

Describes Swift AssociatedType

  • Associated type name

    Declaration

    Swift

    public let name: String
  • Associated type type constraint name, if specified

    Declaration

    Swift

    public let typeName: TypeName?
  • Associated type constrained type, if known, i.e. if the type is declared in the scanned sources.

    Declaration

    Swift

    public var type: Type?
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/AssociatedValue.html ================================================ AssociatedValue Class Reference

AssociatedValue

@objcMembers
public final class AssociatedValue : NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable
extension AssociatedValue: NSCoding

Defines enum case associated value

  • Associated value local name. This is a name to be used to construct enum case value

    Declaration

    Swift

    public let localName: String?
  • Associated value external name. This is a name to be used to access value in value-bindig

    Declaration

    Swift

    public let externalName: String?
  • Associated value type name

    Declaration

    Swift

    public let typeName: TypeName
  • Associated value type, if known

    Declaration

    Swift

    public var type: Type?
  • Associated value default value

    Declaration

    Swift

    public let defaultValue: String?
  • Annotations, that were created with // sourcery: annotation1, other = “annotation value”, alterantive = 2

    Declaration

    Swift

    public var annotations: Annotations
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
  • Whether type is optional. Shorthand for typeName.isOptional

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional. Shorthand for typeName.isImplicitlyUnwrappedOptional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information. Shorthand for typeName.unwrappedTypeName

    Declaration

    Swift

    public var unwrappedTypeName: String { get }
  • Actual type name if declaration uses typealias, otherwise just a typeName. Shorthand for typeName.actualTypeName

    Declaration

    Swift

    public var actualTypeName: TypeName? { get }
  • Whether type is a tuple. Shorthand for typeName.isTuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Whether type is a closure. Shorthand for typeName.isClosure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Whether type is an array. Shorthand for typeName.isArray

    Declaration

    Swift

    public var isArray: Bool { get }
  • Whether type is a set. Shorthand for typeName.isSet

    Declaration

    Swift

    public var isSet: Bool { get }
  • Whether type is a dictionary. Shorthand for typeName.isDictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
================================================ FILE: docs/Classes/Attribute.html ================================================ Attribute Class Reference

Attribute

@objcMembers
public class Attribute : NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable
extension Attribute: NSCoding

Describes Swift attribute

  • Attribute name

    Declaration

    Swift

    public let name: String
  • Attribute arguments

    Declaration

    Swift

    public let arguments: [String : NSObject]
  • TODO: unify asSource / description?

    Declaration

    Swift

    public var asSource: String { get }
  • Attribute description that can be used in a template.

    Declaration

    Swift

    public override var description: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/Class.html ================================================ Class Class Reference

Class

@objc(SwiftClass)
@objcMembers
public final class Class : Type

Descibes Swift class

  • Declaration

    Swift

    public class var kind: String { get }
  • Returns “class”

    Declaration

    Swift

    public override var kind: String { get }
  • Whether type is final

    Declaration

    Swift

    public var isFinal: Bool { get }
  • Declaration

    Swift

    override public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/ClosureParameter.html ================================================ ClosureParameter Class Reference

ClosureParameter

@objcMembers
public final class ClosureParameter : NSObject, SourceryModel, Typed, Annotated
extension ClosureParameter: NSCoding
  • Parameter external name

    Declaration

    Swift

    public var argumentLabel: String?
  • Parameter internal name

    Declaration

    Swift

    public let name: String?
  • Parameter type name

    Declaration

    Swift

    public let typeName: TypeName
  • Parameter flag whether it’s inout or not

    Declaration

    Swift

    public let `inout`: Bool
  • Parameter type, if known

    Declaration

    Swift

    public var type: Type?
  • Parameter if the argument has a variadic type or not

    Declaration

    Swift

    public let isVariadic: Bool
  • Parameter type attributes, i.e. @escaping

    Declaration

    Swift

    public var typeAttributes: AttributeList { get }
  • Method parameter default value expression

    Declaration

    Swift

    public var defaultValue: String?
  • Annotations, that were created with // sourcery: annotation1, other = “annotation value”, alterantive = 2

    Declaration

    Swift

    public var annotations: Annotations
  • Declaration

    Swift

    public var asSource: String { get }
  • Whether type is optional. Shorthand for typeName.isOptional

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional. Shorthand for typeName.isImplicitlyUnwrappedOptional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information. Shorthand for typeName.unwrappedTypeName

    Declaration

    Swift

    public var unwrappedTypeName: String { get }
  • Actual type name if declaration uses typealias, otherwise just a typeName. Shorthand for typeName.actualTypeName

    Declaration

    Swift

    public var actualTypeName: TypeName? { get }
  • Whether type is a tuple. Shorthand for typeName.isTuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Whether type is a closure. Shorthand for typeName.isClosure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Whether type is an array. Shorthand for typeName.isArray

    Declaration

    Swift

    public var isArray: Bool { get }
  • Whether type is a set. Shorthand for typeName.isSet

    Declaration

    Swift

    public var isSet: Bool { get }
  • Whether type is a dictionary. Shorthand for typeName.isDictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
================================================ FILE: docs/Classes/ClosureType.html ================================================ ClosureType Class Reference

ClosureType

@objcMembers
public final class ClosureType : NSObject, SourceryModel, Diffable
extension ClosureType: NSCoding

Describes closure type

  • Type name used in declaration with stripped whitespaces and new lines

    Declaration

    Swift

    public let name: String
  • List of closure parameters

    Declaration

    Swift

    public let parameters: [ClosureParameter]
  • Return value type name

    Declaration

    Swift

    public let returnTypeName: TypeName
  • Actual return value type name if declaration uses typealias, otherwise just a returnTypeName

    Declaration

    Swift

    public var actualReturnTypeName: TypeName { get }
  • Actual return value type, if known

    Declaration

    Swift

    public var returnType: Type?
  • Whether return value type is optional

    Declaration

    Swift

    public var isOptionalReturnType: Bool { get }
  • Whether return value type is implicitly unwrapped optional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptionalReturnType: Bool { get }
  • Return value type name without attributes and optional type information

    Declaration

    Swift

    public var unwrappedReturnTypeName: String { get }
  • Whether method is async method

    Declaration

    Swift

    public let isAsync: Bool
  • async keyword

    Declaration

    Swift

    public let asyncKeyword: String?
  • Whether closure throws

    Declaration

    Swift

    public let `throws`: Bool
  • throws or rethrows keyword

    Declaration

    Swift

    public let throwsOrRethrowsKeyword: String?
  • Type of thrown error if specified

    Declaration

    Swift

    public let throwsTypeName: TypeName?
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/DictionaryType.html ================================================ DictionaryType Class Reference

DictionaryType

@objcMembers
public final class DictionaryType : NSObject, SourceryModel, Diffable
extension DictionaryType: NSCoding

Describes dictionary type

  • Type name used in declaration

    Declaration

    Swift

    public var name: String
  • Dictionary value type name

    Declaration

    Swift

    public var valueTypeName: TypeName
  • Dictionary value type, if known

    Declaration

    Swift

    public var valueType: Type?
  • Dictionary key type name

    Declaration

    Swift

    public var keyTypeName: TypeName
  • Dictionary key type, if known

    Declaration

    Swift

    public var keyType: Type?
  • Returns dictionary as generic type

    Declaration

    Swift

    public var asGeneric: GenericType { get }
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/DiffableResult.html ================================================ DiffableResult Class Reference
================================================ FILE: docs/Classes/Enum.html ================================================ Enum Class Reference

Enum

@objcMembers
public final class Enum : Type

Defines Swift enum

  • Declaration

    Swift

    public class var kind: String { get }
  • Returns “enum”

    Declaration

    Swift

    public override var kind: String { get }
  • Enum cases

    Declaration

    Swift

    public var cases: [EnumCase]
  • Enum raw value type name, if any. This type is removed from enum’s based and inherited types collections.

    Important

    Unless raw type is specified explicitly via type alias RawValue it will be set to the first type in the inheritance chain. So if your enum does not have raw value but implements protocols you’ll have to specify conformance to these protocols via extension to get enum with nil raw value type and all based and inherited types.

    Declaration

    Swift

    public var rawTypeName: TypeName? { get set }
  • Enum raw value type, if known

    Declaration

    Swift

    public var rawType: Type?
  • Names of types or protocols this type inherits from, including unknown (not scanned) types

    Declaration

    Swift

    public override var based: [String : String] { get set }
  • Whether enum contains any associated values

    Declaration

    Swift

    public var hasAssociatedValues: Bool { get }
  • Declaration

    Swift

    override public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/EnumCase.html ================================================ EnumCase Class Reference

EnumCase

@objcMembers
public final class EnumCase : NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable
extension EnumCase: NSCoding

Defines enum case

================================================ FILE: docs/Classes/GenericParameter.html ================================================ GenericParameter Class Reference

GenericParameter

@objcMembers
public final class GenericParameter : NSObject, SourceryModel, Diffable
extension GenericParameter: NSCoding

Descibes Swift generic parameter

================================================ FILE: docs/Classes/GenericRequirement/Relationship.html ================================================ Relationship Enumeration Reference
================================================ FILE: docs/Classes/GenericRequirement.html ================================================ GenericRequirement Class Reference

GenericRequirement

@objcMembers
public class GenericRequirement : NSObject, SourceryModel, Diffable
extension GenericRequirement: NSCoding

Descibes Swift generic requirement

================================================ FILE: docs/Classes/GenericType.html ================================================ GenericType Class Reference

GenericType

@objcMembers
public final class GenericType : NSObject, SourceryModelWithoutDescription, Diffable
extension GenericType: NSCoding

Descibes Swift generic type

  • The name of the base type, i.e. Array for Array<Int>

    Declaration

    Swift

    public var name: String
  • This generic type parameters

    Declaration

    Swift

    public let typeParameters: [GenericTypeParameter]
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public override var description: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/GenericTypeParameter.html ================================================ GenericTypeParameter Class Reference

GenericTypeParameter

@objcMembers
public final class GenericTypeParameter : NSObject, SourceryModel, Diffable
extension GenericTypeParameter: NSCoding

Descibes Swift generic type parameter

  • Generic parameter type name

    Declaration

    Swift

    public var typeName: TypeName
  • Generic parameter type, if known

    Declaration

    Swift

    public var type: Type?
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/Import.html ================================================ Import Class Reference

Import

@objcMembers
public class Import : NSObject, SourceryModelWithoutDescription, Diffable
extension Import: NSCoding

Defines import type

  • Import kind, e.g. class, struct in import class Module.ClassName

    Declaration

    Swift

    public var kind: String?
  • Import path

    Declaration

    Swift

    public var path: String
  • Full import value e.g. import struct Module.StructName

    Declaration

    Swift

    public override var description: String { get }
  • Returns module name from a import, e.g. if you had import struct Module.Submodule.Struct it will return Module.Submodule

    Declaration

    Swift

    public var moduleName: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/Method.html ================================================ Method Class Reference

Method

@objc(SwiftMethod)
@objcMembers
public final class Method : NSObject, SourceryModel, Annotated, Documented, Definition, Diffable
extension Method: NSCoding

Describes method

  • Full method name, including generic constraints, i.e. foo<T>(bar: T)

    Declaration

    Swift

    public let name: String
  • Method name including arguments names, i.e. foo(bar:)

    Declaration

    Swift

    public var selectorName: String
  • Method name without arguments names and parentheses, i.e. foo<T>

    Declaration

    Swift

    public var shortName: String { get }
  • Method name without arguments names, parentheses and generic types, i.e. foo (can be used to generate code for method call)

    Declaration

    Swift

    public var callName: String { get }
  • Method parameters

    Declaration

    Swift

    public var parameters: [MethodParameter]
  • Return value type name used in declaration, including generic constraints, i.e. where T: Equatable

    Declaration

    Swift

    public var returnTypeName: TypeName
  • Actual return value type name if declaration uses typealias, otherwise just a returnTypeName

    Declaration

    Swift

    public var actualReturnTypeName: TypeName { get }
  • Actual return value type, if known

    Declaration

    Swift

    public var returnType: Type?
  • Whether return value type is optional

    Declaration

    Swift

    public var isOptionalReturnType: Bool { get }
  • Whether return value type is implicitly unwrapped optional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptionalReturnType: Bool { get }
  • Return value type name without attributes and optional type information

    Declaration

    Swift

    public var unwrappedReturnTypeName: String { get }
  • Whether method is async method

    Declaration

    Swift

    public let isAsync: Bool
  • Whether method is distributed

    Declaration

    Swift

    public var isDistributed: Bool { get }
  • Whether method throws

    Declaration

    Swift

    public let `throws`: Bool
  • Type of thrown error if specified

    Declaration

    Swift

    public let throwsTypeName: TypeName?
  • Return if the throwsType is generic

    Declaration

    Swift

    public var isThrowsTypeGeneric: Bool { get }
  • Whether method rethrows

    Declaration

    Swift

    public let `rethrows`: Bool
  • Method access level, i.e. internal, private, fileprivate, public, open

    Declaration

    Swift

    public let accessLevel: String
  • Whether method is a static method

    Declaration

    Swift

    public let isStatic: Bool
  • Whether method is a class method

    Declaration

    Swift

    public let isClass: Bool
  • Whether method is an initializer

    Declaration

    Swift

    public var isInitializer: Bool { get }
  • Whether method is an deinitializer

    Declaration

    Swift

    public var isDeinitializer: Bool { get }
  • Whether method is a failable initializer

    Declaration

    Swift

    public let isFailableInitializer: Bool
  • Whether method is a convenience initializer

    Declaration

    Swift

    public var isConvenienceInitializer: Bool { get }
  • Whether method is required

    Declaration

    Swift

    public var isRequired: Bool { get }
  • Whether method is final

    Declaration

    Swift

    public var isFinal: Bool { get }
  • Whether method is mutating

    Declaration

    Swift

    public var isMutating: Bool { get }
  • Whether method is generic

    Declaration

    Swift

    public var isGeneric: Bool { get }
  • Whether method is optional (in an Objective-C protocol)

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether method is nonisolated (this modifier only applies to actor methods)

    Declaration

    Swift

    public var isNonisolated: Bool { get }
  • Whether method is dynamic

    Declaration

    Swift

    public var isDynamic: Bool { get }
  • Annotations, that were created with // sourcery: annotation1, other = “annotation value”, alterantive = 2

    Declaration

    Swift

    public let annotations: Annotations
  • Declaration

    Swift

    public let documentation: Documentation
  • Reference to type name where the method is defined, nil if defined outside of any enum, struct, class etc

    Declaration

    Swift

    public let definedInTypeName: TypeName?
  • Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a definedInTypeName

    Declaration

    Swift

    public var actualDefinedInTypeName: TypeName? { get }
  • Reference to actual type where the object is defined, nil if defined outside of any enum, struct, class etc or type is unknown

    Declaration

    Swift

    public var definedInType: Type?
  • Method attributes, i.e. @discardableResult

    Declaration

    Swift

    public let attributes: AttributeList
  • Method modifiers, i.e. private

    Declaration

    Swift

    public let modifiers: [SourceryModifier]
  • list of generic requirements

    Declaration

    Swift

    public var genericRequirements: [GenericRequirement]
  • List of generic parameters

    • Example:
      func method<GenericParameter>(foo: GenericParameter)
                       ^ ~ a generic parameter
    

    Declaration

    Swift

    public var genericParameters: [GenericParameter]
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/MethodParameter.html ================================================ MethodParameter Class Reference

MethodParameter

@objcMembers
public class MethodParameter : NSObject, SourceryModel, Typed, Annotated, Diffable
extension MethodParameter: NSCoding

Describes method parameter

  • Parameter external name

    Declaration

    Swift

    public var argumentLabel: String?
  • Parameter internal name

    Declaration

    Swift

    public let name: String
  • Parameter type name

    Declaration

    Swift

    public let typeName: TypeName
  • Parameter flag whether it’s inout or not

    Declaration

    Swift

    public let `inout`: Bool
  • Is this variadic parameter?

    Declaration

    Swift

    public let isVariadic: Bool
  • Parameter type, if known

    Declaration

    Swift

    public var type: Type?
  • Parameter type attributes, i.e. @escaping

    Declaration

    Swift

    public var typeAttributes: AttributeList { get }
  • Method parameter default value expression

    Declaration

    Swift

    public var defaultValue: String?
  • Annotations, that were created with // sourcery: annotation1, other = “annotation value”, alterantive = 2

    Declaration

    Swift

    public var annotations: Annotations
  • Method parameter index in the argument list

    Declaration

    Swift

    public var index: Int
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
  • Whether type is optional. Shorthand for typeName.isOptional

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional. Shorthand for typeName.isImplicitlyUnwrappedOptional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information. Shorthand for typeName.unwrappedTypeName

    Declaration

    Swift

    public var unwrappedTypeName: String { get }
  • Actual type name if declaration uses typealias, otherwise just a typeName. Shorthand for typeName.actualTypeName

    Declaration

    Swift

    public var actualTypeName: TypeName? { get }
  • Whether type is a tuple. Shorthand for typeName.isTuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Whether type is a closure. Shorthand for typeName.isClosure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Whether type is an array. Shorthand for typeName.isArray

    Declaration

    Swift

    public var isArray: Bool { get }
  • Whether type is a set. Shorthand for typeName.isSet

    Declaration

    Swift

    public var isSet: Bool { get }
  • Whether type is a dictionary. Shorthand for typeName.isDictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
================================================ FILE: docs/Classes/Modifier.html ================================================ Modifier Class Reference

Modifier

@objcMembers
public class Modifier : NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable
extension Modifier: NSCoding

modifier can be thing like private, class, nonmutating if a declaration has modifier like private(set) it’s name will be private and detail will be set

  • The declaration modifier name.

    Declaration

    Swift

    public let name: String
  • The modifier detail, if any.

    Declaration

    Swift

    public let detail: String?
  • Declaration

    Swift

    public init(name: String, detail: String? = nil)
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/Protocol.html ================================================ Protocol Class Reference

Protocol

@objcMembers
public final class Protocol : Type

Describes Swift protocol

  • Declaration

    Swift

    public class var kind: String { get }
  • Returns “protocol”

    Declaration

    Swift

    public override var kind: String { get }
  • list of all declared associated types with their names as keys

    Declaration

    Swift

    public var associatedTypes: [String : AssociatedType] { get set }
  • list of generic requirements

    Declaration

    Swift

    public override var genericRequirements: [GenericRequirement] { get set }
  • Declaration

    Swift

    override public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/ProtocolComposition.html ================================================ ProtocolComposition Class Reference

ProtocolComposition

@objcMembers
public final class ProtocolComposition : Type

Describes a Swift protocol composition.

  • Declaration

    Swift

    public class var kind: String { get }
  • Returns “protocolComposition”

    Declaration

    Swift

    public override var kind: String { get }
  • The names of the types composed to form this composition

    Declaration

    Swift

    public let composedTypeNames: [TypeName]
  • The types composed to form this composition, if known

    Declaration

    Swift

    public var composedTypes: [Type]?
  • Declaration

    Swift

    override public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/SetType.html ================================================ SetType Class Reference

SetType

@objcMembers
public final class SetType : NSObject, SourceryModel, Diffable
extension SetType: NSCoding

Describes set type

  • Type name used in declaration

    Declaration

    Swift

    public var name: String
  • Array element type name

    Declaration

    Swift

    public var elementTypeName: TypeName
  • Array element type, if known

    Declaration

    Swift

    public var elementType: Type?
  • Returns array as generic type

    Declaration

    Swift

    public var asGeneric: GenericType { get }
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/Struct.html ================================================ Struct Class Reference
================================================ FILE: docs/Classes/Subscript.html ================================================ Subscript Class Reference

Subscript

@objcMembers
public final class Subscript : NSObject, SourceryModel, Annotated, Documented, Definition, Diffable
extension Subscript: NSCoding

Describes subscript

================================================ FILE: docs/Classes/TupleElement.html ================================================ TupleElement Class Reference

TupleElement

@objcMembers
public final class TupleElement : NSObject, SourceryModel, Typed, Diffable
extension TupleElement: NSCoding

Describes tuple type element

  • Tuple element name

    Declaration

    Swift

    public let name: String?
  • Tuple element type name

    Declaration

    Swift

    public var typeName: TypeName
  • Tuple element type, if known

    Declaration

    Swift

    public var type: Type?
  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
  • Whether type is optional. Shorthand for typeName.isOptional

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional. Shorthand for typeName.isImplicitlyUnwrappedOptional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information. Shorthand for typeName.unwrappedTypeName

    Declaration

    Swift

    public var unwrappedTypeName: String { get }
  • Actual type name if declaration uses typealias, otherwise just a typeName. Shorthand for typeName.actualTypeName

    Declaration

    Swift

    public var actualTypeName: TypeName? { get }
  • Whether type is a tuple. Shorthand for typeName.isTuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Whether type is a closure. Shorthand for typeName.isClosure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Whether type is an array. Shorthand for typeName.isArray

    Declaration

    Swift

    public var isArray: Bool { get }
  • Whether type is a set. Shorthand for typeName.isSet

    Declaration

    Swift

    public var isSet: Bool { get }
  • Whether type is a dictionary. Shorthand for typeName.isDictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
================================================ FILE: docs/Classes/TupleType.html ================================================ TupleType Class Reference
================================================ FILE: docs/Classes/Type.html ================================================ Type Class Reference

Type

@objcMembers
public class Type : NSObject, SourceryModel, Annotated, Documented, Diffable
extension Type: NSCoding

Defines Swift type

  • Imports that existed in the file that contained this type declaration

    Declaration

    Swift

    public var imports: [Import]
  • Imports existed in all files containing this type and all its super classes/protocols

    Declaration

    Swift

    public var allImports: [Import] { get }
  • Whether declaration is an extension of some type

    Declaration

    Swift

    public var isExtension: Bool
  • Kind of type declaration, i.e. enum, struct, class, protocol or extension

    Declaration

    Swift

    public var kind: String { get }
  • Type access level, i.e. internal, private, fileprivate, public, open

    Declaration

    Swift

    public let accessLevel: String
  • Type name in global scope. For inner types includes the name of its containing type, i.e. Type.Inner

    Declaration

    Swift

    public var name: String { get }
  • Whether the type has been resolved as unknown extension

    Declaration

    Swift

    public var isUnknownExtension: Bool
  • Global type name including module name, unless it’s an extension of unknown type

    Declaration

    Swift

    public var globalName: String { get }
  • Whether type is generic

    Declaration

    Swift

    public var isGeneric: Bool
  • Type name in its own scope.

    Declaration

    Swift

    public var localName: String
  • Variables defined in this type only, inluding variables defined in its extensions, but not including variables inherited from superclasses (for classes only) and protocols

    Declaration

    Swift

    public var variables: [Variable] { get }
  • Unfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions, but not including variables inherited from superclasses (for classes only) and protocols

    Declaration

    Swift

    public var rawVariables: [Variable]
  • All variables defined for this type, including variables defined in extensions, in superclasses (for classes only) and protocols

    Declaration

    Swift

    public var allVariables: [Variable] { get }
  • Methods defined in this type only, inluding methods defined in its extensions, but not including methods inherited from superclasses (for classes only) and protocols

    Declaration

    Swift

    public var methods: [Method] { get }
  • Unfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions, but not including methods inherited from superclasses (for classes only) and protocols

    Declaration

    Swift

    public var rawMethods: [Method]
  • All methods defined for this type, including methods defined in extensions, in superclasses (for classes only) and protocols

    Declaration

    Swift

    public var allMethods: [Method] { get }
  • Subscripts defined in this type only, inluding subscripts defined in its extensions, but not including subscripts inherited from superclasses (for classes only) and protocols

    Declaration

    Swift

    public var subscripts: [Subscript] { get }
  • Unfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions, but not including subscripts inherited from superclasses (for classes only) and protocols

    Declaration

    Swift

    public var rawSubscripts: [Subscript]
  • All subscripts defined for this type, including subscripts defined in extensions, in superclasses (for classes only) and protocols

    Declaration

    Swift

    public var allSubscripts: [Subscript] { get }
  • Bytes position of the body of this type in its declaration file if available.

    Declaration

    Swift

    public var bodyBytesRange: BytesRange?
  • Bytes position of the whole declaration of this type in its declaration file if available.

    Declaration

    Swift

    public var completeDeclarationRange: BytesRange?
  • All initializers defined in this type

    Declaration

    Swift

    public var initializers: [Method] { get }
  • All annotations for this type

    Declaration

    Swift

    public var annotations: Annotations
  • Declaration

    Swift

    public var documentation: Documentation
  • Static variables defined in this type

    Declaration

    Swift

    public var staticVariables: [Variable] { get }
  • Static methods defined in this type

    Declaration

    Swift

    public var staticMethods: [Method] { get }
  • Class methods defined in this type

    Declaration

    Swift

    public var classMethods: [Method] { get }
  • Instance variables defined in this type

    Declaration

    Swift

    public var instanceVariables: [Variable] { get }
  • Instance methods defined in this type

    Declaration

    Swift

    public var instanceMethods: [Method] { get }
  • Computed instance variables defined in this type

    Declaration

    Swift

    public var computedVariables: [Variable] { get }
  • Stored instance variables defined in this type

    Declaration

    Swift

    public var storedVariables: [Variable] { get }
  • Names of types this type inherits from (for classes only) and protocols it implements, in order of definition

    Declaration

    Swift

    public var inheritedTypes: [String] { get set }
  • Names of types or protocols this type inherits from, including unknown (not scanned) types

    Declaration

    Swift

    public var based: [String : String]
  • Types this type inherits from or implements, including unknown (not scanned) types with extensions defined

    Declaration

    Swift

    public var basedTypes: [String : Type]
  • Types this type inherits from

    Declaration

    Swift

    public var inherits: [String : Type]
  • Protocols this type implements. Does not contain classes in case where composition (&) is used in the declaration

    Declaration

    Swift

    public var implements: [String : Type]
  • Contained types

    Declaration

    Swift

    public var containedTypes: [Type] { get set }
  • Contained types groupd by their names

    Declaration

    Swift

    public private(set) var containedType: [String : Type] { get }
  • Name of parent type (for contained types only)

    Declaration

    Swift

    public private(set) var parentName: String? { get }
  • Parent type, if known (for contained types only)

    Declaration

    Swift

    public var parent: Type? { get set }
  • Superclass type, if known (only for classes)

    Declaration

    Swift

    public var supertype: Type?
  • Type attributes, i.e. @objc

    Declaration

    Swift

    public var attributes: AttributeList
  • Type modifiers, i.e. private, final

    Declaration

    Swift

    public var modifiers: [SourceryModifier]
  • Path to file where the type is defined

    Declaration

    Swift

    public var path: String? { get set }
  • Directory to file where the type is defined

    Declaration

    Swift

    public var directory: String? { get }
  • list of generic requirements

    Declaration

    Swift

    public var genericRequirements: [GenericRequirement] { get set }
  • File name where the type was defined

    Declaration

    Swift

    public var fileName: String?
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
================================================ FILE: docs/Classes/TypeName.html ================================================ TypeName Class Reference

TypeName

@objcMembers
public final class TypeName : NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable
extension TypeName: NSCoding

Describes name of the type used in typed declaration (variable, method parameter or return value etc.)

  • Type name used in declaration

    Declaration

    Swift

    public var name: String
  • The generics of this TypeName

    Declaration

    Swift

    public var generic: GenericType?
  • Whether this TypeName is generic

    Declaration

    Swift

    public var isGeneric: Bool { get }
  • Whether this TypeName is protocol composition

    Declaration

    Swift

    public var isProtocolComposition: Bool
  • Actual type name if given type name is a typealias

    Declaration

    Swift

    public var actualTypeName: TypeName?
  • Type name attributes, i.e. @escaping

    Declaration

    Swift

    public var attributes: AttributeList
  • Modifiers, i.e. escaping

    Declaration

    Swift

    public var modifiers: [SourceryModifier]
  • Whether type is optional

    Declaration

    Swift

    public let isOptional: Bool
  • Whether type is implicitly unwrapped optional

    Declaration

    Swift

    public let isImplicitlyUnwrappedOptional: Bool
  • Type name without attributes and optional type information

    Declaration

    Swift

    public var unwrappedTypeName: String
  • Whether type is void (Void or ())

    Declaration

    Swift

    public var isVoid: Bool { get }
  • Whether type is a tuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Tuple type data

    Declaration

    Swift

    public var tuple: TupleType?
  • Whether type is an array

    Declaration

    Swift

    public var isArray: Bool { get }
  • Array type data

    Declaration

    Swift

    public var array: ArrayType?
  • Whether type is a dictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
  • Dictionary type data

    Declaration

    Swift

    public var dictionary: DictionaryType?
  • Whether type is a closure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Closure type data

    Declaration

    Swift

    public var closure: ClosureType?
  • Whether type is a Set

    Declaration

    Swift

    public var isSet: Bool { get }
  • set

    Set type data

    Declaration

    Swift

    public var set: SetType?
  • Whether type is Never

    Declaration

    Swift

    public var isNever: Bool { get }
  • Prints typename as it would appear on definition

    Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public override var description: String { get }
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
  • Declaration

    Swift

    public override var hash: Int { get }
  • Declaration

    Swift

    public convenience init(_ description: String)
  • Declaration

    Swift

    public static func unknown(description: String?, attributes: AttributeList = [:]) -> TypeName
================================================ FILE: docs/Classes/Types.html ================================================ Types Class Reference

Types

@objcMembers
public final class Types : NSObject, SourceryModel, Diffable
extension Types: NSCoding

Collection of scanned types for accessing in templates

  • All known typealiases

    Declaration

    Swift

    public let typealiases: [Typealias]
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
  • all

    All known types, excluding protocols or protocol compositions.

    Declaration

    Swift

    public lazy internal(set) var all: [Type] { get set }
  • All known protocols

    Declaration

    Swift

    public lazy internal(set) var protocols: [Protocol] { get set }
  • All known protocol compositions

    Declaration

    Swift

    public lazy internal(set) var protocolCompositions: [ProtocolComposition] { get set }
  • All known classes

    Declaration

    Swift

    public lazy internal(set) var classes: [Class] { get set }
  • All known structs

    Declaration

    Swift

    public lazy internal(set) var structs: [Struct] { get set }
  • All known enums

    Declaration

    Swift

    public lazy internal(set) var enums: [Enum] { get set }
  • All known extensions

    Declaration

    Swift

    public lazy internal(set) var extensions: [Type] { get set }
  • Types based on any other type, grouped by its name, even if they are not known. types.based.MyType returns list of types based on MyType

    Declaration

    Swift

    public lazy internal(set) var based: TypesCollection { get set }
  • Classes inheriting from any known class, grouped by its name. types.inheriting.MyClass returns list of types inheriting from MyClass

    Declaration

    Swift

    public lazy internal(set) var inheriting: TypesCollection { get set }
  • Types implementing known protocol, grouped by its name. types.implementing.MyProtocol returns list of types implementing MyProtocol

    Declaration

    Swift

    public lazy internal(set) var implementing: TypesCollection { get set }
================================================ FILE: docs/Classes/Variable.html ================================================ Variable Class Reference

Variable

@objcMembers
public final class Variable : NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable
extension Variable: NSCoding

Defines variable

  • Variable name

    Declaration

    Swift

    public let name: String
  • Variable type name

    Declaration

    Swift

    public let typeName: TypeName
  • Variable type, if known, i.e. if the type is declared in the scanned sources. For explanation, see https://cdn.rawgit.com/krzysztofzablocki/Sourcery/master/docs/writing-templates.html#what-are-em-known-em-and-em-unknown-em-types

    Declaration

    Swift

    public var type: Type?
  • Whether variable is computed and not stored

    Declaration

    Swift

    public let isComputed: Bool
  • Whether variable is async

    Declaration

    Swift

    public let isAsync: Bool
  • Whether variable throws

    Declaration

    Swift

    public let `throws`: Bool
  • Type of thrown error if specified

    Declaration

    Swift

    public let throwsTypeName: TypeName?
  • Whether variable is static

    Declaration

    Swift

    public let isStatic: Bool
  • Variable read access level, i.e. internal, private, fileprivate, public, open

    Declaration

    Swift

    public let readAccess: String
  • Variable write access, i.e. internal, private, fileprivate, public, open. For immutable variables this value is empty string

    Declaration

    Swift

    public let writeAccess: String
  • composed access level sourcery: skipJSExport

    Declaration

    Swift

    public var accessLevel: (read: AccessLevel, write: AccessLevel) { get }
  • Whether variable is mutable or not

    Declaration

    Swift

    public var isMutable: Bool { get }
  • Variable default value expression

    Declaration

    Swift

    public var defaultValue: String?
  • Annotations, that were created with // sourcery: annotation1, other = “annotation value”, alterantive = 2

    Declaration

    Swift

    public var annotations: Annotations
  • Declaration

    Swift

    public var documentation: Documentation
  • Variable attributes, i.e. @IBOutlet, @IBInspectable

    Declaration

    Swift

    public var attributes: AttributeList
  • Modifiers, i.e. private

    Declaration

    Swift

    public var modifiers: [SourceryModifier]
  • Whether variable is final or not

    Declaration

    Swift

    public var isFinal: Bool { get }
  • Whether variable is lazy or not

    Declaration

    Swift

    public var isLazy: Bool { get }
  • Whether variable is dynamic or not

    Declaration

    Swift

    public var isDynamic: Bool { get }
  • Reference to type name where the variable is defined, nil if defined outside of any enum, struct, class etc

    Declaration

    Swift

    public internal(set) var definedInTypeName: TypeName? { get }
  • Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a definedInTypeName

    Declaration

    Swift

    public var actualDefinedInTypeName: TypeName? { get }
  • Reference to actual type where the object is defined, nil if defined outside of any enum, struct, class etc or type is unknown

    Declaration

    Swift

    public var definedInType: Type?
  • Declaration

    Swift

    public func diffAgainst(_ object: Any?) -> DiffableResult
  • Whether type is optional. Shorthand for typeName.isOptional

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional. Shorthand for typeName.isImplicitlyUnwrappedOptional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information. Shorthand for typeName.unwrappedTypeName

    Declaration

    Swift

    public var unwrappedTypeName: String { get }
  • Actual type name if declaration uses typealias, otherwise just a typeName. Shorthand for typeName.actualTypeName

    Declaration

    Swift

    public var actualTypeName: TypeName? { get }
  • Whether type is a tuple. Shorthand for typeName.isTuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Whether type is a closure. Shorthand for typeName.isClosure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Whether type is an array. Shorthand for typeName.isArray

    Declaration

    Swift

    public var isArray: Bool { get }
  • Whether type is a set. Shorthand for typeName.isSet

    Declaration

    Swift

    public var isSet: Bool { get }
  • Whether type is a dictionary. Shorthand for typeName.isDictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
================================================ FILE: docs/Enums/Composer.html ================================================ Composer Enumeration Reference

Composer

public enum Composer

Responsible for composing results of FileParser.

  • Performs final processing of discovered types:

    • extends types with their corresponding extensions;
    • replaces typealiases with actual types
    • finds actual types for variables and enums raw values
    • filters out any private types and extensions

    Declaration

    Swift

    public static func uniqueTypesAndFunctions(_ parserResult: FileParserResult, serial: Bool = false) -> (types: [Type], functions: [SourceryMethod], typealiases: [Typealias])

    Parameters

    parserResult

    Result of parsing source code.

    serial

    Whether to process results serially instead of concurrently

    Return Value

    Final types and extensions of unknown types.

================================================ FILE: docs/Examples.html ================================================ Examples Reference
================================================ FILE: docs/Extensions/Array.html ================================================ Array Extension Reference

Array

public extension Array
extension Array where Element == ClosureParameter
extension Array where Element == MethodParameter
extension Array where Element == TupleElement

Available where Element == ClosureParameter

  • Declaration

    Swift

    public var asSource: String { get }

Available where Element == MethodParameter

  • Declaration

    Swift

    public var asSource: String { get }

Available where Element == TupleElement

  • Declaration

    Swift

    public var asSource: String { get }
  • Declaration

    Swift

    public var asTypeName: String { get }
================================================ FILE: docs/Extensions/String.html ================================================ String Extension Reference
================================================ FILE: docs/Extensions/StringProtocol.html ================================================ StringProtocol Extension Reference
================================================ FILE: docs/Extensions/Typealias.html ================================================ Typealias Extension Reference

Typealias

extension Typealias: NSCoding
  • Whether type is optional. Shorthand for typeName.isOptional

    Declaration

    Swift

    public var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional. Shorthand for typeName.isImplicitlyUnwrappedOptional

    Declaration

    Swift

    public var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information. Shorthand for typeName.unwrappedTypeName

    Declaration

    Swift

    public var unwrappedTypeName: String { get }
  • Actual type name if declaration uses typealias, otherwise just a typeName. Shorthand for typeName.actualTypeName

    Declaration

    Swift

    public var actualTypeName: TypeName? { get }
  • Whether type is a tuple. Shorthand for typeName.isTuple

    Declaration

    Swift

    public var isTuple: Bool { get }
  • Whether type is a closure. Shorthand for typeName.isClosure

    Declaration

    Swift

    public var isClosure: Bool { get }
  • Whether type is an array. Shorthand for typeName.isArray

    Declaration

    Swift

    public var isArray: Bool { get }
  • Whether type is a set. Shorthand for typeName.isSet

    Declaration

    Swift

    public var isSet: Bool { get }
  • Whether type is a dictionary. Shorthand for typeName.isDictionary

    Declaration

    Swift

    public var isDictionary: Bool { get }
================================================ FILE: docs/Guides.html ================================================ Guides Reference
================================================ FILE: docs/Other Classes.html ================================================ Other Classes Reference

Other Classes

The following classes are available globally.

  • Descibes Swift actor

    See more

    Declaration

    Swift

    @objc(SwiftActor)
    @objcMembers
    public final class Actor : Type
  • Defines import type

    See more

    Declaration

    Swift

    @objcMembers
    public class Import : NSObject, SourceryModelWithoutDescription, Diffable
    extension Import: NSCoding
  • modifier can be thing like private, class, nonmutating if a declaration has modifier like private(set) it’s name will be private and detail will be set

    See more

    Declaration

    Swift

    @objcMembers
    public class Modifier : NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable
    extension Modifier: NSCoding
  • Describes set type

    See more

    Declaration

    Swift

    @objcMembers
    public final class SetType : NSObject, SourceryModel, Diffable
    extension SetType: NSCoding
  • Declaration

    Swift

    @objcMembers
    public class DiffableResult : NSObject, AutoEquatable
  • Declaration

    Swift

    @objcMembers
    public final class ClosureParameter : NSObject, SourceryModel, Typed, Annotated
    extension ClosureParameter: NSCoding
  • Descibes Swift generic parameter

    See more

    Declaration

    Swift

    @objcMembers
    public final class GenericParameter : NSObject, SourceryModel, Diffable
    extension GenericParameter: NSCoding
  • Descibes Swift generic requirement

    See more

    Declaration

    Swift

    @objcMembers
    public class GenericRequirement : NSObject, SourceryModel, Diffable
    extension GenericRequirement: NSCoding
================================================ FILE: docs/Other Enums.html ================================================ Other Enumerations Reference
================================================ FILE: docs/Other Extensions.html ================================================ Other Extensions Reference

Other Extensions

The following extensions are available globally.

================================================ FILE: docs/Other Protocols.html ================================================ Other Protocols Reference

Other Protocols

The following protocols are available globally.

  • Describes annotated declaration, i.e. type, method, variable, enum case

    See more

    Declaration

    Swift

    public protocol Annotated
  • Describes that the object is defined in a context of some Type

    See more

    Declaration

    Swift

    public protocol Definition : AnyObject
  • Describes a declaration with documentation, i.e. type, method, variable, enum case

    See more

    Declaration

    Swift

    public protocol Documented
  • Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value

    See more

    Declaration

    Swift

    public protocol Typed
================================================ FILE: docs/Other Typealiases.html ================================================ Other Type Aliases Reference
================================================ FILE: docs/Protocols/Annotated.html ================================================ Annotated Protocol Reference

Annotated

public protocol Annotated

Describes annotated declaration, i.e. type, method, variable, enum case

  • All annotations of declaration stored by their name. Value can be bool, String, float NSNumber or array of those types if you use several annotations with the same name.

    Example:

    //sourcery: booleanAnnotation
    //sourcery: stringAnnotation = "value"
    //sourcery: numericAnnotation = 0.5
    
    [
     "booleanAnnotation": true,
     "stringAnnotation": "value",
     "numericAnnotation": 0.5
    ]
    

    Declaration

    Swift

    var annotations: Annotations { get }
================================================ FILE: docs/Protocols/Definition.html ================================================ Definition Protocol Reference

Definition

public protocol Definition : AnyObject

Describes that the object is defined in a context of some Type

  • Reference to type name where the object is defined, nil if defined outside of any enum, struct, class etc

    Declaration

    Swift

    var definedInTypeName: TypeName? { get }
  • Reference to actual type where the object is defined, nil if defined outside of any enum, struct, class etc or type is unknown

    Declaration

    Swift

    var definedInType: Type? { get }
  • Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a definedInTypeName

    Declaration

    Swift

    var actualDefinedInTypeName: TypeName? { get }
================================================ FILE: docs/Protocols/Diffable.html ================================================ Diffable Protocol Reference
================================================ FILE: docs/Protocols/Documented.html ================================================ Documented Protocol Reference
================================================ FILE: docs/Protocols/Typed.html ================================================ Typed Protocol Reference

Typed

public protocol Typed

Descibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value

  • Type, if known

    Declaration

    Swift

    var type: Type? { get }
  • Type name

    Declaration

    Swift

    var typeName: TypeName { get }
  • Whether type is optional

    Declaration

    Swift

    var isOptional: Bool { get }
  • Whether type is implicitly unwrapped optional

    Declaration

    Swift

    var isImplicitlyUnwrappedOptional: Bool { get }
  • Type name without attributes and optional type information

    Declaration

    Swift

    var unwrappedTypeName: String { get }
================================================ FILE: docs/Types.html ================================================ Types Reference

Types

  • Collection of scanned types for accessing in templates

    See more

    Declaration

    Swift

    @objcMembers
    public final class Types : NSObject, SourceryModel, Diffable
    extension Types: NSCoding
  • Defines Swift type

    See more

    Declaration

    Swift

    @objcMembers
    public class Type : NSObject, SourceryModel, Annotated, Documented, Diffable
    extension Type: NSCoding
  • Describes Swift protocol

    See more

    Declaration

    Swift

    @objcMembers
    public final class Protocol : Type
  • Descibes Swift class

    See more

    Declaration

    Swift

    @objc(SwiftClass)
    @objcMembers
    public final class Class : Type
  • Describes Swift struct

    See more

    Declaration

    Swift

    @objcMembers
    public final class Struct : Type
  • Defines Swift enum

    See more

    Declaration

    Swift

    @objcMembers
    public final class Enum : Type
  • Defines enum case

    See more

    Declaration

    Swift

    @objcMembers
    public final class EnumCase : NSObject, SourceryModel, AutoDescription, Annotated, Documented, Diffable
    extension EnumCase: NSCoding
  • Defines enum case associated value

    See more

    Declaration

    Swift

    @objcMembers
    public final class AssociatedValue : NSObject, SourceryModel, AutoDescription, Typed, Annotated, Diffable
    extension AssociatedValue: NSCoding
  • Describes Swift AssociatedType

    See more

    Declaration

    Swift

    @objcMembers
    public final class AssociatedType : NSObject, SourceryModel
    extension AssociatedType: NSCoding
  • Defines variable

    See more

    Declaration

    Swift

    @objcMembers
    public final class Variable : NSObject, SourceryModel, Typed, Annotated, Documented, Definition, Diffable
    extension Variable: NSCoding
  • Describes method

    See more

    Declaration

    Swift

    @objc(SwiftMethod)
    @objcMembers
    public final class Method : NSObject, SourceryModel, Annotated, Documented, Definition, Diffable
    extension Method: NSCoding
  • Describes method parameter

    See more

    Declaration

    Swift

    @objcMembers
    public class MethodParameter : NSObject, SourceryModel, Typed, Annotated, Diffable
    extension MethodParameter: NSCoding
  • Describes subscript

    See more

    Declaration

    Swift

    @objcMembers
    public final class Subscript : NSObject, SourceryModel, Annotated, Documented, Definition, Diffable
    extension Subscript: NSCoding
  • Describes name of the type used in typed declaration (variable, method parameter or return value etc.)

    See more

    Declaration

    Swift

    @objcMembers
    public final class TypeName : NSObject, SourceryModelWithoutDescription, LosslessStringConvertible, Diffable
    extension TypeName: NSCoding
  • Describes tuple type

    See more

    Declaration

    Swift

    @objcMembers
    public final class TupleType : NSObject, SourceryModel, Diffable
    extension TupleType: NSCoding
  • Describes tuple type element

    See more

    Declaration

    Swift

    @objcMembers
    public final class TupleElement : NSObject, SourceryModel, Typed, Diffable
    extension TupleElement: NSCoding
  • Describes array type

    See more

    Declaration

    Swift

    @objcMembers
    public final class ArrayType : NSObject, SourceryModel, Diffable
    extension ArrayType: NSCoding
  • Describes dictionary type

    See more

    Declaration

    Swift

    @objcMembers
    public final class DictionaryType : NSObject, SourceryModel, Diffable
    extension DictionaryType: NSCoding
  • Describes closure type

    See more

    Declaration

    Swift

    @objcMembers
    public final class ClosureType : NSObject, SourceryModel, Diffable
    extension ClosureType: NSCoding
  • Descibes Swift generic type

    See more

    Declaration

    Swift

    @objcMembers
    public final class GenericType : NSObject, SourceryModelWithoutDescription, Diffable
    extension GenericType: NSCoding
  • Descibes Swift generic type parameter

    See more

    Declaration

    Swift

    @objcMembers
    public final class GenericTypeParameter : NSObject, SourceryModel, Diffable
    extension GenericTypeParameter: NSCoding
  • Describes Swift attribute

    See more

    Declaration

    Swift

    @objcMembers
    public class Attribute : NSObject, AutoCoding, AutoEquatable, AutoDiffable, AutoJSExport, Diffable
    extension Attribute: NSCoding
  • Describes a Swift protocol composition.

    See more

    Declaration

    Swift

    @objcMembers
    public final class ProtocolComposition : Type
================================================ FILE: docs/codable.html ================================================ Codable Reference

I want to generate Codable implementation

This template generates Codable implementation for structs that implement AutoCodable, AutoDecodable or AutoEncodable protocols. You should define these protocols as follows:

protocol AutoDecodable: Decodable {}
protocol AutoEncodable: Encodable {}
protocol AutoCodable: AutoDecodable, AutoEncodable {}

Swift template

Generating coding keys.

If you have few keys that are not matching default key strategy you have to specify only these keys, all other keys will be generated and inlined by the template:

struct Person: AutoDecodable {
    let id: String
    let firstName: Bool
    let surname: String

    enum CodingKeys: String, CodingKey {
        // this is the custom key that you define manually
        case firstName = "first_name"

// sourcery:inline:auto:Person.CodingKeys.AutoCodable
        // the rest is generated by the template
        case id
        case surname
// sourcery:end
    }

}

Computed properties are not encoded by default, but if you define a coding key for computed property, template will generate code that will encode it.

If you don’t define any keys manually the template will generate CodingKeys enum with the keys for all stored properties, but only if custom implementation of init(from:) or encode(to:) is needed.

Generating init(from:) constructor.

Template will generate implementation of init(from:) when needed. You can define additional methods and properties on your type to be used to decode it.

  • method to get decoding container. This is useful if your type needs to be decoded from a nested key(s):
struct MyStruct: AutoDecodable {
    let value: Int

    enum CodingKeys: String, CodingKey {
        case nested
        case value
    }

    static func decodingContainer(_ decoder: Decoder) throws -> KeyedDecodingContainer<CodingKeys> {
        return try decoder.container(keyedBy: CodingKeys.self)
            .nestedContainer(keyedBy: CodingKeys.self, forKey: .nested)
    }
}
  • method to decode a property. This is useful if you need to decode some property manually:
struct MyStruct: AutoDecodable {
    let myProperty: Int

    static func decodeMyProperty(from container: KeyedDecodingContainer<CodingKeys>) -> Int? {
        return (try? container.decode(String.self, forKey: .myProperty)).flatMap(Int.init)
    }
    //or
    static func decodeMyProperty(from decoder: Decoder) throws -> Int {
        return try decoder.container(keyedBy: CodingKeys.self)
            .decode(Int.self, forKey: .myProperty)
    }
}

These methods can throw or not and can return optional or non-optional result.

  • default property value. You can define a static variable that will be used as a default value of a property if decoding results in nil value:
struct MyStruct: AutoDecodable {
    let myProperty: Int

    static let defaultMyProperty: Int = 0
}

Generating encode(to:) method.

Template will generate implementation of encode(to:) method when needed. You can define additional methods to be used to encode it.

  • method to get encoding container. This is useful if your type needs to be encoded into a nested key(s):
struct MyStruct: AutoDecodable {
    let value: Int

    enum CodingKeys: String, CodingKey {
        case nested
        case value
    }

    func encodingContainer(_ encoder: Encoder) -> KeyedEncodingContainer<CodingKeys> {
        var container = encoder.container(keyedBy: CodingKeys.self)
        return container.nestedContainer(keyedBy: CodingKeys.self, forKey: .nested)
    }
}
  • method to encode a property. This is useful when you need to manually encode a property:
struct MyStruct: AutoDecodable {
    let myProperty: Int

    func encodeMyProperty(to container: inout KeyedEncodingContainer<CodingKeys>) {
        try? container.decode(String(myProperty), forKey: .myProperty)
    }
    //or
    func encodeMyProperty(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(String(myProperty), forKey: .myProperty)
    }
}

These methods may throw or not.

If you need to manually encode computed property and you have defined custom encoding method for it, template will generate a coding key for it too, so you don’t have to define it manually (though you may still need to define it if it needs custom raw value).

  • method to encode any additional values. This is useful when you need to encode computed properties or constant values:
struct MyStruct: AutoDecodable {

    func encodeAdditionalValues(to container: inout KeyedEncodingContainer<CodingKeys>) throws {
        ...
    }
    // or
    func encodeAdditionalValues(to encoder: Encoder) throws {
        ...
    }
}

This method will be called in the end of generated encoding method.

  • enum SkipEncodingKeys for keys to be skipped during encoding. This is useful when you have stored properties that you don’t want to encode, i.e. constants:
  struct MyStruct: AutoCodable {
      let value: Int
      let skipValue: Int

      enum SkipEncodingKeys {
          case skipValue
      }
  }

Codable enums

Enums with numeric or string raw values are Codable by default. For enums with no raw value or with associated values template will generate Codable implementation.

Enums with no raw values and no associated values

For such enums template will generate decoding/encoding code that will expect values in JSON to be exactly the same as cases’ names.

enum SimpleEnum: AutoDecodable {
  case someCase
  case anotherCase
}

For such enum template will generate code that will successfully decode from/encode to JSON of following form:

{
  "value": "someCase"
  "anotherValue": "anotherCase"
}

You can define coding keys to change the values:

enum SimpleEnum: AutoDecodable {
  case someCase
  case anotherCase

  enum CodingKeys: String, CodingKey {
    case someCase = "some_case"
    case anotherCase = "another_case"
  }
}

Enums with assoicated values

Template supports two different representations of such enums in JSON format.

enum SimpleEnum: AutoDecodable {
  case someCase(id: Int, name: String)
  case anotherCase
}

If you define a coding key named enumCaseKey then the template will generate code that will encode/decode enum in/from following format:

{
  "type": "someCase" // enum case is encoded in a special key
  "id": 1,
  "name": "John"
}

All enum cases associated values must be named.

If you don’t define enumCaseKey then the template will generate code that will encode/decode enum in/from following format:

{
  "someCase": {
    "id": 1,
    "name": "John"
  }
}

Associated values of each enum case must be either all named or all unnamed. For cases with unnamed associated values JSON format will use array instead of dictionary for associated values, in the same order in which they are defined:

{
  "someCase": [
    1,
    "Jhon"
  ]
}

You can use all other customisation methods described for structs to decode/encode enum case associated values individually.

================================================ FILE: docs/css/highlight.css ================================================ /*! Jazzy - https://github.com/realm/jazzy * Copyright Realm Inc. * SPDX-License-Identifier: MIT */ /* Credit to https://gist.github.com/wataru420/2048287 */ .highlight .c { color: #999988; font-style: italic; } .highlight .err { color: #a61717; background-color: #e3d2d2; } .highlight .k { color: #000000; font-weight: bold; } .highlight .o { color: #000000; font-weight: bold; } .highlight .cm { color: #999988; font-style: italic; } .highlight .cp { color: #999999; font-weight: bold; } .highlight .c1 { color: #999988; font-style: italic; } .highlight .cs { color: #999999; font-weight: bold; font-style: italic; } .highlight .gd { color: #000000; background-color: #ffdddd; } .highlight .gd .x { color: #000000; background-color: #ffaaaa; } .highlight .ge { color: #000000; font-style: italic; } .highlight .gr { color: #aa0000; } .highlight .gh { color: #999999; } .highlight .gi { color: #000000; background-color: #ddffdd; } .highlight .gi .x { color: #000000; background-color: #aaffaa; } .highlight .go { color: #888888; } .highlight .gp { color: #555555; } .highlight .gs { font-weight: bold; } .highlight .gu { color: #aaaaaa; } .highlight .gt { color: #aa0000; } .highlight .kc { color: #000000; font-weight: bold; } .highlight .kd { color: #000000; font-weight: bold; } .highlight .kp { color: #000000; font-weight: bold; } .highlight .kr { color: #000000; font-weight: bold; } .highlight .kt { color: #445588; } .highlight .m { color: #009999; } .highlight .s { color: #d14; } .highlight .na { color: #008080; } .highlight .nb { color: #0086B3; } .highlight .nc { color: #445588; font-weight: bold; } .highlight .no { color: #008080; } .highlight .ni { color: #800080; } .highlight .ne { color: #990000; font-weight: bold; } .highlight .nf { color: #990000; } .highlight .nn { color: #555555; } .highlight .nt { color: #000080; } .highlight .nv { color: #008080; } .highlight .ow { color: #000000; font-weight: bold; } .highlight .w { color: #bbbbbb; } .highlight .mf { color: #009999; } .highlight .mh { color: #009999; } .highlight .mi { color: #009999; } .highlight .mo { color: #009999; } .highlight .sb { color: #d14; } .highlight .sc { color: #d14; } .highlight .sd { color: #d14; } .highlight .s2 { color: #d14; } .highlight .se { color: #d14; } .highlight .sh { color: #d14; } .highlight .si { color: #d14; } .highlight .sx { color: #d14; } .highlight .sr { color: #009926; } .highlight .s1 { color: #d14; } .highlight .ss { color: #990073; } .highlight .bp { color: #999999; } .highlight .vc { color: #008080; } .highlight .vg { color: #008080; } .highlight .vi { color: #008080; } .highlight .il { color: #009999; } ================================================ FILE: docs/css/jazzy.css ================================================ /*! Jazzy - https://github.com/realm/jazzy * Copyright Realm Inc. * SPDX-License-Identifier: MIT */ html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { background: transparent; border: 0; margin: 0; outline: 0; padding: 0; vertical-align: baseline; } body { background-color: #f2f2f2; font-family: Helvetica, freesans, Arial, sans-serif; font-size: 14px; -webkit-font-smoothing: subpixel-antialiased; word-wrap: break-word; } h1, h2, h3 { margin-top: 0.8em; margin-bottom: 0.3em; font-weight: 100; color: black; } h1 { font-size: 2.5em; } h2 { font-size: 2em; border-bottom: 1px solid #e2e2e2; } h4 { font-size: 13px; line-height: 1.5; margin-top: 21px; } h5 { font-size: 1.1em; } h6 { font-size: 1.1em; color: #777; } .section-name { color: gray; display: block; font-family: Helvetica; font-size: 22px; font-weight: 100; margin-bottom: 15px; } pre, code { font: 0.95em Menlo, monospace; color: #777; word-wrap: normal; } p code, li code { background-color: #eee; padding: 2px 4px; border-radius: 4px; } pre > code { padding: 0; } a { color: #0088cc; text-decoration: none; } a code { color: inherit; } ul { padding-left: 15px; } li { line-height: 1.8em; } img { max-width: 100%; } blockquote { margin-left: 0; padding: 0 10px; border-left: 4px solid #ccc; } hr { height: 1px; border: none; background-color: #e2e2e2; } .footnote-ref { display: inline-block; scroll-margin-top: 70px; } .footnote-def { scroll-margin-top: 70px; } .content-wrapper { margin: 0 auto; width: 980px; } header { font-size: 0.85em; line-height: 32px; background-color: #414141; position: fixed; width: 100%; z-index: 3; } header img { padding-right: 6px; vertical-align: -3px; height: 16px; } header a { color: #fff; } header p { float: left; color: #999; } header .header-right { float: right; margin-left: 16px; } #breadcrumbs { background-color: #f2f2f2; height: 21px; padding-top: 17px; position: fixed; width: 100%; z-index: 2; margin-top: 32px; } #breadcrumbs #carat { height: 10px; margin: 0 5px; } .sidebar { background-color: #f9f9f9; border: 1px solid #e2e2e2; overflow-y: auto; overflow-x: hidden; position: fixed; top: 70px; bottom: 0; width: 230px; word-wrap: normal; } .nav-groups { list-style-type: none; background: #fff; padding-left: 0; } .nav-group-name { border-bottom: 1px solid #e2e2e2; font-size: 1.1em; font-weight: 100; padding: 15px 0 15px 20px; } .nav-group-name > a { color: #333; } .nav-group-tasks { margin-top: 5px; } .nav-group-task { font-size: 0.9em; list-style-type: none; white-space: nowrap; } .nav-group-task a { color: #888; } .main-content { background-color: #fff; border: 1px solid #e2e2e2; margin-left: 246px; position: absolute; overflow: hidden; padding-bottom: 20px; top: 70px; width: 734px; } .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { margin-bottom: 1em; } .main-content p { line-height: 1.8em; } .main-content section .section:first-child { margin-top: 0; padding-top: 0; } .main-content section .task-group-section .task-group:first-of-type { padding-top: 10px; } .main-content section .task-group-section .task-group:first-of-type .section-name { padding-top: 15px; } .main-content section .heading:before { content: ""; display: block; padding-top: 70px; margin: -70px 0 0; } .main-content .section-name p { margin-bottom: inherit; line-height: inherit; } .main-content .section-name code { background-color: inherit; padding: inherit; color: inherit; } .section { padding: 0 25px; } .highlight { background-color: #eee; padding: 10px 12px; border: 1px solid #e2e2e2; border-radius: 4px; overflow-x: auto; } .declaration .highlight { overflow-x: initial; padding: 0 40px 40px 0; margin-bottom: -25px; background-color: transparent; border: none; } .section-name { margin: 0; margin-left: 18px; } .task-group-section { margin-top: 10px; padding-left: 6px; border-top: 1px solid #e2e2e2; } .task-group { padding-top: 0px; } .task-name-container a[name]:before { content: ""; display: block; padding-top: 70px; margin: -70px 0 0; } .section-name-container { position: relative; display: inline-block; } .section-name-container .section-name-link { position: absolute; top: 0; left: 0; bottom: 0; right: 0; margin-bottom: 0; } .section-name-container .section-name { position: relative; pointer-events: none; z-index: 1; } .section-name-container .section-name a { pointer-events: auto; } .item { padding-top: 8px; width: 100%; list-style-type: none; } .item a[name]:before { content: ""; display: block; padding-top: 70px; margin: -70px 0 0; } .item code { background-color: transparent; padding: 0; } .item .token, .item .direct-link { display: inline-block; text-indent: -20px; padding-left: 3px; margin-left: 35px; font-size: 11.9px; transition: all 300ms; } .item .token-open { margin-left: 20px; } .item .discouraged { text-decoration: line-through; } .item .declaration-note { font-size: .85em; color: gray; font-style: italic; } .pointer-container { border-bottom: 1px solid #e2e2e2; left: -23px; padding-bottom: 13px; position: relative; width: 110%; } .pointer { background: #f9f9f9; border-left: 1px solid #e2e2e2; border-top: 1px solid #e2e2e2; height: 12px; left: 21px; top: -7px; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -o-transform: rotate(45deg); transform: rotate(45deg); position: absolute; width: 12px; } .height-container { display: none; left: -25px; padding: 0 25px; position: relative; width: 100%; overflow: hidden; } .height-container .section { background: #f9f9f9; border-bottom: 1px solid #e2e2e2; left: -25px; position: relative; width: 100%; padding-top: 10px; padding-bottom: 5px; } .aside, .language { padding: 6px 12px; margin: 12px 0; border-left: 5px solid #dddddd; overflow-y: hidden; } .aside .aside-title, .language .aside-title { font-size: 9px; letter-spacing: 2px; text-transform: uppercase; padding-bottom: 0; margin: 0; color: #aaa; -webkit-user-select: none; } .aside p:last-child, .language p:last-child { margin-bottom: 0; } .language { border-left: 5px solid #cde9f4; } .language .aside-title { color: #4b8afb; } .aside-warning, .aside-deprecated, .aside-unavailable { border-left: 5px solid #ff6666; } .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { color: #ff0000; } .graybox { border-collapse: collapse; width: 100%; } .graybox p { margin: 0; word-break: break-word; min-width: 50px; } .graybox td { border: 1px solid #e2e2e2; padding: 5px 25px 5px 10px; vertical-align: middle; } .graybox tr td:first-of-type { text-align: right; padding: 7px; vertical-align: top; word-break: normal; width: 40px; } .slightly-smaller { font-size: 0.9em; } #footer { position: relative; top: 10px; bottom: 0px; margin-left: 25px; } #footer p { margin: 0; color: #aaa; font-size: 0.8em; } html.dash header, html.dash #breadcrumbs, html.dash .sidebar { display: none; } html.dash .main-content { width: 980px; margin-left: 0; border: none; width: 100%; top: 0; padding-bottom: 0; } html.dash .height-container { display: block; } html.dash .item .token { margin-left: 0; } html.dash .content-wrapper { width: auto; } html.dash #footer { position: static; } form[role=search] { float: right; } form[role=search] input { font: Helvetica, freesans, Arial, sans-serif; margin-top: 6px; font-size: 13px; line-height: 20px; padding: 0px 10px; border: none; border-radius: 1em; } .loading form[role=search] input { background: white url(../img/spinner.gif) center right 4px no-repeat; } form[role=search] .tt-menu { margin: 0; min-width: 300px; background: #fff; color: #333; border: 1px solid #e2e2e2; z-index: 4; } form[role=search] .tt-highlight { font-weight: bold; } form[role=search] .tt-suggestion { font: Helvetica, freesans, Arial, sans-serif; font-size: 14px; padding: 0 8px; } form[role=search] .tt-suggestion span { display: table-cell; white-space: nowrap; } form[role=search] .tt-suggestion .doc-parent-name { width: 100%; text-align: right; font-weight: normal; font-size: 0.9em; padding-left: 16px; } form[role=search] .tt-suggestion:hover, form[role=search] .tt-suggestion.tt-cursor { cursor: pointer; background-color: #4183c4; color: #fff; } form[role=search] .tt-suggestion:hover .doc-parent-name, form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { color: #fff; } ================================================ FILE: docs/decorator.html ================================================ Decorator Reference

I want to generate simple decorator for my type

In Swift it can be cumbersome to write a simple decorator that decorates all the calls to decorated type methods, you basically have to do it manually for each single method. With this template you can generate simple decorator that generate all the methods and property calls automatically, skipping methods and properties already implemented manually.

You can use this template as a starting point for more sophisticated implementations. This template also shows you some powers of swift templates, like using helper methods and whitespace control tags.

Swift template

Available annotations

  • decorate - what type to decorate
  • decorateMethod - code to decorate each method call with
  • decorateGet - code to decorate each property getter
  • decorateSet - code to decorate each property setter

Example input:

protocol Service {
    var prop1: Int { get }
    var prop2: Int { get set }
    func foo(f: Int, _ a: Int) throws -> Int
    func bar(_ b: String)
}

// sourcery: decorate = "Service"
// sourcery: decorateMethod = "print(#function)"
// sourcery: decorateGet = "print("get: \(#function)")"
// sourcery: decorateSet = "print("set: \(#function)")"
struct ServiceDecorator: Service {
    // generated code will go here
}

extension ServiceDecorator {
     // manually implemented method
    internal func bar(_ b: String) {
        decorated.bar(b)
    }

}

Example output:

...

// sourcery: decorate = Service
// sourcery: decorateMethod = print(#function)
// sourcery: decorateGet = "print("get: \(#function)")"
// sourcery: decorateSet = "print("set: \(#function)")"
struct ServiceDecorator: Service {

// sourcery:inline:auto:ServiceDecorator.autoDecorated
    internal private(set) var decorated: Service

    internal init(decorated: Service) {
        self.decorated = decorated
    }

    internal var prop1: Int {
        print("get: \(#function)")
        return decorated.prop1
    }

    internal var prop2: Int {
        get {
            print("get: \(#function)")
            return decorated.prop2
        }
        set {
            print("set: \(#function)")
            decorated.prop2 = newValue
        }
    }

    internal func foo(f: Int, _ a: Int) throws -> Int {
        print(#function)
        return try decorated.foo(f: f, a)
    }
// sourcery:end
}
...
================================================ FILE: docs/diffable.html ================================================ Diffable Reference
================================================ FILE: docs/enum-cases.html ================================================ Enum cases Reference

I want to list all cases in an enum

Generate count and allCases for any enumeration that is marked with AutoCases phantom protocol.

Stencil Template

Example output:

extension BetaSettingsGroup {
  static let count: Int = return 8

  static let allCases: [BetaSettingsGroup] = [
      .featuresInDevelopment,
      .advertising,
      .analytics,
      .marketing,
      .news,
      .notifications,
      .tech,
      .appInformation
    ]
}
================================================ FILE: docs/equatable.html ================================================ Equatable Reference

I want to generate Equatable implementation

Template used to generate equality for all types that either conform to the AutoEquatable protocol or are annotated with AutoEquatable annotation, allowing us to avoid writing boilerplate code.

It adds :Equatable conformance to all types, except protocols (because it would require turning them into PAT’s). For protocols it’s just generating func ==.

Stencil template

Available variable annotations:

  • skipEquality allows you to skip variable from being compared.
  • arrayEquality mark this to use array comparsion for variables that have array of items that don’t implement Equatable but have == operator e.g. Protocols

Example output:

// MARK: - AdNodeViewModel AutoEquatable
extension AdNodeViewModel: Equatable {}

internal func == (lhs: AdNodeViewModel, rhs: AdNodeViewModel) -> Bool {
    guard lhs.remoteAdView == rhs.remoteAdView else { return false }
    guard lhs.hidesDisclaimer == rhs.hidesDisclaimer else { return false }
    guard lhs.type == rhs.type else { return false }
    guard lhs.height == rhs.height else { return false }

    guard lhs.attributedDisclaimer == rhs.attributedDisclaimer else { return false }

    return true
}
================================================ FILE: docs/hashable.html ================================================ Hashable Reference

I want to generate Hashable implementation

Template used to generate hashing for all types that conform to :AutoHashable, allowing us to avoid writing boilerplate code.

It adds :Hashable conformance to all types, except protocols (because it would require turning them into PAT’s). For protocols it’s just generating var hashValue comparator.

Stencil template

Available variable annotations:

  • skipHashing allows you to skip variable from being compared.
  • includeInHashing is only applied on enums and allows us to add some computed variable into hashing logic

Example output:

// MARK: - AdNodeViewModel AutoHashable
extension AdNodeViewModel: Hashable {

    internal var hashValue: Int {
        return combineHashes(remoteAdView.hashValue, hidesDisclaimer.hashValue, type.hashValue, height.hashValue, attributedDisclaimer.hashValue, 0)
    }
}
================================================ FILE: docs/index.html ================================================ Sourcery Reference

What is Sourcery?

Sourcery scans your source code, applies your personal templates and generates Swift code for you, allowing you to use meta-programming techniques to save time and decrease potential mistakes.

Using it offers many benefits:

  • Write less repetitive code and make it easy to adhere to DRY principle.
  • It allows you to create better code, one that would be hard to maintain without it, e.g. performing automatic property level difference in tests
  • Limits the risk of introducing human error when refactoring.
  • Sourcery doesn’t use runtime tricks, in fact, it allows you to leverage compiler, even more, creating more safety.
  • Immediate feedback: Sourcery features built-in daemon support, enabling you to write your templates in real-time side-by-side with generated code.

Sourcery is so meta that it is used to code-generate its boilerplate code

Why?

Swift features very limited runtime and no meta-programming features. Which leads our projects to contain boilerplate code.

Sourcery exists to allow Swift developers to stop doing the same thing over and over again while still maintaining strong typing, preventing bugs and leveraging compiler.

Have you ever?

  • Had to write equatable/hashable?
  • Had to write NSCoding support?
  • Had to implement JSON serialization?
  • Wanted to use Lenses?

If you did then you probably found yourself writing repetitive code to deal with those scenarios, does this feel right?

Even worse, if you ever add a new property to a type all of those implementations have to be updated, or you will end up with bugs. In those scenarios usually compiler will not generate the error for you, which leads to error prone code.

================================================ FILE: docs/installing.html ================================================ Installing Reference

Installing

  • Binary form

    Download latest release with prebuilt binary from release tab. Unzip the archive into desired destination and run bin/sourcery

  • CocoaPods

    Add pod ‘Sourcery’ to your Podfile and run pod update Sourcery. This will download latest release binary and will put it to your project’s CocoaPods path so you will run it with $PODS_ROOT/Sourcery/bin/sourcery

  • Building from source

    Download latest release source code from release tab or clone the repository an build Sourcery manually.

    • Building with Swift Package Manager

      Run swift build -c release in the root folder. This will create a .build/release folder and will put binary there. Move the whole .build/release folder to your desired destination and run with path_to_release_folder/sourcery

      Note

      JS templates are not supported when building with SPM yet.

    • Building with Xcode

      Open Sourcery.xcworkspace and build with Sourcery-Release scheme. This will create Sourcery.app in the Derived Data folder. You can copy it to your desired destination and run with path_to_sourcery_app/Sourcery.app/Contents/MacOS/Sourcery

================================================ FILE: docs/js/jazzy.js ================================================ // Jazzy - https://github.com/realm/jazzy // Copyright Realm Inc. // SPDX-License-Identifier: MIT window.jazzy = {'docset': false} if (typeof window.dash != 'undefined') { document.documentElement.className += ' dash' window.jazzy.docset = true } if (navigator.userAgent.match(/xcode/i)) { document.documentElement.className += ' xcode' window.jazzy.docset = true } function toggleItem($link, $content) { var animationDuration = 300; $link.toggleClass('token-open'); $content.slideToggle(animationDuration); } function itemLinkToContent($link) { return $link.parent().parent().next(); } // On doc load + hash-change, open any targetted item function openCurrentItemIfClosed() { if (window.jazzy.docset) { return; } var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); $content = itemLinkToContent($link); if ($content.is(':hidden')) { toggleItem($link, $content); } } $(openCurrentItemIfClosed); $(window).on('hashchange', openCurrentItemIfClosed); // On item link ('token') click, toggle its discussion $('.token').on('click', function(event) { if (window.jazzy.docset) { return; } var $link = $(this); toggleItem($link, itemLinkToContent($link)); // Keeps the document from jumping to the hash. var href = $link.attr('href'); if (history.pushState) { history.pushState({}, '', href); } else { location.hash = href; } event.preventDefault(); }); // Clicks on links to the current, closed, item need to open the item $("a:not('.token')").on('click', function() { if (location == this.href) { openCurrentItemIfClosed(); } }); // KaTeX rendering if ("katex" in window) { $($('.math').each( (_, element) => { katex.render(element.textContent, element, { displayMode: $(element).hasClass('m-block'), throwOnError: false, trust: true }); })) } ================================================ FILE: docs/js/jazzy.search.js ================================================ // Jazzy - https://github.com/realm/jazzy // Copyright Realm Inc. // SPDX-License-Identifier: MIT $(function(){ var $typeahead = $('[data-typeahead]'); var $form = $typeahead.parents('form'); var searchURL = $form.attr('action'); function displayTemplate(result) { return result.name; } function suggestionTemplate(result) { var t = '
'; t += '' + result.name + ''; if (result.parent_name) { t += '' + result.parent_name + ''; } t += '
'; return t; } $typeahead.one('focus', function() { $form.addClass('loading'); $.getJSON(searchURL).then(function(searchData) { const searchIndex = lunr(function() { this.ref('url'); this.field('name'); this.field('abstract'); for (const [url, doc] of Object.entries(searchData)) { this.add({url: url, name: doc.name, abstract: doc.abstract}); } }); $typeahead.typeahead( { highlight: true, minLength: 3, autoselect: true }, { limit: 10, display: displayTemplate, templates: { suggestion: suggestionTemplate }, source: function(query, sync) { const lcSearch = query.toLowerCase(); const results = searchIndex.query(function(q) { q.term(lcSearch, { boost: 100 }); q.term(lcSearch, { boost: 10, wildcard: lunr.Query.wildcard.TRAILING }); }).map(function(result) { var doc = searchData[result.ref]; doc.url = result.ref; return doc; }); sync(results); } } ); $form.removeClass('loading'); $typeahead.trigger('focus'); }); }); var baseURL = searchURL.slice(0, -"search.json".length); $typeahead.on('typeahead:select', function(e, result) { window.location = baseURL + result.url; }); }); ================================================ FILE: docs/js/typeahead.jquery.js ================================================ /*! * typeahead.js 1.3.1 * https://github.com/corejavascript/typeahead.js * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT */ (function(root, factory) { if (typeof define === "function" && define.amd) { define([ "jquery" ], function(a0) { return factory(a0); }); } else if (typeof module === "object" && module.exports) { module.exports = factory(require("jquery")); } else { factory(root["jQuery"]); } })(this, function($) { var _ = function() { "use strict"; return { isMsie: function() { return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; }, isBlankString: function(str) { return !str || /^\s*$/.test(str); }, escapeRegExChars: function(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }, isString: function(obj) { return typeof obj === "string"; }, isNumber: function(obj) { return typeof obj === "number"; }, isArray: $.isArray, isFunction: $.isFunction, isObject: $.isPlainObject, isUndefined: function(obj) { return typeof obj === "undefined"; }, isElement: function(obj) { return !!(obj && obj.nodeType === 1); }, isJQuery: function(obj) { return obj instanceof $; }, toStr: function toStr(s) { return _.isUndefined(s) || s === null ? "" : s + ""; }, bind: $.proxy, each: function(collection, cb) { $.each(collection, reverseArgs); function reverseArgs(index, value) { return cb(value, index); } }, map: $.map, filter: $.grep, every: function(obj, test) { var result = true; if (!obj) { return result; } $.each(obj, function(key, val) { if (!(result = test.call(null, val, key, obj))) { return false; } }); return !!result; }, some: function(obj, test) { var result = false; if (!obj) { return result; } $.each(obj, function(key, val) { if (result = test.call(null, val, key, obj)) { return false; } }); return !!result; }, mixin: $.extend, identity: function(x) { return x; }, clone: function(obj) { return $.extend(true, {}, obj); }, getIdGenerator: function() { var counter = 0; return function() { return counter++; }; }, templatify: function templatify(obj) { return $.isFunction(obj) ? obj : template; function template() { return String(obj); } }, defer: function(fn) { setTimeout(fn, 0); }, debounce: function(func, wait, immediate) { var timeout, result; return function() { var context = this, args = arguments, later, callNow; later = function() { timeout = null; if (!immediate) { result = func.apply(context, args); } }; callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); } return result; }; }, throttle: function(func, wait) { var context, args, timeout, result, previous, later; previous = 0; later = function() { previous = new Date(); timeout = null; result = func.apply(context, args); }; return function() { var now = new Date(), remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); } else if (!timeout) { timeout = setTimeout(later, remaining); } return result; }; }, stringify: function(val) { return _.isString(val) ? val : JSON.stringify(val); }, guid: function() { function _p8(s) { var p = (Math.random().toString(16) + "000000000").substr(2, 8); return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p; } return "tt-" + _p8() + _p8(true) + _p8(true) + _p8(); }, noop: function() {} }; }(); var WWW = function() { "use strict"; var defaultClassNames = { wrapper: "twitter-typeahead", input: "tt-input", hint: "tt-hint", menu: "tt-menu", dataset: "tt-dataset", suggestion: "tt-suggestion", selectable: "tt-selectable", empty: "tt-empty", open: "tt-open", cursor: "tt-cursor", highlight: "tt-highlight" }; return build; function build(o) { var www, classes; classes = _.mixin({}, defaultClassNames, o); www = { css: buildCss(), classes: classes, html: buildHtml(classes), selectors: buildSelectors(classes) }; return { css: www.css, html: www.html, classes: www.classes, selectors: www.selectors, mixin: function(o) { _.mixin(o, www); } }; } function buildHtml(c) { return { wrapper: '', menu: '
' }; } function buildSelectors(classes) { var selectors = {}; _.each(classes, function(v, k) { selectors[k] = "." + v; }); return selectors; } function buildCss() { var css = { wrapper: { position: "relative", display: "inline-block" }, hint: { position: "absolute", top: "0", left: "0", borderColor: "transparent", boxShadow: "none", opacity: "1" }, input: { position: "relative", verticalAlign: "top", backgroundColor: "transparent" }, inputWithNoHint: { position: "relative", verticalAlign: "top" }, menu: { position: "absolute", top: "100%", left: "0", zIndex: "100", display: "none" }, ltr: { left: "0", right: "auto" }, rtl: { left: "auto", right: " 0" } }; if (_.isMsie()) { _.mixin(css.input, { backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" }); } return css; } }(); var EventBus = function() { "use strict"; var namespace, deprecationMap; namespace = "typeahead:"; deprecationMap = { render: "rendered", cursorchange: "cursorchanged", select: "selected", autocomplete: "autocompleted" }; function EventBus(o) { if (!o || !o.el) { $.error("EventBus initialized without el"); } this.$el = $(o.el); } _.mixin(EventBus.prototype, { _trigger: function(type, args) { var $e = $.Event(namespace + type); this.$el.trigger.call(this.$el, $e, args || []); return $e; }, before: function(type) { var args, $e; args = [].slice.call(arguments, 1); $e = this._trigger("before" + type, args); return $e.isDefaultPrevented(); }, trigger: function(type) { var deprecatedType; this._trigger(type, [].slice.call(arguments, 1)); if (deprecatedType = deprecationMap[type]) { this._trigger(deprecatedType, [].slice.call(arguments, 1)); } } }); return EventBus; }(); var EventEmitter = function() { "use strict"; var splitter = /\s+/, nextTick = getNextTick(); return { onSync: onSync, onAsync: onAsync, off: off, trigger: trigger }; function on(method, types, cb, context) { var type; if (!cb) { return this; } types = types.split(splitter); cb = context ? bindContext(cb, context) : cb; this._callbacks = this._callbacks || {}; while (type = types.shift()) { this._callbacks[type] = this._callbacks[type] || { sync: [], async: [] }; this._callbacks[type][method].push(cb); } return this; } function onAsync(types, cb, context) { return on.call(this, "async", types, cb, context); } function onSync(types, cb, context) { return on.call(this, "sync", types, cb, context); } function off(types) { var type; if (!this._callbacks) { return this; } types = types.split(splitter); while (type = types.shift()) { delete this._callbacks[type]; } return this; } function trigger(types) { var type, callbacks, args, syncFlush, asyncFlush; if (!this._callbacks) { return this; } types = types.split(splitter); args = [].slice.call(arguments, 1); while ((type = types.shift()) && (callbacks = this._callbacks[type])) { syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); syncFlush() && nextTick(asyncFlush); } return this; } function getFlush(callbacks, context, args) { return flush; function flush() { var cancelled; for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { cancelled = callbacks[i].apply(context, args) === false; } return !cancelled; } } function getNextTick() { var nextTickFn; if (window.setImmediate) { nextTickFn = function nextTickSetImmediate(fn) { setImmediate(function() { fn(); }); }; } else { nextTickFn = function nextTickSetTimeout(fn) { setTimeout(function() { fn(); }, 0); }; } return nextTickFn; } function bindContext(fn, context) { return fn.bind ? fn.bind(context) : function() { fn.apply(context, [].slice.call(arguments, 0)); }; } }(); var highlight = function(doc) { "use strict"; var defaults = { node: null, pattern: null, tagName: "strong", className: null, wordsOnly: false, caseSensitive: false, diacriticInsensitive: false }; var accented = { A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" }; return function hightlight(o) { var regex; o = _.mixin({}, defaults, o); if (!o.node || !o.pattern) { return; } o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); traverse(o.node, hightlightTextNode); function hightlightTextNode(textNode) { var match, patternNode, wrapperNode; if (match = regex.exec(textNode.data)) { wrapperNode = doc.createElement(o.tagName); o.className && (wrapperNode.className = o.className); patternNode = textNode.splitText(match.index); patternNode.splitText(match[0].length); wrapperNode.appendChild(patternNode.cloneNode(true)); textNode.parentNode.replaceChild(wrapperNode, patternNode); } return !!match; } function traverse(el, hightlightTextNode) { var childNode, TEXT_NODE_TYPE = 3; for (var i = 0; i < el.childNodes.length; i++) { childNode = el.childNodes[i]; if (childNode.nodeType === TEXT_NODE_TYPE) { i += hightlightTextNode(childNode) ? 1 : 0; } else { traverse(childNode, hightlightTextNode); } } } }; function accent_replacer(chr) { return accented[chr.toUpperCase()] || chr; } function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { var escapedPatterns = [], regexStr; for (var i = 0, len = patterns.length; i < len; i++) { var escapedWord = _.escapeRegExChars(patterns[i]); if (diacriticInsensitive) { escapedWord = escapedWord.replace(/\S/g, accent_replacer); } escapedPatterns.push(escapedWord); } regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); } }(window.document); var Input = function() { "use strict"; var specialKeyCodeMap; specialKeyCodeMap = { 9: "tab", 27: "esc", 37: "left", 39: "right", 13: "enter", 38: "up", 40: "down" }; function Input(o, www) { var id; o = o || {}; if (!o.input) { $.error("input is missing"); } www.mixin(this); this.$hint = $(o.hint); this.$input = $(o.input); this.$menu = $(o.menu); id = this.$input.attr("id") || _.guid(); this.$menu.attr("id", id + "_listbox"); this.$hint.attr({ "aria-hidden": true }); this.$input.attr({ "aria-owns": id + "_listbox", role: "combobox", "aria-autocomplete": "list", "aria-expanded": false }); this.query = this.$input.val(); this.queryWhenFocused = this.hasFocus() ? this.query : null; this.$overflowHelper = buildOverflowHelper(this.$input); this._checkLanguageDirection(); if (this.$hint.length === 0) { this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; } this.onSync("cursorchange", this._updateDescendent); } Input.normalizeQuery = function(str) { return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); }; _.mixin(Input.prototype, EventEmitter, { _onBlur: function onBlur() { this.resetInputValue(); this.trigger("blurred"); }, _onFocus: function onFocus() { this.queryWhenFocused = this.query; this.trigger("focused"); }, _onKeydown: function onKeydown($e) { var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; this._managePreventDefault(keyName, $e); if (keyName && this._shouldTrigger(keyName, $e)) { this.trigger(keyName + "Keyed", $e); } }, _onInput: function onInput() { this._setQuery(this.getInputValue()); this.clearHintIfInvalid(); this._checkLanguageDirection(); }, _managePreventDefault: function managePreventDefault(keyName, $e) { var preventDefault; switch (keyName) { case "up": case "down": preventDefault = !withModifier($e); break; default: preventDefault = false; } preventDefault && $e.preventDefault(); }, _shouldTrigger: function shouldTrigger(keyName, $e) { var trigger; switch (keyName) { case "tab": trigger = !withModifier($e); break; default: trigger = true; } return trigger; }, _checkLanguageDirection: function checkLanguageDirection() { var dir = (this.$input.css("direction") || "ltr").toLowerCase(); if (this.dir !== dir) { this.dir = dir; this.$hint.attr("dir", dir); this.trigger("langDirChanged", dir); } }, _setQuery: function setQuery(val, silent) { var areEquivalent, hasDifferentWhitespace; areEquivalent = areQueriesEquivalent(val, this.query); hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; this.query = val; if (!silent && !areEquivalent) { this.trigger("queryChanged", this.query); } else if (!silent && hasDifferentWhitespace) { this.trigger("whitespaceChanged", this.query); } }, _updateDescendent: function updateDescendent(event, id) { this.$input.attr("aria-activedescendant", id); }, bind: function() { var that = this, onBlur, onFocus, onKeydown, onInput; onBlur = _.bind(this._onBlur, this); onFocus = _.bind(this._onFocus, this); onKeydown = _.bind(this._onKeydown, this); onInput = _.bind(this._onInput, this); this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); if (!_.isMsie() || _.isMsie() > 9) { this.$input.on("input.tt", onInput); } else { this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { if (specialKeyCodeMap[$e.which || $e.keyCode]) { return; } _.defer(_.bind(that._onInput, that, $e)); }); } return this; }, focus: function focus() { this.$input.focus(); }, blur: function blur() { this.$input.blur(); }, getLangDir: function getLangDir() { return this.dir; }, getQuery: function getQuery() { return this.query || ""; }, setQuery: function setQuery(val, silent) { this.setInputValue(val); this._setQuery(val, silent); }, hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { return this.query !== this.queryWhenFocused; }, getInputValue: function getInputValue() { return this.$input.val(); }, setInputValue: function setInputValue(value) { this.$input.val(value); this.clearHintIfInvalid(); this._checkLanguageDirection(); }, resetInputValue: function resetInputValue() { this.setInputValue(this.query); }, getHint: function getHint() { return this.$hint.val(); }, setHint: function setHint(value) { this.$hint.val(value); }, clearHint: function clearHint() { this.setHint(""); }, clearHintIfInvalid: function clearHintIfInvalid() { var val, hint, valIsPrefixOfHint, isValid; val = this.getInputValue(); hint = this.getHint(); valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); !isValid && this.clearHint(); }, hasFocus: function hasFocus() { return this.$input.is(":focus"); }, hasOverflow: function hasOverflow() { var constraint = this.$input.width() - 2; this.$overflowHelper.text(this.getInputValue()); return this.$overflowHelper.width() >= constraint; }, isCursorAtEnd: function() { var valueLength, selectionStart, range; valueLength = this.$input.val().length; selectionStart = this.$input[0].selectionStart; if (_.isNumber(selectionStart)) { return selectionStart === valueLength; } else if (document.selection) { range = document.selection.createRange(); range.moveStart("character", -valueLength); return valueLength === range.text.length; } return true; }, destroy: function destroy() { this.$hint.off(".tt"); this.$input.off(".tt"); this.$overflowHelper.remove(); this.$hint = this.$input = this.$overflowHelper = $("
"); }, setAriaExpanded: function setAriaExpanded(value) { this.$input.attr("aria-expanded", value); } }); return Input; function buildOverflowHelper($input) { return $('').css({ position: "absolute", visibility: "hidden", whiteSpace: "pre", fontFamily: $input.css("font-family"), fontSize: $input.css("font-size"), fontStyle: $input.css("font-style"), fontVariant: $input.css("font-variant"), fontWeight: $input.css("font-weight"), wordSpacing: $input.css("word-spacing"), letterSpacing: $input.css("letter-spacing"), textIndent: $input.css("text-indent"), textRendering: $input.css("text-rendering"), textTransform: $input.css("text-transform") }).insertAfter($input); } function areQueriesEquivalent(a, b) { return Input.normalizeQuery(a) === Input.normalizeQuery(b); } function withModifier($e) { return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; } }(); var Dataset = function() { "use strict"; var keys, nameGenerator; keys = { dataset: "tt-selectable-dataset", val: "tt-selectable-display", obj: "tt-selectable-object" }; nameGenerator = _.getIdGenerator(); function Dataset(o, www) { o = o || {}; o.templates = o.templates || {}; o.templates.notFound = o.templates.notFound || o.templates.empty; if (!o.source) { $.error("missing source"); } if (!o.node) { $.error("missing node"); } if (o.name && !isValidName(o.name)) { $.error("invalid dataset name: " + o.name); } www.mixin(this); this.highlight = !!o.highlight; this.name = _.toStr(o.name || nameGenerator()); this.limit = o.limit || 5; this.displayFn = getDisplayFn(o.display || o.displayKey); this.templates = getTemplates(o.templates, this.displayFn); this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; this._resetLastSuggestion(); this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); } Dataset.extractData = function extractData(el) { var $el = $(el); if ($el.data(keys.obj)) { return { dataset: $el.data(keys.dataset) || "", val: $el.data(keys.val) || "", obj: $el.data(keys.obj) || null }; } return null; }; _.mixin(Dataset.prototype, EventEmitter, { _overwrite: function overwrite(query, suggestions) { suggestions = suggestions || []; if (suggestions.length) { this._renderSuggestions(query, suggestions); } else if (this.async && this.templates.pending) { this._renderPending(query); } else if (!this.async && this.templates.notFound) { this._renderNotFound(query); } else { this._empty(); } this.trigger("rendered", suggestions, false, this.name); }, _append: function append(query, suggestions) { suggestions = suggestions || []; if (suggestions.length && this.$lastSuggestion.length) { this._appendSuggestions(query, suggestions); } else if (suggestions.length) { this._renderSuggestions(query, suggestions); } else if (!this.$lastSuggestion.length && this.templates.notFound) { this._renderNotFound(query); } this.trigger("rendered", suggestions, true, this.name); }, _renderSuggestions: function renderSuggestions(query, suggestions) { var $fragment; $fragment = this._getSuggestionsFragment(query, suggestions); this.$lastSuggestion = $fragment.children().last(); this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); }, _appendSuggestions: function appendSuggestions(query, suggestions) { var $fragment, $lastSuggestion; $fragment = this._getSuggestionsFragment(query, suggestions); $lastSuggestion = $fragment.children().last(); this.$lastSuggestion.after($fragment); this.$lastSuggestion = $lastSuggestion; }, _renderPending: function renderPending(query) { var template = this.templates.pending; this._resetLastSuggestion(); template && this.$el.html(template({ query: query, dataset: this.name })); }, _renderNotFound: function renderNotFound(query) { var template = this.templates.notFound; this._resetLastSuggestion(); template && this.$el.html(template({ query: query, dataset: this.name })); }, _empty: function empty() { this.$el.empty(); this._resetLastSuggestion(); }, _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { var that = this, fragment; fragment = document.createDocumentFragment(); _.each(suggestions, function getSuggestionNode(suggestion) { var $el, context; context = that._injectQuery(query, suggestion); $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); fragment.appendChild($el[0]); }); this.highlight && highlight({ className: this.classes.highlight, node: fragment, pattern: query }); return $(fragment); }, _getFooter: function getFooter(query, suggestions) { return this.templates.footer ? this.templates.footer({ query: query, suggestions: suggestions, dataset: this.name }) : null; }, _getHeader: function getHeader(query, suggestions) { return this.templates.header ? this.templates.header({ query: query, suggestions: suggestions, dataset: this.name }) : null; }, _resetLastSuggestion: function resetLastSuggestion() { this.$lastSuggestion = $(); }, _injectQuery: function injectQuery(query, obj) { return _.isObject(obj) ? _.mixin({ _query: query }, obj) : obj; }, update: function update(query) { var that = this, canceled = false, syncCalled = false, rendered = 0; this.cancel(); this.cancel = function cancel() { canceled = true; that.cancel = $.noop; that.async && that.trigger("asyncCanceled", query, that.name); }; this.source(query, sync, async); !syncCalled && sync([]); function sync(suggestions) { if (syncCalled) { return; } syncCalled = true; suggestions = (suggestions || []).slice(0, that.limit); rendered = suggestions.length; that._overwrite(query, suggestions); if (rendered < that.limit && that.async) { that.trigger("asyncRequested", query, that.name); } } function async(suggestions) { suggestions = suggestions || []; if (!canceled && rendered < that.limit) { that.cancel = $.noop; var idx = Math.abs(rendered - that.limit); rendered += idx; that._append(query, suggestions.slice(0, idx)); that.async && that.trigger("asyncReceived", query, that.name); } } }, cancel: $.noop, clear: function clear() { this._empty(); this.cancel(); this.trigger("cleared"); }, isEmpty: function isEmpty() { return this.$el.is(":empty"); }, destroy: function destroy() { this.$el = $("
"); } }); return Dataset; function getDisplayFn(display) { display = display || _.stringify; return _.isFunction(display) ? display : displayFn; function displayFn(obj) { return obj[display]; } } function getTemplates(templates, displayFn) { return { notFound: templates.notFound && _.templatify(templates.notFound), pending: templates.pending && _.templatify(templates.pending), header: templates.header && _.templatify(templates.header), footer: templates.footer && _.templatify(templates.footer), suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate }; function userSuggestionTemplate(context) { var template = templates.suggestion; return $(template(context)).attr("id", _.guid()); } function suggestionTemplate(context) { return $('
').attr("id", _.guid()).text(displayFn(context)); } } function isValidName(str) { return /^[_a-zA-Z0-9-]+$/.test(str); } }(); var Menu = function() { "use strict"; function Menu(o, www) { var that = this; o = o || {}; if (!o.node) { $.error("node is required"); } www.mixin(this); this.$node = $(o.node); this.query = null; this.datasets = _.map(o.datasets, initializeDataset); function initializeDataset(oDataset) { var node = that.$node.find(oDataset.node).first(); oDataset.node = node.length ? node : $("
").appendTo(that.$node); return new Dataset(oDataset, www); } } _.mixin(Menu.prototype, EventEmitter, { _onSelectableClick: function onSelectableClick($e) { this.trigger("selectableClicked", $($e.currentTarget)); }, _onRendered: function onRendered(type, dataset, suggestions, async) { this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); this.trigger("datasetRendered", dataset, suggestions, async); }, _onCleared: function onCleared() { this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); this.trigger("datasetCleared"); }, _propagate: function propagate() { this.trigger.apply(this, arguments); }, _allDatasetsEmpty: function allDatasetsEmpty() { return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { var isEmpty = dataset.isEmpty(); this.$node.attr("aria-expanded", !isEmpty); return isEmpty; }, this)); }, _getSelectables: function getSelectables() { return this.$node.find(this.selectors.selectable); }, _removeCursor: function _removeCursor() { var $selectable = this.getActiveSelectable(); $selectable && $selectable.removeClass(this.classes.cursor); }, _ensureVisible: function ensureVisible($el) { var elTop, elBottom, nodeScrollTop, nodeHeight; elTop = $el.position().top; elBottom = elTop + $el.outerHeight(true); nodeScrollTop = this.$node.scrollTop(); nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); if (elTop < 0) { this.$node.scrollTop(nodeScrollTop + elTop); } else if (nodeHeight < elBottom) { this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); } }, bind: function() { var that = this, onSelectableClick; onSelectableClick = _.bind(this._onSelectableClick, this); this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); this.$node.on("mouseover", this.selectors.selectable, function() { that.setCursor($(this)); }); this.$node.on("mouseleave", function() { that._removeCursor(); }); _.each(this.datasets, function(dataset) { dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); }); return this; }, isOpen: function isOpen() { return this.$node.hasClass(this.classes.open); }, open: function open() { this.$node.scrollTop(0); this.$node.addClass(this.classes.open); }, close: function close() { this.$node.attr("aria-expanded", false); this.$node.removeClass(this.classes.open); this._removeCursor(); }, setLanguageDirection: function setLanguageDirection(dir) { this.$node.attr("dir", dir); }, selectableRelativeToCursor: function selectableRelativeToCursor(delta) { var $selectables, $oldCursor, oldIndex, newIndex; $oldCursor = this.getActiveSelectable(); $selectables = this._getSelectables(); oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; newIndex = oldIndex + delta; newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; return newIndex === -1 ? null : $selectables.eq(newIndex); }, setCursor: function setCursor($selectable) { this._removeCursor(); if ($selectable = $selectable && $selectable.first()) { $selectable.addClass(this.classes.cursor); this._ensureVisible($selectable); } }, getSelectableData: function getSelectableData($el) { return $el && $el.length ? Dataset.extractData($el) : null; }, getActiveSelectable: function getActiveSelectable() { var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); return $selectable.length ? $selectable : null; }, getTopSelectable: function getTopSelectable() { var $selectable = this._getSelectables().first(); return $selectable.length ? $selectable : null; }, update: function update(query) { var isValidUpdate = query !== this.query; if (isValidUpdate) { this.query = query; _.each(this.datasets, updateDataset); } return isValidUpdate; function updateDataset(dataset) { dataset.update(query); } }, empty: function empty() { _.each(this.datasets, clearDataset); this.query = null; this.$node.addClass(this.classes.empty); function clearDataset(dataset) { dataset.clear(); } }, destroy: function destroy() { this.$node.off(".tt"); this.$node = $("
"); _.each(this.datasets, destroyDataset); function destroyDataset(dataset) { dataset.destroy(); } } }); return Menu; }(); var Status = function() { "use strict"; function Status(options) { this.$el = $("", { role: "status", "aria-live": "polite" }).css({ position: "absolute", padding: "0", border: "0", height: "1px", width: "1px", "margin-bottom": "-1px", "margin-right": "-1px", overflow: "hidden", clip: "rect(0 0 0 0)", "white-space": "nowrap" }); options.$input.after(this.$el); _.each(options.menu.datasets, _.bind(function(dataset) { if (dataset.onSync) { dataset.onSync("rendered", _.bind(this.update, this)); dataset.onSync("cleared", _.bind(this.cleared, this)); } }, this)); } _.mixin(Status.prototype, { update: function update(event, suggestions) { var length = suggestions.length; var words; if (length === 1) { words = { result: "result", is: "is" }; } else { words = { result: "results", is: "are" }; } this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); }, cleared: function() { this.$el.text(""); } }); return Status; }(); var DefaultMenu = function() { "use strict"; var s = Menu.prototype; function DefaultMenu() { Menu.apply(this, [].slice.call(arguments, 0)); } _.mixin(DefaultMenu.prototype, Menu.prototype, { open: function open() { !this._allDatasetsEmpty() && this._show(); return s.open.apply(this, [].slice.call(arguments, 0)); }, close: function close() { this._hide(); return s.close.apply(this, [].slice.call(arguments, 0)); }, _onRendered: function onRendered() { if (this._allDatasetsEmpty()) { this._hide(); } else { this.isOpen() && this._show(); } return s._onRendered.apply(this, [].slice.call(arguments, 0)); }, _onCleared: function onCleared() { if (this._allDatasetsEmpty()) { this._hide(); } else { this.isOpen() && this._show(); } return s._onCleared.apply(this, [].slice.call(arguments, 0)); }, setLanguageDirection: function setLanguageDirection(dir) { this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); }, _hide: function hide() { this.$node.hide(); }, _show: function show() { this.$node.css("display", "block"); } }); return DefaultMenu; }(); var Typeahead = function() { "use strict"; function Typeahead(o, www) { var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; o = o || {}; if (!o.input) { $.error("missing input"); } if (!o.menu) { $.error("missing menu"); } if (!o.eventBus) { $.error("missing event bus"); } www.mixin(this); this.eventBus = o.eventBus; this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; this.input = o.input; this.menu = o.menu; this.enabled = true; this.autoselect = !!o.autoselect; this.active = false; this.input.hasFocus() && this.activate(); this.dir = this.input.getLangDir(); this._hacks(); this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); onFocused = c(this, "activate", "open", "_onFocused"); onBlurred = c(this, "deactivate", "_onBlurred"); onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); onEscKeyed = c(this, "isActive", "_onEscKeyed"); onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); } _.mixin(Typeahead.prototype, { _hacks: function hacks() { var $input, $menu; $input = this.input.$input || $("
"); $menu = this.menu.$node || $("
"); $input.on("blur.tt", function($e) { var active, isActive, hasActive; active = document.activeElement; isActive = $menu.is(active); hasActive = $menu.has(active).length > 0; if (_.isMsie() && (isActive || hasActive)) { $e.preventDefault(); $e.stopImmediatePropagation(); _.defer(function() { $input.focus(); }); } }); $menu.on("mousedown.tt", function($e) { $e.preventDefault(); }); }, _onSelectableClicked: function onSelectableClicked(type, $el) { this.select($el); }, _onDatasetCleared: function onDatasetCleared() { this._updateHint(); }, _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { this._updateHint(); if (this.autoselect) { var cursorClass = this.selectors.cursor.substr(1); this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); } this.eventBus.trigger("render", suggestions, async, dataset); }, _onAsyncRequested: function onAsyncRequested(type, dataset, query) { this.eventBus.trigger("asyncrequest", query, dataset); }, _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { this.eventBus.trigger("asynccancel", query, dataset); }, _onAsyncReceived: function onAsyncReceived(type, dataset, query) { this.eventBus.trigger("asyncreceive", query, dataset); }, _onFocused: function onFocused() { this._minLengthMet() && this.menu.update(this.input.getQuery()); }, _onBlurred: function onBlurred() { if (this.input.hasQueryChangedSinceLastFocus()) { this.eventBus.trigger("change", this.input.getQuery()); } }, _onEnterKeyed: function onEnterKeyed(type, $e) { var $selectable; if ($selectable = this.menu.getActiveSelectable()) { if (this.select($selectable)) { $e.preventDefault(); $e.stopPropagation(); } } else if (this.autoselect) { if (this.select(this.menu.getTopSelectable())) { $e.preventDefault(); $e.stopPropagation(); } } }, _onTabKeyed: function onTabKeyed(type, $e) { var $selectable; if ($selectable = this.menu.getActiveSelectable()) { this.select($selectable) && $e.preventDefault(); } else if (this.autoselect) { if ($selectable = this.menu.getTopSelectable()) { this.autocomplete($selectable) && $e.preventDefault(); } } }, _onEscKeyed: function onEscKeyed() { this.close(); }, _onUpKeyed: function onUpKeyed() { this.moveCursor(-1); }, _onDownKeyed: function onDownKeyed() { this.moveCursor(+1); }, _onLeftKeyed: function onLeftKeyed() { if (this.dir === "rtl" && this.input.isCursorAtEnd()) { this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); } }, _onRightKeyed: function onRightKeyed() { if (this.dir === "ltr" && this.input.isCursorAtEnd()) { this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); } }, _onQueryChanged: function onQueryChanged(e, query) { this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); }, _onWhitespaceChanged: function onWhitespaceChanged() { this._updateHint(); }, _onLangDirChanged: function onLangDirChanged(e, dir) { if (this.dir !== dir) { this.dir = dir; this.menu.setLanguageDirection(dir); } }, _openIfActive: function openIfActive() { this.isActive() && this.open(); }, _minLengthMet: function minLengthMet(query) { query = _.isString(query) ? query : this.input.getQuery() || ""; return query.length >= this.minLength; }, _updateHint: function updateHint() { var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; $selectable = this.menu.getTopSelectable(); data = this.menu.getSelectableData($selectable); val = this.input.getInputValue(); if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { query = Input.normalizeQuery(val); escapedQuery = _.escapeRegExChars(query); frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); match = frontMatchRegEx.exec(data.val); match && this.input.setHint(val + match[1]); } else { this.input.clearHint(); } }, isEnabled: function isEnabled() { return this.enabled; }, enable: function enable() { this.enabled = true; }, disable: function disable() { this.enabled = false; }, isActive: function isActive() { return this.active; }, activate: function activate() { if (this.isActive()) { return true; } else if (!this.isEnabled() || this.eventBus.before("active")) { return false; } else { this.active = true; this.eventBus.trigger("active"); return true; } }, deactivate: function deactivate() { if (!this.isActive()) { return true; } else if (this.eventBus.before("idle")) { return false; } else { this.active = false; this.close(); this.eventBus.trigger("idle"); return true; } }, isOpen: function isOpen() { return this.menu.isOpen(); }, open: function open() { if (!this.isOpen() && !this.eventBus.before("open")) { this.input.setAriaExpanded(true); this.menu.open(); this._updateHint(); this.eventBus.trigger("open"); } return this.isOpen(); }, close: function close() { if (this.isOpen() && !this.eventBus.before("close")) { this.input.setAriaExpanded(false); this.menu.close(); this.input.clearHint(); this.input.resetInputValue(); this.eventBus.trigger("close"); } return !this.isOpen(); }, setVal: function setVal(val) { this.input.setQuery(_.toStr(val)); }, getVal: function getVal() { return this.input.getQuery(); }, select: function select($selectable) { var data = this.menu.getSelectableData($selectable); if (data && !this.eventBus.before("select", data.obj, data.dataset)) { this.input.setQuery(data.val, true); this.eventBus.trigger("select", data.obj, data.dataset); this.close(); return true; } return false; }, autocomplete: function autocomplete($selectable) { var query, data, isValid; query = this.input.getQuery(); data = this.menu.getSelectableData($selectable); isValid = data && query !== data.val; if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { this.input.setQuery(data.val); this.eventBus.trigger("autocomplete", data.obj, data.dataset); return true; } return false; }, moveCursor: function moveCursor(delta) { var query, $candidate, data, suggestion, datasetName, cancelMove, id; query = this.input.getQuery(); $candidate = this.menu.selectableRelativeToCursor(delta); data = this.menu.getSelectableData($candidate); suggestion = data ? data.obj : null; datasetName = data ? data.dataset : null; id = $candidate ? $candidate.attr("id") : null; this.input.trigger("cursorchange", id); cancelMove = this._minLengthMet() && this.menu.update(query); if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { this.menu.setCursor($candidate); if (data) { if (typeof data.val === "string") { this.input.setInputValue(data.val); } } else { this.input.resetInputValue(); this._updateHint(); } this.eventBus.trigger("cursorchange", suggestion, datasetName); return true; } return false; }, destroy: function destroy() { this.input.destroy(); this.menu.destroy(); } }); return Typeahead; function c(ctx) { var methods = [].slice.call(arguments, 1); return function() { var args = [].slice.call(arguments); _.each(methods, function(method) { return ctx[method].apply(ctx, args); }); }; } }(); (function() { "use strict"; var old, keys, methods; old = $.fn.typeahead; keys = { www: "tt-www", attrs: "tt-attrs", typeahead: "tt-typeahead" }; methods = { initialize: function initialize(o, datasets) { var www; datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); o = o || {}; www = WWW(o.classNames); return this.each(attach); function attach() { var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; _.each(datasets, function(d) { d.highlight = !!o.highlight; }); $input = $(this); $wrapper = $(www.html.wrapper); $hint = $elOrNull(o.hint); $menu = $elOrNull(o.menu); defaultHint = o.hint !== false && !$hint; defaultMenu = o.menu !== false && !$menu; defaultHint && ($hint = buildHintFromInput($input, www)); defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); $hint && $hint.val(""); $input = prepInput($input, www); if (defaultHint || defaultMenu) { $wrapper.css(www.css.wrapper); $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); } MenuConstructor = defaultMenu ? DefaultMenu : Menu; eventBus = new EventBus({ el: $input }); input = new Input({ hint: $hint, input: $input, menu: $menu }, www); menu = new MenuConstructor({ node: $menu, datasets: datasets }, www); status = new Status({ $input: $input, menu: menu }); typeahead = new Typeahead({ input: input, menu: menu, eventBus: eventBus, minLength: o.minLength, autoselect: o.autoselect }, www); $input.data(keys.www, www); $input.data(keys.typeahead, typeahead); } }, isEnabled: function isEnabled() { var enabled; ttEach(this.first(), function(t) { enabled = t.isEnabled(); }); return enabled; }, enable: function enable() { ttEach(this, function(t) { t.enable(); }); return this; }, disable: function disable() { ttEach(this, function(t) { t.disable(); }); return this; }, isActive: function isActive() { var active; ttEach(this.first(), function(t) { active = t.isActive(); }); return active; }, activate: function activate() { ttEach(this, function(t) { t.activate(); }); return this; }, deactivate: function deactivate() { ttEach(this, function(t) { t.deactivate(); }); return this; }, isOpen: function isOpen() { var open; ttEach(this.first(), function(t) { open = t.isOpen(); }); return open; }, open: function open() { ttEach(this, function(t) { t.open(); }); return this; }, close: function close() { ttEach(this, function(t) { t.close(); }); return this; }, select: function select(el) { var success = false, $el = $(el); ttEach(this.first(), function(t) { success = t.select($el); }); return success; }, autocomplete: function autocomplete(el) { var success = false, $el = $(el); ttEach(this.first(), function(t) { success = t.autocomplete($el); }); return success; }, moveCursor: function moveCursoe(delta) { var success = false; ttEach(this.first(), function(t) { success = t.moveCursor(delta); }); return success; }, val: function val(newVal) { var query; if (!arguments.length) { ttEach(this.first(), function(t) { query = t.getVal(); }); return query; } else { ttEach(this, function(t) { t.setVal(_.toStr(newVal)); }); return this; } }, destroy: function destroy() { ttEach(this, function(typeahead, $input) { revert($input); typeahead.destroy(); }); return this; } }; $.fn.typeahead = function(method) { if (methods[method]) { return methods[method].apply(this, [].slice.call(arguments, 1)); } else { return methods.initialize.apply(this, arguments); } }; $.fn.typeahead.noConflict = function noConflict() { $.fn.typeahead = old; return this; }; function ttEach($els, fn) { $els.each(function() { var $input = $(this), typeahead; (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); }); } function buildHintFromInput($input, www) { return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ readonly: true, required: false }).removeAttr("id name placeholder").removeClass("required").attr({ spellcheck: "false", tabindex: -1 }); } function prepInput($input, www) { $input.data(keys.attrs, { dir: $input.attr("dir"), autocomplete: $input.attr("autocomplete"), spellcheck: $input.attr("spellcheck"), style: $input.attr("style") }); $input.addClass(www.classes.input).attr({ spellcheck: false }); try { !$input.attr("dir") && $input.attr("dir", "auto"); } catch (e) {} return $input; } function getBackgroundStyles($el) { return { backgroundAttachment: $el.css("background-attachment"), backgroundClip: $el.css("background-clip"), backgroundColor: $el.css("background-color"), backgroundImage: $el.css("background-image"), backgroundOrigin: $el.css("background-origin"), backgroundPosition: $el.css("background-position"), backgroundRepeat: $el.css("background-repeat"), backgroundSize: $el.css("background-size") }; } function revert($input) { var www, $wrapper; www = $input.data(keys.www); $wrapper = $input.parent().filter(www.selectors.wrapper); _.each($input.data(keys.attrs), function(val, key) { _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); }); $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); if ($wrapper.length) { $input.detach().insertAfter($wrapper); $wrapper.remove(); } } function $elOrNull(obj) { var isValid, $el; isValid = _.isJQuery(obj) || _.isElement(obj); $el = isValid ? $(obj).first() : []; return $el.length ? $el : null; } })(); }); ================================================ FILE: docs/lenses.html ================================================ Lenses Reference

I want to generate Lenses for all structs

Contributed by @filip_zawada

What are Lenses? Great explanation by @mbrandonw

This script assumes you follow swift naming convention, e.g. structs start with an upper letter.

Stencil template

Example output:

extension House {

  static let roomsLens = Lens<House, Room>(
    get: { $0.rooms },
    set: { rooms, house in
       House(rooms: rooms, address: house.address, size: house.size)
    }
  )
  static let addressLens = Lens<House, String>(
  get: { $0.address },
  set: { address, house in
     House(rooms: house.rooms, address: address, size: house.size)
    }
  )
  ...
================================================ FILE: docs/linuxmain.html ================================================ LinuxMain Reference

I want to generate LinuxMain.swift for all my tests

For all test cases generates allTests static variable and passes all of them as XCTestCaseEntry to XCTMain. Run with --args testimports='import MyTests' parameter to import test modules.

Stencil template

Available annotations:

  • disableTests allows you to disable the whole test case.

Example output:

import XCTest
//testimports

extension AutoInjectionTests {
  static var allTests = [
    ("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies),
    ...
  ]
}

extension AutoWiringTests {
  static var allTests = [
    ("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring),
    ...
  ]
}

...

XCTMain([
  testCase(AutoInjectionTests.allTests),
  testCase(AutoWiringTests.allTests),
  ...
])

================================================ FILE: docs/mocks.html ================================================ Mocks Reference

I want to generate test mocks for protocols

Contributed by @marinbenc

For each protocol implementing AutoMockable protocol or annotated with AutoMockable annotation it will…

Create a class called ProtocolNameMock in which it will…

For each function:

  • Implement the function
  • Add a functionCalled boolean to check if the function was called
  • Add a functionReceivedArguments tuple to check the arguments that were passed to the function
  • Add a functionReturnValue variable and return it when the function is called.

For each variable:

  • Add a gettable and settable variable with the same name and type

Issues and limitations:

  • Overloaded methods will produce compiler errors since the variables above the functions have the same name. Workaround: delete the variables on top of one of the functions, or rename them.
  • Handling success/failure cases (for callbacks) is tricky to do automatically, so you have to do that yourself.
  • This is not a full replacement for hand-written mocks, but it will get you 90% of the way there. Any more complex logic than changing return types, you will have to implement yourself. This only removes the most boring boilerplate you have to write.

Stencil template

Example output:

class MockableServiceMock: MockableService {
    //MARK: - functionWithArguments
    var functionWithArgumentsCalled = false
    var functionWithArgumentsReceivedArguments: (firstArgument: String, onComplete: (String)-> Void)?

    //MARK: - functionWithCallback
    var functionWithCallbackCalled = false
    var functionWithCallbackReceivedArguments: (firstArgument: String, onComplete: (String)-> Void)?

    func functionWithCallback(_ firstArgument: String, onComplete: @escaping (String)-> Void) {
        functionWithCallbackCalled = true
        functionWithCallbackReceivedArguments = (firstArgument: firstArgument, onComplete: onComplete)
    }
  ...
================================================ FILE: docs/search.json ================================================ {"Other%20Typealiases.html#/s:15SourceryRuntime11Annotationsa":{"name":"Annotations"},"Other%20Typealiases.html#/s:15SourceryRuntime13Documentationa":{"name":"Documentation"},"Other%20Typealiases.html#/s:15SourceryRuntime0A8Modifiera":{"name":"SourceryModifier"},"Protocols/Typed.html#/s:15SourceryRuntime5TypedP4typeAA4TypeCSgvp":{"name":"type","abstract":"\u003cp\u003eType, if known\u003c/p\u003e","parent_name":"Typed"},"Protocols/Typed.html#/s:15SourceryRuntime5TypedP8typeNameAA04TypeE0Cvp":{"name":"typeName","abstract":"\u003cp\u003eType name\u003c/p\u003e","parent_name":"Typed"},"Protocols/Typed.html#/s:15SourceryRuntime5TypedP10isOptionalSbvp":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional\u003c/p\u003e","parent_name":"Typed"},"Protocols/Typed.html#/s:15SourceryRuntime5TypedP29isImplicitlyUnwrappedOptionalSbvp":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional\u003c/p\u003e","parent_name":"Typed"},"Protocols/Typed.html#/s:15SourceryRuntime5TypedP17unwrappedTypeNameSSvp":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information\u003c/p\u003e","parent_name":"Typed"},"Protocols/Documented.html#/s:15SourceryRuntime10DocumentedP13documentationSaySSGvp":{"name":"documentation","parent_name":"Documented"},"Protocols/Definition.html#/s:15SourceryRuntime10DefinitionP17definedInTypeNameAA0fG0CSgvp":{"name":"definedInTypeName","abstract":"\u003cp\u003eReference to type name where the object is defined,","parent_name":"Definition"},"Protocols/Definition.html#/s:15SourceryRuntime10DefinitionP13definedInTypeAA0F0CSgvp":{"name":"definedInType","abstract":"\u003cp\u003eReference to actual type where the object is defined,","parent_name":"Definition"},"Protocols/Definition.html#/s:15SourceryRuntime10DefinitionP23actualDefinedInTypeNameAA0gH0CSgvp":{"name":"actualDefinedInTypeName","abstract":"\u003cp\u003eReference to actual type name where the method is defined if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/Definition.html#/s:15SourceryRuntime10DefinitionP17definedInTypeNameAA0fG0CSgvp\"\u003edefinedInTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"Definition"},"Protocols/Annotated.html#/s:15SourceryRuntime9AnnotatedP11annotationsSDySSSo8NSObjectCGvp":{"name":"annotations","abstract":"\u003cp\u003eAll annotations of declaration stored by their name. Value can be \u003ccode\u003ebool\u003c/code\u003e, \u003ccode\u003eString\u003c/code\u003e, float \u003ccode\u003eNSNumber\u003c/code\u003e","parent_name":"Annotated"},"Protocols/Annotated.html":{"name":"Annotated","abstract":"\u003cp\u003eDescribes annotated declaration, i.e. type, method, variable, enum case\u003c/p\u003e"},"Protocols/Definition.html":{"name":"Definition","abstract":"\u003cp\u003eDescribes that the object is defined in a context of some \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Type.html\"\u003eType\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e"},"Protocols/Documented.html":{"name":"Documented","abstract":"\u003cp\u003eDescribes a declaration with documentation, i.e. type, method, variable, enum case\u003c/p\u003e"},"Protocols/Typed.html":{"name":"Typed","abstract":"\u003cp\u003eDescibes typed declaration, i.e. variable, method parameter, tuple element, enum case associated value\u003c/p\u003e"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional. Shorthand for \u003ccode\u003etypeName.isOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional. Shorthand for \u003ccode\u003etypeName.isImplicitlyUnwrappedOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information. Shorthand for \u003ccode\u003etypeName.unwrappedTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if declaration uses typealias, otherwise just a \u003ccode\u003etypeName\u003c/code\u003e. Shorthand for \u003ccode\u003etypeName.actualTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple. Shorthand for \u003ccode\u003etypeName.isTuple\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure. Shorthand for \u003ccode\u003etypeName.isClosure\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array. Shorthand for \u003ccode\u003etypeName.isArray\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a set. Shorthand for \u003ccode\u003etypeName.isSet\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/Typealias.html#/c:@CM@SourceryRuntime@objc(cs)Typealias(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary. Shorthand for \u003ccode\u003etypeName.isDictionary\u003c/code\u003e\u003c/p\u003e","parent_name":"Typealias"},"Extensions/String.html#/s:SS15SourceryRuntimeE10nilIfEmptySSSgvp":{"name":"nilIfEmpty","abstract":"\u003cp\u003eReturns nil if string is empty\u003c/p\u003e","parent_name":"String"},"Extensions/String.html#/s:SS15SourceryRuntimeE26nilIfNotValidParameterNameSSSgvp":{"name":"nilIfNotValidParameterName","abstract":"\u003cp\u003eReturns nil if string is empty or contains \u003ccode\u003e_\u003c/code\u003e character\u003c/p\u003e","parent_name":"String"},"Extensions/StringProtocol.html#/s:Sy15SourceryRuntimeE7trimmedSSvp":{"name":"trimmed","abstract":"\u003cp\u003eTrimms leading and trailing whitespaces and newlines\u003c/p\u003e","parent_name":"StringProtocol"},"Extensions/Array.html#/s:Sa15SourceryRuntimeE15parallelFlatMap9transformSayqd__GADxXE_tlF":{"name":"parallelFlatMap(transform:)","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeE18parallelCompactMap9transformSayqd__Gqd__SgxXE_tlF":{"name":"parallelCompactMap(transform:)","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeE11parallelMap9transformSayqd__Gqd__xXE_tlF":{"name":"parallelMap(transform:)","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeE15parallelPerformyyyxXEF":{"name":"parallelPerform(_:)","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeAA16ClosureParameterCRszlE8asSourceSSvp":{"name":"asSource","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeAA15MethodParameterCRszlE8asSourceSSvp":{"name":"asSource","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeAA12TupleElementCRszlE8asSourceSSvp":{"name":"asSource","parent_name":"Array"},"Extensions/Array.html#/s:Sa15SourceryRuntimeAA12TupleElementCRszlE10asTypeNameSSvp":{"name":"asTypeName","parent_name":"Array"},"Extensions/Array.html":{"name":"Array"},"Extensions/StringProtocol.html":{"name":"StringProtocol"},"Extensions/String.html":{"name":"String"},"Other%20Extensions.html#/c:@M@SourceryRuntime@objc(cs)BytesRange":{"name":"BytesRange"},"Other%20Extensions.html#/c:@M@SourceryRuntime@objc(cs)FileParserResult":{"name":"FileParserResult"},"Extensions/Typealias.html":{"name":"Typealias"},"Enums/Composer.html#/s:15SourceryRuntime8ComposerO23uniqueTypesAndFunctions_6serialSayAA4TypeCG5types_SayAA6MethodCG9functionsSayAA9TypealiasCG11typealiasestAA16FileParserResultC_SbtFZ":{"name":"uniqueTypesAndFunctions(_:serial:)","abstract":"\u003cp\u003ePerforms final processing of discovered types:\u003c/p\u003e","parent_name":"Composer"},"Enums/Composer.html":{"name":"Composer","abstract":"\u003cp\u003eResponsible for composing results of \u003ccode\u003eFileParser\u003c/code\u003e.\u003c/p\u003e"},"Classes/GenericRequirement/Relationship.html#/s:15SourceryRuntime18GenericRequirementC12RelationshipO6equalsyA2EmF":{"name":"equals","parent_name":"Relationship"},"Classes/GenericRequirement/Relationship.html#/s:15SourceryRuntime18GenericRequirementC12RelationshipO10conformsToyA2EmF":{"name":"conformsTo","parent_name":"Relationship"},"Classes/GenericRequirement/Relationship.html":{"name":"Relationship","parent_name":"GenericRequirement"},"Classes/GenericRequirement.html#/c:@M@SourceryRuntime@objc(cs)GenericRequirement(py)leftType":{"name":"leftType","parent_name":"GenericRequirement"},"Classes/GenericRequirement.html#/c:@M@SourceryRuntime@objc(cs)GenericRequirement(py)rightType":{"name":"rightType","parent_name":"GenericRequirement"},"Classes/GenericRequirement.html#/c:@M@SourceryRuntime@objc(cs)GenericRequirement(py)relationship":{"name":"relationship","abstract":"\u003cp\u003erelationship name\u003c/p\u003e","parent_name":"GenericRequirement"},"Classes/GenericRequirement.html#/c:@M@SourceryRuntime@objc(cs)GenericRequirement(py)relationshipSyntax":{"name":"relationshipSyntax","abstract":"\u003cp\u003eSyntax e.g. \u003ccode\u003e==\u003c/code\u003e or \u003ccode\u003e:\u003c/code\u003e\u003c/p\u003e","parent_name":"GenericRequirement"},"Classes/GenericRequirement.html#/s:15SourceryRuntime18GenericRequirementC8leftType05rightF012relationshipAcA010AssociatedF0C_AA0cF9ParameterCAC12RelationshipOtcfc":{"name":"init(leftType:rightType:relationship:)","parent_name":"GenericRequirement"},"Classes/GenericRequirement.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"GenericRequirement"},"Classes/GenericParameter.html#/c:@M@SourceryRuntime@objc(cs)GenericParameter(py)name":{"name":"name","abstract":"\u003cp\u003eGeneric parameter name\u003c/p\u003e","parent_name":"GenericParameter"},"Classes/GenericParameter.html#/c:@M@SourceryRuntime@objc(cs)GenericParameter(py)inheritedTypeName":{"name":"inheritedTypeName","abstract":"\u003cp\u003eGeneric parameter inherited type\u003c/p\u003e","parent_name":"GenericParameter"},"Classes/GenericParameter.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"GenericParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)argumentLabel":{"name":"argumentLabel","abstract":"\u003cp\u003eParameter external name\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)name":{"name":"name","abstract":"\u003cp\u003eParameter internal name\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eParameter type name\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)inout":{"name":"inout","abstract":"\u003cp\u003eParameter flag whether it\u0026rsquo;s inout or not\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)type":{"name":"type","abstract":"\u003cp\u003eParameter type, if known\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)isVariadic":{"name":"isVariadic","abstract":"\u003cp\u003eParameter if the argument has a variadic type or not\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)typeAttributes":{"name":"typeAttributes","abstract":"\u003cp\u003eParameter type attributes, i.e. \u003ccode\u003e@escaping\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)defaultValue":{"name":"defaultValue","abstract":"\u003cp\u003eMethod parameter default value expression\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAnnotations, that were created with // sourcery: annotation1, other = \u0026ldquo;annotation value\u0026rdquo;, alterantive = 2\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)asSource":{"name":"asSource","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional. Shorthand for \u003ccode\u003etypeName.isOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional. Shorthand for \u003ccode\u003etypeName.isImplicitlyUnwrappedOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information. Shorthand for \u003ccode\u003etypeName.unwrappedTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/ClosureParameter.html#/c:@M@SourceryRuntime@objc(cs)ClosureParameter(py)typeName\"\u003etypeName\u003c/a\u003e\u003c/code\u003e. Shorthand for \u003ccode\u003etypeName.actualTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple. Shorthand for \u003ccode\u003etypeName.isTuple\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure. Shorthand for \u003ccode\u003etypeName.isClosure\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array. Shorthand for \u003ccode\u003etypeName.isArray\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a set. Shorthand for \u003ccode\u003etypeName.isSet\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/ClosureParameter.html#/c:@CM@SourceryRuntime@objc(cs)ClosureParameter(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary. Shorthand for \u003ccode\u003etypeName.isDictionary\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureParameter"},"Classes/DiffableResult.html#/c:@M@SourceryRuntime@objc(cs)DiffableResult(py)description":{"name":"description","parent_name":"DiffableResult"},"Classes/SetType.html#/c:@M@SourceryRuntime@objc(cs)SetType(py)name":{"name":"name","abstract":"\u003cp\u003eType name used in declaration\u003c/p\u003e","parent_name":"SetType"},"Classes/SetType.html#/c:@M@SourceryRuntime@objc(cs)SetType(py)elementTypeName":{"name":"elementTypeName","abstract":"\u003cp\u003eArray element type name\u003c/p\u003e","parent_name":"SetType"},"Classes/SetType.html#/c:@M@SourceryRuntime@objc(cs)SetType(py)elementType":{"name":"elementType","abstract":"\u003cp\u003eArray element type, if known\u003c/p\u003e","parent_name":"SetType"},"Classes/SetType.html#/c:@M@SourceryRuntime@objc(cs)SetType(py)asGeneric":{"name":"asGeneric","abstract":"\u003cp\u003eReturns array as generic type\u003c/p\u003e","parent_name":"SetType"},"Classes/SetType.html#/c:@M@SourceryRuntime@objc(cs)SetType(py)asSource":{"name":"asSource","parent_name":"SetType"},"Classes/SetType.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"SetType"},"Classes/Modifier.html#/c:@M@SourceryRuntime@objc(cs)Modifier(py)name":{"name":"name","abstract":"\u003cp\u003eThe declaration modifier name.\u003c/p\u003e","parent_name":"Modifier"},"Classes/Modifier.html#/c:@M@SourceryRuntime@objc(cs)Modifier(py)detail":{"name":"detail","abstract":"\u003cp\u003eThe modifier detail, if any.\u003c/p\u003e","parent_name":"Modifier"},"Classes/Modifier.html#/c:@M@SourceryRuntime@objc(cs)Modifier(im)initWithName:detail:":{"name":"init(name:detail:)","parent_name":"Modifier"},"Classes/Modifier.html#/c:@M@SourceryRuntime@objc(cs)Modifier(py)asSource":{"name":"asSource","parent_name":"Modifier"},"Classes/Modifier.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Modifier"},"Classes/Import.html#/c:@M@SourceryRuntime@objc(cs)Import(py)kind":{"name":"kind","abstract":"\u003cp\u003eImport kind, e.g. class, struct in \u003ccode\u003eimport class Module.ClassName\u003c/code\u003e\u003c/p\u003e","parent_name":"Import"},"Classes/Import.html#/c:@M@SourceryRuntime@objc(cs)Import(py)path":{"name":"path","abstract":"\u003cp\u003eImport path\u003c/p\u003e","parent_name":"Import"},"Classes/Import.html#/c:@M@SourceryRuntime@objc(cs)Import(py)description":{"name":"description","abstract":"\u003cp\u003eFull import value e.g. \u003ccode\u003eimport struct Module.StructName\u003c/code\u003e\u003c/p\u003e","parent_name":"Import"},"Classes/Import.html#/c:@M@SourceryRuntime@objc(cs)Import(py)moduleName":{"name":"moduleName","abstract":"\u003cp\u003eReturns module name from a import, e.g. if you had \u003ccode\u003eimport struct Module.Submodule.Struct\u003c/code\u003e it will return \u003ccode\u003eModule.Submodule\u003c/code\u003e\u003c/p\u003e","parent_name":"Import"},"Classes/Import.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Import"},"Classes/Actor.html#/c:@M@SourceryRuntime@objc(cs)SwiftActor(cpy)kind":{"name":"kind","parent_name":"Actor"},"Classes/Actor.html#/c:@M@SourceryRuntime@objc(cs)SwiftActor(py)kind":{"name":"kind","abstract":"\u003cp\u003eReturns \u0026ldquo;actor\u0026rdquo;\u003c/p\u003e","parent_name":"Actor"},"Classes/Actor.html#/c:@M@SourceryRuntime@objc(cs)SwiftActor(py)isFinal":{"name":"isFinal","abstract":"\u003cp\u003eWhether type is final\u003c/p\u003e","parent_name":"Actor"},"Classes/Actor.html#/c:@M@SourceryRuntime@objc(cs)SwiftActor(py)isDistributed":{"name":"isDistributed","abstract":"\u003cp\u003eWhether method is distributed method\u003c/p\u003e","parent_name":"Actor"},"Classes/Actor.html#/c:@M@SourceryRuntime@objc(cs)SwiftActor(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"Actor"},"Classes/Actor.html":{"name":"Actor","abstract":"\u003cp\u003eDescibes Swift actor\u003c/p\u003e"},"Classes/Import.html":{"name":"Import","abstract":"\u003cp\u003eDefines import type\u003c/p\u003e"},"Classes/Modifier.html":{"name":"Modifier","abstract":"\u003cp\u003emodifier can be thing like \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003eclass\u003c/code\u003e, \u003ccode\u003enonmutating\u003c/code\u003e"},"Classes/SetType.html":{"name":"SetType","abstract":"\u003cp\u003eDescribes set type\u003c/p\u003e"},"Classes/DiffableResult.html":{"name":"DiffableResult"},"Classes/ClosureParameter.html":{"name":"ClosureParameter"},"Classes/GenericParameter.html":{"name":"GenericParameter","abstract":"\u003cp\u003eDescibes Swift generic parameter\u003c/p\u003e"},"Classes/GenericRequirement.html":{"name":"GenericRequirement","abstract":"\u003cp\u003eDescibes Swift generic requirement\u003c/p\u003e"},"Classes/ProtocolComposition.html#/c:@M@SourceryRuntime@objc(cs)ProtocolComposition(cpy)kind":{"name":"kind","parent_name":"ProtocolComposition"},"Classes/ProtocolComposition.html#/c:@M@SourceryRuntime@objc(cs)ProtocolComposition(py)kind":{"name":"kind","abstract":"\u003cp\u003eReturns \u0026ldquo;protocolComposition\u0026rdquo;\u003c/p\u003e","parent_name":"ProtocolComposition"},"Classes/ProtocolComposition.html#/c:@M@SourceryRuntime@objc(cs)ProtocolComposition(py)composedTypeNames":{"name":"composedTypeNames","abstract":"\u003cp\u003eThe names of the types composed to form this composition\u003c/p\u003e","parent_name":"ProtocolComposition"},"Classes/ProtocolComposition.html#/c:@M@SourceryRuntime@objc(cs)ProtocolComposition(py)composedTypes":{"name":"composedTypes","abstract":"\u003cp\u003eThe types composed to form this composition, if known\u003c/p\u003e","parent_name":"ProtocolComposition"},"Classes/ProtocolComposition.html#/c:@M@SourceryRuntime@objc(cs)ProtocolComposition(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"ProtocolComposition"},"Classes/Attribute.html#/c:@M@SourceryRuntime@objc(cs)Attribute(py)name":{"name":"name","abstract":"\u003cp\u003eAttribute name\u003c/p\u003e","parent_name":"Attribute"},"Classes/Attribute.html#/c:@M@SourceryRuntime@objc(cs)Attribute(py)arguments":{"name":"arguments","abstract":"\u003cp\u003eAttribute arguments\u003c/p\u003e","parent_name":"Attribute"},"Classes/Attribute.html#/c:@M@SourceryRuntime@objc(cs)Attribute(py)asSource":{"name":"asSource","abstract":"\u003cp\u003eTODO: unify \u003ccode\u003easSource\u003c/code\u003e / \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Attribute.html#/c:@M@SourceryRuntime@objc(cs)Attribute(py)description\"\u003edescription\u003c/a\u003e\u003c/code\u003e?\u003c/p\u003e","parent_name":"Attribute"},"Classes/Attribute.html#/c:@M@SourceryRuntime@objc(cs)Attribute(py)description":{"name":"description","abstract":"\u003cp\u003eAttribute description that can be used in a template.\u003c/p\u003e","parent_name":"Attribute"},"Classes/Attribute.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Attribute"},"Classes/GenericTypeParameter.html#/c:@M@SourceryRuntime@objc(cs)GenericTypeParameter(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eGeneric parameter type name\u003c/p\u003e","parent_name":"GenericTypeParameter"},"Classes/GenericTypeParameter.html#/c:@M@SourceryRuntime@objc(cs)GenericTypeParameter(py)type":{"name":"type","abstract":"\u003cp\u003eGeneric parameter type, if known\u003c/p\u003e","parent_name":"GenericTypeParameter"},"Classes/GenericTypeParameter.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"GenericTypeParameter"},"Classes/GenericType.html#/c:@M@SourceryRuntime@objc(cs)GenericType(py)name":{"name":"name","abstract":"\u003cp\u003eThe name of the base type, i.e. \u003ccode\u003eArray\u003c/code\u003e for \u003ccode\u003eArray\u0026lt;Int\u0026gt;\u003c/code\u003e\u003c/p\u003e","parent_name":"GenericType"},"Classes/GenericType.html#/c:@M@SourceryRuntime@objc(cs)GenericType(py)typeParameters":{"name":"typeParameters","abstract":"\u003cp\u003eThis generic type parameters\u003c/p\u003e","parent_name":"GenericType"},"Classes/GenericType.html#/c:@M@SourceryRuntime@objc(cs)GenericType(py)asSource":{"name":"asSource","parent_name":"GenericType"},"Classes/GenericType.html#/c:@M@SourceryRuntime@objc(cs)GenericType(py)description":{"name":"description","parent_name":"GenericType"},"Classes/GenericType.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"GenericType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)name":{"name":"name","abstract":"\u003cp\u003eType name used in declaration with stripped whitespaces and new lines\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)parameters":{"name":"parameters","abstract":"\u003cp\u003eList of closure parameters\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)returnTypeName":{"name":"returnTypeName","abstract":"\u003cp\u003eReturn value type name\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)actualReturnTypeName":{"name":"actualReturnTypeName","abstract":"\u003cp\u003eActual return value type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)returnTypeName\"\u003ereturnTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)returnType":{"name":"returnType","abstract":"\u003cp\u003eActual return value type, if known\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)isOptionalReturnType":{"name":"isOptionalReturnType","abstract":"\u003cp\u003eWhether return value type is optional\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)isImplicitlyUnwrappedOptionalReturnType":{"name":"isImplicitlyUnwrappedOptionalReturnType","abstract":"\u003cp\u003eWhether return value type is implicitly unwrapped optional\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)unwrappedReturnTypeName":{"name":"unwrappedReturnTypeName","abstract":"\u003cp\u003eReturn value type name without attributes and optional type information\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)isAsync":{"name":"isAsync","abstract":"\u003cp\u003eWhether method is async method\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)asyncKeyword":{"name":"asyncKeyword","abstract":"\u003cp\u003easync keyword\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)throws":{"name":"throws","abstract":"\u003cp\u003eWhether closure throws\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)throwsOrRethrowsKeyword":{"name":"throwsOrRethrowsKeyword","abstract":"\u003cp\u003ethrows or rethrows keyword\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)throwsTypeName":{"name":"throwsTypeName","abstract":"\u003cp\u003eType of thrown error if specified\u003c/p\u003e","parent_name":"ClosureType"},"Classes/ClosureType.html#/c:@M@SourceryRuntime@objc(cs)ClosureType(py)asSource":{"name":"asSource","parent_name":"ClosureType"},"Classes/ClosureType.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"ClosureType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)name":{"name":"name","abstract":"\u003cp\u003eType name used in declaration\u003c/p\u003e","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)valueTypeName":{"name":"valueTypeName","abstract":"\u003cp\u003eDictionary value type name\u003c/p\u003e","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)valueType":{"name":"valueType","abstract":"\u003cp\u003eDictionary value type, if known\u003c/p\u003e","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)keyTypeName":{"name":"keyTypeName","abstract":"\u003cp\u003eDictionary key type name\u003c/p\u003e","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)keyType":{"name":"keyType","abstract":"\u003cp\u003eDictionary key type, if known\u003c/p\u003e","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)asGeneric":{"name":"asGeneric","abstract":"\u003cp\u003eReturns dictionary as generic type\u003c/p\u003e","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/c:@M@SourceryRuntime@objc(cs)DictionaryType(py)asSource":{"name":"asSource","parent_name":"DictionaryType"},"Classes/DictionaryType.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"DictionaryType"},"Classes/ArrayType.html#/c:@M@SourceryRuntime@objc(cs)ArrayType(py)name":{"name":"name","abstract":"\u003cp\u003eType name used in declaration\u003c/p\u003e","parent_name":"ArrayType"},"Classes/ArrayType.html#/c:@M@SourceryRuntime@objc(cs)ArrayType(py)elementTypeName":{"name":"elementTypeName","abstract":"\u003cp\u003eArray element type name\u003c/p\u003e","parent_name":"ArrayType"},"Classes/ArrayType.html#/c:@M@SourceryRuntime@objc(cs)ArrayType(py)elementType":{"name":"elementType","abstract":"\u003cp\u003eArray element type, if known\u003c/p\u003e","parent_name":"ArrayType"},"Classes/ArrayType.html#/c:@M@SourceryRuntime@objc(cs)ArrayType(py)asGeneric":{"name":"asGeneric","abstract":"\u003cp\u003eReturns array as generic type\u003c/p\u003e","parent_name":"ArrayType"},"Classes/ArrayType.html#/c:@M@SourceryRuntime@objc(cs)ArrayType(py)asSource":{"name":"asSource","parent_name":"ArrayType"},"Classes/ArrayType.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"ArrayType"},"Classes/TupleElement.html#/c:@M@SourceryRuntime@objc(cs)TupleElement(py)name":{"name":"name","abstract":"\u003cp\u003eTuple element name\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@M@SourceryRuntime@objc(cs)TupleElement(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eTuple element type name\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@M@SourceryRuntime@objc(cs)TupleElement(py)type":{"name":"type","abstract":"\u003cp\u003eTuple element type, if known\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@M@SourceryRuntime@objc(cs)TupleElement(py)asSource":{"name":"asSource","parent_name":"TupleElement"},"Classes/TupleElement.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional. Shorthand for \u003ccode\u003etypeName.isOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional. Shorthand for \u003ccode\u003etypeName.isImplicitlyUnwrappedOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information. Shorthand for \u003ccode\u003etypeName.unwrappedTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/TupleElement.html#/c:@M@SourceryRuntime@objc(cs)TupleElement(py)typeName\"\u003etypeName\u003c/a\u003e\u003c/code\u003e. Shorthand for \u003ccode\u003etypeName.actualTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple. Shorthand for \u003ccode\u003etypeName.isTuple\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure. Shorthand for \u003ccode\u003etypeName.isClosure\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array. Shorthand for \u003ccode\u003etypeName.isArray\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a set. Shorthand for \u003ccode\u003etypeName.isSet\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleElement.html#/c:@CM@SourceryRuntime@objc(cs)TupleElement(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary. Shorthand for \u003ccode\u003etypeName.isDictionary\u003c/code\u003e\u003c/p\u003e","parent_name":"TupleElement"},"Classes/TupleType.html#/c:@M@SourceryRuntime@objc(cs)TupleType(py)name":{"name":"name","abstract":"\u003cp\u003eType name used in declaration\u003c/p\u003e","parent_name":"TupleType"},"Classes/TupleType.html#/c:@M@SourceryRuntime@objc(cs)TupleType(py)elements":{"name":"elements","abstract":"\u003cp\u003eTuple elements\u003c/p\u003e","parent_name":"TupleType"},"Classes/TupleType.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"TupleType"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)name":{"name":"name","abstract":"\u003cp\u003eType name used in declaration\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)generic":{"name":"generic","abstract":"\u003cp\u003eThe generics of this TypeName\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isGeneric":{"name":"isGeneric","abstract":"\u003cp\u003eWhether this TypeName is generic\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isProtocolComposition":{"name":"isProtocolComposition","abstract":"\u003cp\u003eWhether this TypeName is protocol composition\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if given type name is a typealias\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)attributes":{"name":"attributes","abstract":"\u003cp\u003eType name attributes, i.e. \u003ccode\u003e@escaping\u003c/code\u003e\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)modifiers":{"name":"modifiers","abstract":"\u003cp\u003eModifiers, i.e. \u003ccode\u003eescaping\u003c/code\u003e\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isVoid":{"name":"isVoid","abstract":"\u003cp\u003eWhether type is void (\u003ccode\u003eVoid\u003c/code\u003e or \u003ccode\u003e()\u003c/code\u003e)\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)tuple":{"name":"tuple","abstract":"\u003cp\u003eTuple type data\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)array":{"name":"array","abstract":"\u003cp\u003eArray type data\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)dictionary":{"name":"dictionary","abstract":"\u003cp\u003eDictionary type data\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)closure":{"name":"closure","abstract":"\u003cp\u003eClosure type data\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a Set\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)set":{"name":"set","abstract":"\u003cp\u003eSet type data\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)isNever":{"name":"isNever","abstract":"\u003cp\u003eWhether type is \u003ccode\u003eNever\u003c/code\u003e\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)asSource":{"name":"asSource","abstract":"\u003cp\u003ePrints typename as it would appear on definition\u003c/p\u003e","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)description":{"name":"description","parent_name":"TypeName"},"Classes/TypeName.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"TypeName"},"Classes/TypeName.html#/c:@M@SourceryRuntime@objc(cs)TypeName(py)hash":{"name":"hash","parent_name":"TypeName"},"Classes/TypeName.html#/s:s25LosslessStringConvertiblePyxSgSScfc":{"name":"init(_:)","parent_name":"TypeName"},"Classes/TypeName.html#/c:@CM@SourceryRuntime@objc(cs)TypeName(cm)unknownWithDescription:attributes:":{"name":"unknown(description:attributes:)","parent_name":"TypeName"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)parameters":{"name":"parameters","abstract":"\u003cp\u003eMethod parameters\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)returnTypeName":{"name":"returnTypeName","abstract":"\u003cp\u003eReturn value type name used in declaration, including generic constraints, i.e. \u003ccode\u003ewhere T: Equatable\u003c/code\u003e\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)actualReturnTypeName":{"name":"actualReturnTypeName","abstract":"\u003cp\u003eActual return value type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)returnTypeName\"\u003ereturnTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)returnType":{"name":"returnType","abstract":"\u003cp\u003eActual return value type, if known\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)isOptionalReturnType":{"name":"isOptionalReturnType","abstract":"\u003cp\u003eWhether return value type is optional\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)isImplicitlyUnwrappedOptionalReturnType":{"name":"isImplicitlyUnwrappedOptionalReturnType","abstract":"\u003cp\u003eWhether return value type is implicitly unwrapped optional\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)unwrappedReturnTypeName":{"name":"unwrappedReturnTypeName","abstract":"\u003cp\u003eReturn value type name without attributes and optional type information\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)isFinal":{"name":"isFinal","abstract":"\u003cp\u003eWhether method is final\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)readAccess":{"name":"readAccess","abstract":"\u003cp\u003eVariable read access level, i.e. \u003ccode\u003einternal\u003c/code\u003e, \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efileprivate\u003c/code\u003e, \u003ccode\u003epublic\u003c/code\u003e, \u003ccode\u003eopen\u003c/code\u003e\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)writeAccess":{"name":"writeAccess","abstract":"\u003cp\u003eVariable write access, i.e. \u003ccode\u003einternal\u003c/code\u003e, \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efileprivate\u003c/code\u003e, \u003ccode\u003epublic\u003c/code\u003e, \u003ccode\u003eopen\u003c/code\u003e.","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)isAsync":{"name":"isAsync","abstract":"\u003cp\u003eWhether subscript is async\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)throws":{"name":"throws","abstract":"\u003cp\u003eWhether subscript throws\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)throwsTypeName":{"name":"throwsTypeName","abstract":"\u003cp\u003eType of thrown error if specified\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)isMutable":{"name":"isMutable","abstract":"\u003cp\u003eWhether variable is mutable or not\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAnnotations, that were created with // sourcery: annotation1, other = \u0026ldquo;annotation value\u0026rdquo;, alterantive = 2\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)documentation":{"name":"documentation","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)definedInTypeName":{"name":"definedInTypeName","abstract":"\u003cp\u003eReference to type name where the method is defined,","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)actualDefinedInTypeName":{"name":"actualDefinedInTypeName","abstract":"\u003cp\u003eReference to actual type name where the method is defined if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)definedInTypeName\"\u003edefinedInTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)definedInType":{"name":"definedInType","abstract":"\u003cp\u003eReference to actual type where the object is defined,","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)attributes":{"name":"attributes","abstract":"\u003cp\u003eMethod attributes, i.e. \u003ccode\u003e@discardableResult\u003c/code\u003e\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)modifiers":{"name":"modifiers","abstract":"\u003cp\u003eMethod modifiers, i.e. \u003ccode\u003eprivate\u003c/code\u003e\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)genericParameters":{"name":"genericParameters","abstract":"\u003cp\u003elist of generic parameters\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)genericRequirements":{"name":"genericRequirements","abstract":"\u003cp\u003elist of generic requirements\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/c:@M@SourceryRuntime@objc(cs)Subscript(py)isGeneric":{"name":"isGeneric","abstract":"\u003cp\u003eWhether subscript is generic or not\u003c/p\u003e","parent_name":"Subscript"},"Classes/Subscript.html#/s:15SourceryRuntime9SubscriptC10parameters14returnTypeName11accessLevel7isAsync6throws0lfG017genericParameters0M12Requirements10attributes9modifiers11annotations13documentation09definedInfG0ACSayAA15MethodParameterCG_AA0fG0CAA06AccessI0O4read_AW5writetS2bAUSgSayAA07GenericW0CGSayAA18GenericRequirementCGSDySSSayAA9AttributeCGGSayAA8ModifierCGSDySSSo8NSObjectCGSaySSGAZtcfc":{"name":"init(parameters:returnTypeName:accessLevel:isAsync:throws:throwsTypeName:genericParameters:genericRequirements:attributes:modifiers:annotations:documentation:definedInTypeName:)","parent_name":"Subscript"},"Classes/Subscript.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Subscript"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)argumentLabel":{"name":"argumentLabel","abstract":"\u003cp\u003eParameter external name\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)name":{"name":"name","abstract":"\u003cp\u003eParameter internal name\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eParameter type name\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)inout":{"name":"inout","abstract":"\u003cp\u003eParameter flag whether it\u0026rsquo;s inout or not\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)isVariadic":{"name":"isVariadic","abstract":"\u003cp\u003eIs this variadic parameter?\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)type":{"name":"type","abstract":"\u003cp\u003eParameter type, if known\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)typeAttributes":{"name":"typeAttributes","abstract":"\u003cp\u003eParameter type attributes, i.e. \u003ccode\u003e@escaping\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)defaultValue":{"name":"defaultValue","abstract":"\u003cp\u003eMethod parameter default value expression\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAnnotations, that were created with // sourcery: annotation1, other = \u0026ldquo;annotation value\u0026rdquo;, alterantive = 2\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)asSource":{"name":"asSource","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional. Shorthand for \u003ccode\u003etypeName.isOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional. Shorthand for \u003ccode\u003etypeName.isImplicitlyUnwrappedOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information. Shorthand for \u003ccode\u003etypeName.unwrappedTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/MethodParameter.html#/c:@M@SourceryRuntime@objc(cs)MethodParameter(py)typeName\"\u003etypeName\u003c/a\u003e\u003c/code\u003e. Shorthand for \u003ccode\u003etypeName.actualTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple. Shorthand for \u003ccode\u003etypeName.isTuple\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure. Shorthand for \u003ccode\u003etypeName.isClosure\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array. Shorthand for \u003ccode\u003etypeName.isArray\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a set. Shorthand for \u003ccode\u003etypeName.isSet\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/MethodParameter.html#/c:@CM@SourceryRuntime@objc(cs)MethodParameter(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary. Shorthand for \u003ccode\u003etypeName.isDictionary\u003c/code\u003e\u003c/p\u003e","parent_name":"MethodParameter"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)name":{"name":"name","abstract":"\u003cp\u003eFull method name, including generic constraints, i.e. \u003ccode\u003efoo\u0026lt;T\u0026gt;(bar: T)\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)selectorName":{"name":"selectorName","abstract":"\u003cp\u003eMethod name including arguments names, i.e. \u003ccode\u003efoo(bar:)\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)shortName":{"name":"shortName","abstract":"\u003cp\u003eMethod name without arguments names and parentheses, i.e. \u003ccode\u003efoo\u0026lt;T\u0026gt;\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)callName":{"name":"callName","abstract":"\u003cp\u003eMethod name without arguments names, parentheses and generic types, i.e. \u003ccode\u003efoo\u003c/code\u003e (can be used to generate code for method call)\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)parameters":{"name":"parameters","abstract":"\u003cp\u003eMethod parameters\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)returnTypeName":{"name":"returnTypeName","abstract":"\u003cp\u003eReturn value type name used in declaration, including generic constraints, i.e. \u003ccode\u003ewhere T: Equatable\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)actualReturnTypeName":{"name":"actualReturnTypeName","abstract":"\u003cp\u003eActual return value type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)returnTypeName\"\u003ereturnTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)returnType":{"name":"returnType","abstract":"\u003cp\u003eActual return value type, if known\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isOptionalReturnType":{"name":"isOptionalReturnType","abstract":"\u003cp\u003eWhether return value type is optional\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isImplicitlyUnwrappedOptionalReturnType":{"name":"isImplicitlyUnwrappedOptionalReturnType","abstract":"\u003cp\u003eWhether return value type is implicitly unwrapped optional\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)unwrappedReturnTypeName":{"name":"unwrappedReturnTypeName","abstract":"\u003cp\u003eReturn value type name without attributes and optional type information\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isAsync":{"name":"isAsync","abstract":"\u003cp\u003eWhether method is async method\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isDistributed":{"name":"isDistributed","abstract":"\u003cp\u003eWhether method is distributed\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)throws":{"name":"throws","abstract":"\u003cp\u003eWhether method throws\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)throwsTypeName":{"name":"throwsTypeName","abstract":"\u003cp\u003eType of thrown error if specified\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isThrowsTypeGeneric":{"name":"isThrowsTypeGeneric","abstract":"\u003cp\u003eReturn if the throwsType is generic\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)rethrows":{"name":"rethrows","abstract":"\u003cp\u003eWhether method rethrows\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)accessLevel":{"name":"accessLevel","abstract":"\u003cp\u003eMethod access level, i.e. \u003ccode\u003einternal\u003c/code\u003e, \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efileprivate\u003c/code\u003e, \u003ccode\u003epublic\u003c/code\u003e, \u003ccode\u003eopen\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isStatic":{"name":"isStatic","abstract":"\u003cp\u003eWhether method is a static method\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isClass":{"name":"isClass","abstract":"\u003cp\u003eWhether method is a class method\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isInitializer":{"name":"isInitializer","abstract":"\u003cp\u003eWhether method is an initializer\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isDeinitializer":{"name":"isDeinitializer","abstract":"\u003cp\u003eWhether method is an deinitializer\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isFailableInitializer":{"name":"isFailableInitializer","abstract":"\u003cp\u003eWhether method is a failable initializer\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isConvenienceInitializer":{"name":"isConvenienceInitializer","abstract":"\u003cp\u003eWhether method is a convenience initializer\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isRequired":{"name":"isRequired","abstract":"\u003cp\u003eWhether method is required\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isFinal":{"name":"isFinal","abstract":"\u003cp\u003eWhether method is final\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isMutating":{"name":"isMutating","abstract":"\u003cp\u003eWhether method is mutating\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isGeneric":{"name":"isGeneric","abstract":"\u003cp\u003eWhether method is generic\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether method is optional (in an Objective-C protocol)\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isNonisolated":{"name":"isNonisolated","abstract":"\u003cp\u003eWhether method is nonisolated (this modifier only applies to actor methods)\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)isDynamic":{"name":"isDynamic","abstract":"\u003cp\u003eWhether method is dynamic\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAnnotations, that were created with // sourcery: annotation1, other = \u0026ldquo;annotation value\u0026rdquo;, alterantive = 2\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)documentation":{"name":"documentation","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)definedInTypeName":{"name":"definedInTypeName","abstract":"\u003cp\u003eReference to type name where the method is defined,","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)actualDefinedInTypeName":{"name":"actualDefinedInTypeName","abstract":"\u003cp\u003eReference to actual type name where the method is defined if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)definedInTypeName\"\u003edefinedInTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)definedInType":{"name":"definedInType","abstract":"\u003cp\u003eReference to actual type where the object is defined,","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)attributes":{"name":"attributes","abstract":"\u003cp\u003eMethod attributes, i.e. \u003ccode\u003e@discardableResult\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)modifiers":{"name":"modifiers","abstract":"\u003cp\u003eMethod modifiers, i.e. \u003ccode\u003eprivate\u003c/code\u003e\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)genericRequirements":{"name":"genericRequirements","abstract":"\u003cp\u003elist of generic requirements\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/c:@M@SourceryRuntime@objc(cs)SwiftMethod(py)genericParameters":{"name":"genericParameters","abstract":"\u003cp\u003eList of generic parameters\u003c/p\u003e","parent_name":"Method"},"Classes/Method.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Method"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)name":{"name":"name","abstract":"\u003cp\u003eVariable name\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eVariable type name\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)type":{"name":"type","abstract":"\u003cp\u003eVariable type, if known, i.e. if the type is declared in the scanned sources.","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isComputed":{"name":"isComputed","abstract":"\u003cp\u003eWhether variable is computed and not stored\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isAsync":{"name":"isAsync","abstract":"\u003cp\u003eWhether variable is async\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)throws":{"name":"throws","abstract":"\u003cp\u003eWhether variable throws\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)throwsTypeName":{"name":"throwsTypeName","abstract":"\u003cp\u003eType of thrown error if specified\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isStatic":{"name":"isStatic","abstract":"\u003cp\u003eWhether variable is static\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)readAccess":{"name":"readAccess","abstract":"\u003cp\u003eVariable read access level, i.e. \u003ccode\u003einternal\u003c/code\u003e, \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efileprivate\u003c/code\u003e, \u003ccode\u003epublic\u003c/code\u003e, \u003ccode\u003eopen\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)writeAccess":{"name":"writeAccess","abstract":"\u003cp\u003eVariable write access, i.e. \u003ccode\u003einternal\u003c/code\u003e, \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efileprivate\u003c/code\u003e, \u003ccode\u003epublic\u003c/code\u003e, \u003ccode\u003eopen\u003c/code\u003e.","parent_name":"Variable"},"Classes/Variable.html#/s:15SourceryRuntime8VariableC11accessLevelAA06AccessE0O4read_AF5writetvp":{"name":"accessLevel","abstract":"\u003cp\u003ecomposed access level","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isMutable":{"name":"isMutable","abstract":"\u003cp\u003eWhether variable is mutable or not\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)defaultValue":{"name":"defaultValue","abstract":"\u003cp\u003eVariable default value expression\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAnnotations, that were created with // sourcery: annotation1, other = \u0026ldquo;annotation value\u0026rdquo;, alterantive = 2\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)documentation":{"name":"documentation","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)attributes":{"name":"attributes","abstract":"\u003cp\u003eVariable attributes, i.e. \u003ccode\u003e@IBOutlet\u003c/code\u003e, \u003ccode\u003e@IBInspectable\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)modifiers":{"name":"modifiers","abstract":"\u003cp\u003eModifiers, i.e. \u003ccode\u003eprivate\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isFinal":{"name":"isFinal","abstract":"\u003cp\u003eWhether variable is final or not\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isLazy":{"name":"isLazy","abstract":"\u003cp\u003eWhether variable is lazy or not\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)isDynamic":{"name":"isDynamic","abstract":"\u003cp\u003eWhether variable is dynamic or not\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)definedInTypeName":{"name":"definedInTypeName","abstract":"\u003cp\u003eReference to type name where the variable is defined,","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)actualDefinedInTypeName":{"name":"actualDefinedInTypeName","abstract":"\u003cp\u003eReference to actual type name where the method is defined if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)definedInTypeName\"\u003edefinedInTypeName\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)definedInType":{"name":"definedInType","abstract":"\u003cp\u003eReference to actual type where the object is defined,","parent_name":"Variable"},"Classes/Variable.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional. Shorthand for \u003ccode\u003etypeName.isOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional. Shorthand for \u003ccode\u003etypeName.isImplicitlyUnwrappedOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information. Shorthand for \u003ccode\u003etypeName.unwrappedTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Variable.html#/c:@M@SourceryRuntime@objc(cs)Variable(py)typeName\"\u003etypeName\u003c/a\u003e\u003c/code\u003e. Shorthand for \u003ccode\u003etypeName.actualTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple. Shorthand for \u003ccode\u003etypeName.isTuple\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure. Shorthand for \u003ccode\u003etypeName.isClosure\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array. Shorthand for \u003ccode\u003etypeName.isArray\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a set. Shorthand for \u003ccode\u003etypeName.isSet\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/Variable.html#/c:@CM@SourceryRuntime@objc(cs)Variable(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary. Shorthand for \u003ccode\u003etypeName.isDictionary\u003c/code\u003e\u003c/p\u003e","parent_name":"Variable"},"Classes/AssociatedType.html#/c:@M@SourceryRuntime@objc(cs)AssociatedType(py)name":{"name":"name","abstract":"\u003cp\u003eAssociated type name\u003c/p\u003e","parent_name":"AssociatedType"},"Classes/AssociatedType.html#/c:@M@SourceryRuntime@objc(cs)AssociatedType(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eAssociated type type constraint name, if specified\u003c/p\u003e","parent_name":"AssociatedType"},"Classes/AssociatedType.html#/c:@M@SourceryRuntime@objc(cs)AssociatedType(py)type":{"name":"type","abstract":"\u003cp\u003eAssociated type constrained type, if known, i.e. if the type is declared in the scanned sources.\u003c/p\u003e","parent_name":"AssociatedType"},"Classes/AssociatedType.html#/c:@M@SourceryRuntime@objc(cs)AssociatedType(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"AssociatedType"},"Classes/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)localName":{"name":"localName","abstract":"\u003cp\u003eAssociated value local name.","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)externalName":{"name":"externalName","abstract":"\u003cp\u003eAssociated value external name.","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)typeName":{"name":"typeName","abstract":"\u003cp\u003eAssociated value type name\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)type":{"name":"type","abstract":"\u003cp\u003eAssociated value type, if known\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)defaultValue":{"name":"defaultValue","abstract":"\u003cp\u003eAssociated value default value\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAnnotations, that were created with // sourcery: annotation1, other = \u0026ldquo;annotation value\u0026rdquo;, alterantive = 2\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isOptional":{"name":"isOptional","abstract":"\u003cp\u003eWhether type is optional. Shorthand for \u003ccode\u003etypeName.isOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isImplicitlyUnwrappedOptional":{"name":"isImplicitlyUnwrappedOptional","abstract":"\u003cp\u003eWhether type is implicitly unwrapped optional. Shorthand for \u003ccode\u003etypeName.isImplicitlyUnwrappedOptional\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)unwrappedTypeName":{"name":"unwrappedTypeName","abstract":"\u003cp\u003eType name without attributes and optional type information. Shorthand for \u003ccode\u003etypeName.unwrappedTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)actualTypeName":{"name":"actualTypeName","abstract":"\u003cp\u003eActual type name if declaration uses typealias, otherwise just a \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/AssociatedValue.html#/c:@M@SourceryRuntime@objc(cs)AssociatedValue(py)typeName\"\u003etypeName\u003c/a\u003e\u003c/code\u003e. Shorthand for \u003ccode\u003etypeName.actualTypeName\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isTuple":{"name":"isTuple","abstract":"\u003cp\u003eWhether type is a tuple. Shorthand for \u003ccode\u003etypeName.isTuple\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isClosure":{"name":"isClosure","abstract":"\u003cp\u003eWhether type is a closure. Shorthand for \u003ccode\u003etypeName.isClosure\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isArray":{"name":"isArray","abstract":"\u003cp\u003eWhether type is an array. Shorthand for \u003ccode\u003etypeName.isArray\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isSet":{"name":"isSet","abstract":"\u003cp\u003eWhether type is a set. Shorthand for \u003ccode\u003etypeName.isSet\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/AssociatedValue.html#/c:@CM@SourceryRuntime@objc(cs)AssociatedValue(py)isDictionary":{"name":"isDictionary","abstract":"\u003cp\u003eWhether type is a dictionary. Shorthand for \u003ccode\u003etypeName.isDictionary\u003c/code\u003e\u003c/p\u003e","parent_name":"AssociatedValue"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)name":{"name":"name","abstract":"\u003cp\u003eEnum case name\u003c/p\u003e","parent_name":"EnumCase"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)rawValue":{"name":"rawValue","abstract":"\u003cp\u003eEnum case raw value, if any\u003c/p\u003e","parent_name":"EnumCase"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)associatedValues":{"name":"associatedValues","abstract":"\u003cp\u003eEnum case associated values\u003c/p\u003e","parent_name":"EnumCase"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eEnum case annotations\u003c/p\u003e","parent_name":"EnumCase"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)documentation":{"name":"documentation","parent_name":"EnumCase"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)indirect":{"name":"indirect","abstract":"\u003cp\u003eWhether enum case is indirect\u003c/p\u003e","parent_name":"EnumCase"},"Classes/EnumCase.html#/c:@M@SourceryRuntime@objc(cs)EnumCase(py)hasAssociatedValue":{"name":"hasAssociatedValue","abstract":"\u003cp\u003eWhether enum case has associated value\u003c/p\u003e","parent_name":"EnumCase"},"Classes/EnumCase.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"EnumCase"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(cpy)kind":{"name":"kind","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)kind":{"name":"kind","abstract":"\u003cp\u003eReturns \u0026ldquo;enum\u0026rdquo;\u003c/p\u003e","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)cases":{"name":"cases","abstract":"\u003cp\u003eEnum cases\u003c/p\u003e","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)rawTypeName":{"name":"rawTypeName","abstract":"\u003cp\u003eEnum raw value type name, if any. This type is removed from enum\u0026rsquo;s \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)based\"\u003ebased\u003c/a\u003e\u003c/code\u003e and \u003ccode\u003einherited\u003c/code\u003e types collections.\u003c/p\u003e","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)rawType":{"name":"rawType","abstract":"\u003cp\u003eEnum raw value type, if known\u003c/p\u003e","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)based":{"name":"based","abstract":"\u003cp\u003eNames of types or protocols this type inherits from, including unknown (not scanned) types\u003c/p\u003e","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(py)hasAssociatedValues":{"name":"hasAssociatedValues","abstract":"\u003cp\u003eWhether enum contains any associated values\u003c/p\u003e","parent_name":"Enum"},"Classes/Enum.html#/c:@M@SourceryRuntime@objc(cs)Enum(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"Enum"},"Classes/Struct.html#/c:@M@SourceryRuntime@objc(cs)Struct(cpy)kind":{"name":"kind","parent_name":"Struct"},"Classes/Struct.html#/c:@M@SourceryRuntime@objc(cs)Struct(py)kind":{"name":"kind","abstract":"\u003cp\u003eReturns \u0026ldquo;struct\u0026rdquo;\u003c/p\u003e","parent_name":"Struct"},"Classes/Struct.html#/c:@M@SourceryRuntime@objc(cs)Struct(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"Struct"},"Classes/Class.html#/c:@M@SourceryRuntime@objc(cs)SwiftClass(cpy)kind":{"name":"kind","parent_name":"Class"},"Classes/Class.html#/c:@M@SourceryRuntime@objc(cs)SwiftClass(py)kind":{"name":"kind","abstract":"\u003cp\u003eReturns \u0026ldquo;class\u0026rdquo;\u003c/p\u003e","parent_name":"Class"},"Classes/Class.html#/c:@M@SourceryRuntime@objc(cs)SwiftClass(py)isFinal":{"name":"isFinal","abstract":"\u003cp\u003eWhether type is final\u003c/p\u003e","parent_name":"Class"},"Classes/Class.html#/c:@M@SourceryRuntime@objc(cs)SwiftClass(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"Class"},"Classes/Protocol.html#/c:@M@SourceryRuntime@objc(cs)Protocol(cpy)kind":{"name":"kind","parent_name":"Protocol"},"Classes/Protocol.html#/c:@M@SourceryRuntime@objc(cs)Protocol(py)kind":{"name":"kind","abstract":"\u003cp\u003eReturns \u0026ldquo;protocol\u0026rdquo;\u003c/p\u003e","parent_name":"Protocol"},"Classes/Protocol.html#/c:@M@SourceryRuntime@objc(cs)Protocol(py)associatedTypes":{"name":"associatedTypes","abstract":"\u003cp\u003elist of all declared associated types with their names as keys\u003c/p\u003e","parent_name":"Protocol"},"Classes/Protocol.html#/c:@M@SourceryRuntime@objc(cs)Protocol(py)genericRequirements":{"name":"genericRequirements","abstract":"\u003cp\u003elist of generic requirements\u003c/p\u003e","parent_name":"Protocol"},"Classes/Protocol.html#/c:@M@SourceryRuntime@objc(cs)Protocol(im)diffAgainst:":{"name":"diffAgainst(_:)","parent_name":"Protocol"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)imports":{"name":"imports","abstract":"\u003cp\u003eImports that existed in the file that contained this type declaration\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)allImports":{"name":"allImports","abstract":"\u003cp\u003eImports existed in all files containing this type and all its super classes/protocols\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)isExtension":{"name":"isExtension","abstract":"\u003cp\u003eWhether declaration is an extension of some type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)kind":{"name":"kind","abstract":"\u003cp\u003eKind of type declaration, i.e. \u003ccode\u003eenum\u003c/code\u003e, \u003ccode\u003estruct\u003c/code\u003e, \u003ccode\u003eclass\u003c/code\u003e, \u003ccode\u003eprotocol\u003c/code\u003e or \u003ccode\u003eextension\u003c/code\u003e\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)accessLevel":{"name":"accessLevel","abstract":"\u003cp\u003eType access level, i.e. \u003ccode\u003einternal\u003c/code\u003e, \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efileprivate\u003c/code\u003e, \u003ccode\u003epublic\u003c/code\u003e, \u003ccode\u003eopen\u003c/code\u003e\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)name":{"name":"name","abstract":"\u003cp\u003eType name in global scope. For inner types includes the name of its containing type, i.e. \u003ccode\u003eType.Inner\u003c/code\u003e\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)isUnknownExtension":{"name":"isUnknownExtension","abstract":"\u003cp\u003eWhether the type has been resolved as unknown extension\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)globalName":{"name":"globalName","abstract":"\u003cp\u003eGlobal type name including module name, unless it\u0026rsquo;s an extension of unknown type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)isGeneric":{"name":"isGeneric","abstract":"\u003cp\u003eWhether type is generic\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)localName":{"name":"localName","abstract":"\u003cp\u003eType name in its own scope.\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)variables":{"name":"variables","abstract":"\u003cp\u003eVariables defined in this type only, inluding variables defined in its extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)rawVariables":{"name":"rawVariables","abstract":"\u003cp\u003eUnfiltered (can contain duplications from extensions) variables defined in this type only, inluding variables defined in its extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)allVariables":{"name":"allVariables","abstract":"\u003cp\u003eAll variables defined for this type, including variables defined in extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)methods":{"name":"methods","abstract":"\u003cp\u003eMethods defined in this type only, inluding methods defined in its extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)rawMethods":{"name":"rawMethods","abstract":"\u003cp\u003eUnfiltered (can contain duplications from extensions) methods defined in this type only, inluding methods defined in its extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)allMethods":{"name":"allMethods","abstract":"\u003cp\u003eAll methods defined for this type, including methods defined in extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)subscripts":{"name":"subscripts","abstract":"\u003cp\u003eSubscripts defined in this type only, inluding subscripts defined in its extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)rawSubscripts":{"name":"rawSubscripts","abstract":"\u003cp\u003eUnfiltered (can contain duplications from extensions) Subscripts defined in this type only, inluding subscripts defined in its extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)allSubscripts":{"name":"allSubscripts","abstract":"\u003cp\u003eAll subscripts defined for this type, including subscripts defined in extensions,","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)bodyBytesRange":{"name":"bodyBytesRange","abstract":"\u003cp\u003eBytes position of the body of this type in its declaration file if available.\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)completeDeclarationRange":{"name":"completeDeclarationRange","abstract":"\u003cp\u003eBytes position of the whole declaration of this type in its declaration file if available.\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)initializers":{"name":"initializers","abstract":"\u003cp\u003eAll initializers defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)annotations":{"name":"annotations","abstract":"\u003cp\u003eAll annotations for this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)documentation":{"name":"documentation","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)staticVariables":{"name":"staticVariables","abstract":"\u003cp\u003eStatic variables defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)staticMethods":{"name":"staticMethods","abstract":"\u003cp\u003eStatic methods defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)classMethods":{"name":"classMethods","abstract":"\u003cp\u003eClass methods defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)instanceVariables":{"name":"instanceVariables","abstract":"\u003cp\u003eInstance variables defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)instanceMethods":{"name":"instanceMethods","abstract":"\u003cp\u003eInstance methods defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)computedVariables":{"name":"computedVariables","abstract":"\u003cp\u003eComputed instance variables defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)storedVariables":{"name":"storedVariables","abstract":"\u003cp\u003eStored instance variables defined in this type\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)inheritedTypes":{"name":"inheritedTypes","abstract":"\u003cp\u003eNames of types this type inherits from (for classes only) and protocols it implements, in order of definition\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)based":{"name":"based","abstract":"\u003cp\u003eNames of types or protocols this type inherits from, including unknown (not scanned) types\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)basedTypes":{"name":"basedTypes","abstract":"\u003cp\u003eTypes this type inherits from or implements, including unknown (not scanned) types with extensions defined\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)inherits":{"name":"inherits","abstract":"\u003cp\u003eTypes this type inherits from\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)implements":{"name":"implements","abstract":"\u003cp\u003eProtocols this type implements. Does not contain classes in case where composition (\u003ccode\u003e\u0026amp;\u003c/code\u003e) is used in the declaration\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)containedTypes":{"name":"containedTypes","abstract":"\u003cp\u003eContained types\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)containedType":{"name":"containedType","abstract":"\u003cp\u003eContained types groupd by their names\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)parentName":{"name":"parentName","abstract":"\u003cp\u003eName of parent type (for contained types only)\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)parent":{"name":"parent","abstract":"\u003cp\u003eParent type, if known (for contained types only)\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)supertype":{"name":"supertype","abstract":"\u003cp\u003eSuperclass type, if known (only for classes)\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)attributes":{"name":"attributes","abstract":"\u003cp\u003eType attributes, i.e. \u003ccode\u003e@objc\u003c/code\u003e\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)modifiers":{"name":"modifiers","abstract":"\u003cp\u003eType modifiers, i.e. \u003ccode\u003eprivate\u003c/code\u003e, \u003ccode\u003efinal\u003c/code\u003e\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)path":{"name":"path","abstract":"\u003cp\u003ePath to file where the type is defined\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)directory":{"name":"directory","abstract":"\u003cp\u003eDirectory to file where the type is defined\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)genericRequirements":{"name":"genericRequirements","abstract":"\u003cp\u003elist of generic requirements\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/c:@M@SourceryRuntime@objc(cs)Type(py)fileName":{"name":"fileName","abstract":"\u003cp\u003eFile name where the type was defined\u003c/p\u003e","parent_name":"Type"},"Classes/Type.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Type"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)typealiases":{"name":"typealiases","abstract":"\u003cp\u003eAll known typealiases\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)all":{"name":"all","abstract":"\u003cp\u003eAll known types, excluding protocols or protocol compositions.\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)protocols":{"name":"protocols","abstract":"\u003cp\u003eAll known protocols\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)protocolCompositions":{"name":"protocolCompositions","abstract":"\u003cp\u003eAll known protocol compositions\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)classes":{"name":"classes","abstract":"\u003cp\u003eAll known classes\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)structs":{"name":"structs","abstract":"\u003cp\u003eAll known structs\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)enums":{"name":"enums","abstract":"\u003cp\u003eAll known enums\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)extensions":{"name":"extensions","abstract":"\u003cp\u003eAll known extensions\u003c/p\u003e","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)based":{"name":"based","abstract":"\u003cp\u003eTypes based on any other type, grouped by its name, even if they are not known.","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)inheriting":{"name":"inheriting","abstract":"\u003cp\u003eClasses inheriting from any known class, grouped by its name.","parent_name":"Types"},"Classes/Types.html#/c:@M@SourceryRuntime@objc(cs)Types(py)implementing":{"name":"implementing","abstract":"\u003cp\u003eTypes implementing known protocol, grouped by its name.","parent_name":"Types"},"Classes/Types.html":{"name":"Types","abstract":"\u003cp\u003eCollection of scanned types for accessing in templates\u003c/p\u003e"},"Classes/Type.html":{"name":"Type","abstract":"\u003cp\u003eDefines Swift type\u003c/p\u003e"},"Classes/Protocol.html":{"name":"Protocol","abstract":"\u003cp\u003eDescribes Swift protocol\u003c/p\u003e"},"Classes/Class.html":{"name":"Class","abstract":"\u003cp\u003eDescibes Swift class\u003c/p\u003e"},"Classes/Struct.html":{"name":"Struct","abstract":"\u003cp\u003eDescribes Swift struct\u003c/p\u003e"},"Classes/Enum.html":{"name":"Enum","abstract":"\u003cp\u003eDefines Swift enum\u003c/p\u003e"},"Classes/EnumCase.html":{"name":"EnumCase","abstract":"\u003cp\u003eDefines enum case\u003c/p\u003e"},"Classes/AssociatedValue.html":{"name":"AssociatedValue","abstract":"\u003cp\u003eDefines enum case associated value\u003c/p\u003e"},"Classes/AssociatedType.html":{"name":"AssociatedType","abstract":"\u003cp\u003eDescribes Swift AssociatedType\u003c/p\u003e"},"Classes/Variable.html":{"name":"Variable","abstract":"\u003cp\u003eDefines variable\u003c/p\u003e"},"Classes/Method.html":{"name":"Method","abstract":"\u003cp\u003eDescribes method\u003c/p\u003e"},"Classes/MethodParameter.html":{"name":"MethodParameter","abstract":"\u003cp\u003eDescribes method parameter\u003c/p\u003e"},"Classes/Subscript.html":{"name":"Subscript","abstract":"\u003cp\u003eDescribes subscript\u003c/p\u003e"},"Classes/TypeName.html":{"name":"TypeName","abstract":"\u003cp\u003eDescribes name of the type used in typed declaration (variable, method parameter or return value etc.)\u003c/p\u003e"},"Classes/TupleType.html":{"name":"TupleType","abstract":"\u003cp\u003eDescribes tuple type\u003c/p\u003e"},"Classes/TupleElement.html":{"name":"TupleElement","abstract":"\u003cp\u003eDescribes tuple type element\u003c/p\u003e"},"Classes/ArrayType.html":{"name":"ArrayType","abstract":"\u003cp\u003eDescribes array type\u003c/p\u003e"},"Classes/DictionaryType.html":{"name":"DictionaryType","abstract":"\u003cp\u003eDescribes dictionary type\u003c/p\u003e"},"Classes/ClosureType.html":{"name":"ClosureType","abstract":"\u003cp\u003eDescribes closure type\u003c/p\u003e"},"Classes/GenericType.html":{"name":"GenericType","abstract":"\u003cp\u003eDescibes Swift generic type\u003c/p\u003e"},"Classes/GenericTypeParameter.html":{"name":"GenericTypeParameter","abstract":"\u003cp\u003eDescibes Swift generic type parameter\u003c/p\u003e"},"Classes/Attribute.html":{"name":"Attribute","abstract":"\u003cp\u003eDescribes Swift attribute\u003c/p\u003e"},"Classes/ProtocolComposition.html":{"name":"ProtocolComposition","abstract":"\u003cp\u003eDescribes a Swift \u003ca href=\"https://docs.swift.org/swift-book/ReferenceManual/Types.html#ID454\"\u003eprotocol composition\u003c/a\u003e.\u003c/p\u003e"},"Protocols/Diffable.html#/s:15SourceryRuntime8DiffableP11diffAgainstyAA0C6ResultCypSgF":{"name":"diffAgainst(_:)","abstract":"\u003cp\u003eReturns \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/DiffableResult.html\"\u003eDiffableResult\u003c/a\u003e\u003c/code\u003e for the given objects.\u003c/p\u003e","parent_name":"Diffable"},"equatable.html":{"name":"Equatable"},"hashable.html":{"name":"Hashable"},"enum-cases.html":{"name":"Enum cases"},"lenses.html":{"name":"Lenses"},"mocks.html":{"name":"Mocks"},"codable.html":{"name":"Codable"},"Protocols/Diffable.html":{"name":"Diffable"},"diffable.html":{"name":"Diffable"},"linuxmain.html":{"name":"LinuxMain"},"decorator.html":{"name":"Decorator"},"installing.html":{"name":"Installing"},"usage.html":{"name":"Usage"},"writing-templates.html":{"name":"Writing templates"},"Guides.html":{"name":"Guides"},"Examples.html":{"name":"Examples"},"Types.html":{"name":"Types"},"Other%20Classes.html":{"name":"Other Classes","abstract":"\u003cp\u003eThe following classes are available globally.\u003c/p\u003e"},"Other%20Enums.html":{"name":"Other Enumerations","abstract":"\u003cp\u003eThe following enumerations are available globally.\u003c/p\u003e"},"Other%20Extensions.html":{"name":"Other Extensions","abstract":"\u003cp\u003eThe following extensions are available globally.\u003c/p\u003e"},"Other%20Protocols.html":{"name":"Other Protocols","abstract":"\u003cp\u003eThe following protocols are available globally.\u003c/p\u003e"},"Other%20Typealiases.html":{"name":"Other Type Aliases","abstract":"\u003cp\u003eThe following type aliases are available globally.\u003c/p\u003e"}} ================================================ FILE: docs/usage.html ================================================ Usage Reference

Usage

Sourcery is a command line tool, you can either run it manually or in a custom build phase using following command:

$ ./sourcery --sources <sources path> --templates <templates path> --output <output path>

Note

this command may be different depending on the way in which you installed Sourcery (see Installing)

Command line options

  • --sources - Path to a source swift files. You can provide multiple paths using multiple --sources option.
  • --templates - Path to templates. File or Directory. You can provide multiple paths using multiple --templates options.
  • --output [default: current path] - Path to output. File or Directory.
  • --config [default: current path] - Path to config file. File or Directory. See Configuration file.
  • --args - Additional arguments to pass to templates. Each argument can have explicit value or will have implicit true value. Arguments should be separated with , without spaces (i.e. --args arg1=value,arg2) or should be passed one by one (i.e --args arg1=value --args arg2). Arguments are accessible in templates via argument.name. To pass in string you should use escaped quotes (\") .
  • --watch [default: false] - Watch both code and template folders for changes and regenerate automatically.
  • --verbose [default: false] - Turn on verbose logging
  • --quiet [default: false] - Turn off any logging, only emit errors
  • --disableCache [default: false] - Turn off caching of parsed data
  • --prune [default: false] - Prune empty generated files
  • --version - Display the current version of Sourcery
  • --help - Display help information.
  • --cacheBasePath - Path to Sourcery internal cache (available only in configuration file)
  • --parseDocumentation [default: false] - Include documentation comments for all declarations.

Use --help to see the list of all available options.

Configuration file

You can also provide arguments using configuration file. Some of the configuration features (like excluding files) are only available when using configuration file. You provide path to this file using --config command line option. If you provide a path to a directory Sourcery will search for a file .sourcery.yml in this directory. You can also provide a path to config file itself. By default Sourcery will search for .sourcery.yml in your current path.

Configuration file should be a valid Yaml file, like this:

sources:
  - <sources path> # you can provide either single path or several paths using `-`
  - <sources path>
templates:
  - <templates path> # as well as for templates
  - <templates path>
output:
  <output path> # note that there is no `-` here as only single output path is supported
args:
  <name>: <value>

Multiple configurations

You can pass multiple paths to configuration files using multiple --config command line options. Single configuration file can contain multiple configurations under root configurations key:

configurations:
    - sources:
        - <sources path>
        - <sources path>
      templates:
        - <templates path>
      output: <output path>
      args:
        <name>: <value>
        <name>: <value>
    - sources:
        - <sources path>
        - <sources path>
      templates:
        - <templates path>
      output: <output path>
      args:
        <name>: <value>
        <name>: <value>

This will be equivalent to running Sourcery separately for each of the configurations. In watch mode Sourcery will observe changes in the paths from all the configurations.

Child configurations

You can specify a child configurations by using the child key:

configurations:
    - child: ./.child_config.yml
    - child: Subdirectory/.another_child_config.yml

Sources will be resolved relative to the child config paths.

Sources

You can provide sources using paths to directories or specific files.

sources:
  - <sources dir path>
  - <source file path>

Or you can provide project which will be scanned and which source files will be processed. You can use several project or target objects to scan multiple targets from one project or to scan multiple projects. You can provide paths to XCFramework files if your target has any and you want to process their swiftinterface files.

project:
  file: <path to xcodeproj file>
  target:
    name: <target name>
    module: <module name> //required if different from target name
    xcframeworks:
        - <path to xcframework file>
        - <path to xcframework file>

You can also provide a Swift Package which will be scanned. Source files will be scanned based on the package’s path and exclude options.

package:
  path: <path to to the Package.swift root directory>
  target: <target name>

Multiple targets:

package:
  path: <path to to the Package.swift root directory>
  target:
    - <target name>
    - <target name>

Excluding sources or templates

You can specify paths to sources files that should be scanned using include key and paths that should be excluded using exclude key. These can be directory or file paths.

sources:
  include:
    - <sources path to include>
    - <sources path to include>
  exclude:
    - <sources path to exclude>
    - <sources path to exclude>

You can also specify path to include and exclude for templates. When source is a project you can use exclude key to exclude some of its source files.

project:
  file: ...
  target: ...
  exclude:
    - <sources path>
    - <sources path>

Output

You can specify the output file using output key. This can be a directory path or a file path. If it’s a file path, all generated content will be written into this file. If it’s a directory path, for each template a separate file will be created with TemplateName.generated.swift name.

output:
  <output path>

Alternatively you can use path key to specify output path.

output:
  path: <output path>

You can use optional link key to automatically link generated files to some target.

output:
  path: <output path>
  link:
    project: <path to the xcodeproj to link to>
    target: <name of the target to link to> // or targets: [target1, target2, ...]
    group: <group in the project to add files to> // by default files are added to project's root group

Note

Paths in configuration file are by default relative to configuration file path. If you want to specify absolute path start it with /.

================================================ FILE: docs/writing-templates.html ================================================ Writing templates Reference

Writing templates

Sourcery supports templates written in Stencil, Swift and even JavaScript.

Discovered types can be accessed in templates via global context with following properties:

  • types: Types - access collections of types, i.e. types.implementing.AutoCoding (types.implementing["AutoCoding"] in swift templates). See Types.
  • type: [String: Type] - access types by their names, i.e. type.MyType (type["MyType"] in swift templates)
  • arguments: [String: NSObject] - access additional parameters passed with --args command line flag or set in .sourcery.yml file

Tip

Make sure you leverage Sourcery built-in daemon to make writing templates a pleasure: you can open template side-by-side with generated code and see it change live.

What are known and unknown types

Currently Sourcery only scans files from paths or targets that you tell it to scan. This way it can get full information about types defined in these sources. These types are considered known types. For each of known types Sourcery provides Type object. You can get it for example by its name from types collection. Type object contains information about whether type that it describes is a struct, enum, class or a protocol, what are its properties and methods, what protocols it implements and so on. This is done recursively, so if you have a class that inherits from another class (or struct that implements a protocol) and they are both known types you will have information about both of them and you will be able to access parent type’s Type object using type.inherits.TypeName (or type.implements.ProtocolName).

Everything defined outside of scanned sources is considered as unknown types. For such types Sourcery doesn’t provide Type object. For that reason variables (and other “typed” types, like method parameters etc.) of such types will only contain typeName property, but their type property will be nil.

If you have an extension of unknown type defined in scanned sources Sourcery will create Type for it (it’s kind property will be extension). But this object will contain only declarations defined in this extension. Several extensions of unknown type will be merged into one Type object the same way as extensions of known types.

See #87 for details.

Stencil templates

Stencil is a simple and powerful template language for Swift. It provides a syntax similar to Django and Mustache. Sourcery also uses its extension StencilSwiftKit so you have access to additional nodes and filteres defined there.

Example: Equality.stencil

Custom Stencil tags and filters

  • {{ name|upperFirstLetter }} - makes first letter in name uppercase
  • {{ name|lowerFirstLetter }} - makes first letter in name lowercase
  • {{ name|replace:"substring","replacement" }} - replaces occurrences of substring with replacement in name (case sensitive)
  • {% if name|contains:"Foo" %} - check if name contains arbitrary substring, can be negated with ! prefix.
  • {% if name|hasPrefix:"Foo" %}- check if name starts with arbitrary substring, can be negated with ! prefix.
  • {% if name|hasSuffix:"Foo" %}- check if name ends with arbitrary substring, can be negated with ! prefix.
  • static, instance, computed, stored, tuple - can be used on Variable[s] as filter e.g. {% for var in variables|instance %}, can be negated with ! prefix.
  • static, instance, class, initializer - can be used on Method[s] as filter e.g. {% for method in allMethods|instance %}, can be negated with ! prefix.
  • enum, class, struct, protocol - can be used for Type[s] as filter, can be negated with ! prefix.
  • based, implements, inherits - can be used for Type[s], Variable[s], Associated value[s], can be negated with ! prefix.
  • count - can be used to get count of filtered array
  • annotated - can be used on Type[s], Variable[s], Method[s] and Enum Case[s] to filter by annotation, e.g. {% for var in variable|annotated:"skipDescription" %}, can be negated with ! prefix.
  • public, open, internal, private, fileprivate - can be used on Type[s] and Method[s] to filter by access level, can be negated with ! prefix.
  • publicGet, publicSet, .etc - can be used on Variable[s] to filter by getter or setter access level, can be negated with ! prefix

You can also use partial templates using include tag. Partial template is loaded from the path of a template that includes it. include tags also supports loading templates from relative path, i.e. {% include "partials/MyPartial.stencil"%} used in the template located in templates directory will load template from templates/partials directory.

Note

You can only load partial templates from child directories of the including template directory, so {% include "../MyPartial.stencil"%} is not supported.

Sourcery treats all the templates as independent and so will generate files based on partial templates too. To avoid that use exclude in configuration file.

Swift templates

Swift templates syntax is very similar to EJS:

  • Control flow with <% %>
  • Output value with <%= %>
  • Trim extra new line after control flow tag with -%>
  • Trim all whitespaces before/after control flow tag with <%_ and _%>
  • Use <%# %> for comments
  • Use <%- include("relative_path_to_template.swifttemplate") %> to include another template. The swifttemplate extension can be omitted. The path is relative to the including template.
  • Use <%- includeFile("relative_path_to_file.swift") %> to include another Swift file. The path is relative to the including template. Included Swift files may depend upon SourceryRuntime module, as this will be injected during processing.

Example: Equality.swifttemplate

Template:

<% for type in types.all { -%>
  <%_ %><%= type.name %>
<% } %>

Output:

Foo
Bar

JavaScript templates

JavaScript templates are powered by EJS and support all the features available in this template engine.

Example: JSExport.ejs

Note

when using JavaScript templates with Sourcery built using Swift Package Manager you must provide path to EJS source code using --ejsPath command line argument. Download EJS source code here, put it in some path and pass it when running Sourcery. Otherwise JavaScript templates will be ignored (you will see a warning in the console output).

You can also use SourceryJS framework independently of Sourcery. You can add it as a Carthage or SPM dependency.

Using Source Annotations

Sourcery supports annotating your classes and variables with special annotations, similar to how attributes work in Rust / Java

// sourcery: skipPersistence
// sourcery: anotherAnnotation = 232, yetAnotherAnnotation = "value"
/// Some documentation comment
var precomputedHash: Int

You can also add attributes to the end of a line of code:

var firstVariable: Int // default = 1
var secondVariable: Int // default = 2

If you want to attribute multiple items with same attributes, you can use section annotations sourcery:begin and sourcery:end:

// sourcery:begin: skipEquality, skipPersistence
  var firstVariable: Int
  var secondVariable: Int
// sourcery:end

To attribute any declaration in the file use sourcery:file at the top of the file:

// sourcery:file: skipEquality
  var firstVariable: Int
  var secondVariable: Int

To group annotations of the same domain you can use annotation namespaces:

// sourcery:decoding: key="first", default=0
  var firstVariable: Int

This will effectively annotate with decoding.key and decoding.default annotations

Rules:

  • Multiple annotations can occur on the same line, separated with ,
  • You can add multiline annotations
  • Multiple annotations values with the same key are merged into array
  • You can interleave annotations with documentation
  • Sourcery scans all sourcery: annotations in the given comment block above the source until first non-comment/doc line
  • Annotations at the end of a line will be applied to all declarations on the same line
  • Using /* and */ for annotation comment you can put annotations on the same line preceding your declaration. This is useful for annotating methods parameters and enum case associated values. All such annotations should be placed in one comment block. Do not mix inline and regular annotations for the same declaration (using inline and block annotations is fine)!

Format:

  • simple entry, e.g. sourcery: skipPersistence
  • key = number, e.g. sourcery: another = 123
  • key = string, e.g. sourcery: jsonKey = "json_key"

Accessing in templates:

{% if variable|!annotated:"skipPersistence" %}
  var local{{ variable.name|capitalize }} = json["{{ variable.annotations.jsonKey }}"] as? {{ variable.typeName }}
{% endif %}

Checking for existence of at least one annotation:

Sometimes it is desirable to only generate code if there’s at least one field annotated.

{% if type.variables|annotated:"jsonKey" %}{% for var in type.variables|instance|annotated:"jsonKey" %}
  var local{{ var.name|capitalize }} = json["{{ var.annotations.jsonKey }}"] as? {{ var.typeName }}
{% endfor %}{% endif %}

Inline code generation

Sourcery supports inline code generation, you just need to put same markup in your code and template, e.g.

// in template:

{% for type in types.all %}
// sourcery:inline:{{ type.name }}.TemplateName
// sourcery:end
{% endfor %}

// in source code:

class MyType {

// sourcery:inline:MyType.TemplateName
// sourcery:end

}

Sourcery will generate the template code and then perform replacement in your source file by matching annotation comments. Inlined generated code is not parsed to avoid chicken-egg problem.

Automatic inline code generation

To avoid having to place the markup in your source files, you can use automatic generation e.g. inline:auto:{{ type.name }}.TemplateName:

// in template:

{% for type in types.all %}
// sourcery:inline:auto:{{ type.name }}.TemplateName
// sourcery:end
{% endfor %}

// in source code:

class MyType {}

// after running Sourcery:

class MyType {
// sourcery:inline:auto:MyType.TemplateName
// sourcery:end
}

The needed markup will be automatically added at the end of the type declaration body. After first parse Sourcery will work with generated code annotated with inline:auto the same way as annotated with inline, so you can even move these blocks of code anywhere in the same file.

If you want to insert code after the type declaration, use after-auto: instead of auto:

Per file code generation

Sourcery supports generating code in a separate file per type, you just need to put file annotation in a template, e.g.

{% for type in types.all %}
// sourcery:file:Generated/{{ type.name}}+TemplateName
// sourcery:end
{% endfor %}

Sourcery will generate the template code and then write its annotated parts to corresponding files. In example above it will create Generated/<type name>+TemplateName.generated.swift file for each of scanned types.

If you add an extension to the file name Sourcery will not append generated.swift extension.

================================================ FILE: guides/Codable.md ================================================ ## I want to generate `Codable` implementation This template generates `Codable` implementation for structs that implement `AutoCodable`, `AutoDecodable` or `AutoEncodable` protocols. You should define these protocols as follows: ```swift protocol AutoDecodable: Decodable {} protocol AutoEncodable: Encodable {} protocol AutoCodable: AutoDecodable, AutoEncodable {} ``` ### [Swift template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoCodable.swifttemplate) ### Generating coding keys. If you have few keys that are not matching default key strategy you have to specify only these keys, all other keys will be generated and inlined by the template: ```swift struct Person: AutoDecodable { let id: String let firstName: Bool let surname: String enum CodingKeys: String, CodingKey { // this is the custom key that you define manually case firstName = "first_name" // sourcery:inline:auto:Person.CodingKeys.AutoCodable // the rest is generated by the template case id case surname // sourcery:end } } ``` Computed properties are not encoded by default, but if you define a coding key for computed property, template will generate code that will encode it. If you don't define any keys manually the template will generate `CodingKeys` enum with the keys for all stored properties, but only if custom implementation of `init(from:)` or `encode(to:)` is needed. ### Generating `init(from:)` constructor. Template will generate implementation of `init(from:)` when needed. You can define additional methods and properties on your type to be used to decode it. - method to get decoding container. This is useful if your type needs to be decoded from a nested key(s): ```swift struct MyStruct: AutoDecodable { let value: Int enum CodingKeys: String, CodingKey { case nested case value } static func decodingContainer(_ decoder: Decoder) throws -> KeyedDecodingContainer { return try decoder.container(keyedBy: CodingKeys.self) .nestedContainer(keyedBy: CodingKeys.self, forKey: .nested) } } ``` - method to decode a property. This is useful if you need to decode some property manually: ```swift struct MyStruct: AutoDecodable { let myProperty: Int static func decodeMyProperty(from container: KeyedDecodingContainer) -> Int? { return (try? container.decode(String.self, forKey: .myProperty)).flatMap(Int.init) } //or static func decodeMyProperty(from decoder: Decoder) throws -> Int { return try decoder.container(keyedBy: CodingKeys.self) .decode(Int.self, forKey: .myProperty) } } ``` These methods can throw or not and can return optional or non-optional result. - default property value. You can define a static variable that will be used as a default value of a property if decoding results in `nil` value: ```swift struct MyStruct: AutoDecodable { let myProperty: Int static let defaultMyProperty: Int = 0 } ``` ### Generating `encode(to:)` method. Template will generate implementation of `encode(to:)` method when needed. You can define additional methods to be used to encode it. - method to get encoding container. This is useful if your type needs to be encoded into a nested key(s): ```swift struct MyStruct: AutoDecodable { let value: Int enum CodingKeys: String, CodingKey { case nested case value } func encodingContainer(_ encoder: Encoder) -> KeyedEncodingContainer { var container = encoder.container(keyedBy: CodingKeys.self) return container.nestedContainer(keyedBy: CodingKeys.self, forKey: .nested) } } ``` - method to encode a property. This is useful when you need to manually encode a property: ```swift struct MyStruct: AutoDecodable { let myProperty: Int func encodeMyProperty(to container: inout KeyedEncodingContainer) { try? container.decode(String(myProperty), forKey: .myProperty) } //or func encodeMyProperty(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(String(myProperty), forKey: .myProperty) } } ``` These methods may throw or not. If you need to manually encode computed property and you have defined custom encoding method for it, template will generate a coding key for it too, so you don't have to define it manually (though you may still need to define it if it needs custom raw value). - method to encode any additional values. This is useful when you need to encode computed properties or constant values: ```swift struct MyStruct: AutoDecodable { func encodeAdditionalValues(to container: inout KeyedEncodingContainer) throws { ... } // or func encodeAdditionalValues(to encoder: Encoder) throws { ... } } ``` This method will be called in the end of generated encoding method. - enum `SkipEncodingKeys` for keys to be skipped during encoding. This is useful when you have stored properties that you don't want to encode, i.e. constants: ```swift struct MyStruct: AutoCodable { let value: Int let skipValue: Int enum SkipEncodingKeys { case skipValue } } ``` ### Codable enums Enums with numeric or string raw values are `Codable` by default. For enums with no raw value or with associated values template will generate `Codable` implementation. #### Enums with no raw values and no associated values For such enums template will generate decoding/encoding code that will expect values in JSON to be exactly the same as cases' names. ```swift enum SimpleEnum: AutoDecodable { case someCase case anotherCase } ``` For such enum template will generate code that will successfully decode from/encode to JSON of following form: ```json { "value": "someCase" "anotherValue": "anotherCase" } ``` You can define coding keys to change the values: ```swift enum SimpleEnum: AutoDecodable { case someCase case anotherCase enum CodingKeys: String, CodingKey { case someCase = "some_case" case anotherCase = "another_case" } } ``` #### Enums with assoicated values Template supports two different representations of such enums in JSON format. ```swift enum SimpleEnum: AutoDecodable { case someCase(id: Int, name: String) case anotherCase } ``` If you define a coding key named `enumCaseKey` then the template will generate code that will encode/decode enum in/from following format: ```json { "type": "someCase" // enum case is encoded in a special key "id": 1, "name": "John" } ``` All enum cases associated values must be named. If you don't define `enumCaseKey` then the template will generate code that will encode/decode enum in/from following format: ```json { "someCase": { "id": 1, "name": "John" } } ``` Associated values of each enum case must be either all named or all unnamed. For cases with unnamed associated values JSON format will use array instead of dictionary for associated values, in the same order in which they are defined: ```json { "someCase": [ 1, "Jhon" ] } ``` You can use all other customisation methods described for structs to decode/encode enum case associated values individually. ================================================ FILE: guides/Decorator.md ================================================ ## I want to generate simple decorator for my type In Swift it can be cumbersome to write a simple decorator that decorates all the calls to decorated type methods, you basically have to do it manually for each single method. With this template you can generate simple decorator that generate all the methods and property calls automatically, skipping methods and properties already implemented manually. You can use this template as a starting point for more sophisticated implementations. This template also shows you some powers of swift templates, like using helper methods and whitespace control tags. ### [Swift template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/Decorator.swifttemplate) #### Available annotations - `decorate` - what type to decorate - `decorateMethod` - code to decorate each method call with - `decorateGet` - code to decorate each property getter - `decorateSet` - code to decorate each property setter **Example input:** ```swift protocol Service { var prop1: Int { get } var prop2: Int { get set } func foo(f: Int, _ a: Int) throws -> Int func bar(_ b: String) } // sourcery: decorate = "Service" // sourcery: decorateMethod = "print(#function)" // sourcery: decorateGet = "print("get: \(#function)")" // sourcery: decorateSet = "print("set: \(#function)")" struct ServiceDecorator: Service { // generated code will go here } extension ServiceDecorator { // manually implemented method internal func bar(_ b: String) { decorated.bar(b) } } ``` **Example output:** ```swift ... // sourcery: decorate = Service // sourcery: decorateMethod = print(#function) // sourcery: decorateGet = "print("get: \(#function)")" // sourcery: decorateSet = "print("set: \(#function)")" struct ServiceDecorator: Service { // sourcery:inline:auto:ServiceDecorator.autoDecorated internal private(set) var decorated: Service internal init(decorated: Service) { self.decorated = decorated } internal var prop1: Int { print("get: \(#function)") return decorated.prop1 } internal var prop2: Int { get { print("get: \(#function)") return decorated.prop2 } set { print("set: \(#function)") decorated.prop2 = newValue } } internal func foo(f: Int, _ a: Int) throws -> Int { print(#function) return try decorated.foo(f: f, a) } // sourcery:end } ... ``` ================================================ FILE: guides/Diffable.md ================================================ ## I want to have diffing in tests Template used to generate much better output when using equality in tests, instead of having to read wall of text it's used to generate precise property level differences. This template uses [Sourcery Diffable implementation](../SourceryRuntime/Sources/Diffable.swift) from this: before to this: after ### [Stencil Template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Sourcery/Templates/Diffable.stencil) #### Available annotations: - `skipEquality` allows you to skip variable from being compared. ================================================ FILE: guides/Enum cases.md ================================================ ## I want to list all cases in an enum Generate `count` and `allCases` for any enumeration that is marked with `AutoCases` phantom protocol. ### [Stencil Template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoCases.stencil) #### Example output: ```swift extension BetaSettingsGroup { static let count: Int = return 8 static let allCases: [BetaSettingsGroup] = [ .featuresInDevelopment, .advertising, .analytics, .marketing, .news, .notifications, .tech, .appInformation ] } ``` ================================================ FILE: guides/Equatable.md ================================================ ## I want to generate `Equatable` implementation Template used to generate equality for all types that either conform to the `AutoEquatable` protocol or are [annotated](Writing%20templates.md#using-source-annotations) with `AutoEquatable` annotation, allowing us to avoid writing boilerplate code. It adds `:Equatable` conformance to all types, except protocols (because it would require turning them into PAT's). For protocols it's just generating `func ==`. ### [Stencil template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoEquatable.stencil) #### Available variable annotations: - `skipEquality` allows you to skip variable from being compared. - `arrayEquality` mark this to use array comparsion for variables that have array of items that don't implement `Equatable` but have `==` operator e.g. Protocols #### Example output: ```swift // MARK: - AdNodeViewModel AutoEquatable extension AdNodeViewModel: Equatable {} internal func == (lhs: AdNodeViewModel, rhs: AdNodeViewModel) -> Bool { guard lhs.remoteAdView == rhs.remoteAdView else { return false } guard lhs.hidesDisclaimer == rhs.hidesDisclaimer else { return false } guard lhs.type == rhs.type else { return false } guard lhs.height == rhs.height else { return false } guard lhs.attributedDisclaimer == rhs.attributedDisclaimer else { return false } return true } ``` ================================================ FILE: guides/Hashable.md ================================================ ## I want to generate `Hashable` implementation Template used to generate hashing for all types that conform to `:AutoHashable`, allowing us to avoid writing boilerplate code. It adds `:Hashable` conformance to all types, except protocols (because it would require turning them into PAT's). For protocols it's just generating `var hashValue` comparator. ### [Stencil template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoHashable.stencil) #### Available variable annotations: - `skipHashing` allows you to skip variable from being compared. - `includeInHashing` is only applied on enums and allows us to add some computed variable into hashing logic #### Example output: ```swift // MARK: - AdNodeViewModel AutoHashable extension AdNodeViewModel: Hashable { internal var hashValue: Int { return combineHashes(remoteAdView.hashValue, hidesDisclaimer.hashValue, type.hashValue, height.hashValue, attributedDisclaimer.hashValue, 0) } } ``` ================================================ FILE: guides/Installing.md ================================================ ## Installing - _Binary form_ Download latest release with prebuilt binary from [release tab](https://github.com/krzysztofzablocki/Sourcery/releases/latest). Unzip the archive into desired destination and run `bin/sourcery` - _CocoaPods_ Add pod 'Sourcery' to your Podfile and run `pod update Sourcery`. This will download latest release binary and will put it to your project's CocoaPods path so you will run it with `$PODS_ROOT/Sourcery/bin/sourcery` - _Building from source_ Download latest release source code from [release tab](https://github.com/krzysztofzablocki/Sourcery/releases/latest) or clone the repository an build Sourcery manually. - _Building with Swift Package Manager_ Run `swift build -c release` in the root folder. This will create a `.build/release` folder and will put binary there. Move the **whole `.build/release` folder** to your desired destination and run with `path_to_release_folder/sourcery` > Note: JS templates are not supported when building with SPM yet. - _Building with Xcode_ Open `Sourcery.xcworkspace` and build with `Sourcery-Release` scheme. This will create `Sourcery.app` in the Derived Data folder. You can copy it to your desired destination and run with `path_to_sourcery_app/Sourcery.app/Contents/MacOS/Sourcery` ================================================ FILE: guides/Lenses.md ================================================ ## I want to generate Lenses for all structs _Contributed by [@filip_zawada](http://twitter.com/filip_zawada)_ What are Lenses? Great explanation by @mbrandonw This script assumes you follow swift naming convention, e.g. structs start with an upper letter. ### [Stencil template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoLenses.stencil) #### Example output: ```swift extension House { static let roomsLens = Lens( get: { $0.rooms }, set: { rooms, house in House(rooms: rooms, address: house.address, size: house.size) } ) static let addressLens = Lens( get: { $0.address }, set: { address, house in House(rooms: house.rooms, address: address, size: house.size) } ) ... ``` ================================================ FILE: guides/LinuxMain.md ================================================ ## I want to generate `LinuxMain.swift` for all my tests For all test cases generates `allTests` static variable and passes all of them as `XCTestCaseEntry` to `XCTMain`. Run with `--args testimports='import MyTests'` parameter to import test modules. ### [Stencil template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/LinuxMain.stencil) #### Available annotations: - `disableTests` allows you to disable the whole test case. #### Example output: ```swift import XCTest //testimports extension AutoInjectionTests { static var allTests = [ ("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies), ... ] } extension AutoWiringTests { static var allTests = [ ("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring), ... ] } ... XCTMain([ testCase(AutoInjectionTests.allTests), testCase(AutoWiringTests.allTests), ... ]) ``` ================================================ FILE: guides/Mocks.md ================================================ ## I want to generate test mocks for protocols _Contributed by [@marinbenc](http://twitter.com/marinbenc)_ #### For each protocol implementing `AutoMockable` protocol or [annotated](Writing%20templates.md#using-source-annotations) with `AutoMockable` annotation it will... Create a class called `ProtocolNameMock` in which it will... **For each function:** - Implement the function - Add a `functionCalled` boolean to check if the function was called - Add a `functionReceivedArguments` tuple to check the arguments that were passed to the function - Add a `functionReturnValue` variable and return it when the function is called. **For each variable:** - Add a gettable and settable variable with the same name and type #### Issues and limitations: * Overloaded methods will produce compiler errors since the variables above the functions have the same name. Workaround: delete the variables on top of one of the functions, or rename them. * Handling success/failure cases (for callbacks) is tricky to do automatically, so you have to do that yourself. * This is **not** a full replacement for hand-written mocks, but it will get you 90% of the way there. Any more complex logic than changing return types, you will have to implement yourself. This only removes the most boring boilerplate you have to write. ### [Stencil template](https://github.com/krzysztofzablocki/Sourcery/blob/master/Templates/Templates/AutoMockable.stencil) #### Example output: ```swift class MockableServiceMock: MockableService { //MARK: - functionWithArguments var functionWithArgumentsCalled = false var functionWithArgumentsReceivedArguments: (firstArgument: String, onComplete: (String)-> Void)? //MARK: - functionWithCallback var functionWithCallbackCalled = false var functionWithCallbackReceivedArguments: (firstArgument: String, onComplete: (String)-> Void)? func functionWithCallback(_ firstArgument: String, onComplete: @escaping (String)-> Void) { functionWithCallbackCalled = true functionWithCallbackReceivedArguments = (firstArgument: firstArgument, onComplete: onComplete) } ... ``` ================================================ FILE: guides/Usage.md ================================================ ## Usage Sourcery is a command line tool, you can either run it manually or in a custom build phase using following command: ``` $ ./sourcery --sources --templates --output ``` > Note: this command may be different depending on the way in which you installed Sourcery (see [Installing](installing.html)) ### Command line options - `--sources` - Path to a source swift files. You can provide multiple paths using multiple `--sources` option. - `--templates` - Path to templates. File or Directory. You can provide multiple paths using multiple `--templates` options. - `--output` [default: current path] - Path to output. File or Directory. - `--config` [default: current path] - Path to config file. File or Directory. See [Configuration file](usage.html#configuration-file). - `--args` - Additional arguments to pass to templates. Each argument can have explicit value or will have implicit `true` value. Arguments should be separated with `,` without spaces (i.e. `--args arg1=value,arg2`) or should be passed one by one (i.e `--args arg1=value --args arg2`). Arguments are accessible in templates via `argument.name`. To pass in string you should use escaped quotes (`\"`) . - `--watch` [default: false] - Watch both code and template folders for changes and regenerate automatically. - `--verbose` [default: false] - Turn on verbose logging - `--quiet` [default: false] - Turn off any logging, only emit errors - `--disableCache` [default: false] - Turn off caching of parsed data - `--prune` [default: false] - Prune empty generated files - `--version` - Display the current version of Sourcery - `--help` - Display help information. - `--cacheBasePath` - Path to Sourcery internal cache (available only in configuration file) - `--parseDocumentation` [default: false] - Include documentation comments for all declarations. Use `--help` to see the list of all available options. ### Configuration file You can also provide arguments using configuration file. Some of the configuration features (like excluding files) are only available when using configuration file. You provide path to this file using `--config` command line option. If you provide a path to a directory Sourcery will search for a file `.sourcery.yml` in this directory. You can also provide a path to config file itself. By default Sourcery will search for `.sourcery.yml` in your current path. Configuration file should be a valid Yaml file, like this: ```yaml sources: - # you can provide either single path or several paths using `-` - templates: - # as well as for templates - output: # note that there is no `-` here as only single output path is supported args: : ``` #### Multiple configurations You can pass multiple paths to configuration files using multiple `--config` command line options. Single configuration file can contain multiple configurations under root `configurations` key: ```yaml configurations: - sources: - - templates: - output: args: : : - sources: - - templates: - output: args: : : ``` This will be equivalent to running Sourcery separately for each of the configurations. In watch mode Sourcery will observe changes in the paths from all the configurations. #### Child configurations You can specify a child configurations by using the `child` key: ```yaml configurations: - child: ./.child_config.yml - child: Subdirectory/.another_child_config.yml ``` Sources will be resolved relative to the child config paths. #### Sources You can provide sources using paths to directories or specific files. ```yaml sources: - - ``` Or you can provide project which will be scanned and which source files will be processed. You can use several `project` or `target` objects to scan multiple targets from one project or to scan multiple projects. You can provide paths to XCFramework files if your target has any and you want to process their `swiftinterface` files. ```yaml project: file: target: name: module: //required if different from target name xcframeworks: - - ``` You can also provide a Swift Package which will be scanned. Source files will be scanned based on the package's `path` and `exclude` options. ```yaml package: path: target: ``` Multiple targets: ```yaml package: path: target: - - ``` #### Excluding sources or templates You can specify paths to sources files that should be scanned using `include` key and paths that should be excluded using `exclude` key. These can be directory or file paths. ```yaml sources: include: - - exclude: - - ``` You can also specify path to include and exclude for templates. When source is a project you can use `exclude` key to exclude some of its source files. ```yaml project: file: ... target: ... exclude: - - ``` #### Output You can specify the output file using `output` key. This can be a directory path or a file path. If it's a file path, all generated content will be written into this file. If it's a directory path, for each template a separate file will be created with `TemplateName.generated.swift` name. ```yaml output: ``` Alternatively you can use `path` key to specify output path. ```yaml output: path: ``` You can use optional `link` key to automatically link generated files to some target. ```yaml output: path: link: project: target: // or targets: [target1, target2, ...] group: // by default files are added to project's root group ``` > Note: Paths in configuration file are by default relative to configuration file path. If you want to specify absolute path start it with `/`. ================================================ FILE: guides/Writing templates.md ================================================ ## Writing templates Sourcery supports templates written in Stencil, Swift and even JavaScript. Discovered types can be accessed in templates via global context with following properties: - `types: Types` - access collections of types, i.e. `types.implementing.AutoCoding` (`types.implementing["AutoCoding"]` in swift templates). See [Types](https://krzysztofzablocki.github.io/Sourcery/Classes/Types.html). - `type: [String: Type]` - access types by their names, i.e. `type.MyType` (`type["MyType"]` in swift templates) - `arguments: [String: NSObject]` - access additional parameters passed with `--args` command line flag or set in `.sourcery.yml` file > Tip: Make sure you leverage Sourcery built-in daemon to make writing templates a pleasure: you can open template side-by-side with generated code and see it change live. ## What are _known_ and _unknown_ types Currently Sourcery only scans files from paths or targets that you tell it to scan. This way it can get full information about types _defined_ in these sources. These types are considered _known_ types. For each of known types Sourcery provides `Type` object. You can get it for example by its name from `types` collection. `Type` object contains information about whether type that it describes is a struct, enum, class or a protocol, what are its properties and methods, what protocols it implements and so on. This is done recursively, so if you have a class that inherits from another class (or struct that implements a protocol) and they are both known types you will have information about both of them and you will be able to access parent type's `Type` object using `type.inherits.TypeName` (or `type.implements.ProtocolName`). Everything _defined_ outside of scanned sources is considered as _unknown_ types. For such types Sourcery doesn't provide `Type` object. For that reason variables (and other "typed" types, like method parameters etc.) of such types will only contain `typeName` property, but their `type` property will be `nil`. If you have an extension of unknown type defined in scanned sources Sourcery will create `Type` for it (it's `kind` property will be `extension`). But this object will contain only declarations defined in this extension. Several extensions of unknown type will be merged into one `Type` object the same way as extensions of known types. See [#87](https://github.com/krzysztofzablocki/Sourcery/issues/87) for details. ## Stencil templates [Stencil](http://stencil.fuller.li/en/latest/) is a simple and powerful template language for Swift. It provides a syntax similar to Django and Mustache. Sourcery also uses its extension [StencilSwiftKit](https://github.com/SwiftGen/StencilSwiftKit) so you have access to additional nodes and filteres defined there. **Example**: [Equality.stencil](https://github.com/krzysztofzablocki/Sourcery/blob/master/Sourcery/Templates/Equality.stencil) ### Custom Stencil tags and filters - `{{ name|upperFirstLetter }}` - makes first letter in `name` uppercase - `{{ name|lowerFirstLetter }}` - makes first letter in `name` lowercase - `{{ name|replace:"substring","replacement" }}` - replaces occurrences of `substring` with `replacement` in `name` (case sensitive) - `{% if name|contains:"Foo" %}` - check if `name` contains arbitrary substring, can be negated with `!` prefix. - `{% if name|hasPrefix:"Foo" %}`- check if `name` starts with arbitrary substring, can be negated with `!` prefix. - `{% if name|hasSuffix:"Foo" %}`- check if `name` ends with arbitrary substring, can be negated with `!` prefix. - `static`, `instance`, `computed`, `stored`, `tuple` - can be used on Variable[s] as filter e.g. `{% for var in variables|instance %}`, can be negated with `!` prefix. - `static`, `instance`, `class`, `initializer` - can be used on Method[s] as filter e.g. `{% for method in allMethods|instance %}`, can be negated with `!` prefix. - `enum`, `class`, `struct`, `protocol` - can be used for Type[s] as filter, can be negated with `!` prefix. - `based`, `implements`, `inherits` - can be used for Type[s], Variable[s], Associated value[s], can be negated with `!` prefix. - `count` - can be used to get count of filtered array - `annotated` - can be used on Type[s], Variable[s], Method[s] and Enum Case[s] to filter by annotation, e.g. `{% for var in variable|annotated:"skipDescription" %}`, can be negated with `!` prefix. - `public`, `open`, `internal`, `private`, `fileprivate` - can be used on Type[s] and Method[s] to filter by access level, can be negated with `!` prefix. - `publicGet`, `publicSet`, .etc - can be used on Variable[s] to filter by getter or setter access level, can be negated with `!` prefix You can also use partial templates using `include` tag. Partial template is loaded from the path of a template that includes it. `include` tags also supports loading templates from relative path, i.e. `{% include "partials/MyPartial.stencil"%}` used in the template located in `templates` directory will load template from `templates/partials` directory. > Note: You can only load partial templates from child directories of the including template directory, so `{% include "../MyPartial.stencil"%}` is not supported. Sourcery treats all the templates as independent and so will generate files based on partial templates too. To avoid that use `exclude` in [configuration file](usage.html#configuration-file). ## Swift templates Swift templates syntax is very similar to EJS: - Control flow with `<% %>` - Output value with `<%= %>` - Trim extra new line after control flow tag with `-%>` - Trim _all_ whitespaces before/after control flow tag with `<%_` and `_%>` - Use `<%# %>` for comments - Use `<%- include("relative_path_to_template.swifttemplate") %>` to include another template. The `swifttemplate` extension can be omitted. The path is relative to the including template. - Use `<%- includeFile("relative_path_to_file.swift") %>` to include another Swift file. The path is relative to the including template. Included Swift files _may_ depend upon `SourceryRuntime` module, as this will be injected during processing. **Example**: [Equality.swifttemplate](https://github.com/krzysztofzablocki/Sourcery/blob/master/SourceryTests/Stub/SwiftTemplates/Equality.swifttemplate) Template: ```swift <% for type in types.all { -%> <%_ %><%= type.name %> <% } %> ``` Output: ```swift Foo Bar ``` ## JavaScript templates JavaScript templates are powered by [EJS](http://ejs.co) and support all the features available in this template engine. **Example**: [JSExport.ejs](https://github.com/krzysztofzablocki/Sourcery/blob/master/Sourcery/Templates/JSExport.ejs) > Note: when using JavaScript templates with Sourcery built using Swift Package Manager you must provide path to EJS source code using `--ejsPath` command line argument. Download EJS source code [here](https://github.com/krzysztofzablocki/Sourcery/blob/master/SourceryJS/Sources/ejs.js), put it in some path and pass it when running Sourcery. Otherwise JavaScript templates will be ignored (you will see a warning in the console output). You can also use `SourceryJS` framework independently of Sourcery. You can add it as a Carthage or SPM dependency. ## Using Source Annotations Sourcery supports annotating your classes and variables with special annotations, similar to how attributes work in Rust / Java ```swift // sourcery: skipPersistence // sourcery: anotherAnnotation = 232, yetAnotherAnnotation = "value" /// Some documentation comment var precomputedHash: Int ``` You can also add attributes to the end of a line of code: ```swift var firstVariable: Int // default = 1 var secondVariable: Int // default = 2 ``` If you want to attribute multiple items with same attributes, you can use section annotations `sourcery:begin` and `sourcery:end`: ```swift // sourcery:begin: skipEquality, skipPersistence var firstVariable: Int var secondVariable: Int // sourcery:end ``` To attribute any declaration in the file use `sourcery:file` at the top of the file: ```swift // sourcery:file: skipEquality var firstVariable: Int var secondVariable: Int ``` To group annotations of the same domain you can use annotation namespaces: ```swift // sourcery:decoding: key="first", default=0 var firstVariable: Int ``` This will effectively annotate with `decoding.key` and `decoding.default` annotations #### Rules: - Multiple annotations can occur on the same line, separated with `,` - You can add multiline annotations - Multiple annotations values with the same key are merged into array - You can interleave annotations with documentation - Sourcery scans all `sourcery:` annotations in the given comment block above the source until first non-comment/doc line - Annotations at the end of a line will be applied to all declarations on the same line - Using `/*` and `*/` for annotation comment you can put annotations on the same line preceding your declaration. This is useful for annotating methods parameters and enum case associated values. All such annotations should be placed in one comment block. Do not mix inline and regular annotations for the same declaration (using inline and block annotations is fine)! #### Format: - simple entry, e.g. `sourcery: skipPersistence` - key = number, e.g. `sourcery: another = 123` - key = string, e.g. `sourcery: jsonKey = "json_key"` #### Accessing in templates: ```swift {% if variable|!annotated:"skipPersistence" %} var local{{ variable.name|capitalize }} = json["{{ variable.annotations.jsonKey }}"] as? {{ variable.typeName }} {% endif %} ``` #### Checking for existence of at least one annotation: Sometimes it is desirable to only generate code if there's at least one field annotated. ```swift {% if type.variables|annotated:"jsonKey" %}{% for var in type.variables|instance|annotated:"jsonKey" %} var local{{ var.name|capitalize }} = json["{{ var.annotations.jsonKey }}"] as? {{ var.typeName }} {% endfor %}{% endif %} ``` ## Inline code generation Sourcery supports inline code generation, you just need to put same markup in your code and template, e.g. ```swift // in template: {% for type in types.all %} // sourcery:inline:{{ type.name }}.TemplateName // sourcery:end {% endfor %} // in source code: class MyType { // sourcery:inline:MyType.TemplateName // sourcery:end } ``` Sourcery will generate the template code and then perform replacement in your source file by matching annotation comments. Inlined generated code is not parsed to avoid chicken-egg problem. #### Automatic inline code generation To avoid having to place the markup in your source files, you can use automatic generation e.g. `inline:auto:{{ type.name }}.TemplateName`: ```swift // in template: {% for type in types.all %} // sourcery:inline:auto:{{ type.name }}.TemplateName // sourcery:end {% endfor %} // in source code: class MyType {} // after running Sourcery: class MyType { // sourcery:inline:auto:MyType.TemplateName // sourcery:end } ``` The needed markup will be automatically added at the end of the type declaration body. After first parse Sourcery will work with generated code annotated with `inline:auto` the same way as annotated with `inline`, so you can even move these blocks of code anywhere in the same file. If you want to insert code after the type declaration, use `after-auto:` instead of `auto:` ## Per file code generation Sourcery supports generating code in a separate file per type, you just need to put `file` annotation in a template, e.g. ```swift {% for type in types.all %} // sourcery:file:Generated/{{ type.name}}+TemplateName // sourcery:end {% endfor %} ``` Sourcery will generate the template code and then write its annotated parts to corresponding files. In example above it will create `Generated/+TemplateName.generated.swift` file for each of scanned types. If you add an extension to the file name Sourcery will not append `generated.swift` extension.