Repository: reinforced/Reinforced.Typings Branch: master Commit: 53d3cf415444 Files: 1171 Total size: 7.1 MB Directory structure: gitextract_icvkxvr6/ ├── .gitignore ├── LICENSE.md ├── README.md ├── Reinforced.Typings/ │ ├── AccessModifier.cs │ ├── Ast/ │ │ ├── Dependency/ │ │ │ ├── RtImport.cs │ │ │ └── RtReference.cs │ │ ├── DocTag.cs │ │ ├── IDecoratable.cs │ │ ├── IRtVisitor.cs │ │ ├── ITypeMember.cs │ │ ├── JsdocTagAttribute.cs │ │ ├── RtArgument.cs │ │ ├── RtClass.cs │ │ ├── RtCompilationUnit.cs │ │ ├── RtConstructor.cs │ │ ├── RtDecorator.cs │ │ ├── RtEnum.cs │ │ ├── RtEnumValue.cs │ │ ├── RtField.cs │ │ ├── RtFunction.cs │ │ ├── RtIdentifier.cs │ │ ├── RtInterface.cs │ │ ├── RtJsdocNode.cs │ │ ├── RtMember.cs │ │ ├── RtNamespace.cs │ │ ├── RtNode.cs │ │ ├── RtRaw.cs │ │ └── TypeNames/ │ │ ├── RtArrayType.cs │ │ ├── RtAsyncType.cs │ │ ├── RtDelegateType.cs │ │ ├── RtDictionaryType.cs │ │ ├── RtSimpleTypeName.cs │ │ ├── RtTuple.cs │ │ └── RtTypeName.cs │ ├── Attributes/ │ │ ├── IAutoexportSwitchAttribute.cs │ │ ├── TsAddTypeImportAttribute.cs │ │ ├── TsAddTypeReference.cs │ │ ├── TsAttributeBase.cs │ │ ├── TsBaseParamAttribute.cs │ │ ├── TsClassAttribute.cs │ │ ├── TsDeclarationAttributeBase.cs │ │ ├── TsDecoratorAttribute.cs │ │ ├── TsEnumAttribute.cs │ │ ├── TsFileAttribute.cs │ │ ├── TsFunctionAttribute.cs │ │ ├── TsGenericAttribute.cs │ │ ├── TsGlobalAttribute.cs │ │ ├── TsIgnoreAttribute.cs │ │ ├── TsImportAttribute.cs │ │ ├── TsInterfaceAttribute.cs │ │ ├── TsParameterAttribute.cs │ │ ├── TsPropertyAttribute.cs │ │ ├── TsReferenceAttribute.cs │ │ ├── TsThirdPartyAttribute.cs │ │ ├── TsTypedAttributeBase.cs │ │ ├── TsTypedMemberAttributeBase.cs │ │ └── TsValueAttribute.cs │ ├── DictionaryExtensions.cs │ ├── Exceptions/ │ │ ├── ErrorMessage.cs │ │ ├── ErrorMessages.cs │ │ ├── RtException.cs │ │ └── RtWarning.cs │ ├── ExportContext/ │ │ ├── ExportContext.Configurables.cs │ │ ├── ExportContext.Initialization.cs │ │ ├── ExportContext.Operations.cs │ │ ├── ExportContext.Readonly.cs │ │ ├── ExportContext.cs │ │ └── IWarningsCollector.cs │ ├── ExportedFile.cs │ ├── FilesOperations.cs │ ├── Fluent/ │ │ ├── ConfigurationBuilder.cs │ │ ├── ConfigurationBuilderExtensions.cs │ │ ├── GlobalConfigurationBuilder.cs │ │ ├── InferringExtensions.cs │ │ ├── LambdaHelpers.cs │ │ ├── MemberBuilders/ │ │ │ ├── MemberExportBuilder.EnumValue.cs │ │ │ ├── MemberExportBuilder.Field.cs │ │ │ ├── MemberExportBuilder.Method.cs │ │ │ ├── MemberExportBuilder.Parameter.cs │ │ │ ├── MemberExportBuilder.Property.cs │ │ │ └── MemberExportBuilder.cs │ │ ├── MemberExtensions/ │ │ │ ├── MemberExportExtensions.EnumValue.cs │ │ │ ├── MemberExportExtensions.Method.cs │ │ │ ├── MemberExportExtensions.Parameter.cs │ │ │ ├── MemberExportExtensions.Property.cs │ │ │ └── MemberExportExtensions.cs │ │ ├── Parameter.cs │ │ ├── TypeBuilders/ │ │ │ ├── TypeExportBuilder.Class.cs │ │ │ ├── TypeExportBuilder.ClassOrInterface.cs │ │ │ ├── TypeExportBuilder.Class`1.cs │ │ │ ├── TypeExportBuilder.Enum.cs │ │ │ ├── TypeExportBuilder.Interface.cs │ │ │ ├── TypeExportBuilder.Interface`1.cs │ │ │ ├── TypeExportBuilder.ThirdParty.cs │ │ │ ├── TypeExportBuilder.ThirdParty`1.cs │ │ │ └── TypeExportBuilder.cs │ │ ├── TypeExtensions/ │ │ │ ├── TypeExportExtensions.All.NamesAndNamespaces.cs │ │ │ ├── TypeExportExtensions.All.ReferencesAndImports.cs │ │ │ ├── TypeExportExtensions.All.Substitutions.cs │ │ │ ├── TypeExportExtensions.All.ThirdParty.cs │ │ │ ├── TypeExportExtensions.Class.cs │ │ │ ├── TypeExportExtensions.Enum.cs │ │ │ ├── TypeExportExtensions.Interface.cs │ │ │ └── TypeExportExtensions.cs │ │ └── WithExtensions/ │ │ ├── WithExtensions.Fields.cs │ │ ├── WithExtensions.Methods.cs │ │ └── WithExtensions.Properties.cs │ ├── GeneratorManager.cs │ ├── Generators/ │ │ ├── ClassAndInterfaceGeneratorBase.cs │ │ ├── ClassCodeGenerator.cs │ │ ├── ConstructorCodeGenerator.cs │ │ ├── ContextExtensions.cs │ │ ├── EnumGenerator.cs │ │ ├── FieldCodeGenerator.cs │ │ ├── ITsCodeGenerator.cs │ │ ├── InterfaceCodeGenerator.cs │ │ ├── MethodCodeGenerator.cs │ │ ├── NamespaceCodeGenerator.cs │ │ ├── ParameterCodeGenerator.cs │ │ ├── PropertyCodeGenerator.cs │ │ └── TsCodeGeneratorBase.cs │ ├── GlobalParameters.cs │ ├── IFilesOperations.cs │ ├── InlineTypeInferers.cs │ ├── Location.cs │ ├── ProjectBlueprint.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ReferencesInspection/ │ │ ├── ImportComparer.cs │ │ ├── InspectedReferences.cs │ │ ├── ReferenceComparer.cs │ │ └── ReferenceProcessorBase.cs │ ├── Reinforced.Typings.Dev.csproj │ ├── Reinforced.Typings.NETCore.csproj │ ├── Reinforced.Typings.csproj │ ├── Reinforced_pub.snk │ ├── Sign.cs │ ├── TsExporter.cs │ ├── TypeBlueprint.cs │ ├── TypeExtensions.cs │ ├── TypeResolver.cs │ ├── Visitors/ │ │ ├── TextExportingVisitor.cs │ │ ├── TypeScript/ │ │ │ ├── TypeScriptExportVisitor.Dependencies.cs │ │ │ ├── TypeScriptExportVisitor.RtArgument.cs │ │ │ ├── TypeScriptExportVisitor.RtClass.cs │ │ │ ├── TypeScriptExportVisitor.RtConstructor.cs │ │ │ ├── TypeScriptExportVisitor.RtEnum.cs │ │ │ ├── TypeScriptExportVisitor.RtEnumValue.cs │ │ │ ├── TypeScriptExportVisitor.RtField.cs │ │ │ ├── TypeScriptExportVisitor.RtFunction.cs │ │ │ ├── TypeScriptExportVisitor.RtIdentifier.cs │ │ │ ├── TypeScriptExportVisitor.RtInterface.cs │ │ │ ├── TypeScriptExportVisitor.RtJsdocNode.cs │ │ │ ├── TypeScriptExportVisitor.RtNamespace.cs │ │ │ ├── TypeScriptExportVisitor.RtRaw.cs │ │ │ ├── TypeScriptExportVisitor.cs │ │ │ └── Types/ │ │ │ ├── TypeScriptExportVisitor.RtArrayType.cs │ │ │ ├── TypeScriptExportVisitor.RtAsyncType.cs │ │ │ ├── TypeScriptExportVisitor.RtDelegateType.cs │ │ │ ├── TypeScriptExportVisitor.RtDictionaryType.cs │ │ │ ├── TypeScriptExportVisitor.RtSimpleTypeName.cs │ │ │ └── TypeScriptExportVisitor.RtTuple.cs │ │ ├── TypedVisitorBase.cs │ │ ├── Typings/ │ │ │ ├── TypingsExportVisitor.RtClass.cs │ │ │ ├── TypingsExportVisitor.RtConstructor.cs │ │ │ ├── TypingsExportVisitor.RtEnum.cs │ │ │ ├── TypingsExportVisitor.RtField.cs │ │ │ ├── TypingsExportVisitor.RtFunction.cs │ │ │ ├── TypingsExportVisitor.RtModule.cs │ │ │ └── TypingsExportVisitor.cs │ │ └── VisitorBase.cs │ └── Xmldoc/ │ ├── DocumentationManager.cs │ └── Model/ │ ├── DocumentationMemberExtensions.cs │ ├── DocumentationMemberType.cs │ ├── Model.cs │ └── XmlIgnoreInner.cs ├── Reinforced.Typings.Cli/ │ ├── AssemblyManager.cs │ ├── Bootstrapper.cs │ ├── ConsoleHelpAttribute.cs │ ├── ErrorMessages.cs │ ├── ExporterConsoleParameters.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ └── launchSettings.json │ ├── Reinforced.Typings.Cli.Dev.csproj │ ├── Reinforced.Typings.Cli.NETCore.csproj │ ├── Reinforced.Typings.Cli.csproj │ ├── VisualStudioFriendlyErrorMessage.cs │ ├── VisualStudioFriendlyMessageType.cs │ └── app.config ├── Reinforced.Typings.Dev.sln ├── Reinforced.Typings.Integrate/ │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── Reinforced.Typings.Integrate.Dev.csproj │ ├── Reinforced.Typings.Integrate.NETCore.csproj │ ├── Reinforced.Typings.Integrate.csproj │ ├── RemoveTypescriptStep.cs │ ├── RtCli.cs │ └── packages.config ├── Reinforced.Typings.NETCore.sln ├── Reinforced.Typings.Tests/ │ ├── BasicTypesResolvationTests.cs │ ├── ClassicMultiFileResolvationTests.cs │ ├── ConfigurationBuilderTestBase.cs │ ├── Core/ │ │ ├── MockFileOperations.cs │ │ └── RtExporterTestBase.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── Reinforced.Typings.Tests.Dev.csproj │ ├── Reinforced.Typings.Tests.Dev.xml │ ├── Reinforced.Typings.Tests.NETCore.csproj │ ├── Reinforced.Typings.Tests.csproj │ ├── SpecificCases/ │ │ ├── SpecificTestCases.ADIXReadonlyDictionaryWorkaround.cs │ │ ├── SpecificTestCases.All.cs │ │ ├── SpecificTestCases.AutoAsync.cs │ │ ├── SpecificTestCases.AutoOptional.cs │ │ ├── SpecificTestCases.AutoOptionalWithCompilerNullable.cs │ │ ├── SpecificTestCases.ClassCodeGenerators.cs │ │ ├── SpecificTestCases.ConstantProperties.cs │ │ ├── SpecificTestCases.Constructor.cs │ │ ├── SpecificTestCases.CrozinSubstitutions.cs │ │ ├── SpecificTestCases.DDanteInheritanceBug.cs │ │ ├── SpecificTestCases.DGoncharovGenericsCase.cs │ │ ├── SpecificTestCases.DaggmanoAutoIBug.cs │ │ ├── SpecificTestCases.DecoratorsTest.cs │ │ ├── SpecificTestCases.DocumentationForNestedTypes.cs │ │ ├── SpecificTestCases.DtsNoDeclareEnumWithoutAmbientScope.cs │ │ ├── SpecificTestCases.EnumKeyedDictionary.cs │ │ ├── SpecificTestCases.EnumStringInitializerIgnoreManyValues.cs │ │ ├── SpecificTestCases.EnumStringInitializers.cs │ │ ├── SpecificTestCases.ExportEnums.cs │ │ ├── SpecificTestCases.ExportEnumsInDtsWithDeclareKeyword.cs │ │ ├── SpecificTestCases.ExportOrderTest1.cs │ │ ├── SpecificTestCases.ExportOrderTest2.cs │ │ ├── SpecificTestCases.FQNs.cs │ │ ├── SpecificTestCases.Fields.cs │ │ ├── SpecificTestCases.FunctionWithParamInitialiser.cs │ │ ├── SpecificTestCases.FunctionalNames.cs │ │ ├── SpecificTestCases.GenericGuidDictionary.cs │ │ ├── SpecificTestCases.GenericSubstitutions.cs │ │ ├── SpecificTestCases.GenericsExport.cs │ │ ├── SpecificTestCases.GenericsExport2.cs │ │ ├── SpecificTestCases.GenericsExport3.cs │ │ ├── SpecificTestCases.HierarchyFlattening.cs │ │ ├── SpecificTestCases.HierarchyFlattening2.cs │ │ ├── SpecificTestCases.HierarchyFlattening3.cs │ │ ├── SpecificTestCases.HierarchyFlattening4.cs │ │ ├── SpecificTestCases.InferTypeTest.cs │ │ ├── SpecificTestCases.InheritDoc.cs │ │ ├── SpecificTestCases.InlineFunctionImplementation.cs │ │ ├── SpecificTestCases.InvalidFlattenOrder.cs │ │ ├── SpecificTestCases.JonsaCustomIndentationTest.cs │ │ ├── SpecificTestCases.JonsaEnumWithouNamespaceTest.cs │ │ ├── SpecificTestCases.KpKozakIssueWithInheritance.cs │ │ ├── SpecificTestCases.LineAfterAnotherWay.cs │ │ ├── SpecificTestCases.LineAfterTest.cs │ │ ├── SpecificTestCases.NestedClassInheritance.cs │ │ ├── SpecificTestCases.NewForceNullable.cs │ │ ├── SpecificTestCases.NewLineTest.cs │ │ ├── SpecificTestCases.NvirthMultilineString.cs │ │ ├── SpecificTestCases.OverrideNamespaceWithModules.cs │ │ ├── SpecificTestCases.OverridenNamesNotCamelCased.cs │ │ ├── SpecificTestCases.PandaWoodCamelCase.cs │ │ ├── SpecificTestCases.PandaWoodForceNullableTest.cs │ │ ├── SpecificTestCases.Records.cs │ │ ├── SpecificTestCases.ReferencesPart1.cs │ │ ├── SpecificTestCases.ReferencesPart2.cs │ │ ├── SpecificTestCases.ReferencesPart3.cs │ │ ├── SpecificTestCases.ReferencesPart4.cs │ │ ├── SpecificTestCases.ReferencesPart5.cs │ │ ├── SpecificTestCases.ReferencesPart6ByDanielWest.cs │ │ ├── SpecificTestCases.ReferencesProcessor.cs │ │ ├── SpecificTestCases.RemarksDocs.cs │ │ ├── SpecificTestCases.RluitenConstEnums.cs │ │ ├── SpecificTestCases.ThirdParty.cs │ │ ├── SpecificTestCases.ThirdPartyWithBaseClass.cs │ │ ├── SpecificTestCases.TsFunctionWorks.cs │ │ ├── SpecificTestCases.TsFunctionWorksWithEnum.cs │ │ ├── SpecificTestCases.TsPropertyWorks.cs │ │ ├── SpecificTestCases.WeirdInheritanceCase.cs │ │ ├── SpecificTestCases._CopyMe_.cs │ │ ├── SpecifiicTestCases.UnresolvedToUnknown.cs │ │ └── TestCases.cs │ ├── SuppressedWarningsParseringTests.cs │ ├── Tokenizing/ │ │ ├── SimpleTokenizer.cs │ │ └── TokenizingComparer.cs │ ├── TokenizingComparerTests.cs │ ├── TypeNameEqualityComparer.cs │ └── packages.config ├── Reinforced.Typings.sln ├── Reinforced_pub.snk ├── Samples/ │ ├── Difficult/ │ │ └── Reinforced.Typings.Samples.Difficult.CodeGenerators/ │ │ ├── App_Start/ │ │ │ ├── BundleConfig.cs │ │ │ ├── FilterConfig.cs │ │ │ └── RouteConfig.cs │ │ ├── Content/ │ │ │ ├── Site.css │ │ │ └── prismjs/ │ │ │ ├── cshtml.css │ │ │ ├── cshtml.js │ │ │ ├── prism.css │ │ │ └── prism.js │ │ ├── Controllers/ │ │ │ ├── AngularController.cs │ │ │ ├── HomeController.cs │ │ │ └── JQueryController.cs │ │ ├── Global.asax │ │ ├── Global.asax.cs │ │ ├── Models/ │ │ │ └── SampleResponseModel.cs │ │ ├── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── Reinforced.Typings.Samples.Difficult.CodeGenerators.csproj │ │ ├── Reinforced.Typings.settings.xml │ │ ├── ReinforcedTypings/ │ │ │ ├── Angular/ │ │ │ │ ├── AngularActionCallGenerator.cs │ │ │ │ ├── AngularControllerGenerator.cs │ │ │ │ └── AngularMethodAttribute.cs │ │ │ ├── Configuration.cs │ │ │ └── jQuery/ │ │ │ ├── JQueryActionCallGenerator.cs │ │ │ └── JQueryMethodAttribute.cs │ │ ├── Scripts/ │ │ │ ├── ReinforcedTypings/ │ │ │ │ ├── AngularDemoController.js │ │ │ │ ├── AngularDemoController.ts │ │ │ │ ├── Generated/ │ │ │ │ │ ├── AngularController.js │ │ │ │ │ ├── AngularController.ts │ │ │ │ │ ├── JQueryController.js │ │ │ │ │ ├── JQueryController.ts │ │ │ │ │ ├── models.js │ │ │ │ │ └── models.ts │ │ │ │ ├── GeneratedTypings.js │ │ │ │ ├── IndexPage.js │ │ │ │ ├── IndexPage.ts │ │ │ │ ├── app.js │ │ │ │ ├── app.ts │ │ │ │ ├── query.js │ │ │ │ └── query.ts │ │ │ ├── _references.js │ │ │ ├── angular-animate.js │ │ │ ├── angular-aria.js │ │ │ ├── angular-cookies.js │ │ │ ├── angular-csp.css │ │ │ ├── angular-loader.js │ │ │ ├── angular-message-format.js │ │ │ ├── angular-messages.js │ │ │ ├── angular-mocks.js │ │ │ ├── angular-resource.js │ │ │ ├── angular-route.js │ │ │ ├── angular-sanitize.js │ │ │ ├── angular-scenario.js │ │ │ ├── angular-touch.js │ │ │ ├── angular.js │ │ │ ├── errors.json │ │ │ ├── i18n/ │ │ │ │ ├── angular-locale_aa-dj.js │ │ │ │ ├── angular-locale_aa-er.js │ │ │ │ ├── angular-locale_aa-et.js │ │ │ │ ├── angular-locale_aa.js │ │ │ │ ├── angular-locale_af-na.js │ │ │ │ ├── angular-locale_af-za.js │ │ │ │ ├── angular-locale_af.js │ │ │ │ ├── angular-locale_agq-cm.js │ │ │ │ ├── angular-locale_agq.js │ │ │ │ ├── angular-locale_ak-gh.js │ │ │ │ ├── angular-locale_ak.js │ │ │ │ ├── angular-locale_am-et.js │ │ │ │ ├── angular-locale_am.js │ │ │ │ ├── angular-locale_ar-001.js │ │ │ │ ├── angular-locale_ar-ae.js │ │ │ │ ├── angular-locale_ar-bh.js │ │ │ │ ├── angular-locale_ar-dj.js │ │ │ │ ├── angular-locale_ar-dz.js │ │ │ │ ├── angular-locale_ar-eg.js │ │ │ │ ├── angular-locale_ar-eh.js │ │ │ │ ├── angular-locale_ar-er.js │ │ │ │ ├── angular-locale_ar-il.js │ │ │ │ ├── angular-locale_ar-iq.js │ │ │ │ ├── angular-locale_ar-jo.js │ │ │ │ ├── angular-locale_ar-km.js │ │ │ │ ├── angular-locale_ar-kw.js │ │ │ │ ├── angular-locale_ar-lb.js │ │ │ │ ├── angular-locale_ar-ly.js │ │ │ │ ├── angular-locale_ar-ma.js │ │ │ │ ├── angular-locale_ar-mr.js │ │ │ │ ├── angular-locale_ar-om.js │ │ │ │ ├── angular-locale_ar-ps.js │ │ │ │ ├── angular-locale_ar-qa.js │ │ │ │ ├── angular-locale_ar-sa.js │ │ │ │ ├── angular-locale_ar-sd.js │ │ │ │ ├── angular-locale_ar-so.js │ │ │ │ ├── angular-locale_ar-ss.js │ │ │ │ ├── angular-locale_ar-sy.js │ │ │ │ ├── angular-locale_ar-td.js │ │ │ │ ├── angular-locale_ar-tn.js │ │ │ │ ├── angular-locale_ar-ye.js │ │ │ │ ├── angular-locale_ar.js │ │ │ │ ├── angular-locale_as-in.js │ │ │ │ ├── angular-locale_as.js │ │ │ │ ├── angular-locale_asa-tz.js │ │ │ │ ├── angular-locale_asa.js │ │ │ │ ├── angular-locale_ast-es.js │ │ │ │ ├── angular-locale_ast.js │ │ │ │ ├── angular-locale_az-cyrl-az.js │ │ │ │ ├── angular-locale_az-cyrl.js │ │ │ │ ├── angular-locale_az-latn-az.js │ │ │ │ ├── angular-locale_az-latn.js │ │ │ │ ├── angular-locale_az.js │ │ │ │ ├── angular-locale_bas-cm.js │ │ │ │ ├── angular-locale_bas.js │ │ │ │ ├── angular-locale_be-by.js │ │ │ │ ├── angular-locale_be.js │ │ │ │ ├── angular-locale_bem-zm.js │ │ │ │ ├── angular-locale_bem.js │ │ │ │ ├── angular-locale_bez-tz.js │ │ │ │ ├── angular-locale_bez.js │ │ │ │ ├── angular-locale_bg-bg.js │ │ │ │ ├── angular-locale_bg.js │ │ │ │ ├── angular-locale_bm-latn-ml.js │ │ │ │ ├── angular-locale_bm-latn.js │ │ │ │ ├── angular-locale_bm-ml.js │ │ │ │ ├── angular-locale_bm.js │ │ │ │ ├── angular-locale_bn-bd.js │ │ │ │ ├── angular-locale_bn-in.js │ │ │ │ ├── angular-locale_bn.js │ │ │ │ ├── angular-locale_bo-cn.js │ │ │ │ ├── angular-locale_bo-in.js │ │ │ │ ├── angular-locale_bo.js │ │ │ │ ├── angular-locale_br-fr.js │ │ │ │ ├── angular-locale_br.js │ │ │ │ ├── angular-locale_brx-in.js │ │ │ │ ├── angular-locale_brx.js │ │ │ │ ├── angular-locale_bs-cyrl-ba.js │ │ │ │ ├── angular-locale_bs-cyrl.js │ │ │ │ ├── angular-locale_bs-latn-ba.js │ │ │ │ ├── angular-locale_bs-latn.js │ │ │ │ ├── angular-locale_bs.js │ │ │ │ ├── angular-locale_byn-er.js │ │ │ │ ├── angular-locale_byn.js │ │ │ │ ├── angular-locale_ca-ad.js │ │ │ │ ├── angular-locale_ca-es-valencia.js │ │ │ │ ├── angular-locale_ca-es.js │ │ │ │ ├── angular-locale_ca-fr.js │ │ │ │ ├── angular-locale_ca-it.js │ │ │ │ ├── angular-locale_ca.js │ │ │ │ ├── angular-locale_cgg-ug.js │ │ │ │ ├── angular-locale_cgg.js │ │ │ │ ├── angular-locale_chr-us.js │ │ │ │ ├── angular-locale_chr.js │ │ │ │ ├── angular-locale_ckb-arab-iq.js │ │ │ │ ├── angular-locale_ckb-arab-ir.js │ │ │ │ ├── angular-locale_ckb-arab.js │ │ │ │ ├── angular-locale_ckb-iq.js │ │ │ │ ├── angular-locale_ckb-ir.js │ │ │ │ ├── angular-locale_ckb-latn-iq.js │ │ │ │ ├── angular-locale_ckb-latn.js │ │ │ │ ├── angular-locale_ckb.js │ │ │ │ ├── angular-locale_cs-cz.js │ │ │ │ ├── angular-locale_cs.js │ │ │ │ ├── angular-locale_cy-gb.js │ │ │ │ ├── angular-locale_cy.js │ │ │ │ ├── angular-locale_da-dk.js │ │ │ │ ├── angular-locale_da-gl.js │ │ │ │ ├── angular-locale_da.js │ │ │ │ ├── angular-locale_dav-ke.js │ │ │ │ ├── angular-locale_dav.js │ │ │ │ ├── angular-locale_de-at.js │ │ │ │ ├── angular-locale_de-be.js │ │ │ │ ├── angular-locale_de-ch.js │ │ │ │ ├── angular-locale_de-de.js │ │ │ │ ├── angular-locale_de-li.js │ │ │ │ ├── angular-locale_de-lu.js │ │ │ │ ├── angular-locale_de.js │ │ │ │ ├── angular-locale_dje-ne.js │ │ │ │ ├── angular-locale_dje.js │ │ │ │ ├── angular-locale_dsb-de.js │ │ │ │ ├── angular-locale_dsb.js │ │ │ │ ├── angular-locale_dua-cm.js │ │ │ │ ├── angular-locale_dua.js │ │ │ │ ├── angular-locale_dyo-sn.js │ │ │ │ ├── angular-locale_dyo.js │ │ │ │ ├── angular-locale_dz-bt.js │ │ │ │ ├── angular-locale_dz.js │ │ │ │ ├── angular-locale_ebu-ke.js │ │ │ │ ├── angular-locale_ebu.js │ │ │ │ ├── angular-locale_ee-gh.js │ │ │ │ ├── angular-locale_ee-tg.js │ │ │ │ ├── angular-locale_ee.js │ │ │ │ ├── angular-locale_el-cy.js │ │ │ │ ├── angular-locale_el-gr.js │ │ │ │ ├── angular-locale_el.js │ │ │ │ ├── angular-locale_en-001.js │ │ │ │ ├── angular-locale_en-150.js │ │ │ │ ├── angular-locale_en-ag.js │ │ │ │ ├── angular-locale_en-ai.js │ │ │ │ ├── angular-locale_en-as.js │ │ │ │ ├── angular-locale_en-au.js │ │ │ │ ├── angular-locale_en-bb.js │ │ │ │ ├── angular-locale_en-be.js │ │ │ │ ├── angular-locale_en-bm.js │ │ │ │ ├── angular-locale_en-bs.js │ │ │ │ ├── angular-locale_en-bw.js │ │ │ │ ├── angular-locale_en-bz.js │ │ │ │ ├── angular-locale_en-ca.js │ │ │ │ ├── angular-locale_en-cc.js │ │ │ │ ├── angular-locale_en-ck.js │ │ │ │ ├── angular-locale_en-cm.js │ │ │ │ ├── angular-locale_en-cx.js │ │ │ │ ├── angular-locale_en-dg.js │ │ │ │ ├── angular-locale_en-dm.js │ │ │ │ ├── angular-locale_en-er.js │ │ │ │ ├── angular-locale_en-fj.js │ │ │ │ ├── angular-locale_en-fk.js │ │ │ │ ├── angular-locale_en-fm.js │ │ │ │ ├── angular-locale_en-gb.js │ │ │ │ ├── angular-locale_en-gd.js │ │ │ │ ├── angular-locale_en-gg.js │ │ │ │ ├── angular-locale_en-gh.js │ │ │ │ ├── angular-locale_en-gi.js │ │ │ │ ├── angular-locale_en-gm.js │ │ │ │ ├── angular-locale_en-gu.js │ │ │ │ ├── angular-locale_en-gy.js │ │ │ │ ├── angular-locale_en-hk.js │ │ │ │ ├── angular-locale_en-ie.js │ │ │ │ ├── angular-locale_en-im.js │ │ │ │ ├── angular-locale_en-in.js │ │ │ │ ├── angular-locale_en-io.js │ │ │ │ ├── angular-locale_en-iso.js │ │ │ │ ├── angular-locale_en-je.js │ │ │ │ ├── angular-locale_en-jm.js │ │ │ │ ├── angular-locale_en-ke.js │ │ │ │ ├── angular-locale_en-ki.js │ │ │ │ ├── angular-locale_en-kn.js │ │ │ │ ├── angular-locale_en-ky.js │ │ │ │ ├── angular-locale_en-lc.js │ │ │ │ ├── angular-locale_en-lr.js │ │ │ │ ├── angular-locale_en-ls.js │ │ │ │ ├── angular-locale_en-mg.js │ │ │ │ ├── angular-locale_en-mh.js │ │ │ │ ├── angular-locale_en-mo.js │ │ │ │ ├── angular-locale_en-mp.js │ │ │ │ ├── angular-locale_en-ms.js │ │ │ │ ├── angular-locale_en-mt.js │ │ │ │ ├── angular-locale_en-mu.js │ │ │ │ ├── angular-locale_en-mw.js │ │ │ │ ├── angular-locale_en-my.js │ │ │ │ ├── angular-locale_en-na.js │ │ │ │ ├── angular-locale_en-nf.js │ │ │ │ ├── angular-locale_en-ng.js │ │ │ │ ├── angular-locale_en-nr.js │ │ │ │ ├── angular-locale_en-nu.js │ │ │ │ ├── angular-locale_en-nz.js │ │ │ │ ├── angular-locale_en-pg.js │ │ │ │ ├── angular-locale_en-ph.js │ │ │ │ ├── angular-locale_en-pk.js │ │ │ │ ├── angular-locale_en-pn.js │ │ │ │ ├── angular-locale_en-pr.js │ │ │ │ ├── angular-locale_en-pw.js │ │ │ │ ├── angular-locale_en-rw.js │ │ │ │ ├── angular-locale_en-sb.js │ │ │ │ ├── angular-locale_en-sc.js │ │ │ │ ├── angular-locale_en-sd.js │ │ │ │ ├── angular-locale_en-sg.js │ │ │ │ ├── angular-locale_en-sh.js │ │ │ │ ├── angular-locale_en-sl.js │ │ │ │ ├── angular-locale_en-ss.js │ │ │ │ ├── angular-locale_en-sx.js │ │ │ │ ├── angular-locale_en-sz.js │ │ │ │ ├── angular-locale_en-tc.js │ │ │ │ ├── angular-locale_en-tk.js │ │ │ │ ├── angular-locale_en-to.js │ │ │ │ ├── angular-locale_en-tt.js │ │ │ │ ├── angular-locale_en-tv.js │ │ │ │ ├── angular-locale_en-tz.js │ │ │ │ ├── angular-locale_en-ug.js │ │ │ │ ├── angular-locale_en-um.js │ │ │ │ ├── angular-locale_en-us.js │ │ │ │ ├── angular-locale_en-vc.js │ │ │ │ ├── angular-locale_en-vg.js │ │ │ │ ├── angular-locale_en-vi.js │ │ │ │ ├── angular-locale_en-vu.js │ │ │ │ ├── angular-locale_en-ws.js │ │ │ │ ├── angular-locale_en-za.js │ │ │ │ ├── angular-locale_en-zm.js │ │ │ │ ├── angular-locale_en-zw.js │ │ │ │ ├── angular-locale_en.js │ │ │ │ ├── angular-locale_eo-001.js │ │ │ │ ├── angular-locale_eo.js │ │ │ │ ├── angular-locale_es-419.js │ │ │ │ ├── angular-locale_es-ar.js │ │ │ │ ├── angular-locale_es-bo.js │ │ │ │ ├── angular-locale_es-cl.js │ │ │ │ ├── angular-locale_es-co.js │ │ │ │ ├── angular-locale_es-cr.js │ │ │ │ ├── angular-locale_es-cu.js │ │ │ │ ├── angular-locale_es-do.js │ │ │ │ ├── angular-locale_es-ea.js │ │ │ │ ├── angular-locale_es-ec.js │ │ │ │ ├── angular-locale_es-es.js │ │ │ │ ├── angular-locale_es-gq.js │ │ │ │ ├── angular-locale_es-gt.js │ │ │ │ ├── angular-locale_es-hn.js │ │ │ │ ├── angular-locale_es-ic.js │ │ │ │ ├── angular-locale_es-mx.js │ │ │ │ ├── angular-locale_es-ni.js │ │ │ │ ├── angular-locale_es-pa.js │ │ │ │ ├── angular-locale_es-pe.js │ │ │ │ ├── angular-locale_es-ph.js │ │ │ │ ├── angular-locale_es-pr.js │ │ │ │ ├── angular-locale_es-py.js │ │ │ │ ├── angular-locale_es-sv.js │ │ │ │ ├── angular-locale_es-us.js │ │ │ │ ├── angular-locale_es-uy.js │ │ │ │ ├── angular-locale_es-ve.js │ │ │ │ ├── angular-locale_es.js │ │ │ │ ├── angular-locale_et-ee.js │ │ │ │ ├── angular-locale_et.js │ │ │ │ ├── angular-locale_eu-es.js │ │ │ │ ├── angular-locale_eu.js │ │ │ │ ├── angular-locale_ewo-cm.js │ │ │ │ ├── angular-locale_ewo.js │ │ │ │ ├── angular-locale_fa-af.js │ │ │ │ ├── angular-locale_fa-ir.js │ │ │ │ ├── angular-locale_fa.js │ │ │ │ ├── angular-locale_ff-cm.js │ │ │ │ ├── angular-locale_ff-gn.js │ │ │ │ ├── angular-locale_ff-mr.js │ │ │ │ ├── angular-locale_ff-sn.js │ │ │ │ ├── angular-locale_ff.js │ │ │ │ ├── angular-locale_fi-fi.js │ │ │ │ ├── angular-locale_fi.js │ │ │ │ ├── angular-locale_fil-ph.js │ │ │ │ ├── angular-locale_fil.js │ │ │ │ ├── angular-locale_fo-fo.js │ │ │ │ ├── angular-locale_fo.js │ │ │ │ ├── angular-locale_fr-be.js │ │ │ │ ├── angular-locale_fr-bf.js │ │ │ │ ├── angular-locale_fr-bi.js │ │ │ │ ├── angular-locale_fr-bj.js │ │ │ │ ├── angular-locale_fr-bl.js │ │ │ │ ├── angular-locale_fr-ca.js │ │ │ │ ├── angular-locale_fr-cd.js │ │ │ │ ├── angular-locale_fr-cf.js │ │ │ │ ├── angular-locale_fr-cg.js │ │ │ │ ├── angular-locale_fr-ch.js │ │ │ │ ├── angular-locale_fr-ci.js │ │ │ │ ├── angular-locale_fr-cm.js │ │ │ │ ├── angular-locale_fr-dj.js │ │ │ │ ├── angular-locale_fr-dz.js │ │ │ │ ├── angular-locale_fr-fr.js │ │ │ │ ├── angular-locale_fr-ga.js │ │ │ │ ├── angular-locale_fr-gf.js │ │ │ │ ├── angular-locale_fr-gn.js │ │ │ │ ├── angular-locale_fr-gp.js │ │ │ │ ├── angular-locale_fr-gq.js │ │ │ │ ├── angular-locale_fr-ht.js │ │ │ │ ├── angular-locale_fr-km.js │ │ │ │ ├── angular-locale_fr-lu.js │ │ │ │ ├── angular-locale_fr-ma.js │ │ │ │ ├── angular-locale_fr-mc.js │ │ │ │ ├── angular-locale_fr-mf.js │ │ │ │ ├── angular-locale_fr-mg.js │ │ │ │ ├── angular-locale_fr-ml.js │ │ │ │ ├── angular-locale_fr-mq.js │ │ │ │ ├── angular-locale_fr-mr.js │ │ │ │ ├── angular-locale_fr-mu.js │ │ │ │ ├── angular-locale_fr-nc.js │ │ │ │ ├── angular-locale_fr-ne.js │ │ │ │ ├── angular-locale_fr-pf.js │ │ │ │ ├── angular-locale_fr-pm.js │ │ │ │ ├── angular-locale_fr-re.js │ │ │ │ ├── angular-locale_fr-rw.js │ │ │ │ ├── angular-locale_fr-sc.js │ │ │ │ ├── angular-locale_fr-sn.js │ │ │ │ ├── angular-locale_fr-sy.js │ │ │ │ ├── angular-locale_fr-td.js │ │ │ │ ├── angular-locale_fr-tg.js │ │ │ │ ├── angular-locale_fr-tn.js │ │ │ │ ├── angular-locale_fr-vu.js │ │ │ │ ├── angular-locale_fr-wf.js │ │ │ │ ├── angular-locale_fr-yt.js │ │ │ │ ├── angular-locale_fr.js │ │ │ │ ├── angular-locale_fur-it.js │ │ │ │ ├── angular-locale_fur.js │ │ │ │ ├── angular-locale_fy-nl.js │ │ │ │ ├── angular-locale_fy.js │ │ │ │ ├── angular-locale_ga-ie.js │ │ │ │ ├── angular-locale_ga.js │ │ │ │ ├── angular-locale_gd-gb.js │ │ │ │ ├── angular-locale_gd.js │ │ │ │ ├── angular-locale_gl-es.js │ │ │ │ ├── angular-locale_gl.js │ │ │ │ ├── angular-locale_gsw-ch.js │ │ │ │ ├── angular-locale_gsw-fr.js │ │ │ │ ├── angular-locale_gsw-li.js │ │ │ │ ├── angular-locale_gsw.js │ │ │ │ ├── angular-locale_gu-in.js │ │ │ │ ├── angular-locale_gu.js │ │ │ │ ├── angular-locale_guz-ke.js │ │ │ │ ├── angular-locale_guz.js │ │ │ │ ├── angular-locale_gv-im.js │ │ │ │ ├── angular-locale_gv.js │ │ │ │ ├── angular-locale_ha-latn-gh.js │ │ │ │ ├── angular-locale_ha-latn-ne.js │ │ │ │ ├── angular-locale_ha-latn-ng.js │ │ │ │ ├── angular-locale_ha-latn.js │ │ │ │ ├── angular-locale_ha.js │ │ │ │ ├── angular-locale_haw-us.js │ │ │ │ ├── angular-locale_haw.js │ │ │ │ ├── angular-locale_he-il.js │ │ │ │ ├── angular-locale_he.js │ │ │ │ ├── angular-locale_hi-in.js │ │ │ │ ├── angular-locale_hi.js │ │ │ │ ├── angular-locale_hr-ba.js │ │ │ │ ├── angular-locale_hr-hr.js │ │ │ │ ├── angular-locale_hr.js │ │ │ │ ├── angular-locale_hsb-de.js │ │ │ │ ├── angular-locale_hsb.js │ │ │ │ ├── angular-locale_hu-hu.js │ │ │ │ ├── angular-locale_hu.js │ │ │ │ ├── angular-locale_hy-am.js │ │ │ │ ├── angular-locale_hy.js │ │ │ │ ├── angular-locale_ia-fr.js │ │ │ │ ├── angular-locale_ia.js │ │ │ │ ├── angular-locale_id-id.js │ │ │ │ ├── angular-locale_id.js │ │ │ │ ├── angular-locale_ig-ng.js │ │ │ │ ├── angular-locale_ig.js │ │ │ │ ├── angular-locale_ii-cn.js │ │ │ │ ├── angular-locale_ii.js │ │ │ │ ├── angular-locale_in.js │ │ │ │ ├── angular-locale_is-is.js │ │ │ │ ├── angular-locale_is.js │ │ │ │ ├── angular-locale_it-ch.js │ │ │ │ ├── angular-locale_it-it.js │ │ │ │ ├── angular-locale_it-sm.js │ │ │ │ ├── angular-locale_it.js │ │ │ │ ├── angular-locale_iw.js │ │ │ │ ├── angular-locale_ja-jp.js │ │ │ │ ├── angular-locale_ja.js │ │ │ │ ├── angular-locale_jgo-cm.js │ │ │ │ ├── angular-locale_jgo.js │ │ │ │ ├── angular-locale_jmc-tz.js │ │ │ │ ├── angular-locale_jmc.js │ │ │ │ ├── angular-locale_ka-ge.js │ │ │ │ ├── angular-locale_ka.js │ │ │ │ ├── angular-locale_kab-dz.js │ │ │ │ ├── angular-locale_kab.js │ │ │ │ ├── angular-locale_kam-ke.js │ │ │ │ ├── angular-locale_kam.js │ │ │ │ ├── angular-locale_kde-tz.js │ │ │ │ ├── angular-locale_kde.js │ │ │ │ ├── angular-locale_kea-cv.js │ │ │ │ ├── angular-locale_kea.js │ │ │ │ ├── angular-locale_khq-ml.js │ │ │ │ ├── angular-locale_khq.js │ │ │ │ ├── angular-locale_ki-ke.js │ │ │ │ ├── angular-locale_ki.js │ │ │ │ ├── angular-locale_kk-cyrl-kz.js │ │ │ │ ├── angular-locale_kk-cyrl.js │ │ │ │ ├── angular-locale_kk.js │ │ │ │ ├── angular-locale_kkj-cm.js │ │ │ │ ├── angular-locale_kkj.js │ │ │ │ ├── angular-locale_kl-gl.js │ │ │ │ ├── angular-locale_kl.js │ │ │ │ ├── angular-locale_kln-ke.js │ │ │ │ ├── angular-locale_kln.js │ │ │ │ ├── angular-locale_km-kh.js │ │ │ │ ├── angular-locale_km.js │ │ │ │ ├── angular-locale_kn-in.js │ │ │ │ ├── angular-locale_kn.js │ │ │ │ ├── angular-locale_ko-kp.js │ │ │ │ ├── angular-locale_ko-kr.js │ │ │ │ ├── angular-locale_ko.js │ │ │ │ ├── angular-locale_kok-in.js │ │ │ │ ├── angular-locale_kok.js │ │ │ │ ├── angular-locale_ks-arab-in.js │ │ │ │ ├── angular-locale_ks-arab.js │ │ │ │ ├── angular-locale_ks.js │ │ │ │ ├── angular-locale_ksb-tz.js │ │ │ │ ├── angular-locale_ksb.js │ │ │ │ ├── angular-locale_ksf-cm.js │ │ │ │ ├── angular-locale_ksf.js │ │ │ │ ├── angular-locale_ksh-de.js │ │ │ │ ├── angular-locale_ksh.js │ │ │ │ ├── angular-locale_kw-gb.js │ │ │ │ ├── angular-locale_kw.js │ │ │ │ ├── angular-locale_ky-cyrl-kg.js │ │ │ │ ├── angular-locale_ky-cyrl.js │ │ │ │ ├── angular-locale_ky.js │ │ │ │ ├── angular-locale_lag-tz.js │ │ │ │ ├── angular-locale_lag.js │ │ │ │ ├── angular-locale_lb-lu.js │ │ │ │ ├── angular-locale_lb.js │ │ │ │ ├── angular-locale_lg-ug.js │ │ │ │ ├── angular-locale_lg.js │ │ │ │ ├── angular-locale_lkt-us.js │ │ │ │ ├── angular-locale_lkt.js │ │ │ │ ├── angular-locale_ln-ao.js │ │ │ │ ├── angular-locale_ln-cd.js │ │ │ │ ├── angular-locale_ln-cf.js │ │ │ │ ├── angular-locale_ln-cg.js │ │ │ │ ├── angular-locale_ln.js │ │ │ │ ├── angular-locale_lo-la.js │ │ │ │ ├── angular-locale_lo.js │ │ │ │ ├── angular-locale_lt-lt.js │ │ │ │ ├── angular-locale_lt.js │ │ │ │ ├── angular-locale_lu-cd.js │ │ │ │ ├── angular-locale_lu.js │ │ │ │ ├── angular-locale_luo-ke.js │ │ │ │ ├── angular-locale_luo.js │ │ │ │ ├── angular-locale_luy-ke.js │ │ │ │ ├── angular-locale_luy.js │ │ │ │ ├── angular-locale_lv-lv.js │ │ │ │ ├── angular-locale_lv.js │ │ │ │ ├── angular-locale_mas-ke.js │ │ │ │ ├── angular-locale_mas-tz.js │ │ │ │ ├── angular-locale_mas.js │ │ │ │ ├── angular-locale_mer-ke.js │ │ │ │ ├── angular-locale_mer.js │ │ │ │ ├── angular-locale_mfe-mu.js │ │ │ │ ├── angular-locale_mfe.js │ │ │ │ ├── angular-locale_mg-mg.js │ │ │ │ ├── angular-locale_mg.js │ │ │ │ ├── angular-locale_mgh-mz.js │ │ │ │ ├── angular-locale_mgh.js │ │ │ │ ├── angular-locale_mgo-cm.js │ │ │ │ ├── angular-locale_mgo.js │ │ │ │ ├── angular-locale_mk-mk.js │ │ │ │ ├── angular-locale_mk.js │ │ │ │ ├── angular-locale_ml-in.js │ │ │ │ ├── angular-locale_ml.js │ │ │ │ ├── angular-locale_mn-cyrl-mn.js │ │ │ │ ├── angular-locale_mn-cyrl.js │ │ │ │ ├── angular-locale_mn.js │ │ │ │ ├── angular-locale_mr-in.js │ │ │ │ ├── angular-locale_mr.js │ │ │ │ ├── angular-locale_ms-latn-bn.js │ │ │ │ ├── angular-locale_ms-latn-my.js │ │ │ │ ├── angular-locale_ms-latn-sg.js │ │ │ │ ├── angular-locale_ms-latn.js │ │ │ │ ├── angular-locale_ms.js │ │ │ │ ├── angular-locale_mt-mt.js │ │ │ │ ├── angular-locale_mt.js │ │ │ │ ├── angular-locale_mua-cm.js │ │ │ │ ├── angular-locale_mua.js │ │ │ │ ├── angular-locale_my-mm.js │ │ │ │ ├── angular-locale_my.js │ │ │ │ ├── angular-locale_naq-na.js │ │ │ │ ├── angular-locale_naq.js │ │ │ │ ├── angular-locale_nb-no.js │ │ │ │ ├── angular-locale_nb-sj.js │ │ │ │ ├── angular-locale_nb.js │ │ │ │ ├── angular-locale_nd-zw.js │ │ │ │ ├── angular-locale_nd.js │ │ │ │ ├── angular-locale_ne-in.js │ │ │ │ ├── angular-locale_ne-np.js │ │ │ │ ├── angular-locale_ne.js │ │ │ │ ├── angular-locale_nl-aw.js │ │ │ │ ├── angular-locale_nl-be.js │ │ │ │ ├── angular-locale_nl-bq.js │ │ │ │ ├── angular-locale_nl-cw.js │ │ │ │ ├── angular-locale_nl-nl.js │ │ │ │ ├── angular-locale_nl-sr.js │ │ │ │ ├── angular-locale_nl-sx.js │ │ │ │ ├── angular-locale_nl.js │ │ │ │ ├── angular-locale_nmg-cm.js │ │ │ │ ├── angular-locale_nmg.js │ │ │ │ ├── angular-locale_nn-no.js │ │ │ │ ├── angular-locale_nn.js │ │ │ │ ├── angular-locale_nnh-cm.js │ │ │ │ ├── angular-locale_nnh.js │ │ │ │ ├── angular-locale_no-no.js │ │ │ │ ├── angular-locale_no.js │ │ │ │ ├── angular-locale_nr-za.js │ │ │ │ ├── angular-locale_nr.js │ │ │ │ ├── angular-locale_nso-za.js │ │ │ │ ├── angular-locale_nso.js │ │ │ │ ├── angular-locale_nus-sd.js │ │ │ │ ├── angular-locale_nus.js │ │ │ │ ├── angular-locale_nyn-ug.js │ │ │ │ ├── angular-locale_nyn.js │ │ │ │ ├── angular-locale_om-et.js │ │ │ │ ├── angular-locale_om-ke.js │ │ │ │ ├── angular-locale_om.js │ │ │ │ ├── angular-locale_or-in.js │ │ │ │ ├── angular-locale_or.js │ │ │ │ ├── angular-locale_os-ge.js │ │ │ │ ├── angular-locale_os-ru.js │ │ │ │ ├── angular-locale_os.js │ │ │ │ ├── angular-locale_pa-arab-pk.js │ │ │ │ ├── angular-locale_pa-arab.js │ │ │ │ ├── angular-locale_pa-guru-in.js │ │ │ │ ├── angular-locale_pa-guru.js │ │ │ │ ├── angular-locale_pa.js │ │ │ │ ├── angular-locale_pl-pl.js │ │ │ │ ├── angular-locale_pl.js │ │ │ │ ├── angular-locale_ps-af.js │ │ │ │ ├── angular-locale_ps.js │ │ │ │ ├── angular-locale_pt-ao.js │ │ │ │ ├── angular-locale_pt-br.js │ │ │ │ ├── angular-locale_pt-cv.js │ │ │ │ ├── angular-locale_pt-gw.js │ │ │ │ ├── angular-locale_pt-mo.js │ │ │ │ ├── angular-locale_pt-mz.js │ │ │ │ ├── angular-locale_pt-pt.js │ │ │ │ ├── angular-locale_pt-st.js │ │ │ │ ├── angular-locale_pt-tl.js │ │ │ │ ├── angular-locale_pt.js │ │ │ │ ├── angular-locale_qu-bo.js │ │ │ │ ├── angular-locale_qu-ec.js │ │ │ │ ├── angular-locale_qu-pe.js │ │ │ │ ├── angular-locale_qu.js │ │ │ │ ├── angular-locale_rm-ch.js │ │ │ │ ├── angular-locale_rm.js │ │ │ │ ├── angular-locale_rn-bi.js │ │ │ │ ├── angular-locale_rn.js │ │ │ │ ├── angular-locale_ro-md.js │ │ │ │ ├── angular-locale_ro-ro.js │ │ │ │ ├── angular-locale_ro.js │ │ │ │ ├── angular-locale_rof-tz.js │ │ │ │ ├── angular-locale_rof.js │ │ │ │ ├── angular-locale_ru-by.js │ │ │ │ ├── angular-locale_ru-kg.js │ │ │ │ ├── angular-locale_ru-kz.js │ │ │ │ ├── angular-locale_ru-md.js │ │ │ │ ├── angular-locale_ru-ru.js │ │ │ │ ├── angular-locale_ru-ua.js │ │ │ │ ├── angular-locale_ru.js │ │ │ │ ├── angular-locale_rw-rw.js │ │ │ │ ├── angular-locale_rw.js │ │ │ │ ├── angular-locale_rwk-tz.js │ │ │ │ ├── angular-locale_rwk.js │ │ │ │ ├── angular-locale_sah-ru.js │ │ │ │ ├── angular-locale_sah.js │ │ │ │ ├── angular-locale_saq-ke.js │ │ │ │ ├── angular-locale_saq.js │ │ │ │ ├── angular-locale_sbp-tz.js │ │ │ │ ├── angular-locale_sbp.js │ │ │ │ ├── angular-locale_se-fi.js │ │ │ │ ├── angular-locale_se-no.js │ │ │ │ ├── angular-locale_se-se.js │ │ │ │ ├── angular-locale_se.js │ │ │ │ ├── angular-locale_seh-mz.js │ │ │ │ ├── angular-locale_seh.js │ │ │ │ ├── angular-locale_ses-ml.js │ │ │ │ ├── angular-locale_ses.js │ │ │ │ ├── angular-locale_sg-cf.js │ │ │ │ ├── angular-locale_sg.js │ │ │ │ ├── angular-locale_shi-latn-ma.js │ │ │ │ ├── angular-locale_shi-latn.js │ │ │ │ ├── angular-locale_shi-tfng-ma.js │ │ │ │ ├── angular-locale_shi-tfng.js │ │ │ │ ├── angular-locale_shi.js │ │ │ │ ├── angular-locale_si-lk.js │ │ │ │ ├── angular-locale_si.js │ │ │ │ ├── angular-locale_sk-sk.js │ │ │ │ ├── angular-locale_sk.js │ │ │ │ ├── angular-locale_sl-si.js │ │ │ │ ├── angular-locale_sl.js │ │ │ │ ├── angular-locale_smn-fi.js │ │ │ │ ├── angular-locale_smn.js │ │ │ │ ├── angular-locale_sn-zw.js │ │ │ │ ├── angular-locale_sn.js │ │ │ │ ├── angular-locale_so-dj.js │ │ │ │ ├── angular-locale_so-et.js │ │ │ │ ├── angular-locale_so-ke.js │ │ │ │ ├── angular-locale_so-so.js │ │ │ │ ├── angular-locale_so.js │ │ │ │ ├── angular-locale_sq-al.js │ │ │ │ ├── angular-locale_sq-mk.js │ │ │ │ ├── angular-locale_sq-xk.js │ │ │ │ ├── angular-locale_sq.js │ │ │ │ ├── angular-locale_sr-cyrl-ba.js │ │ │ │ ├── angular-locale_sr-cyrl-me.js │ │ │ │ ├── angular-locale_sr-cyrl-rs.js │ │ │ │ ├── angular-locale_sr-cyrl-xk.js │ │ │ │ ├── angular-locale_sr-cyrl.js │ │ │ │ ├── angular-locale_sr-latn-ba.js │ │ │ │ ├── angular-locale_sr-latn-me.js │ │ │ │ ├── angular-locale_sr-latn-rs.js │ │ │ │ ├── angular-locale_sr-latn-xk.js │ │ │ │ ├── angular-locale_sr-latn.js │ │ │ │ ├── angular-locale_sr.js │ │ │ │ ├── angular-locale_ss-sz.js │ │ │ │ ├── angular-locale_ss-za.js │ │ │ │ ├── angular-locale_ss.js │ │ │ │ ├── angular-locale_ssy-er.js │ │ │ │ ├── angular-locale_ssy.js │ │ │ │ ├── angular-locale_st-ls.js │ │ │ │ ├── angular-locale_st-za.js │ │ │ │ ├── angular-locale_st.js │ │ │ │ ├── angular-locale_sv-ax.js │ │ │ │ ├── angular-locale_sv-fi.js │ │ │ │ ├── angular-locale_sv-se.js │ │ │ │ ├── angular-locale_sv.js │ │ │ │ ├── angular-locale_sw-cd.js │ │ │ │ ├── angular-locale_sw-ke.js │ │ │ │ ├── angular-locale_sw-tz.js │ │ │ │ ├── angular-locale_sw-ug.js │ │ │ │ ├── angular-locale_sw.js │ │ │ │ ├── angular-locale_swc-cd.js │ │ │ │ ├── angular-locale_swc.js │ │ │ │ ├── angular-locale_ta-in.js │ │ │ │ ├── angular-locale_ta-lk.js │ │ │ │ ├── angular-locale_ta-my.js │ │ │ │ ├── angular-locale_ta-sg.js │ │ │ │ ├── angular-locale_ta.js │ │ │ │ ├── angular-locale_te-in.js │ │ │ │ ├── angular-locale_te.js │ │ │ │ ├── angular-locale_teo-ke.js │ │ │ │ ├── angular-locale_teo-ug.js │ │ │ │ ├── angular-locale_teo.js │ │ │ │ ├── angular-locale_tg-cyrl-tj.js │ │ │ │ ├── angular-locale_tg-cyrl.js │ │ │ │ ├── angular-locale_tg.js │ │ │ │ ├── angular-locale_th-th.js │ │ │ │ ├── angular-locale_th.js │ │ │ │ ├── angular-locale_ti-er.js │ │ │ │ ├── angular-locale_ti-et.js │ │ │ │ ├── angular-locale_ti.js │ │ │ │ ├── angular-locale_tig-er.js │ │ │ │ ├── angular-locale_tig.js │ │ │ │ ├── angular-locale_tl.js │ │ │ │ ├── angular-locale_tn-bw.js │ │ │ │ ├── angular-locale_tn-za.js │ │ │ │ ├── angular-locale_tn.js │ │ │ │ ├── angular-locale_to-to.js │ │ │ │ ├── angular-locale_to.js │ │ │ │ ├── angular-locale_tr-cy.js │ │ │ │ ├── angular-locale_tr-tr.js │ │ │ │ ├── angular-locale_tr.js │ │ │ │ ├── angular-locale_ts-za.js │ │ │ │ ├── angular-locale_ts.js │ │ │ │ ├── angular-locale_twq-ne.js │ │ │ │ ├── angular-locale_twq.js │ │ │ │ ├── angular-locale_tzm-latn-ma.js │ │ │ │ ├── angular-locale_tzm-latn.js │ │ │ │ ├── angular-locale_tzm.js │ │ │ │ ├── angular-locale_ug-arab-cn.js │ │ │ │ ├── angular-locale_ug-arab.js │ │ │ │ ├── angular-locale_ug.js │ │ │ │ ├── angular-locale_uk-ua.js │ │ │ │ ├── angular-locale_uk.js │ │ │ │ ├── angular-locale_ur-in.js │ │ │ │ ├── angular-locale_ur-pk.js │ │ │ │ ├── angular-locale_ur.js │ │ │ │ ├── angular-locale_uz-arab-af.js │ │ │ │ ├── angular-locale_uz-arab.js │ │ │ │ ├── angular-locale_uz-cyrl-uz.js │ │ │ │ ├── angular-locale_uz-cyrl.js │ │ │ │ ├── angular-locale_uz-latn-uz.js │ │ │ │ ├── angular-locale_uz-latn.js │ │ │ │ ├── angular-locale_uz.js │ │ │ │ ├── angular-locale_vai-latn-lr.js │ │ │ │ ├── angular-locale_vai-latn.js │ │ │ │ ├── angular-locale_vai-vaii-lr.js │ │ │ │ ├── angular-locale_vai-vaii.js │ │ │ │ ├── angular-locale_vai.js │ │ │ │ ├── angular-locale_ve-za.js │ │ │ │ ├── angular-locale_ve.js │ │ │ │ ├── angular-locale_vi-vn.js │ │ │ │ ├── angular-locale_vi.js │ │ │ │ ├── angular-locale_vo-001.js │ │ │ │ ├── angular-locale_vo.js │ │ │ │ ├── angular-locale_vun-tz.js │ │ │ │ ├── angular-locale_vun.js │ │ │ │ ├── angular-locale_wae-ch.js │ │ │ │ ├── angular-locale_wae.js │ │ │ │ ├── angular-locale_wal-et.js │ │ │ │ ├── angular-locale_wal.js │ │ │ │ ├── angular-locale_xh-za.js │ │ │ │ ├── angular-locale_xh.js │ │ │ │ ├── angular-locale_xog-ug.js │ │ │ │ ├── angular-locale_xog.js │ │ │ │ ├── angular-locale_yav-cm.js │ │ │ │ ├── angular-locale_yav.js │ │ │ │ ├── angular-locale_yi-001.js │ │ │ │ ├── angular-locale_yi.js │ │ │ │ ├── angular-locale_yo-bj.js │ │ │ │ ├── angular-locale_yo-ng.js │ │ │ │ ├── angular-locale_yo.js │ │ │ │ ├── angular-locale_zgh-ma.js │ │ │ │ ├── angular-locale_zgh.js │ │ │ │ ├── angular-locale_zh-cn.js │ │ │ │ ├── angular-locale_zh-hans-cn.js │ │ │ │ ├── angular-locale_zh-hans-hk.js │ │ │ │ ├── angular-locale_zh-hans-mo.js │ │ │ │ ├── angular-locale_zh-hans-sg.js │ │ │ │ ├── angular-locale_zh-hans.js │ │ │ │ ├── angular-locale_zh-hant-hk.js │ │ │ │ ├── angular-locale_zh-hant-mo.js │ │ │ │ ├── angular-locale_zh-hant-tw.js │ │ │ │ ├── angular-locale_zh-hant.js │ │ │ │ ├── angular-locale_zh-hk.js │ │ │ │ ├── angular-locale_zh-tw.js │ │ │ │ ├── angular-locale_zh.js │ │ │ │ ├── angular-locale_zu-za.js │ │ │ │ └── angular-locale_zu.js │ │ │ ├── jquery-1.10.2.intellisense.js │ │ │ ├── jquery-1.10.2.js │ │ │ ├── jquery.validate-vsdoc.js │ │ │ ├── jquery.validate.js │ │ │ ├── jquery.validate.unobtrusive.js │ │ │ ├── modernizr-2.6.2.js │ │ │ ├── respond.js │ │ │ ├── typings/ │ │ │ │ ├── angularjs/ │ │ │ │ │ ├── angular-animate.d.ts │ │ │ │ │ ├── angular-component-router.d.ts │ │ │ │ │ ├── angular-cookies.d.ts │ │ │ │ │ ├── angular-mocks.d.ts │ │ │ │ │ ├── angular-resource.d.ts │ │ │ │ │ ├── angular-route.d.ts │ │ │ │ │ ├── angular-sanitize.d.ts │ │ │ │ │ └── angular.d.ts │ │ │ │ ├── es6-promise/ │ │ │ │ │ └── es6-promise.d.ts │ │ │ │ └── jquery/ │ │ │ │ └── jquery.d.ts │ │ │ └── version.json │ │ ├── Startup.cs │ │ ├── Views/ │ │ │ ├── Home/ │ │ │ │ ├── Angular.cshtml │ │ │ │ ├── Index.cshtml │ │ │ │ └── JQuery.cshtml │ │ │ ├── Shared/ │ │ │ │ └── _Layout.cshtml │ │ │ ├── Web.config │ │ │ └── _ViewStart.cshtml │ │ ├── Web.Debug.config │ │ ├── Web.Release.config │ │ ├── Web.config │ │ └── packages.config │ ├── Reinforced.Typings.Samples.sln │ └── Simple/ │ └── Reinforced.Typings.Samples.Simple.Quickstart/ │ ├── App_Start/ │ │ └── RouteConfig.cs │ ├── Controllers/ │ │ └── HomeController.cs │ ├── Global.asax │ ├── Global.asax.cs │ ├── Models/ │ │ └── OrderViewModel.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── Reinforced.Typings.Samples.Simple.Quickstart.csproj │ ├── Reinforced.Typings.settings.xml │ ├── Scripts/ │ │ ├── MyApplication/ │ │ │ └── .gitignore │ │ ├── app/ │ │ │ ├── HomeIndex.js │ │ │ ├── HomeIndex.ts │ │ │ ├── Server.js │ │ │ └── Server.ts │ │ ├── jquery-2.1.4.intellisense.js │ │ ├── jquery-2.1.4.js │ │ └── typings/ │ │ └── jquery/ │ │ └── jquery.d.ts │ ├── Views/ │ │ ├── Home/ │ │ │ └── Index.cshtml │ │ ├── Shared/ │ │ │ └── _Layout.cshtml │ │ ├── _ViewStart.cshtml │ │ └── web.config │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Web.config │ └── packages.config ├── TestFluentAssembly/ │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── TestFluentAssembly.Dev.csproj │ ├── TestFluentAssembly.NETCore.csproj │ ├── TestFluentAssembly.csproj │ └── TwoInterfaces.cs ├── cake/ │ ├── .config/ │ │ └── dotnet-tools.json │ ├── .gitignore │ └── build.cake └── stuff/ ├── Reinforced.Typings.Multi.targets ├── Reinforced.Typings.nuspec ├── Reinforced.Typings.settings.xml ├── Reinforced.Typings.targets ├── license.txt ├── readme.txt └── relnotes/ ├── 1.4.96.md ├── 1.4.97.md ├── 1.5.1.md ├── 1.5.2.md ├── 1.5.3.md ├── 1.5.4.md ├── 1.5.6.md ├── 1.5.7.md ├── 1.5.8.md ├── 1.5.9.md ├── 1.5.md ├── 1.6.0.md ├── 1.6.1.md ├── 1.6.2.md ├── 1.6.3.md ├── 1.6.4.md ├── 1.6.5.md ├── 1.6.6.md └── 1.6.7.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates *.nupkg package/lib/net45/ package/tools/ package/build/*.dll package/build/*.xml package/build/*.exe package/build/*.config # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ # Visual Studo 2015 cache/options directory .vs/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding addin-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # Windows Azure Build Output csx/ *.build.csdef # Windows Store app package directory AppPackages/ # Others *.[Cc]ache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ bower_components/ .idea Reinforced.snk # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file .vscode *.opt Playground/ # Reinforced Typings specific Reinforced.Typings.Private.sln Reinforced.Typings.pfx docplan.txt /package/build /package/buildMultiTargeting /package/lib /Reinforced.Typings/Reinforced.snk /Reinforced.Typings.Cli/Reinforced.snk /Reinforced.Typings.Integrate/Reinforced.snk \.idea/ /package ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2019 Reinforced Opensource Products Family and Pavel B. Novikov personally 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: README.md ================================================ What is that? ================= You develop frontend applications with TypeScript and .NET Backend? You need Reinforced.Typings. It converts .NET classes into TypeScript code. Suffering has ended - you don't need to write and maintain boring TypeScript glue code for your DTOs/ViewModels/APIs anymore - RT can generate it from C# app. Moreover, it integrates with MSBuild build process and (re)generates glue code every time you rebuild .NET backend. So you get immediately notified when backend's API/DTOs changed and frontend is broken. Check out [documentation](https://github.com/reinforced/Reinforced.Typings/wiki) to discover numbers of useful features (type substitutions, modules, code generators, fluent configuration, multi-file export, JSDOC). Reinforced.Typings is available on [NuGet](https://www.nuget.org/packages/Reinforced.Typings/). ================= ```sh PM> Install-Package Reinforced.Typings ``` **Find out detailed information in Reinforced.Typings [wiki](https://github.com/reinforced/Reinforced.Typings/wiki)** News ================= > Version **1.6.7** released - .NET 10 support. Do not search for 1.6.6 😊 Support policy ================= Please **do not** ask your questions in github issues anymore. Such format is not suitable for storing FAQ. If you have question - please go to StackOverflow and ask it there. Tag your question with [reinforced-typings](https://stackoverflow.com/questions/tagged/reinforced-typings) tag. I watch full list of questions and will answer ASAP. Make experience that you've got available for other users! GitHub issues are for confirmed bugs/feature requests now. If you've found bug - please write and PR test if you can. If you have feature idea - please describe it from fluent/attribute configuration point of view. Describe how'd you gonna to configure RT for desired result. Thanks in advance! Best to be used for ================= Exporting ViewModels -----------------
C#TypeScript
namespace MyApp
{
    using Reinforced.Typings.Attributes;

    [TsInterface]
    public class Order
    {
        public string ItemName { get; set; }
        public int Quantity { get; set; }
        public double Subtotal { get; set; }
        public bool IsPaid { get; set; }
        public string ClientName { get; set; }
        public string Address { get; set; }
    }
    
    [TsClass]
    public class User
    {
        public string FirstName { get; set; }
        public string Email { get; set; }
        public UserType Type { get; set; }
    }

    [TsEnum]
    public enum UserType { One, Two }
}

module MyApp {
	export interface IOrder
	{
		ItemName: string;
		Quantity: number;
		Subtotal: number;
		IsPaid: boolean;
		ClientName: string;
		Address: string;
	}
	export class User
	{
		public FirstName: string;
		public Email: string;
		public Type: MyApp.UserType;
	}
	export enum UserType { 
		One = 0, 
		Two = 1, 
	}
}	
	
...even complex ViewModels -------------
C#TypeScript
namespace MyApp
{
    using Reinforced.Typings.Attributes;

    [TsInterface]
    public class Page
    {
        public List Orders { get; set; }

        public Dictionary 
                        Cache { get; set; }

        public string[] Tags { get; set; }

        public IEnumerable 
                        Things { get; set; }
    }
}

module MyApp {
	export interface IPage
	{
		Orders: MyApp.IOrder[];
		Cache: { [key:number]: MyApp.IOrder };
		Tags: string[];
		Things: any[];
	}
}	
	
Temporary disabling TypeScript compilation in your project ------------- Now you will not stay powerless when generated typings fail your TypeScript build in project. See [RtBypassTypeScriptCompilation](https://github.com/reinforced/Reinforced.Typings/wiki/Reinforced.Typings.settings.xml#RtBypassTypeScriptCompilation) configuration parameter. Inheritance preservation -------------
C#TypeScript
namespace MyApp
{
    using Reinforced.Typings.Attributes;

    public interface INonExport
    {
        string Boom { get; }
    }

    [TsInterface]
    public class WithoutInterface
                : INonExport
    {
        public string Boom { get; set; }
    }

    [TsInterface]
    public interface IEntity
    {
        int Id { get; set; }
    }

    [TsInterface]
    public class User : IEntity
    {
        public int Id { get; set; }

        public string Login { get; set; }
    }
}

module MyApp {
	export interface IWithoutInterface
	{
		Boom: string;
	}
	export interface IEntity
	{
		Id: number;
	}
	export interface IUser extends MyApp.IEntity
	{
		Id: number;
		Login: string;
	}
}	
	
Use fluent configuration ------------- Details can be found [on the corresponding wiki page](https://github.com/reinforced/Reinforced.Typings/wiki/Fluent-configuration)
C#TypeScript
namespace MyApp
{
    using Reinforced.Typings.Fluent;
    using System.Web.Mvc;
    
    public class Configuration
    {
        public static void 
            Configure(ConfigurationBuilder builder)
        {
            builder
            	.ExportAsInterface()
                .OverrideNamespace("MyApp")
                .WithPublicProperties();
        }
    }
}

module MyApp {
	export interface ISelectListItem
	{
		Disabled: boolean;
		Group: any;
		Selected: boolean;
		Text: string;
		Value: string;
	}
}	
	
Reinforced.Typings.settings.xml: <RtConfigurationMethod>MyApp.Configuration.Configure</RtConfigurationMethod>
Generate any custom glue code ------------- Read more [here](https://github.com/reinforced/Reinforced.Typings/wiki#writing-custom-code-generators).
C#TypeScript
namespace MyApp
{
    using Reinforced.Typings.Fluent;
    using System.Web.Mvc;
    
    [TsClass(CodeGeneratorType = typeof(AngularControllerGenerator)]
    public class AngularController : Controller
    {
        [AngularMethod(typeof(SampleResponseModel))]
        public ActionResult Save(Order order)
        {
            return Json(new {
                Message = "Success",
                Success = true
            });
        }
    }
    
    public class AngularMethodAttribute 
            : TsFunctionAttribute
    {
        public AngularMethodAttribute(Type returnType)
        {
            StrongType = returnType;
            CodeGeneratorType = typeof 
             (AngularActionCallGenerator);
        }
    }
    
    public class AngularActionCallGenerator 
            : MethodCodeGenerator
    {
        // too long - see sample
    }
    
    public class AngularControllerGenerator 
            : ClassCodeGenerator
    {
        // too long - see sample
    }
    
    [TsInterface]
    public class SampleResponseModel
    {
        public string Message { get; set; }
        public bool Success { get; set; }    
    }
}

module MyApp {
	export interface ISampleResponseModel
	{
		Message: string;
		Success: boolean;
	}
    
	if (window['app']) {
        window['app'].factory('Api.AngularController', 
        ['$http', 
            ($http: angular.IHttpService) => new AngularController($http)]);
    }
    
	/** Result of AngularControllerGenerator activity */
	export class AngularController
	{
		constructor ($http: angular.IHttpService)
		{
			this.http = $http;
		}
		public Save(order: IOrder) : angular.IPromise<ISampleResponseModel>
		{
			var params = { 'order': order };
			return this.http.post('/Angular/Save', params)
			    .then((response) => { return response.data; });
		}
    }        
}	
	
================================================ FILE: Reinforced.Typings/AccessModifier.cs ================================================ namespace Reinforced.Typings { /// /// Represents member's access modifier /// public enum AccessModifier { /// /// private /// Private, /// /// protected /// Protected, /// /// public /// Public } } ================================================ FILE: Reinforced.Typings/Ast/Dependency/RtImport.cs ================================================ using System; using System.Collections.Generic; namespace Reinforced.Typings.Ast.Dependency { /// /// Import declaration /// public class RtImport : RtNode { private string _target; /// /// Targets list /// public string Target { get { return _target; } set { _target = value == null ? null : value.Trim(); CheckWildcardImport(); } } /// /// Gets flag whether RtImport is wildcard import /// public bool IsWildcard { get { return WildcardAlias != null; } } /// /// Gets wildcard alias of import /// public string WildcardAlias { get; private set; } private void CheckWildcardImport() { if (_target.StartsWith("*")) { var arr = _target.Split(new[] { " as " }, StringSplitOptions.RemoveEmptyEntries); if (arr.Length < 2) { WildcardAlias = null; } else { WildcardAlias = arr[1]; } } else { WildcardAlias = null; } } /// /// Import source /// public string From { get; set; } /// /// When true, "from" part will be replaced with "= require('From')" /// public bool IsRequire { get; set; } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { if (IsRequire) return string.Format("import {0} = require('{1}');", Target, From); return string.Format("import {0} from '{1}';", Target, From); } } } ================================================ FILE: Reinforced.Typings/Ast/Dependency/RtReference.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast.Dependency { /// /// AST node for TS reference exposed as comment /// public class RtReference : RtNode { /// /// File to reference /// public string Path { get; set; } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { return string.Format("///", Path); } } } ================================================ FILE: Reinforced.Typings/Ast/DocTag.cs ================================================ using System.Reflection; namespace Reinforced.Typings.Ast { /// /// Describes all possible JSDOC tags /// public enum DocTag { /// This member must be implemented (or overridden) by the inheritor. [JsdocTag("@abstract")] Abstract, /// Specify the access level of this member (private, public, or protected). [JsdocTag("@access")] Access, /// Treat a member as if it had a different name. [JsdocTag("@alias")] Alias, /// Indicate that a symbol inherits from, ands adds to, a parent symbol. [JsdocTag("@augments")] Augments, /// Identify the author of an item. [JsdocTag("@author")] Author, /// This object uses something from another object. [JsdocTag("@borrows")] Borrows, /// Document a callback function. [JsdocTag("@callback")] Callback, /// This function is intended to be called with the "new" keyword. [JsdocTag("@class")] Class, /// Use the following text to describe the entire class. [JsdocTag("@classdesc")] Classdesc, /// Document an object as a constant. [JsdocTag("@constant")] Constant, /// This function member will be the constructor for the previous class. [JsdocTag("@constructs")] Constructs, /// Document some copyright information. [JsdocTag("@copyright")] Copyright, /// Document the default value. [JsdocTag("@default")] Default, /// Document that this is no longer the preferred way. [JsdocTag("@deprecated")] Deprecated, /// Describe a symbol. [JsdocTag("@description")] Description, /// Document a collection of related properties. [JsdocTag("@enum")] Enum, /// Document an event. [JsdocTag("@event")] Event, /// Provide an example of how to use a documented item. [JsdocTag("@example")] Example, /// Identify the member that is exported by a JavaScript module. [JsdocTag("@exports")] Exports, /// Identifies an external class, namespace, or module. [JsdocTag("@external")] External, /// Describe a file. [JsdocTag("@file")] File, /// Describe the events this method may fire. [JsdocTag("@fires")] Fires, /// Describe a function or method. [JsdocTag("@function")] Function, /// Document a global object. [JsdocTag("@global")] Global, /// Omit a symbol from the documentation. [JsdocTag("@ignore")] Ignore, /// This symbol implements an interface. [JsdocTag("@implements")] Implements, /// Indicate that a symbol should inherit its parent's documentation. [JsdocTag("@inheritdoc")] Inheritdoc, /// Document an inner object. [JsdocTag("@inner")] Inner, /// Document an instance member. [JsdocTag("@instance")] Instance, /// This symbol is an interface that others can implement. [JsdocTag("@interface")] Interface, /// What kind of symbol is this? [JsdocTag("@kind")] Kind, /// Document properties on an object literal as if they belonged to a symbol with a given name. [JsdocTag("@lends")] Lends, /// Identify the license that applies to this code. [JsdocTag("@license")] License, /// List the events that a symbol listens for. [JsdocTag("@listens")] Listens, /// Document a member. [JsdocTag("@member")] Member, /// This symbol belongs to a parent symbol. [JsdocTag("@memberof")] Memberof, /// This object mixes in all the members from another object. [JsdocTag("@mixes")] Mixes, /// Document a mixin object. [JsdocTag("@mixin")] Mixin, /// Document a JavaScript module. [JsdocTag("@module")] Module, /// Document the name of an object. [JsdocTag("@name")] Name, /// Document a namespace object. [JsdocTag("@namespace")] Namespace, /// Indicate that a symbol overrides its parent. [JsdocTag("@override")] Override, /// Document the parameter to a function. [JsdocTag("@param")] Param, /// This symbol is meant to be private. [JsdocTag("@private")] Private, /// Document a property of an object. [JsdocTag("@property")] Property, /// This symbol is meant to be protected. [JsdocTag("@protected")] Protected, /// This symbol is meant to be public. [JsdocTag("@public")] Public, /// This symbol is meant to be read-only. [JsdocTag("@readonly")] Readonly, /// This file requires a JavaScript module. [JsdocTag("@requires")] Requires, /// Document the return value of a function. [JsdocTag("@returns")] Returns, /// Refer to some other documentation for more information. [JsdocTag("@see")] See, /// When was this feature added? [JsdocTag("@since")] Since, /// Document a static member. [JsdocTag("@static")] Static, /// A shorter version of the full description. [JsdocTag("@summary")] Summary, /// What does the 'this' keyword refer to here? [JsdocTag("@this")] This, /// Describe what errors could be thrown. [JsdocTag("@throws")] Throws, /// Document tasks to be completed. [JsdocTag("@todo")] Todo, /// Insert a link to an included tutorial file. [JsdocTag("@tutorial")] Tutorial, /// Document the type of an object. [JsdocTag("@type")] Type, /// Document a custom type. [JsdocTag("@typedef")] Typedef, /// Distinguish different objects with the same name. [JsdocTag("@variation")] Variation, /// /// Documents the version number of an item /// [JsdocTag("@version")] Version, } /// /// Extension methods for DocTag enum /// public static class DocTagExtensions { /// /// Converts DocTag value to corresponding JSDOC-friendly name /// /// Tag instance /// JSDOC-friendly name public static string Tagname(this DocTag tag) { var member = typeof (DocTag)._GetField(tag.ToString()); return member.GetCustomAttribute().RawTagName; } } } ================================================ FILE: Reinforced.Typings/Ast/IDecoratable.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// Node containing decorators /// public interface IDecoratable { /// /// Set of decorators applied to node /// List Decorators { get; } } } ================================================ FILE: Reinforced.Typings/Ast/IRtVisitor.cs ================================================ using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Ast { /// /// Base interface for visitor traversing simple TypeScript AST tree /// /// Node traverse result public interface IRtVisitor { T Visit(RtNode node); T Visit(RtField node); T Visit(RtInterface node); T Visit(RtFunction node); T Visit(RtArgument node); T Visit(RtClass node); T Visit(RtIdentifier node); T Visit(RtDelegateType node); T Visit(RtSimpleTypeName node); T Visit(RtRaw node); T Visit(RtJsdocNode node); T Visit(RtNamespace node); T Visit(RtEnumValue node); T Visit(RtEnum node); T Visit(RtDictionaryType node); T Visit(RtArrayType node); T Visit(RtConstructor node); T Visit(RtImport node); T Visit(RtDecorator node); T Visit(RtReference node); T Visit(RtTuple node); } /// /// Base interface for void visitor traversing simple TypeScript AST tree /// public interface IRtVisitor { void Visit(RtNode node); void Visit(RtField node); void Visit(RtInterface node); void Visit(RtFunction node); void Visit(RtArgument node); void Visit(RtClass node); void Visit(RtIdentifier node); void Visit(RtDelegateType node); void Visit(RtSimpleTypeName node); void Visit(RtRaw node); void Visit(RtJsdocNode node); void Visit(RtNamespace node); void Visit(RtEnumValue node); void Visit(RtEnum node); void Visit(RtDictionaryType node); void Visit(RtArrayType node); void Visit(RtConstructor node); void Visit(RtImport node); void Visit(RtDecorator node); void Visit(RtReference node); void Visit(RtTuple node); } } ================================================ FILE: Reinforced.Typings/Ast/ITypeMember.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// Abstraction for RtClass and RtInterface AST /// public interface ITypeMember { /// /// Denotes current class to be exported /// bool Export { get; set; } /// /// Denotes that current class must be default export of module /// bool DefaultExport { get; set; } /// /// JSDOC /// RtJsdocNode Documentation { get; set; } /// /// Class/interface members /// List Members { get; } /// /// class/interface name /// RtSimpleTypeName Name { get; set; } /// /// Implementing types names /// List Implementees { get; } /// /// Order of writing /// double Order { get; set; } } } ================================================ FILE: Reinforced.Typings/Ast/JsdocTagAttribute.cs ================================================ using System; namespace Reinforced.Typings.Ast { /// /// JSDOC tag attribute to convert enum name back to JSDOC tag /// internal class JsdocTagAttribute : Attribute { /// /// Raw tag name /// public string RawTagName { get; set; } /// /// Constructs new instance of JsdicTag attribute /// /// Raw tag name public JsdocTagAttribute(string rawTagName) { RawTagName = rawTagName; } } } ================================================ FILE: Reinforced.Typings/Ast/RtArgument.cs ================================================ using System.Collections.Generic; using System.Text; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// AST node for method parameter /// public class RtArgument : RtNode, IDecoratable { /// /// Constructs new RtArgument /// public RtArgument() { Decorators = new List(); } /// /// Parameter identifier /// public RtIdentifier Identifier { get; set; } /// /// Default value (raw typescript expression) /// public string DefaultValue { get; set; } /// /// Is this parameter represents variable method parameterss /// public bool IsVariableParameters { get; set; } /// /// Argument type /// public RtTypeName Type { get; set; } /// public override IEnumerable Children { get { foreach (var rtDecorator in Decorators) { yield return rtDecorator; } yield return Identifier; yield return Type; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { StringBuilder sb = new StringBuilder(); if (IsVariableParameters) sb.Append("..."); sb.AppendFormat("{0}: {1}", Identifier, Type); if (!string.IsNullOrEmpty(DefaultValue)) { sb.AppendFormat(" = {0}", DefaultValue); } return sb.ToString(); } /// public List Decorators { get; private set; } } } ================================================ FILE: Reinforced.Typings/Ast/RtClass.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// AST node for TypeScript class /// public class RtClass : RtCompilationUnit, ITypeMember, IDecoratable { /// public List Decorators { get; private set; } /// public RtJsdocNode Documentation { get; set; } /// public RtSimpleTypeName Name { get; set; } /// public List Implementees { get; private set; } /// /// Gets or sets type name that this class is being extened (inherit) from /// public RtTypeName Extendee { get; set; } /// public List Members { get; private set; } /// /// Gets or sets whether generated class will be abstract or not /// public bool Abstract { get; set; } /// /// Constructs new instance of AST node /// public RtClass() { Members = new List(); Implementees = new List(); Decorators = new List(); } /// public override IEnumerable Children { get { yield return Documentation; foreach (var rtDecorator in Decorators) { yield return rtDecorator; } yield return Name; foreach (var implementee in Implementees) { yield return implementee; } yield return Extendee; foreach (var rtMember in Members) { yield return rtMember; } } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } } } ================================================ FILE: Reinforced.Typings/Ast/RtCompilationUnit.cs ================================================ namespace Reinforced.Typings.Ast { /// /// Abstract AST node for class/interface/enum /// public abstract class RtCompilationUnit : RtNode { /// /// Denotes current class to be exported /// public bool Export { get; set; } /// /// Denotes that current class must be default export of module /// public bool DefaultExport { get; set; } /// /// Order of writing /// public double Order { get; set; } } } ================================================ FILE: Reinforced.Typings/Ast/RtConstructor.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// AST node for class constructor /// public class RtConstructor : RtMember { /// /// Constructor parameters /// public List Arguments { get; set; } /// /// Array of arguments to be substitute to super(...) call /// public List SuperCallParameters { get; private set; } /// /// When true, super(...) call will be generated. Otherwise will not /// public bool NeedsSuperCall { get; set; } /// /// Constructs new instance of AST node /// public RtConstructor() { Arguments = new List(); SuperCallParameters = new List(); } /// /// Implementation body (raw content) /// public RtRaw Body { get; set; } /// public override IEnumerable Children { get { foreach (var rtArgument in Arguments) { yield return rtArgument; } yield return Body; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } } } ================================================ FILE: Reinforced.Typings/Ast/RtDecorator.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// Syntax node for TS decorator /// public class RtDecorator : RtNode { /// /// Decorator name (everything that must follow after "@") /// public string Decorator { get; private set; } /// /// Order of appearence /// public double Order { get; set; } /// public override IEnumerable Children { get {yield break;} } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// /// Constructs new RtDecorator /// /// Decorator content /// Decorator order public RtDecorator(string decorator, double order = 0) { Decorator = decorator; Order = order; } } } ================================================ FILE: Reinforced.Typings/Ast/RtEnum.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// AST node for TypeScript enumeration /// public class RtEnum : RtCompilationUnit, IDecoratable { /// /// JSDOC /// public RtJsdocNode Documentation { get; set; } /// /// Enum name /// public RtSimpleTypeName EnumName { get; set; } /// /// Enum values /// public List Values { get; private set; } /// /// Constructs new instance of AST node /// public RtEnum() { Values = new List(); Decorators = new List(); } /// /// When true, results "const" enum instead of usual /// public bool IsConst { get; set; } /// public override IEnumerable Children { get { foreach (var rtNode in Decorators) { yield return rtNode; } if (Values != null) { foreach (var rtEnumValue in Values) { yield return rtEnumValue; } } } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public List Decorators { get; private set; } } } ================================================ FILE: Reinforced.Typings/Ast/RtEnumValue.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// AST node for TypeScript enumeration value /// public class RtEnumValue : RtNode { /// /// JSDOC /// public RtJsdocNode Documentation { get; set; } /// /// Value name /// public string EnumValueName { get; set; } /// /// Value value /// public string EnumValue { get; set; } /// /// Gets or sets line that will follow after member /// public string LineAfter { get; set; } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } } } ================================================ FILE: Reinforced.Typings/Ast/RtField.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// AST node for TypeScript field /// public class RtField : RtMember, IDecoratable { /// /// Field name /// public RtIdentifier Identifier { get; set; } /// /// Field type /// public RtTypeName Type { get; set; } /// /// TypeScript expression to initialize field /// public string InitializationExpression { get; set; } /// public override IEnumerable Children { get { yield return Documentation; foreach (var rtDecorator in Decorators) { yield return rtDecorator; } yield return Identifier; yield return Type; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// /// Constructs new RtField /// public RtField() { Decorators = new List(); } /// public List Decorators { get; private set; } } } ================================================ FILE: Reinforced.Typings/Ast/RtFunction.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// AST node for TypeScript member function /// public class RtFunction : RtMember, IDecoratable { /// /// Constructs new instance of AST node /// public RtFunction() { Arguments = new List(); Decorators = new List(); } /// /// Gets or sets whether function is async /// public bool IsAsync { get; set; } /// /// Function name /// public RtIdentifier Identifier { get; set; } /// /// Function return type /// public RtTypeName ReturnType { get; set; } /// /// Function parameters /// public List Arguments { get; private set; } /// public List Decorators { get; private set; } /// /// Function body (supplied as raw text) /// public RtRaw Body { get; set; } /// public override IEnumerable Children { get { foreach (var rtDecorator in Decorators) { yield return rtDecorator; } yield return Identifier; yield return ReturnType; foreach (var rtArgument in Arguments) { yield return rtArgument; } if (Body != null) yield return Body; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } } } ================================================ FILE: Reinforced.Typings/Ast/RtIdentifier.cs ================================================ using System; using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// AST node for identifier name /// public class RtIdentifier : RtNode { /// /// Constructs new instance of AST node /// public RtIdentifier() { } /// /// Constructs new instance of AST node /// /// identifier name public RtIdentifier(string identifierName) { IdentifierName = identifierName; } /// /// Identifier name /// public string IdentifierName { get; set; } /// /// Is current identifier nullable /// public bool IsNullable { get; set; } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { return IdentifierName + (IsNullable?"?":String.Empty); } } } ================================================ FILE: Reinforced.Typings/Ast/RtInterface.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Ast { /// /// AST node for typeScript interface /// public class RtInterface : RtCompilationUnit, ITypeMember { /// public RtSimpleTypeName Name { get; set; } /// public List Implementees { get; private set; } /// public RtJsdocNode Documentation { get; set; } /// public List Members { get; private set; } /// public override IEnumerable Children { get { yield return Documentation; yield return Name; foreach (var rtSimpleTypeName in Implementees) { yield return rtSimpleTypeName; } foreach (var rtMember in Members) { yield return rtMember; } } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// /// Constructs new instance of AST node /// public RtInterface() { Members = new List(); Implementees = new List(); } } } ================================================ FILE: Reinforced.Typings/Ast/RtJsdocNode.cs ================================================ using System; using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// AST node for JSDOC documentation /// public class RtJsdocNode : RtNode { /// /// Main documentation text /// public string Description { get; set; } /// /// Additional JSDOC documentation tags /// public List> TagToDescription { get; private set; } /// /// Constructs new instance of AST node /// public RtJsdocNode() { TagToDescription = new List>(); } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// /// Adds an additional JSDOC documentation tag. /// public void AddTag(DocTag tag, string value = null) => TagToDescription.Add(new Tuple(tag, value)); } } ================================================ FILE: Reinforced.Typings/Ast/RtMember.cs ================================================ namespace Reinforced.Typings.Ast { /// /// Abstract AST node for class/interface member /// public abstract class RtMember : RtNode { /// /// JSDOC /// public RtJsdocNode Documentation { get; set; } /// /// Access modifier /// public AccessModifier? AccessModifier { get; set; } /// /// Is member static /// public bool IsStatic { get; set; } /// /// Gets or sets line that will follow after member /// public string LineAfter { get; set; } /// /// Member order /// public double Order { get { return _order; } set { _order = value; } } } } ================================================ FILE: Reinforced.Typings/Ast/RtNamespace.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// AST node for TypeScript module /// public class RtNamespace : RtNode { /// /// Constructs new instance of AST node /// public RtNamespace() { CompilationUnits = new List(); Export = true; } /// /// Identifies nameless namespace that only wraps CompilationUnits without module name /// public bool IsAmbientNamespace { get; set; } /// /// Module name /// public string Name { get; set; } /// /// Denotes whether namespace must be exported or not /// public bool Export { get; set; } /// /// Denotes namespace generation mode /// public NamespaceGenerationMode GenerationMode { get; internal set; } /// /// Members of module - compilation units. Classes/enums/interfaces /// public List CompilationUnits { get; set; } /// public override IEnumerable Children { get { return CompilationUnits; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } } /// /// Switches mode for generating namespace. /// If UseModules set to true then namespace must be /// exported as Namespaces. /// If modules are not used then namespaces must represent modules /// public enum NamespaceGenerationMode { /// /// Export namespace as module /// Module, /// /// Export namespace as namespace /// Namespace } } ================================================ FILE: Reinforced.Typings/Ast/RtNode.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// Base Reinforced.Typings AST node /// public abstract class RtNode { /// /// Child nodes /// public abstract IEnumerable Children { get; } /// /// Visitor acceptance /// /// Visitor public abstract void Accept(IRtVisitor visitor); /// /// Typed visitor acceptance /// /// Visitor public abstract void Accept(IRtVisitor visitor); internal double _order; } } ================================================ FILE: Reinforced.Typings/Ast/RtRaw.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast { /// /// AST node exposing raw text to be output to resulting file /// public class RtRaw : RtNode { /// /// Constructs new instance of AST node /// public RtRaw() { } /// /// Constructs new instance of AST node /// /// Raw text to be output to resulting file public RtRaw(string rawContent) { RawContent = rawContent; } /// /// Raw text to be output to resulting file /// public string RawContent { get; set; } /// /// Order of RtRaw appearance /// public double Order { get { return _order; } set { _order = value; } } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtArrayType.cs ================================================ using System; using System.Collections.Generic; namespace Reinforced.Typings.Ast.TypeNames { /// /// AST node for array type /// public sealed class RtArrayType : RtTypeName { /// /// Array element type /// public RtTypeName ElementType { get; private set; } /// /// Constructs array type from existing type /// /// public RtArrayType(RtTypeName elementType) { ElementType = elementType; } /// public override IEnumerable Children { get { yield return ElementType; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { return String.Format("{0}[]",ElementType); } private bool Equals(RtArrayType other) { return Equals(ElementType, other.ElementType); } /// Determines whether the specified object is equal to the current object. /// The object to compare with the current object. /// /// if the specified object is equal to the current object; otherwise, . public override bool Equals(object obj) { return ReferenceEquals(this, obj) || obj is RtArrayType other && Equals(other); } /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode() { return (ElementType != null ? ElementType.GetHashCode() : 0); } /// Returns a value that indicates whether the values of two objects are equal. /// The first value to compare. /// The second value to compare. /// true if the and parameters have the same value; otherwise, false. public static bool operator ==(RtArrayType left, RtArrayType right) { return Equals(left, right); } /// Returns a value that indicates whether two objects have different values. /// The first value to compare. /// The second value to compare. /// true if and are not equal; otherwise, false. public static bool operator !=(RtArrayType left, RtArrayType right) { return !Equals(left, right); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtAsyncType.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Reinforced.Typings.Ast.TypeNames { /// /// AST node for async return types of type "Promise". /// /// With TypeScript, "Promise" use "generics" to define the resulting type of the "Promise". This is /// defined by a nested public sealed class RtAsyncType : RtTypeName { /// /// Constructs new instance of AST node /// public RtAsyncType(RtTypeName nestedType) : this() { TypeNameOfAsync = nestedType; } /// /// Type name /// public RtTypeName TypeNameOfAsync { get; private set; } /// /// Constructs new instance of AST node /// public RtAsyncType() { } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { return $"Promise<{TypeNameOfAsync?.ToString() ?? "void"}>"; } private bool Equals(RtAsyncType other) { return Equals(TypeNameOfAsync, other.TypeNameOfAsync); } /// Determines whether the specified object is equal to the current object. /// The object to compare with the current object. /// /// if the specified object is equal to the current object; otherwise, . public override bool Equals(object obj) { return ReferenceEquals(this, obj) || obj is RtAsyncType other && Equals(other); } /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode() { return (TypeNameOfAsync != null ? TypeNameOfAsync.GetHashCode() : 0); } /// Returns a value that indicates whether the values of two objects are equal. /// The first value to compare. /// The second value to compare. /// true if the and parameters have the same value; otherwise, false. public static bool operator ==(RtAsyncType left, RtAsyncType right) { return Equals(left, right); } /// Returns a value that indicates whether two objects have different values. /// The first value to compare. /// The second value to compare. /// true if and are not equal; otherwise, false. public static bool operator !=(RtAsyncType left, RtAsyncType right) { return !Equals(left, right); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtDelegateType.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Reinforced.Typings.Ast.TypeNames { /// /// AST node for delegate type /// public sealed class RtDelegateType : RtTypeName { private readonly RtArgument[] _arguments; /// /// Consumed arguments /// public RtArgument[] Arguments { get { return _arguments; } } /// /// Returning result /// public RtTypeName Result { get; private set; } /// /// Constructs new instance of AST node /// /// Delegate parameters /// Delegate result type public RtDelegateType(RtArgument[] arguments, RtTypeName result) { _arguments = arguments; Result = result; } /// public override IEnumerable Children { get { foreach (var rtArgument in Arguments) { yield return rtArgument; } yield return Result; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { return String.Format("({0}) => {1}", String.Join(", ", Arguments.AsEnumerable()), Result); } private bool Equals(RtDelegateType other) { return Equals(_arguments, other._arguments) && Equals(Result, other.Result); } /// Determines whether the specified object is equal to the current object. /// The object to compare with the current object. /// /// if the specified object is equal to the current object; otherwise, . public override bool Equals(object obj) { return ReferenceEquals(this, obj) || obj is RtDelegateType other && Equals(other); } /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode() { unchecked { return ((_arguments != null ? _arguments.GetHashCode() : 0) * 397) ^ (Result != null ? Result.GetHashCode() : 0); } } /// Returns a value that indicates whether the values of two objects are equal. /// The first value to compare. /// The second value to compare. /// true if the and parameters have the same value; otherwise, false. public static bool operator ==(RtDelegateType left, RtDelegateType right) { return Equals(left, right); } /// Returns a value that indicates whether two objects have different values. /// The first value to compare. /// The second value to compare. /// true if and are not equal; otherwise, false. public static bool operator !=(RtDelegateType left, RtDelegateType right) { return !Equals(left, right); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtDictionaryType.cs ================================================ using System; using System.Collections.Generic; namespace Reinforced.Typings.Ast.TypeNames { /// /// AST node for Dictionary type /// public sealed class RtDictionaryType : RtTypeName { /// /// Constructs new instance of AST node /// public RtDictionaryType() { } /// /// Constructs new instance of AST node /// /// Type for dictionary key /// Type for disctionary value public RtDictionaryType(RtTypeName keySimpleType, RtTypeName valueSimpleType) : this(keySimpleType, valueSimpleType, false) { } /// /// Constructs new instance of AST node /// /// Type for dictionary key /// Type for disctionary value /// A flag specifying whether the key is an enum type. public RtDictionaryType(RtTypeName keySimpleType, RtTypeName valueSimpleType, bool isKeyEnum) { KeyType = keySimpleType; ValueType = valueSimpleType; IsKeyEnum = isKeyEnum; } /// /// Type for dictionary key /// public RtTypeName KeyType { get; } /// /// Type for disctionary value /// public RtTypeName ValueType { get; } /// /// A flag indicating whether the key is an enum type, and a mapped type should be generated. /// public bool IsKeyEnum { get; } /// public override IEnumerable Children { get { yield return KeyType; yield return ValueType; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { string keyTypeSpec = IsKeyEnum ? " in " : ":"; return $"{{ [key{keyTypeSpec}{KeyType}]: {ValueType} }}"; } private bool Equals(RtDictionaryType other) { return Equals(KeyType, other.KeyType) && Equals(ValueType, other.ValueType) && IsKeyEnum == other.IsKeyEnum; } /// Determines whether the specified object is equal to the current object. /// The object to compare with the current object. /// /// if the specified object is equal to the current object; otherwise, . public override bool Equals(object obj) { return ReferenceEquals(this, obj) || obj is RtDictionaryType other && Equals(other); } /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode() { unchecked { var hashCode = (KeyType != null ? KeyType.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (ValueType != null ? ValueType.GetHashCode() : 0); hashCode = (hashCode * 397) ^ IsKeyEnum.GetHashCode(); return hashCode; } } /// Returns a value that indicates whether the values of two objects are equal. /// The first value to compare. /// The second value to compare. /// true if the and parameters have the same value; otherwise, false. public static bool operator ==(RtDictionaryType left, RtDictionaryType right) { return Equals(left, right); } /// Returns a value that indicates whether two objects have different values. /// The first value to compare. /// The second value to compare. /// true if and are not equal; otherwise, false. public static bool operator !=(RtDictionaryType left, RtDictionaryType right) { return !Equals(left, right); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtSimpleTypeName.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Reinforced.Typings.Ast.TypeNames { /// /// AST node for simple type name /// public sealed class RtSimpleTypeName : RtTypeName { /// /// Constructs new instance of AST node /// public RtSimpleTypeName(RtTypeName[] genericArguments, string ns, string typeName) { _genericArguments = genericArguments; Prefix = ns; TypeName = typeName; } /// /// Constructs new instance of AST node /// public RtSimpleTypeName(string typeName) : this() { TypeName = typeName; } /// /// Constructs new instance of AST node /// public RtSimpleTypeName(string typeName, params RtTypeName[] genericArguments) { TypeName = typeName; if (genericArguments == null) genericArguments = new RtTypeName[0]; _genericArguments = genericArguments; } private readonly RtTypeName[] _genericArguments; /// /// Type name generic arguments /// public RtTypeName[] GenericArguments { get { return _genericArguments; } } /// /// Type namespace /// public string Prefix { get; set; } /// /// true if the is not empty. /// public bool HasPrefix => !string.IsNullOrEmpty(Prefix); /// /// Type name /// public string TypeName { get; private set; } /// /// Constructs new instance of AST node /// public RtSimpleTypeName() { _genericArguments = new RtTypeName[0]; } /// public override IEnumerable Children { get { yield break; } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { string generics = _genericArguments.Length > 0 ? "<" + String.Join(",", _genericArguments.AsEnumerable()) + ">" : null; var result = String.Concat(TypeName, generics); if (HasPrefix) { result = Prefix + "." + result; } return result; } private bool Equals(RtSimpleTypeName other) { return Prefix == other.Prefix && TypeName == other.TypeName; } /// Determines whether the specified object is equal to the current object. /// The object to compare with the current object. /// /// if the specified object is equal to the current object; otherwise, . public override bool Equals(object obj) { return ReferenceEquals(this, obj) || obj is RtSimpleTypeName other && Equals(other); } /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode() { unchecked { var hashCode = (_genericArguments != null ? _genericArguments.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (Prefix != null ? Prefix.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (TypeName != null ? TypeName.GetHashCode() : 0); return hashCode; } } /// Returns a value that indicates whether the values of two objects are equal. /// The first value to compare. /// The second value to compare. /// true if the and parameters have the same value; otherwise, false. public static bool operator ==(RtSimpleTypeName left, RtSimpleTypeName right) { return Equals(left, right); } /// Returns a value that indicates whether two objects have different values. /// The first value to compare. /// The second value to compare. /// true if and are not equal; otherwise, false. public static bool operator !=(RtSimpleTypeName left, RtSimpleTypeName right) { return !Equals(left, right); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtTuple.cs ================================================ using System.Collections.Generic; namespace Reinforced.Typings.Ast.TypeNames { /// /// AST node for TypeScript tuple type /// public class RtTuple : RtTypeName { /// /// Constructs new RtTuple /// public RtTuple() { TupleTypes = new List(); } /// /// Constructs new RtTuple with specified type paranmeters /// /// Types for tuple public RtTuple(IEnumerable tupleTypes) { TupleTypes = new List(tupleTypes); } /// /// Constructs new RtTuple with specified type paranmeters /// /// Types for tuple public RtTuple(params RtTypeName[] tupleTypes) { TupleTypes = new List(tupleTypes); } /// /// All types that must participate tuple /// public List TupleTypes { get; private set; } /// public override IEnumerable Children { get { foreach (var rtTypeName in TupleTypes) { yield return rtTypeName; } } } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override void Accept(IRtVisitor visitor) { visitor.Visit(this); } /// public override string ToString() { return $"[{string.Join(", ", TupleTypes)}]"; } protected bool Equals(RtTuple other) { return Equals(TupleTypes, other.TupleTypes); } /// Determines whether the specified object is equal to the current object. /// The object to compare with the current object. /// /// if the specified object is equal to the current object; otherwise, . public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((RtTuple) obj); } /// Serves as the default hash function. /// A hash code for the current object. public override int GetHashCode() { return (TupleTypes != null ? TupleTypes.GetHashCode() : 0); } /// Returns a value that indicates whether the values of two objects are equal. /// The first value to compare. /// The second value to compare. /// true if the and parameters have the same value; otherwise, false. public static bool operator ==(RtTuple left, RtTuple right) { return Equals(left, right); } /// Returns a value that indicates whether two objects have different values. /// The first value to compare. /// The second value to compare. /// true if and are not equal; otherwise, false. public static bool operator !=(RtTuple left, RtTuple right) { return !Equals(left, right); } } } ================================================ FILE: Reinforced.Typings/Ast/TypeNames/RtTypeName.cs ================================================ namespace Reinforced.Typings.Ast.TypeNames { /// /// Abstract AST node for type name /// public abstract class RtTypeName : RtNode { } } ================================================ FILE: Reinforced.Typings/Attributes/IAutoexportSwitchAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Interface containing base properties for some attributes /// public interface IAutoexportSwitchAttribute { /// /// When true, code for all methods will be automatically generated /// bool AutoExportMethods { get; set; } /// /// When true, code for all properties will be automatically generated /// bool AutoExportProperties { get; set; } /// /// When true, code for all fields will be automatically generated /// bool AutoExportFields { get; } /// /// Reference to code geenrator which will be applied to every method /// Type DefaultMethodCodeGenerator { get; } /// /// When true, code for all constructors will be automatically generated /// bool AutoExportConstructors { get; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsAddTypeImportAttribute.cs ================================================ using System; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.Attributes { /// /// This attribute is used to add import directive to file containing single TS class typing. /// It is only used while splitting generated type sto different files /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum, AllowMultiple = true)] public class TsAddTypeImportAttribute : Attribute { /// /// What we are importing from module. /// Everything that is placed after "import" keyword and before "from" or "= require(..)" /// Examples: /// - "import * as shape from './Shapes'" -> "* as shape" is target
/// - "import { Foo } from 'Bar'" -> "{ Foo }" is target
/// - "import { Bar2 as bar } from 'Baz'" -> "{ Bar2 as bar }" is target
/// If ImportTarget is null then side-effect import will be generated. ///
public string ImportTarget { get; set; } /// /// Import source is everything that follows after "from" keyword. /// Please note that you do not have to specify quotes here! Quotes will be added automatically /// public string ImportSource { get; set; } /// /// When true, import will be generated as "import ImportTarget = require('ImportSource')" /// public bool ImportRequire { get; set; } /// /// Cosntructs new Rtimport /// /// Target /// Source /// Is import "=require(...)" public TsAddTypeImportAttribute(string importTarget, string importSource, bool importRequire = false) { ImportTarget = importTarget; ImportSource = importSource; ImportRequire = importRequire; } private RtImport _import; internal RtImport ToImport() { if (_import == null) _import = new RtImport() { Target = ImportTarget, From = ImportSource, IsRequire = ImportRequire }; return _import; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsAddTypeReference.cs ================================================ using System; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.Attributes { /// /// This attribute is used to add reference directive to file containing single TS class typing. /// It is only used while splitting generated type sto different files /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum, AllowMultiple = true)] public class TsAddTypeReferenceAttribute : Attribute { /// /// Constructs new instance of TsAddTypeReferenceAttribute using referenced type /// /// Type reference public TsAddTypeReferenceAttribute(Type type) { Type = type; } /// /// Constructs new instance of TsAddTypeReferenceAttribute using referenced type /// /// Raw reference public TsAddTypeReferenceAttribute(string rawPath) { RawPath = rawPath; } /// /// Type that should be referenced /// public Type Type { get; set; } /// /// Raw reference path that will be added to target file /// public string RawPath { get; set; } private RtReference _reference; internal RtReference ToReference() { if (_reference == null) _reference = new RtReference() { Path = RawPath }; return _reference; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsAttributeBase.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Base for all attributes /// public abstract class TsAttributeBase : Attribute { /// /// Dummy function body generator /// If empty then it's being generated empty/return null body. /// public virtual Type CodeGeneratorType { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsBaseParamAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Denotes parameter name and constant value for constructor's :base call /// We need this attribute because it is programmatically impossible to determine :base call parameters /// via reflection. So in this case we need some help from user's side /// [AttributeUsage(AttributeTargets.Constructor)] public class TsBaseParamAttribute : Attribute { /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call public TsBaseParamAttribute(string value) { Values = new []{ value }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 public TsBaseParamAttribute(string firstValue, string secondValue) { Values = new[] { firstValue, secondValue }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 /// TypeScript expression to be supplied for super() call at position 3 public TsBaseParamAttribute(string firstValue, string secondValue, string thirdValue) { Values = new[] { firstValue, secondValue, thirdValue }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 /// TypeScript expression to be supplied for super() call at position 3 /// TypeScript expression to be supplied for super() call at position 4 public TsBaseParamAttribute(string firstValue, string secondValue, string thirdValue, string fourthValue) { Values = new[] { firstValue, secondValue, thirdValue, fourthValue }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 /// TypeScript expression to be supplied for super() call at position 3 /// TypeScript expression to be supplied for super() call at position 4 /// TypeScript expression to be supplied for super() call at position 5 public TsBaseParamAttribute(string firstValue, string secondValue, string thirdValue, string fourthValue, string fifthValue) { Values = new[] { firstValue, secondValue, thirdValue, fourthValue, fifthValue }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 /// TypeScript expression to be supplied for super() call at position 3 /// TypeScript expression to be supplied for super() call at position 4 /// TypeScript expression to be supplied for super() call at position 5 /// TypeScript expression to be supplied for super() call at position 6 public TsBaseParamAttribute(string firstValue, string secondValue, string thirdValue, string fourthValue, string fifthValue, string sixthValue) { Values = new[] { firstValue, secondValue, thirdValue, fourthValue, fifthValue, sixthValue }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 /// TypeScript expression to be supplied for super() call at position 3 /// TypeScript expression to be supplied for super() call at position 4 /// TypeScript expression to be supplied for super() call at position 5 /// TypeScript expression to be supplied for super() call at position 6 /// TypeScript expression to be supplied for super() call at position 7 public TsBaseParamAttribute(string firstValue, string secondValue, string thirdValue, string fourthValue, string fifthValue, string sixthValue, string seventhValue) { Values = new[] { firstValue, secondValue, thirdValue, fourthValue, fifthValue, sixthValue, seventhValue }; } /// /// Creates instance of TsBaseParamAttribute /// /// TypeScript expression to be supplied for super() call at position 1 /// TypeScript expression to be supplied for super() call at position 2 /// TypeScript expression to be supplied for super() call at position 3 /// TypeScript expression to be supplied for super() call at position 4 /// TypeScript expression to be supplied for super() call at position 5 /// TypeScript expression to be supplied for super() call at position 6 /// TypeScript expression to be supplied for super() call at position 7 /// TypeScript expression to be supplied for super() call at position 8 public TsBaseParamAttribute(string firstValue, string secondValue, string thirdValue, string fourthValue, string fifthValue, string sixthValue, string seventhValue, string eighthValue) { Values = new[] { firstValue, secondValue, thirdValue, fourthValue, fifthValue, sixthValue, seventhValue, eighthValue }; } /// /// Parameters for super() call /// Here should be stored TypeScript expressions /// public string[] Values { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsClassAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// This attribute will export member as typescript class definition /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class TsClassAttribute : TsDeclarationAttributeBase, IAutoexportSwitchAttribute { /// /// Constructs new instance of TsClassAttribute /// public TsClassAttribute() { // ReSharper disable VirtualMemberCallInConstructor AutoExportProperties = true; AutoExportMethods = true; IncludeNamespace = true; AutoExportConstructors = false; // ReSharper restore VirtualMemberCallInConstructor } /// /// Export all methods automatically or not. /// public virtual bool AutoExportMethods { get; set; } /// /// Export all properties automatically or not. /// public virtual bool AutoExportProperties { get; set; } /// /// Export all fields automatically or not. /// public virtual bool AutoExportFields { get; set; } /// /// Reference to code geenrator which will be applied to every method /// public virtual Type DefaultMethodCodeGenerator { get; set; } /// /// When true, code for all constructors will be automatically generated /// public virtual bool AutoExportConstructors { get; set; } /// /// Gets or sets whether class is being exported as abstract or not. /// Null value means automatic detection /// public virtual bool? IsAbstract { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsDeclarationAttributeBase.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Base attribute for so-called compilation unit (class, enum, interface etc) /// public abstract class TsDeclarationAttributeBase : TsAttributeBase { /// /// Constructs new instance of TsDeclarationAttributeBase /// protected TsDeclarationAttributeBase() { // ReSharper disable VirtualMemberCallInConstructor IncludeNamespace = true; // ReSharper restore VirtualMemberCallInConstructor FlattenLimiter = typeof(object); } /// /// Place to corresponding namespace /// public virtual bool IncludeNamespace { get; set; } /// /// Overrides namespace /// public virtual string Namespace { get; set; } /// /// Overrides name /// public virtual string Name { get; set; } /// /// Sets order this membter will be written to output file in /// public double Order { get; set; } /// /// Gets or sets whether to generate properties/methods flattering inheritance hierarchy /// public bool FlattenHierarchy { get; set; } /// /// Flattering limiter. /// All types "deeper" than specified parent will not be considered as exporting members donors /// public Type FlattenLimiter { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsDecoratorAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Adds decorator to class/method/parameter/property /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Field, AllowMultiple = true)] public class TsDecoratorAttribute : Attribute { /// /// Decorator text - everything that must follow after @ /// public string Decorator { get; set; } /// /// Decorator order /// public double Order { get; set; } /// /// Creates decorator attribute /// /// Decorator text - everything that follows after @ /// Decorator order of appearence public TsDecoratorAttribute(string decorator,double order = 0) { Decorator = decorator; Order = order; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsEnumAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Exports enum as TypeScript Enum /// [AttributeUsage(AttributeTargets.Enum)] public class TsEnumAttribute : TsDeclarationAttributeBase { /// /// When true, results "const" enum instead of usual /// public bool IsConst { get; set; } /// /// Gets or sets whetner enum fields must be exported with string initializers (TypeScript 2.4) /// public bool UseString { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsFileAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Specifies file where to put generated code for type. /// This attribute is being ignored when RtDivideTypesAmongFiles is false. /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum)] public class TsFileAttribute : Attribute { /// /// Constructs new TsFile attribute /// /// File name (related to RtTargetDirectory) where to put generated code public TsFileAttribute(string fileName) { FileName = fileName; } /// /// File name (related to RtTargetDirectory) where to put generated code /// public string FileName { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsFunctionAttribute.cs ================================================ using System; using System.Reflection; namespace Reinforced.Typings.Attributes { /// /// Overrides function export /// [AttributeUsage(AttributeTargets.Method)] public class TsFunctionAttribute : TsTypedMemberAttributeBase, ISupportsInferring { private readonly InlineTypeInferers _typeInferers = new InlineTypeInferers(); /// /// Sets order this membter will be written to output file in /// public double Order { get; set; } /// /// Inline function code to be converted to RtRaw and used as function body /// public string Implementation { get; set; } /// /// Gets or sets whether function forcibly should be made async/left as usual function /// public bool? ForceAsync { get; set; } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return _typeInferers; } // ReSharper disable once ValueParameterNotUsed private set { } } } } ================================================ FILE: Reinforced.Typings/Attributes/TsGenericAttribute.cs ================================================ using System; // ReSharper disable VirtualMemberCallInConstructor namespace Reinforced.Typings.Attributes { /// /// Denotes type for generic attribute /// [AttributeUsage(AttributeTargets.GenericParameter)] public class TsGenericAttribute : TsTypedAttributeBase, ISupportsInferring { private readonly InlineTypeInferers _typeInferers = new InlineTypeInferers(); /// /// Constructs new instance of TsGenericAttribute /// /// Raw TypeScript type name public TsGenericAttribute(string type) { Type = type; } /// /// Constructs new instance of TsGenericAttribute /// /// Type to be resolved to TypeScript name during export public TsGenericAttribute(Type strongType) { StrongType = strongType; } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return _typeInferers; } private set { } } } } ================================================ FILE: Reinforced.Typings/Attributes/TsGlobalAttribute.cs ================================================ using System; using Reinforced.Typings.Fluent; namespace Reinforced.Typings.Attributes { /// /// Sets global parameters for RT export. /// Warning! Use Priority property to control [TsGlobal] processing order. /// When exporting multiple assemblies and several ones will contain [TsGlobal] then the one with /// highest priority will be used. Global parameters configured from fluent configuration /// using builder.Global method always has highest priority /// [AttributeUsage(AttributeTargets.Assembly)] public class TsGlobalAttribute : Attribute { /// /// Boolean parameter that controls writing of "auto-generated warning" comment to each generated file. /// It meant the comment like "// This code was generated blah blah blah..." /// 'true' (default) to write warning comment about auto-generated to every file. /// 'false' to do not. /// public bool WriteWarningComment { get; set; } /// /// Specifies root namespace for hierarchical export. /// Helps to avoid creating redundant directories when hierarchical export. /// public string RootNamespace { get; set; } /// /// Use camelCase for methods naming /// public bool CamelCaseForMethods { get; set; } /// /// Use camelCase for properties naming /// public bool CamelCaseForProperties { get; set; } /// /// Enables or disables documentation generator /// public bool GenerateDocumentation { get; set; } /// /// Specifies symbol used for tabulation /// public string TabSymbol { get; set; } /// /// Specifies string used as the line terminator. /// public string NewLine { get; set; } /// /// Switches RT to using TS modules system (--module tsc.exe parameter) and import references /// public bool UseModules { get; set; } /// /// When true, RT will ignore classes' namespaces when arraging classes and interfaces among files. /// This parameter only makes difference when using (--module) /// public bool DiscardNamespacesWhenUsingModules { get; set; } /// /// If true, export will be performed in .d.ts manner (only typings, declare module etc). /// Otherwise, export will be performed to regulat .ts file /// public bool ExportPureTypings { get; set; } ///// ///// Set to true and all nullable value types will be revealed to "type | null" ///// //public bool StrictNullChecks { get; set; } /// /// Sets order of applying paramters from this attribute /// public double Priority { get; set; } /// /// Type of to be used to /// refilter/reorder references and imports while exporting files /// public Type ReferenceProcessorType { get; set; } /// /// Gets or sets whether members reordering (aphabetical, constructors-fields-properties-methods) is enabled /// Warning! Enabling this option discards calls as well as "Order" member attributes property /// public bool ReorderMembers { get; set; } /// /// Gets or sets whether all nullable properties must be exported as optional /// public bool AutoOptionalProperties { get; set; } /// /// Gets or sets whether unresolved types must be exported as 'unknown' instead of 'any' /// public bool UnresolvedToUnknown { get; set; } /// /// Default constructor for TsGlobal attribute /// public TsGlobalAttribute() { WriteWarningComment = true; TabSymbol = "\t"; NewLine = Environment.NewLine; } /// /// Gets or sets type of AST visitor that will be used to write code to output. /// Visitor has to be child class of /// public Type VisitorType { get; set; } /// /// Gets or sets whether RT must automatically treat methods returning Task as async methods /// public bool AutoAsync { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsIgnoreAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Instructs DynTyping do not to export mentioned member /// [AttributeUsage( AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Constructor)] public class TsIgnoreAttribute : Attribute { } } ================================================ FILE: Reinforced.Typings/Attributes/TsImportAttribute.cs ================================================ using System; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.Attributes { /// /// Specifies path of reference which required to be added to result .ts file /// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class TsImportAttribute : Attribute { /// /// What we are importing from module. /// Everything that is placed after "import" keyword and before "from" or "= require(..)" /// Examples: /// - "import * as shape from './Shapes'" -> "* as shape" is target
/// - "import { Foo } from 'Bar'" -> "{ Foo }" is target
/// - "import { Bar2 as bar } from 'Baz'" -> "{ Bar2 as bar }" is target
/// If ImportTarget is null then side-effect import will be generated. ///
public string ImportTarget { get; set; } /// /// Import source is everything that follows after "from" keyword. /// Please not the you do not have to specify quotes here! Quotes will be added automatically /// public string ImportSource { get; set; } /// /// When true, import will be generated as "import ImportTarget = require('ImportSource')" /// public bool ImportRequire { get; set; } private RtImport _import; internal RtImport ToImport() { if (_import==null) _import = new RtImport() {Target = ImportTarget, From = ImportSource, IsRequire = ImportRequire}; return _import; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsInterfaceAttribute.cs ================================================ using System; // ReSharper disable VirtualMemberCallInConstructor namespace Reinforced.Typings.Attributes { /// /// Exports specified class or interface as typescript interface /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct)] public class TsInterfaceAttribute : TsDeclarationAttributeBase, IAutoexportSwitchAttribute { /// /// Constructs new instance of TsInterfaceAttribute /// public TsInterfaceAttribute() { AutoI = true; IncludeNamespace = true; AutoExportMethods = true; AutoExportProperties = true; } /// /// Automatically appends I prefix if non-interfaces /// public virtual bool AutoI { get; set; } /// /// Export all methods automatically or not. /// public virtual bool AutoExportMethods { get; set; } /// /// Export all properties automatically or not. /// public virtual bool AutoExportProperties { get; set; } bool IAutoexportSwitchAttribute.AutoExportFields { get { return false; } } Type IAutoexportSwitchAttribute.DefaultMethodCodeGenerator { get { return null; } } bool IAutoexportSwitchAttribute.AutoExportConstructors { get { return false; } } } } ================================================ FILE: Reinforced.Typings/Attributes/TsParameterAttribute.cs ================================================ using System; using System.Reflection; namespace Reinforced.Typings.Attributes { /// /// Overrides settings for exporting parameters /// [AttributeUsage(AttributeTargets.Parameter)] public class TsParameterAttribute : TsTypedMemberAttributeBase, ISupportsInferring { private readonly InlineTypeInferers _typeInferers = new InlineTypeInferers(); /// /// Specifies default value /// public virtual object DefaultValue { get; set; } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return _typeInferers; } } } } ================================================ FILE: Reinforced.Typings/Attributes/TsPropertyAttribute.cs ================================================ using System; using System.Reflection; // ReSharper disable ValueParameterNotUsed namespace Reinforced.Typings.Attributes { /// /// Overrides property/field export settings /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public class TsPropertyAttribute : TsTypedMemberAttributeBase, ISupportsInferring { /// /// Constructor /// public TsPropertyAttribute() { Constant = true; } private readonly InlineTypeInferers _typeInferers = new InlineTypeInferers(); /// /// Forces property to be a nullable /// E.g. `field:boolean` becomes `field?:boolean` when you specify `[TsProperty(ForceNullable = true)]` in attribute configuration /// internal virtual bool? NilForceNullable { get; set; } /// /// Forces property to be a nullable /// E.g. `field:boolean` becomes `field?:boolean` when you specify `[TsProperty(ForceNullable = true)]` in attribute configuration /// public virtual bool ForceNullable { get { return NilForceNullable ?? false; } set { NilForceNullable = value; } } /// /// Sets order this membter will be written to output file in /// public double Order { get; set; } /// /// When true, static property with well-known simple static value will be exported as object property with corresponding static initializer. /// Otherwise, setting this parameter to "true" will not take effect /// public bool Constant { get; set; } internal Func InitializerEvaluator { get; set; } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return _typeInferers; } private set { } } } } ================================================ FILE: Reinforced.Typings/Attributes/TsReferenceAttribute.cs ================================================ using System; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.Attributes { /// /// Specifies path of reference which required to be added to result .ts file /// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class TsReferenceAttribute : Attribute { /// /// Constructs new instance of TsReferenceAttribute /// /// Path that should be written as file to reference tag public TsReferenceAttribute(string path) { Path = path; } /// /// Path to referenced TS file /// public virtual string Path { get; private set; } private RtReference _reference; internal RtReference ToReference() { if (_reference==null) _reference = new RtReference() {Path = Path}; return _reference; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsThirdPartyAttribute.cs ================================================ using System; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.Attributes { /// /// Prevents class or interface or enum to be exported. /// Instead of that it will be used like type from third-party library. /// Use and attributes to specify imports that must be used /// when this type appears /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum)] public class TsThirdPartyAttribute : Attribute { /// public TsThirdPartyAttribute(string name) { Name = name; } /// /// Gets or sets full quialified name of third party type to avoid dealing with namespaces, I letters etc /// public string Name { get; internal set; } } /// /// This attribute is used to add import directive to any file using third-party type (that is marked with ) /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum, AllowMultiple = true)] public class TsThirdPartyImportAttribute : Attribute { /// /// What we are importing from module. /// Everything that is placed after "import" keyword and before "from" or "= require(..)" /// Examples: /// - "import * as shape from './Shapes'" -> "* as shape" is target
/// - "import { Foo } from 'Bar'" -> "{ Foo }" is target
/// - "import { Bar2 as bar } from 'Baz'" -> "{ Bar2 as bar }" is target
/// If ImportTarget is null then side-effect import will be generated. ///
public string ImportTarget { get; set; } /// /// Import source is everything that follows after "from" keyword. /// Please note that you do not have to specify quotes here! Quotes will be added automatically /// public string ImportSource { get; set; } /// /// When true, import will be generated as "import ImportTarget = require('ImportSource')" /// public bool ImportRequire { get; set; } /// /// Cosntructs new Rtimport /// /// Target /// Source /// Is import "=require(...)" public TsThirdPartyImportAttribute(string importTarget, string importSource, bool importRequire = false) { ImportTarget = importTarget; ImportSource = importSource; ImportRequire = importRequire; } private RtImport _import; internal RtImport ToImport() { if (_import == null) _import = new RtImport() { Target = ImportTarget, From = ImportSource, IsRequire = ImportRequire }; return _import; } } /// /// This attribute is used to add reference directive to file using third-party type (that is marked with ) /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum, AllowMultiple = true)] public class TsThirdPartyReferenceAttribute : Attribute { /// /// Constructs new instance of TsAddTypeReferenceAttribute using referenced type /// /// Raw reference public TsThirdPartyReferenceAttribute(string path) { Path = path; } /// /// Raw reference path that will be added to target file /// public string Path { get; set; } private RtReference _reference; internal RtReference ToReference() { if (_reference == null) _reference = new RtReference() { Path = Path }; return _reference; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsTypedAttributeBase.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Base attribute for typed members/parameters /// public abstract class TsTypedAttributeBase : TsAttributeBase { /// /// Overrides member type name in resulting TypeScript. /// Supplied as string. Helpful when property type is not present in your project. /// E.g. - JQquery object. /// public virtual string Type { get; set; } /// /// Similar to `Type`, but you can specify .NET type using typeof. /// It is useful e.g. for delegates /// public virtual Type StrongType { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsTypedMemberAttributeBase.cs ================================================ namespace Reinforced.Typings.Attributes { /// /// Base attribute for class members and method parameters /// public abstract class TsTypedMemberAttributeBase : TsTypedAttributeBase { /// /// When true them member name will be camelCased regardless configuration setting /// public bool ShouldBeCamelCased { get; set; } /// /// When true them member name will be PascalCased regardless configuration setting /// public bool ShouldBePascalCased { get; set; } /// /// Overrides member name /// public virtual string Name { get; set; } } } ================================================ FILE: Reinforced.Typings/Attributes/TsValueAttribute.cs ================================================ using System; namespace Reinforced.Typings.Attributes { /// /// Specifies exporting enum value /// [AttributeUsage(AttributeTargets.Field)] public class TsValueAttribute : TsAttributeBase { /// /// Overrides enum value name /// public virtual string Name { get; set; } /// /// Overrides enum value's string initializer. This property works only if there is property set to true. /// Please escape quotes manually. /// public string Initializer { get; set; } } } ================================================ FILE: Reinforced.Typings/DictionaryExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace Reinforced.Typings { internal static class DictionaryExtensions { public static TV GetOrNull(this Dictionary dictionary, T key) { if (!dictionary.ContainsKey(key)) return default(TV); return dictionary[key]; } public static TV GetOr(this Dictionary dictionary, T key, Func or) { if (!dictionary.ContainsKey(key)) { var v = or(); if (v != null) dictionary[key] = v; return v; } return dictionary[key]; } public static TV GetUnion(this Dictionary dictionary, T key, Func union) where TV : IEnumerable { var u = union(); if (dictionary.ContainsKey(key)) { u = (TV) u.Union(dictionary[key]); } return u; } public static TV GetOrCreate(this Dictionary dictionary, T key) where TV : new() { TV result; if (dictionary.ContainsKey(key)) result = dictionary[key]; else { result = new TV(); dictionary[key] = result; } return result; } public static TV GetOrCreate(this Dictionary dictionary, T key, Func createDelegate) { TV result; if (dictionary.ContainsKey(key)) result = dictionary[key]; else { result = createDelegate(); dictionary[key] = result; } return result; } } } ================================================ FILE: Reinforced.Typings/Exceptions/ErrorMessage.cs ================================================ namespace Reinforced.Typings.Exceptions { /// /// Data object for RT error message /// public class ErrorMessage { /// /// Error code /// public int Code { get; private set; } /// /// Message test /// public string MessageText { get; private set; } /// /// Error message subcategory (for Visual Studio) /// public string Subcategory { get; private set; } public ErrorMessage(int code, string messageText, string subcategory = "") { Code = code; MessageText = messageText; Subcategory = subcategory; } /// /// Throws error message as exception /// /// Format arguments /// RtException corresponding to error message will be thrown in all cases public void Throw(params object[] formatParameters) { throw new RtException(string.Format(MessageText, formatParameters), Code, Subcategory); } /// /// Converts error message to RtWarning to be processed further /// /// /// public RtWarning Warn(params object[] formatParameters) { return new RtWarning(Code, text: string.Format(MessageText, formatParameters), subcategory: Subcategory); } } } ================================================ FILE: Reinforced.Typings/Exceptions/ErrorMessages.cs ================================================  namespace Reinforced.Typings.Exceptions { /// /// This class contains all RT's error and siagnostic messages. /// Why didnt I use resources? I dont want to add one more .dll to RT's NuGet package. /// if localization will be required through issues then I will add one /// class ErrorMessages { #region Errors /// /// Could not acquire temporary file {0}: {1} /// public static readonly ErrorMessage RTE0001_TempFileError = new ErrorMessage(0001,"Could not acquire temporary file {0}: {1}","IO"); /// /// Could not replace source file {0}: {1} /// public static readonly ErrorMessage RTE0002_DeployingFilesError = new ErrorMessage(0002,"Could not replace source file {0}: {1}","IO"); /// /// Could not instantiate code generator {0}: {1} /// public static readonly ErrorMessage RTE0003_GeneratorInstantiate = new ErrorMessage(0003,"Could not instantiate code generator {0}: {1}","Code generation"); /// /// Code generator {0} has thrown an error: {1} /// public static readonly ErrorMessage RTE0004_GeneratorError = new ErrorMessage(0004,"Code generator {0} has thrown an error: {1}","Code generation"); /// /// Could not resolve type for {0}. An error occured: {1} /// public static readonly ErrorMessage RTE0005_TypeResolvationError = new ErrorMessage(0005, "Could not resolve type for {0}. An error occured: {1}", "Type resolvation"); /// /// Exception thrown when applying fluent configuration method for {1} '{2}': {0} /// public static readonly ErrorMessage RTE0006_FluentSingleError = new ErrorMessage(0006, "Exception thrown when applying fluent configuration method for {1} '{2}': {0}", "Fluent configuration"); /// /// Exception thrown when applying fluent configuration method for collection of {1}: {0} /// public static readonly ErrorMessage RTE0007_FluentBatchError = new ErrorMessage(0007, "Exception thrown when applying fluent configuration method for collection of {1}: {0}", "Fluent configuration"); /// /// MethodCallExpression should be provided for .WithMethod call. Please use only lamba expressions in this place. /// public static readonly ErrorMessage RTE0008_FluentWithMethodError = new ErrorMessage(0008, "MethodCallExpression should be provided for .WithMethod call. Please use only lamba expressions in this place.", "Fluent configuration"); /// /// Sorry, but {0} is not very good idea for parameter configuration. Try using simplier lambda expression. /// public static readonly ErrorMessage RTE0009_FluentWithMethodCouldNotParse = new ErrorMessage(0009, "Sorry, but {0} is not very good idea for parameter configuration. Try using simplier lambda expression.", "Fluent configuration"); /// /// Property lambda expression expected in {0} /// public static readonly ErrorMessage RTE0010_PropertyLambdaExpected = new ErrorMessage(0010, "Property lambda expression expected in {0}", "Fluent configuration"); /// /// Field lambda expression expected in {0} /// public static readonly ErrorMessage RTE0011_FieldLambdaExpected = new ErrorMessage(0011, "Field lambda expression expected in {0}", "Fluent configuration"); /// /// NewExpression should be provided for .WithConstructor call. Please use only lamba expressions in this place. /// public static readonly ErrorMessage RTE0012_NewExpressionLambdaExpected = new ErrorMessage(0012, "NewExpression should be provided for .WithConstructor call. Please use only 'new ...' lamba expressions in this place.", "Fluent configuration"); /// /// Error when trying to locate particular field /// public static readonly ErrorMessage RTE0013_InvalidField = new ErrorMessage(0013, "Could not locate field {0} in class {1}", "Reflection"); /// /// Error when trying to locate particular property /// public static readonly ErrorMessage RTE0014_InvalidProperty = new ErrorMessage(0014, "Could not locate property {0} in class {1}", "Reflection"); /// /// Error when trying to locate particular property /// public static readonly ErrorMessage RTE0015_CannotFlatten = new ErrorMessage(0015, "Could not flatten hierarchy for class {0}. Hierarchy flattening must appear before .With* methods", "Hierarchy flattening"); /// /// Error when trying to specify invalid references processor type /// public static readonly ErrorMessage RTE0016_InvalidRefProcessorType = new ErrorMessage(0016, "Type {0} does not seem to be inherit from Reinforced.Typings.ReferencesInspection.ReferenceProcessorBase type", "References processor"); /// /// Contradictious export instructions: class {0} cannot be exported as {1} because it is already exported as something else /// public static readonly ErrorMessage RTE0017_FluentContradict = new ErrorMessage(0017, "Contradictious export instructions: class {0} cannot be exported as {1} because it is already exported as something else (probably via attributes)", "Fluent configuration"); /// /// Contradictious export instructions: class {0} cannot be exported as {1} because it is already exported as something else /// public static readonly ErrorMessage RTE0018_FluentThirdParty = new ErrorMessage(0018, "Contradictious export instructions: class {0} is already being exported as third-party, but you try to reexport it as {1}", "Fluent configuration"); #endregion #region Warnings /// /// XMLDOC file not supplied /// public static readonly ErrorMessage RTW0001_DocumentationNotSupplied = new ErrorMessage(0001, "XMLDOC file not supplied", "JSDOC"); /// /// Could not find XMLDOC file {0} /// public static readonly ErrorMessage RTW0002_DocumentationNotFound = new ErrorMessage(0002, "Could not find XMLDOC file {0}", "JSDOC"); /// /// Could not find suitable TypeScript type for {0}. 'any' assumed. /// public static readonly ErrorMessage RTW0003_TypeUnknown = new ErrorMessage(0003, "Could not find suitable TypeScript type for {0}. '{1}' assumed.", "Type resolvation"); /// /// No suitable base constructor found for {0}. Generating 'super' call with all nulls. /// public static readonly ErrorMessage RTW0004_DefaultSuperCall = new ErrorMessage(0004, "No suitable base constructor found for {0}. Generating 'super' call with all nulls.", "Class code generation"); /// /// Class {0} (base for {1}) is exported as interface. It is potentially unsafe facility. /// public static readonly ErrorMessage RTW0005_BaseClassExportingAsInterface = new ErrorMessage(0005, "Class {0} (base for {1}) is exported as interface. It is potentially unsafe facility.", "Class code generation"); /// /// Error parsering XMLDOC file {0}: {1} /// public static readonly ErrorMessage RTW0006_DocumentationParseringError = new ErrorMessage(0006, "Error parsing XMLDOC file {0}: {1}", "JSDOC"); /// /// Error parsering XMLDOC file {0}: {1} /// public static readonly ErrorMessage RTW0007_InvalidDictionaryKey = new ErrorMessage(0007, "{0} is not valid type for JS object key (original type {1})", "Type resolvation"); /// /// Error of type loding /// public static readonly ErrorMessage RTW0008_TypeloadException = new ErrorMessage(0008, "Some types cannot be loaded via reflection: {0}", "Type loading"); #endregion } } ================================================ FILE: Reinforced.Typings/Exceptions/RtException.cs ================================================ using System; namespace Reinforced.Typings.Exceptions { /// /// Base class for RT exception. /// All the RT exceptions will be provided to VisualStudio's errors tab /// public class RtException : Exception { /// /// Internal error code /// public int Code { get; private set; } /// /// Error subcategory /// public string Subcategory { get; private set; } /// /// Constructs new RT exception /// /// Error message /// Error code /// Error subcategory (optional) public RtException(string message, int code, string subcategory = "") : base(message) { Code = code; Subcategory = subcategory; } } } ================================================ FILE: Reinforced.Typings/Exceptions/RtWarning.cs ================================================ namespace Reinforced.Typings.Exceptions { /// /// Represents warning message that could be displayed during build. /// Warnings can be added to global warnings collection located at ExportContext.Warnings. /// ExportContext instance can be found inside every TsCodeGeneratorBase /// public class RtWarning { /// /// Warning code /// public int Code { get; set; } /// /// Warning subcategory /// public string Subcategory { get; set; } /// /// Warning detailed text /// public string Text { get; set; } /// /// Instantiates new RtWarning that is suitable be added to warnings collection. /// /// Warning code /// Warning subcategory (optional). Important! Warning subcategory should not contain word "warning" and ":" symbol /// Warning text public RtWarning(int code, string subcategory = null, string text = null) { Code = code; Subcategory = subcategory; Text = text; } } } ================================================ FILE: Reinforced.Typings/ExportContext/ExportContext.Configurables.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Reinforced.Typings.Fluent; // ReSharper disable CheckNamespace namespace Reinforced.Typings { /// /// TsExport exporting settings /// public partial class ExportContext { private bool _hierarchical; /// /// True to create project hierarchy in target folder. /// False to store generated typings in single file /// public bool Hierarchical { get { return _hierarchical; } set { if (_isLocked) return; _hierarchical = value; } } private string _targetDirectory; /// /// Target directory where to store generated typing files. /// This parameter is not used when Hierarcy is false /// public string TargetDirectory { get { return _targetDirectory; } set { if (_isLocked) return; _targetDirectory = value; } } private string _targetFile; /// /// Target file where to store generated sources. /// This parameter is not used when Hierarchy is true /// public string TargetFile { get { return _targetFile; } set { if (_isLocked) return; _targetFile = value; } } private Action _configurationMethod; /// /// Fluent configuration method /// public Action ConfigurationMethod { get { return _configurationMethod; } set { if (_isLocked) return; _configurationMethod = value; } } private string _documentationFilePath; /// /// Path to assembly's XMLDOC file /// public string DocumentationFilePath { get { return _documentationFilePath; } set { if (_isLocked) return; _documentationFilePath = value; } } private HashSet _suppressedWarningCodes = new HashSet(); /// /// Gets or sets the list of suppressed warning codes /// public IEnumerable SuppressedWarningCodes { get { return _suppressedWarningCodes; } set { if (_isLocked) return; _suppressedWarningCodes = new HashSet(value); } } } } ================================================ FILE: Reinforced.Typings/ExportContext/ExportContext.Initialization.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.ReferencesInspection; using Reinforced.Typings.Xmldoc; // ReSharper disable CheckNamespace namespace Reinforced.Typings { /// /// TsExport exporting settings /// public partial class ExportContext { private bool _isInitialized; internal void Initialize() { if (_isInitialized) return; ApplyFluent(); InitializeDocumentation(); BuildTypesCache(); InspectGlobalReferences(); Generators = new GeneratorManager(this); _isInitialized = true; } private void ApplyFluent() { var hasFluentConfiguration = ConfigurationMethod != null; if (hasFluentConfiguration) { var configurationBuilder = new ConfigurationBuilder(this); ConfigurationMethod(configurationBuilder); } } private void InitializeDocumentation() { Documentation = new DocumentationManager(Global.GenerateDocumentation ? DocumentationFilePath : null, this); foreach (var additionalDocumentationPath in Project.AdditionalDocumentationPathes) { Documentation.CacheDocumentation(additionalDocumentationPath, this); } } internal InspectedReferences _globalReferences; private void InspectGlobalReferences() { var assemblies = SourceAssemblies; var references = assemblies.Where(c => c.GetCustomAttributes().Any()) .SelectMany(c => c.GetCustomAttributes()) .Select(c => c.ToReference()) .Union(Project.References); if (Global.UseModules) { var imports = assemblies.Where(c => c.GetCustomAttributes().Any()) .SelectMany(c => c.GetCustomAttributes()) .Select(c => c.ToImport()) .Union(Project.Imports); _globalReferences = new InspectedReferences(references, imports); return; } _globalReferences = new InspectedReferences(references); } private HashSet _allTypesHash; private void BuildTypesCache() { var allTypes = SourceAssemblies .SelectMany(c => c._GetTypes(this) .Where(d => d.GetCustomAttribute(false) != null || d.GetCustomAttribute() != null)) .Union(Project.BlueprintedTypes) .Distinct() .ToList(); _allTypesHash = new HashSet(allTypes); if (Hierarchical) { foreach (var type in _allTypesHash) { Project.AddFileSeparationSettings(type); } } if (!Hierarchical) TypesToFilesMap = new Dictionary>(); else TypesToFilesMap = allTypes.Where(d => Project.Blueprint(d).ThirdParty == null) .GroupBy(c => GetPathForType(c, stripExtension: false)) .ToDictionary(c => c.Key, c => c.AsEnumerable()); } } } ================================================ FILE: Reinforced.Typings/ExportContext/ExportContext.Operations.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace namespace Reinforced.Typings { /// /// TsExport exporting settings /// public partial class ExportContext { internal void Lock() { _isLocked = true; Global.Lock(); } internal void Unlock() { _isLocked = false; Global.Unlock(); } /// /// Retrieves full path to file where specified type will be exported to /// /// Type /// Remove file extension. Set to false if you still want to get path with extension in case of module export /// Full path to file containing exporting type internal string GetPathForType(Type t, bool stripExtension = true) { var fromConfiguration = Project.GetPathForFile(t); if (!string.IsNullOrEmpty(fromConfiguration)) { if (Global.UseModules && stripExtension) { if (fromConfiguration.EndsWith(".d.ts")) fromConfiguration = fromConfiguration.Substring(0, fromConfiguration.Length - 5); if (fromConfiguration.EndsWith(".ts")) fromConfiguration = fromConfiguration.Substring(0, fromConfiguration.Length - 3); } var r = Path.Combine(TargetDirectory, fromConfiguration); return r; } var ns = Project.Blueprint(t).GetNamespace(); var tn = Project.Blueprint(t).GetName().ToString(); var idx = tn.IndexOf('<'); if (idx != -1) tn = tn.Substring(0, idx); if (!Global.UseModules || !stripExtension) { if (Global.ExportPureTypings) tn = tn + ".d.ts"; else tn = tn + ".ts"; } if (string.IsNullOrEmpty(ns)) return Path.Combine(TargetDirectory, tn); if (!string.IsNullOrEmpty(Global.RootNamespace)) { ns = ns.Replace(Global.RootNamespace, string.Empty); } ns = ns.Trim('.').Replace('.', Path.DirectorySeparatorChar); var pth = Path.Combine( !string.IsNullOrEmpty(ns) ? Path.Combine(TargetDirectory, ns) : TargetDirectory, tn); return pth; } /// /// Sets up exported file dummy /// /// File name /// Exported file dummy public ExportedFile CreateExportedFile(string fileName = null) { if (!Hierarchical && fileName == TargetFile) fileName = null; IEnumerable types = null; if (!string.IsNullOrEmpty(fileName)) { if (!TypesToFilesMap.ContainsKey(fileName)) { var allFiles = string.Join(", ", TypesToFilesMap.Keys); throw new Exception("Current configuration does not contain file " + fileName + ", only " + allFiles); } types = new HashSet(TypesToFilesMap[fileName]); } else { types = _allTypesHash; } var typesHash = new HashSet(types.Where(d => Project.Blueprint(d).ThirdParty == null)); ExportedFile ef = new ExportedFile(typesHash, fileName, _globalReferences.Duplicate(), this); return ef; } /// /// Adds export-time warning that will be raised to the common warnings list ar the end /// /// Warning instance public void AddWarning(RtWarning warning) { if (!_suppressedWarningCodes.Contains(warning.Code)) { _warnings.Add(warning); } } /// /// Clears warnings list /// public void ClearWarnings() { _warnings.Clear(); } } } ================================================ FILE: Reinforced.Typings/ExportContext/ExportContext.Readonly.cs ================================================ using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Exceptions; using Reinforced.Typings.ReferencesInspection; using Reinforced.Typings.Xmldoc; // ReSharper disable CheckNamespace namespace Reinforced.Typings { /// /// TsExport exporting settings /// public partial class ExportContext { /// /// File I/O operations frontend /// public IFilesOperations FileOperations { get; private set; } /// /// Identifies where current export is performed in terms of AST. /// Context.Location could be used to conditionally add members to different places of generated source code /// public Location Location { get; private set; } /// /// Gets the assemblies to extract typings from. /// Important! TsExporter do not perform any job for loading assemblies. It is left upon a calling side. /// That is because loading assemblies is highly dependent on calling side's AppDomain. /// TsExporter shouldnt handle all this shit /// public Assembly[] SourceAssemblies { get; private set; } /// /// Documentation manager /// public DocumentationManager Documentation { get; private set; } private readonly List _warnings = new List(); /// /// Warnings that should be displayed after build. /// Feel free to add messages from generators here. /// public IEnumerable Warnings { get { return _warnings; } } /// /// Blueprint of type currently being exported /// public TypeBlueprint CurrentBlueprint { get { if (Location._typesStack.Count == 0) return null; return Location._typesStack.Peek(); } } /// /// Global generation parameters /// public GlobalParameters Global { get; private set; } /// /// Generators cache /// public GeneratorManager Generators { get; private set; } /// /// Project blueprint /// public ProjectBlueprint Project { get; private set; } } } ================================================ FILE: Reinforced.Typings/ExportContext/ExportContext.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; namespace Reinforced.Typings { /// /// TsExport exporting settings /// public sealed partial class ExportContext : IWarningsCollector { private bool _isLocked; /// /// Instantiates new ExportContext instance (only for testing/integration) /// public ExportContext(Assembly[] sourceAssemblies, IFilesOperations fileOperationsServiceOverride = null) { FileOperations = fileOperationsServiceOverride ?? new FilesOperations(); FileOperations.Context = this; Global = new GlobalParameters(sourceAssemblies); SourceAssemblies = sourceAssemblies; Location = new Location(this); Project = new ProjectBlueprint(); } /// /// There is a case when you are exporting base class as interface. It may lead to some unusual handling of generation, /// so I'm using this property to denote such cases and fix it in-place /// internal bool SpecialCase { get; set; } internal Dictionary> TypesToFilesMap { get; private set; } } } ================================================ FILE: Reinforced.Typings/ExportContext/IWarningsCollector.cs ================================================ using Reinforced.Typings.Exceptions; namespace Reinforced.Typings { internal interface IWarningsCollector { void AddWarning(RtWarning warning); } } ================================================ FILE: Reinforced.Typings/ExportedFile.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Text; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.ReferencesInspection; namespace Reinforced.Typings { /// /// Resulting TS file model /// public class ExportedFile { private readonly ExportContext _context; internal ExportContext Context { get { return _context; } } /// Initializes a new instance of the class. internal ExportedFile(HashSet typesToExport, string fileName, InspectedReferences references, ExportContext context) { _context = context; TypesToExport = typesToExport; FileName = fileName; AllTypesIsSingleFile = !_context.Hierarchical; References = references; TypeResolver = new TypeResolver(this); AddReferencesFromTypes(); } /// /// File references and imports /// public InspectedReferences References { get; private set; } /// /// Namespaces ASTs /// public RtNamespace[] Namespaces { get; internal set; } /// /// Type Resolver object /// public TypeResolver TypeResolver { get; private set; } /// /// Gets or sets whether all exported types are stored in single file /// public bool AllTypesIsSingleFile { get; private set; } /// /// Set of types being exported within this file /// public HashSet TypesToExport { get; private set; } /// /// Absolute file path+name+extension /// public string FileName { get; private set; } private IEnumerable _refinedReferences; private IEnumerable _refinedImports; /// /// Gets final version of references (after conditional user processing) /// public IEnumerable FinalReferences { get { return _refinedReferences ?? References.References; } } /// /// Gets final version of references (after conditional user processing) /// public IEnumerable FinalImports { get { return _refinedImports ?? References.Imports; } } internal void ApplyReferenceProcessor(ReferenceProcessorBase refProcessor = null) { if (refProcessor == null) return; var references = References.References; references = refProcessor.FilterReferences(references, this); if (references == null) references = new RtReference[0]; _refinedReferences = references; var imports = References.Imports; imports = refProcessor.FilterImports(imports, this); if (imports == null) imports = new RtImport[0]; _refinedImports = imports; } /// /// Ensures that imports for specified type presents in specified file /// /// Type to import /// Type name (probably overriden) /// Import AST node or null if no import needed. Returns existing import in case if type is already imported internal RtImport EnsureImport(Type t, string typeName) { if (TypesToExport.Contains(t)) return null; var bp = _context.Project.Blueprint(t); if (bp.ThirdParty != null) { foreach (var tpi in bp.ThirdPartyImports) { References.AddImport(tpi); } return null; } if (AllTypesIsSingleFile) return null; var relPath = GetRelativePathForType(t, FileName); if (string.IsNullOrEmpty(relPath)) return null; RtImport result = null; if (References.StarImports.ContainsKey(relPath)) { return References.StarImports[relPath]; } if (_context.Global.DiscardNamespacesWhenUsingModules) { var target = string.Format("{{ {0} }}", typeName); result = new RtImport() { From = relPath, Target = target }; References.AddImport(result); } else { var alias = Path.GetFileNameWithoutExtension(relPath); var target = string.Format("* as {0}", alias); result = new RtImport() { From = relPath, Target = target }; References.AddImport(result); } return result; } /// /// Ensures that reference for specified type presents in specified file /// /// Type to reference /// Reference AST node or null if no reference needed. Returns existing reference in case if type is already referenced internal void EnsureReference(Type t) { if (TypesToExport.Contains(t)) return; var bp = _context.Project.Blueprint(t); if (bp.ThirdParty != null) { foreach (var tpi in bp.ThirdPartyReferences) { References.AddReference(tpi); } return; } if (AllTypesIsSingleFile) return; var relPath = GetRelativePathForType(t, FileName); var result = new RtReference() { Path = relPath }; References.AddReference(result); } private string GetRelativePathForType(Type typeToReference, string currentFile) { if (_context.Global.UseModules) { currentFile = Path.Combine(Path.GetDirectoryName(currentFile), Path.GetFileNameWithoutExtension(currentFile)); } var desiredFile = _context.GetPathForType(typeToReference); if (currentFile == desiredFile) return String.Empty; var desiredFileName = Path.GetFileName(desiredFile); var relPath = GetRelativeNamespacePath(Path.GetDirectoryName(currentFile), Path.GetDirectoryName(desiredFile)); relPath = Path.Combine(relPath, desiredFileName); if (_context.Global.UseModules) { if (!relPath.StartsWith(".")) relPath = "./" + relPath; } return relPath; } private string GetRelativeNamespacePath(string currentNamespace, string desiredNamespace) { if (currentNamespace == desiredNamespace) return string.Empty; if (string.IsNullOrEmpty(currentNamespace)) return desiredNamespace; var current = currentNamespace.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); var desired = desiredNamespace.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); var result = new StringBuilder(); if (string.IsNullOrEmpty(desiredNamespace)) { for (var i = 0; i < current.Length; i++) result.Append("../"); } else { var level = current.Length; //var cr1 = current.I(level); //var ds1 = desired.I(level); while (level >= 0 && (!ArrayExtensions.PartialCompare(current, desired, level))) { //var cr = current.I(level); //var ds = desired.I(level); result.Append("../"); level--; } //level++; for (; level < desired.Length; level++) { result.AppendFormat("{0}/", desired[level]); } } return result.ToString().Trim(Path.DirectorySeparatorChar); } private void AddReferencesFromTypes() { foreach (var type in TypesToExport) { AddTypeSpecificReferences(type); if (_context.Global.UseModules) AddTypeSpecificImports(type); } } private void AddTypeSpecificReferences(Type t) { var references = _context.Project.Blueprint(t).References; foreach (var tsAddTypeReferenceAttribute in references) { if (tsAddTypeReferenceAttribute.Type != null) { TypeResolver.ResolveTypeName(tsAddTypeReferenceAttribute.Type); } else { References.AddReference(tsAddTypeReferenceAttribute.ToReference()); } } } private void AddTypeSpecificImports(Type t) { var imports = _context.Project.Blueprint(t).Imports; foreach (var tsAddTypeImportAttribute in imports) { References.AddImport(tsAddTypeImportAttribute.ToImport()); } } } } ================================================ FILE: Reinforced.Typings/FilesOperations.cs ================================================ using System; using System.Collections.Generic; using System.IO; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Exceptions; using Reinforced.Typings.ReferencesInspection; using Reinforced.Typings.Visitors; using Reinforced.Typings.Visitors.TypeScript; using Reinforced.Typings.Visitors.Typings; namespace Reinforced.Typings { /// /// Implementation of file operations abstraction /// public class FilesOperations : IFilesOperations { private readonly List _tmpFiles = new List(); /// /// /// public ExportContext Context { get; set; } /// /// /// public void DeployTempFiles() { foreach (var tmpFile in _tmpFiles) { var origFile = Path.GetFileNameWithoutExtension(tmpFile); var origDir = Path.GetDirectoryName(tmpFile); origFile = Path.Combine(origDir, origFile); try { if (File.Exists(origFile)) File.Delete(origFile); File.Move(tmpFile, origFile); #if DEBUG Console.WriteLine("File replaced: {0} -> {1}", tmpFile, origFile); #endif } catch (Exception ex) { ErrorMessages.RTE0002_DeployingFilesError.Throw(origFile, ex.Message); } } } /// /// Internal implementation of file Export operation /// /// Target stream /// Exported file protected virtual void ExportCore(StreamWriter tw, ExportedFile file) { var visitor = Context.Global.VisitorType == null ? Context.Global.ExportPureTypings ? new TypingsExportVisitor(tw, Context) : new TypeScriptExportVisitor(tw, Context) : (TextExportingVisitor) Activator.CreateInstance(Context.Global.VisitorType, new object[] { tw, Context }); WriteWarning(tw); visitor.VisitFile(file); } /// /// /// public void Export(string fileName, ExportedFile file) { using (var fs = GetTmpFile(fileName)) { using (var tw = new StreamWriter(fs)) { tw.NewLine = Context.Global.NewLine; ExportCore(tw, file); } } } private void WriteWarning(TextWriter tw) { if (Context.Global.WriteWarningComment) { tw.WriteLine("// This code was generated by a Reinforced.Typings tool."); tw.WriteLine("// Changes to this file may cause incorrect behavior and will be lost if"); tw.WriteLine("// the code is regenerated."); tw.WriteLine(); } } private Stream GetTmpFile(string fileName) { fileName = fileName + ".tmp"; try { var dir = Path.GetDirectoryName(fileName); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); if (File.Exists(fileName)) { File.Delete(fileName); } #if DEBUG Console.WriteLine("Temp file aquired: {0}", fileName); #endif _tmpFiles.Add(fileName); } catch (Exception ex) { ErrorMessages.RTE0001_TempFileError.Throw(fileName, ex.Message); } return File.OpenWrite(fileName); } /// /// /// public void ClearTempRegistry() { _tmpFiles.Clear(); } } internal static class ArrayExtensions { public static bool PartialCompare(string[] array1, string[] array2, int idx) { var minLen = array1.Length > array2.Length ? array2.Length : array1.Length; if (idx > minLen) return false; for (int i = 0; i < idx; i++) { if (array1[i] != array2[i]) return false; } return true; } } } ================================================ FILE: Reinforced.Typings/Fluent/ConfigurationBuilder.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Exceptions; namespace Reinforced.Typings.Fluent { /// /// Fluent configuration builder /// public class ConfigurationBuilder { private readonly Dictionary _typeExportBuilders = new Dictionary(); private readonly Dictionary _thirdPartyBuilders = new Dictionary(); /// /// Export context /// public ExportContext Context { get; private set; } internal ConfigurationBuilder(ExportContext context) { Context = context; GlobalBuilder = new GlobalConfigurationBuilder(context.Global); } internal List AdditionalDocumentationPathes { get { return Context.Project.AdditionalDocumentationPathes; } } internal List References { get { return Context.Project.References; } } internal List Imports { get { return Context.Project.Imports; } } internal Dictionary TypeExportBuilders { get { return _typeExportBuilders; } } internal Dictionary ThirdPartyBuilders { get { return _thirdPartyBuilders; } } internal Dictionary GlobalSubstitutions { get { return Context.Project.GlobalSubstitutions; } } internal Dictionary> GenericSubstitutions { get { return Context.Project.GlobalGenericSubstitutions; } } internal GlobalConfigurationBuilder GlobalBuilder { get; private set; } internal TypeBlueprint GetCheckedBlueprint(Type type) { var bp = Context.Project.Blueprint(type); if (bp.TypeAttribute != null && !typeof(TAttr)._IsAssignableFrom(bp.TypeAttribute.GetType())) { var name = typeof(TAttr).Name.Substring(2).Replace("Attribute", string.Empty).ToLower(); ErrorMessages.RTE0017_FluentContradict.Throw(type, name); } if (bp.ThirdParty != null) { var name = typeof(TAttr).Name.Substring(2).Replace("Attribute", string.Empty).ToLower(); ErrorMessages.RTE0018_FluentThirdParty.Throw(type, name); } return bp; } internal TypeBlueprint GetCheckedThirdPartyBlueprint(Type type) { var bp = Context.Project.Blueprint(type); if (bp.TypeAttribute != null) { ErrorMessages.RTE0017_FluentContradict.Throw(type, "third party"); } return bp; } } } ================================================ FILE: Reinforced.Typings/Fluent/ConfigurationBuilderExtensions.cs ================================================ using System; using System.IO; using System.Reflection; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Fluent { /// /// Set of extensions for configuration builder /// public static class ConfigurationBuilderExtensions { /// /// Adds global reference to another typescript library /// /// Table configurator /// Full path to .d.ts or .ts file /// Fluent public static ConfigurationBuilder AddReference(this ConfigurationBuilder conf, string path) { conf.Context.Project.References.Add(new RtReference { Path = path }); return conf; } /// /// Adds import directive to file containing typing for current type /// This method is only used while splitting generated types to different files /// /// Configurator /// /// What we are importing from module. /// Everything that is placed after "import" keyword and before "from" or "= require(..)" /// Examples: /// - "import * as shape from './Shapes'" -> "* as shape" is target
/// - "import { Foo } from 'Bar'" -> "{ Foo }" is target
/// - "import { Bar2 as bar } from 'Baz'" -> "{ Bar2 as bar }" is target
/// If ImportTarget is null then side-effect import will be generated. /// /// /// Import source is everything that follows after "from" keyword. /// Please not the you do not have to specify quotes here! Quotes will be added automatically /// /// When true, import will be generated as "import ImportTarget = require('ImportSource')" public static ConfigurationBuilder AddImport(this ConfigurationBuilder conf, string target, string from, bool isRequire = false) { conf.Imports.Add(new RtImport() { Target = target, From = from, IsRequire = isRequire }); return conf; } /// /// Defines global type substitution. Substituted type will be strictly replaced with substitution during export /// /// /// Type to substitute /// Substitution for type /// Fluent public static ConfigurationBuilder Substitute(this ConfigurationBuilder builder, Type substitute, RtTypeName substitution) { builder.GlobalSubstitutions[substitute] = substitution; return builder; } /// /// Defines global generic type substitution. Substituted type will be strictly replaced with substitution during export /// /// /// Type to substitute /// Substitution for type /// Fluent public static ConfigurationBuilder SubstituteGeneric(this ConfigurationBuilder builder, Type genericType, Func substitutionFn) { if (!genericType._IsGenericTypeDefinition()) { if (!genericType._IsGenericType()) { throw new Exception(string.Format( "Type {0} does not appear to be generic type definition. Use MyType<> to define substitution", genericType.FullName)); } genericType = genericType.GetGenericTypeDefinition(); } builder.GenericSubstitutions[genericType] = substitutionFn; return builder; } /// /// Tries to find documentation .xml file for specified assembly and take it in account when generating documentaion /// /// Table configurator /// Assembly which documentation should be included /// Override XMLDOC file name if differs (please include .xml extension) /// Fluent public static ConfigurationBuilder TryLookupDocumentationForAssembly(this ConfigurationBuilder conf, Assembly assmbly, string documentationFileName = null) { if (!string.IsNullOrEmpty(documentationFileName) && Path.IsPathRooted(documentationFileName)) { conf.AdditionalDocumentationPathes.Add(documentationFileName); return conf; } var locationFilePath = Path.Combine( string.IsNullOrEmpty(assmbly.Location) ? string.Empty : Path.GetDirectoryName(assmbly.Location), string.IsNullOrEmpty(documentationFileName) ? Path.GetFileNameWithoutExtension(assmbly.Location) + ".xml" : documentationFileName); var codebaseFilePath = Path.Combine( Path.GetDirectoryName(assmbly.GetCodeBase()), string.IsNullOrEmpty(documentationFileName) ? Path.GetFileNameWithoutExtension(assmbly.CodeBase) + ".xml" : documentationFileName); if (File.Exists(locationFilePath)) conf.AdditionalDocumentationPathes.Add(locationFilePath); else if (File.Exists(codebaseFilePath)) conf.AdditionalDocumentationPathes.Add(codebaseFilePath); return conf; } private static string GetCodeBase(this Assembly asmbly) { if (string.IsNullOrEmpty(asmbly.CodeBase)) return string.Empty; return asmbly.CodeBase.Replace("file:///", string.Empty); } } } ================================================ FILE: Reinforced.Typings/Fluent/GlobalConfigurationBuilder.cs ================================================ using System; using Reinforced.Typings.ReferencesInspection; using Reinforced.Typings.Visitors; namespace Reinforced.Typings.Fluent { /// /// Global configuration builder /// public class GlobalConfigurationBuilder { internal GlobalConfigurationBuilder(GlobalParameters parameters) { Parameters = parameters; } internal GlobalParameters Parameters { get; private set; } } /// /// Set of extensions for global configuration /// public static class GlobalConfigurationExtensions { /// /// Configures global exporting parameters /// /// Conf builder /// Global configuration action public static void Global(this ConfigurationBuilder builder, Action config) { config(builder.GlobalBuilder); } /// /// Disables writing of "auto-generated warning" comment to each generated file. /// It meant the comment like "// This code was generated blah blah blah..." /// /// Conf builder /// Pass 'true' (default) to disable adding warning comment to target file. Pass 'false' to leave this label in place. public static GlobalConfigurationBuilder DontWriteWarningComment(this GlobalConfigurationBuilder builder, bool dontWrite = true) { builder.Parameters.WriteWarningComment = !dontWrite; return builder; } /// /// Changes indentation symbol (by default is \t). /// This ability is made by @jonsa's request - boring perfectionist /// /// Conf builder /// New indentation symbol public static GlobalConfigurationBuilder TabSymbol(this GlobalConfigurationBuilder builder, string symbol) { builder.Parameters.TabSymbol = symbol; return builder; } /// /// Changes line termination string. Default is . /// /// Conf builder /// String that used as the line terminator. public static GlobalConfigurationBuilder NewLine(this GlobalConfigurationBuilder builder, string newLine) { builder.Parameters.NewLine = newLine; return builder; } /// /// Specifies root namespace for hierarchical export. /// Helps to avoid creating redundant directories when hierarchical export. /// /// Conf builder /// Application root namespace public static GlobalConfigurationBuilder RootNamespace(this GlobalConfigurationBuilder builder, string rootNamespace) { builder.Parameters.RootNamespace = rootNamespace; return builder; } /// /// Use camelCase for methods naming /// /// Conf builder /// Pass 'true' to convert all MethodsNames to camelCase public static GlobalConfigurationBuilder CamelCaseForMethods(this GlobalConfigurationBuilder builder, bool cameCase = true) { builder.Parameters.CamelCaseForMethods = cameCase; return builder; } /// /// Use camelCase for properties naming /// /// Conf builder /// Pass 'true' to convert all MethodsNames to camelCase public static GlobalConfigurationBuilder CamelCaseForProperties(this GlobalConfigurationBuilder builder, bool cameCase = true) { builder.Parameters.CamelCaseForProperties = cameCase; return builder; } /// /// Enables documentation generator /// /// Conf builder /// Pass 'true' to generate JSDOC for exported types from XMLDOC public static GlobalConfigurationBuilder GenerateDocumentation(this GlobalConfigurationBuilder builder, bool generate = true) { builder.Parameters.GenerateDocumentation = generate; return builder; } /// /// Enables adaptation for TS modules system (--modules tsc.exe option) /// /// Conf builder /// True will enable usage of modules system and exports/imports /// True will automatically ignore namespaces while exporting types public static GlobalConfigurationBuilder UseModules(this GlobalConfigurationBuilder builder, bool useModules = true, bool discardNamespaces = true) { builder.Parameters.UseModules = useModules; builder.Parameters.DiscardNamespacesWhenUsingModules = discardNamespaces; return builder; } /// /// If true, export will be performed in .d.ts manner (only typings, declare module etc). /// Otherwise, export will be performed to regulat .ts file /// /// Conf builder /// Enables or disables option public static GlobalConfigurationBuilder ExportPureTypings(this GlobalConfigurationBuilder builder, bool typings = true) { builder.Parameters.ExportPureTypings = typings; return builder; } /// /// Sets rype of to be used to /// refilter/reorder references and imports while exporting files /// /// Type of references processor to be used /// Conf builder /// When false then disables usage of references processor public static GlobalConfigurationBuilder WithReferencesProcessor(this GlobalConfigurationBuilder builder, bool use = true) where T:ReferenceProcessorBase { builder.Parameters.ReferencesProcessorType = use ? typeof(T) : null; return builder; } /// /// Enables or disables exporting members reordering (aphabetical, constructors-fields-properties-methods). /// Warning! Enabling this option discards calls as well as "Order" member attributes property /// /// Conf builder /// True to reorder exported members alphabetically, false otherwise public static GlobalConfigurationBuilder ReorderMembers(this GlobalConfigurationBuilder builder, bool reorder = true) { builder.Parameters.ReorderMembers = reorder; return builder; } /// /// Sets override of type of AST visitor that will be used to write code to output. /// Warning! This option overrides configuration! /// /// Conf builder public static GlobalConfigurationBuilder UseVisitor(this GlobalConfigurationBuilder builder) where T:TextExportingVisitor { builder.Parameters.VisitorType = typeof(T); return builder; } /// /// Tells RT to make all nullable value-type properties optional automatically /// /// Conf builder /// True to export make all nullable-typed properties optional public static GlobalConfigurationBuilder AutoOptionalProperties(this GlobalConfigurationBuilder builder, bool autoOptional = true) { builder.Parameters.AutoOptionalProperties = autoOptional; return builder; } /// /// Makes RT to export unresolved types as 'unknown' instead of 'any' /// /// Conf builder /// True to export unresolved types as 'unknown', false to export as 'any' public static GlobalConfigurationBuilder UnresolvedToUnknown(this GlobalConfigurationBuilder builder, bool unresolvedToUnknown = false) { builder.Parameters.UnresolvedToUnknown = unresolvedToUnknown; return builder; } /// /// Makes RT automatically to turn methods returning Task into async ones /// /// Conf builder /// True to enable the feature public static GlobalConfigurationBuilder AutoAsync(this GlobalConfigurationBuilder builder, bool value = true) { builder.Parameters.AutoAsync = value; return builder; } //{ // bool strict = true) //public static GlobalConfigurationBuilder StrictNullChecks(this GlobalConfigurationBuilder builder, ///// Pass 'true' reveal all nullable types to "type | null" ///// Conf builder ///// ///// Enables strict null checks. Particularry, makes all exported nullable value-types of type "type | null" ///// // builder.Parameters.StrictNullChecks = strict; // return builder; //} } } ================================================ FILE: Reinforced.Typings/Fluent/InferringExtensions.cs ================================================ using System; using Reinforced.Typings.Ast.TypeNames; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Set of extensions for inline inferring /// public static class InferringExtensions { /// /// Overrides type resolver for member type /// /// /// Inferrable /// Type inferer /// Fluent public static ISupportsInferring InferType(this ISupportsInferring x, Func inferrer) { x.TypeInferers.StringResolver = inferrer; return x; } /// /// Overrides type resolver for member type /// /// /// Inferrable /// Type inferer /// Fluent public static ISupportsInferring InferType(this ISupportsInferring x, Func inferrer) { x.TypeInferers.TypenameResolver = inferrer; return x; } /// /// Overrides type resolver for member type /// /// /// Inferrable /// Type inferer /// Fluent public static ISupportsInferring InferType(this ISupportsInferring x, Func inferrer) { x.TypeInferers.StringSimpleResolver = inferrer; return x; } /// /// Overrides type resolver for member type /// /// /// Inferrable /// Type inferer /// Fluent public static ISupportsInferring InferType(this ISupportsInferring x, Func inferrer) { x.TypeInferers.TypenameSimpleResolver = inferrer; return x; } } } ================================================ FILE: Reinforced.Typings/Fluent/LambdaHelpers.cs ================================================ using System; using System.Linq.Expressions; using System.Reflection; using Reinforced.Typings.Exceptions; // ReSharper disable PossibleNullReferenceException namespace Reinforced.Typings.Fluent { /// /// Set of helper reflection methods /// internal static class LambdaHelpers { /// /// Parses supplied lambda expression and retrieves PropertyInfo from it /// /// T1 /// T2 /// Property Lambda expression /// PropertyInfo referenced by this expression public static PropertyInfo ParsePropertyLambda(Expression> lambda) { return ParsePropertyLambda((LambdaExpression)lambda); } /// /// Parses supplied lambda expression and retrieves PropertyInfo from it /// /// Property Lambda expression /// PropertyInfo referenced by this expression public static PropertyInfo ParsePropertyLambda(LambdaExpression lambda) { var mex = lambda.Body as MemberExpression; if (mex == null) ErrorMessages.RTE0010_PropertyLambdaExpected.Throw(lambda.ToString()); var pi = mex.Member as PropertyInfo; if (pi == null) ErrorMessages.RTE0010_PropertyLambdaExpected.Throw(lambda.ToString()); return pi; } /// /// Parses supplied lambda expression and retrieves PropertyInfo from it /// /// T1 /// T2 /// Property Lambda expression /// PropertyInfo referenced by this expression public static FieldInfo ParseFieldLambda(Expression> lambda) { return ParseFieldLambda((LambdaExpression)lambda); } /// /// Parses supplied lambda expression and retrieves PropertyInfo from it /// /// Property Lambda expression /// PropertyInfo referenced by this expression public static FieldInfo ParseFieldLambda(LambdaExpression lambda) { var mex = lambda.Body as MemberExpression; if (mex == null) ErrorMessages.RTE0011_FieldLambdaExpected.Throw(lambda.ToString()); var pi = mex.Member as FieldInfo; if (pi == null) ErrorMessages.RTE0011_FieldLambdaExpected.Throw(lambda.ToString()); return pi; } /// /// Parses supplied lambda expression and retrieves MethodInfo from it /// /// Method lambda expression /// MethodInfo referenced by this expression public static MethodInfo ParseMethodLambda(LambdaExpression lambda) { var mex = lambda.Body as MethodCallExpression; if (mex == null) ErrorMessages.RTE0008_FluentWithMethodError.Throw(); return mex.Method; } /// /// Parses supplied lambda expression and retrieves ConstructorInfo from it /// /// Constructor lambda expression ( => new Obejct(Ts.Parameter...)) /// Constructor referenced by this expression public static ConstructorInfo ParseConstructorLambda(LambdaExpression lambda) { var nex = lambda.Body as NewExpression; if (nex == null) ErrorMessages.RTE0012_NewExpressionLambdaExpected.Throw(); return nex.Constructor; } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberBuilders/MemberExportBuilder.EnumValue.cs ================================================ using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for enum value /// public class EnumValueExportBuilder { internal TypeBlueprint _containingTypeBlueprint; internal FieldInfo _member; /// Initializes a new instance of the class. internal EnumValueExportBuilder(TypeBlueprint containingTypeBlueprint, FieldInfo member) { _containingTypeBlueprint = containingTypeBlueprint; _member = member; } internal bool Ignore { get { return _containingTypeBlueprint.IsIgnored(_member); } set { if (value) _containingTypeBlueprint.Ignored.Add(_member); else if (_containingTypeBlueprint.Ignored.Contains(_member)) _containingTypeBlueprint.Ignored.Remove(_member); } } internal List Decorators { get { return _containingTypeBlueprint.DecoratorsListFor(_member); } } internal TsValueAttribute Attr { get { return _containingTypeBlueprint.ForEnumValue(_member,true); } } /// /// Gets value being configured /// public FieldInfo Member { get { return _member; } } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberBuilders/MemberExportBuilder.Field.cs ================================================ using System.Reflection; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for a field /// public class FieldExportBuilder : PropertyExportBuilder { /// Initializes a new instance of the class. internal FieldExportBuilder(TypeBlueprint containingTypeBlueprint, MemberInfo member) : base(containingTypeBlueprint, member) { } /// /// Gets property being configured /// public new FieldInfo Member { get { return (FieldInfo) _member; } } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberBuilders/MemberExportBuilder.Method.cs ================================================ using System.Reflection; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for method /// public class MethodExportBuilder : MemberExportBuilder, ISupportsInferring { /// Initializes a new instance of the class. internal MethodExportBuilder(TypeBlueprint containingTypeBlueprint, MemberInfo member) : base(containingTypeBlueprint, member) { } internal TsFunctionAttribute Attr { get { return (TsFunctionAttribute)_forMember; } } /// /// Gets method being configured /// public MethodInfo Member { get { return (MethodInfo)_member; } } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return Attr.TypeInferers; } } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberBuilders/MemberExportBuilder.Parameter.cs ================================================ using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for method parameter /// public class ParameterExportBuilder : MemberExportBuilder, ISupportsInferring { private readonly ParameterInfo _parMember; internal ParameterExportBuilder(TypeBlueprint containingTypeBlueprint, ParameterInfo member) : base(containingTypeBlueprint, null) { _parMember = member; _forMember = containingTypeBlueprint.ForMember(member, true); } internal TsParameterAttribute Attr { get { return (TsParameterAttribute)_forMember; } } internal override bool IsIgnored { get { return _containingTypeBlueprint.IsIgnored(_parMember); } set { if (value) _containingTypeBlueprint.Ignored.Add(_parMember); else if (_containingTypeBlueprint.Ignored.Contains(_parMember)) _containingTypeBlueprint.Ignored.Remove(_parMember); } } internal override List Decorators { get { return _containingTypeBlueprint.DecoratorsListFor(_parMember); } } /// /// Gets parameter being configured /// public ParameterInfo Member { get { return _parMember; } } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return Attr.TypeInferers; } } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberBuilders/MemberExportBuilder.Property.cs ================================================ using System.Reflection; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for property or field /// public class PropertyExportBuilder : MemberExportBuilder, ISupportsInferring { /// Initializes a new instance of the class. internal PropertyExportBuilder(TypeBlueprint containingTypeBlueprint, MemberInfo member) : base(containingTypeBlueprint, member) { } internal TsPropertyAttribute Attr { get { return (TsPropertyAttribute)_forMember; } } /// /// Gets property being configured /// public PropertyInfo Member { get { return (PropertyInfo) _member; } } /// /// Type inferers set instance /// public InlineTypeInferers TypeInferers { get { return Attr.TypeInferers; } } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberBuilders/MemberExportBuilder.cs ================================================ using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for Type Member /// public class MemberExportBuilder { internal TypeBlueprint _containingTypeBlueprint; internal readonly MemberInfo _member; internal TsTypedMemberAttributeBase _forMember; /// Initializes a new instance of the class. internal MemberExportBuilder(TypeBlueprint containingTypeBlueprint, MemberInfo member) { _containingTypeBlueprint = containingTypeBlueprint; if (member != null) { _member = member; _forMember = containingTypeBlueprint.ForMember(member,true); } } internal virtual bool IsIgnored { get { return _containingTypeBlueprint.IsIgnored(_member); } set { if (value) _containingTypeBlueprint.Ignored.Add(_member); else if (_containingTypeBlueprint.Ignored.Contains(_member)) _containingTypeBlueprint.Ignored.Remove(_member); } } internal virtual List Decorators { get { return _containingTypeBlueprint.DecoratorsListFor(_member); } } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberExtensions/MemberExportExtensions.EnumValue.cs ================================================ using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class MemberExportExtensions { /// /// Adds decorator to member /// /// Member configurator /// Decorator to add (everything that must follow after "@") /// Order of appearence /// Fluent public static EnumValueExportBuilder Decorator(this EnumValueExportBuilder conf, string decorator, double order = 0) { conf.Decorators.Add(new TsDecoratorAttribute(decorator, order)); return conf; } /// /// Overrides name of exported type /// /// Configuration /// Custom name to be used public static EnumValueExportBuilder OverrideName(this EnumValueExportBuilder conf, string name) { conf.Attr.Name = name; return conf; } /// /// Ignores specified mambers during exporting /// public static EnumValueExportBuilder Ignore(this EnumValueExportBuilder conf, bool ignore = true) { conf.Ignore = ignore; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberExtensions/MemberExportExtensions.Method.cs ================================================ using System; using System.Reflection; using Reinforced.Typings.Generators; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class MemberExportExtensions { /// /// Specifies code generator for member /// public static MethodExportBuilder WithCodeGenerator(this MethodExportBuilder conf) where T : ITsCodeGenerator { conf.Attr.CodeGeneratorType = typeof(T); return conf; } /// /// Sets order this membter will be written to output file in /// /// Configurator /// Order of member /// Fluent public static MethodExportBuilder Order(this MethodExportBuilder conf, double order) { conf.Attr.Order = order; return conf; } /// /// Sets function body (works in case of class export) that will be converted to RtRaw and inserted as code block /// /// /// Function code /// public static MethodExportBuilder Implement(this MethodExportBuilder builder, string functionCode) { builder.Attr.Implementation = functionCode; return builder; } /// /// Overrides member type name on export with textual string. /// Beware of using this setting because specified type may not present in your TypeScript code and /// this will lead to TypeScript compilation errors. /// Actually this method does the same as .Type call. Just for your convinence /// /// Configurator /// TS-friendly type name /// public static MethodExportBuilder Returns(this MethodExportBuilder conf, string typeName) { conf.Attr.Type = typeName; return conf; } /// /// Overrides member type on export with strong type. /// Feel free to use delegates here. It is very comfortable instead of regular TS functions syntax. /// Actually this method does the same as .Type call. Just for your convinence /// /// Configurator public static MethodExportBuilder Returns(this MethodExportBuilder conf) { conf.Attr.StrongType = typeof(T); return conf; } /// /// Overrides member type on export with strong type. /// Feel free to use delegates here. It is very comfortable instead of regular TS functions syntax. /// Actually this method does the same as .Type call. Just for your convinence /// /// Configurator /// Type to override with /// public static MethodExportBuilder Returns(this MethodExportBuilder conf, Type type) { conf.Attr.StrongType = type; return conf; } /// /// Specifies whether exported method must be considered async. /// If this value is specified explicitly then exported method will be considered async based on /// this value. If the value is null then RT will automatically decide whether method must be async /// based on its return type (Task`N). /// /// Configurator /// True to make method async, false otherwise /// public static MethodExportBuilder ForceAsync(this MethodExportBuilder conf, bool? isAsync) { conf.Attr.ForceAsync = isAsync; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberExtensions/MemberExportExtensions.Parameter.cs ================================================ using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Generators; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class MemberExportExtensions { /// /// Sets parameter default value. /// /// Configuration /// Default value for parameter public static ParameterExportBuilder DefaultValue(this ParameterExportBuilder conf, object value) { conf.Attr.DefaultValue = value; return conf; } /// /// Specifies code generator for member /// public static ParameterExportBuilder WithCodeGenerator(this ParameterExportBuilder conf) where T : TsCodeGeneratorBase { conf.Attr.CodeGeneratorType = typeof(T); return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberExtensions/MemberExportExtensions.Property.cs ================================================ using System; using System.Reflection; using Reinforced.Typings.Generators; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class MemberExportExtensions { /// /// Specifies code generator for member /// public static PropertyExportBuilder WithCodeGenerator(this PropertyExportBuilder conf) where T : ITsCodeGenerator { conf.Attr.CodeGeneratorType = typeof(T); return conf; } /// /// Specifies code generator for member /// public static FieldExportBuilder WithFieldCodeGenerator(this FieldExportBuilder conf) where T : ITsCodeGenerator { conf.Attr.CodeGeneratorType = typeof(T); return conf; } /// /// Sets order this membter will be written to output file in /// /// Configurator /// Order of member /// Fluent public static PropertyExportBuilder Order(this PropertyExportBuilder conf, double order) { conf.Attr.Order = order; return conf; } /// /// Forces property to be a nullable. /// When set to true then property will be generated as [property]? : [type] with /// forcibly added question mark denoting nullable field. /// /// Configuration /// Force nullable or not public static PropertyExportBuilder ForceNullable(this PropertyExportBuilder conf, bool? force = true) { conf.Attr.NilForceNullable = force; return conf; } /// /// Forces static property to be exported with constant initializer. /// Works only on numeric/boolean/string/null properties /// /// Configuration /// Switches constant export behavior public static PropertyExportBuilder Constant(this PropertyExportBuilder conf, bool constant = true) { conf.Attr.Constant = constant; return conf; } /// /// Specifies initialization expression evaluator for property /// /// Configuration /// /// Initialization expression evaluator. Returns TypeScript code that will be used as initialization expression for /// particular property /// public static PropertyExportBuilder InitializeWith(this PropertyExportBuilder conf, Func evaluator) { conf.Attr.InitializerEvaluator = evaluator; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/MemberExtensions/MemberExportExtensions.cs ================================================ using System; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Extensions for members export configuration /// public static partial class MemberExportExtensions { /// /// Forces member name to be camelCase /// /// Configuration public static T CamelCase(this T conf) where T : MemberExportBuilder { conf._forMember.ShouldBeCamelCased = true; return conf; } /// /// Forces member name to be PascalCase /// /// Configuration public static T PascalCase(this T conf) where T : MemberExportBuilder { conf._forMember.ShouldBePascalCased = true; return conf; } /// /// Adds decorator to member /// /// Member configurator /// Decorator to add (everything that must follow after "@") /// Order of appearence /// Fluent public static MemberExportBuilder Decorator(this MemberExportBuilder conf, string decorator, double order = 0) { conf.Decorators.Add(new TsDecoratorAttribute(decorator, order)); return conf; } /// /// Overrides name of exported type /// /// Configuration /// Custom name to be used public static MemberExportBuilder OverrideName(this MemberExportBuilder conf, string name) { conf._forMember.Name = name; return conf; } /// /// Overrides member type name on export with textual string. /// Beware of using this setting because specified type may not present in your TypeScript code and /// this will lead to TypeScript compilation errors /// /// Configurator /// TS-friendly type name /// public static MemberExportBuilder Type(this MemberExportBuilder conf, string typeName) { conf._forMember.Type = typeName; return conf; } /// /// Overrides member type on export with strong type. /// Feel free to use delegates here. It is very comfortable instead of regular TS functions syntax. /// /// Configurator public static MemberExportBuilder Type(this MemberExportBuilder conf) { conf._forMember.StrongType = typeof(T); return conf; } /// /// Overrides member type on export with strong type. /// Feel free to use delegates here. It is very comfortable instead of regular TS functions syntax. /// /// Configurator /// Type to override with /// public static MemberExportBuilder Type(this MemberExportBuilder conf, Type type) { conf._forMember.StrongType = type; return conf; } /// /// Ignores specified members during exporting /// public static MemberExportBuilder Ignore(this MemberExportBuilder conf) { conf.IsIgnored = true; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/Parameter.cs ================================================ using System; using System.Linq.Expressions; using System.Reflection; namespace Reinforced.Typings.Fluent { /// /// Shortcut for method parameters mocking /// public class Ts { internal static MethodInfo ParametrizedParameterMethod; static Ts() { Expression> lambda = () => Parameter(a => a.Ignore()); ParametrizedParameterMethod = LambdaHelpers.ParseMethodLambda(lambda).GetGenericMethodDefinition(); } /// /// Parameter mock for specified type /// /// Parameter type /// Mock public static T Parameter() { return default(T); } /// /// Parameter mock with parameter configuration /// /// Parameter type /// Fluent parameter configuration /// Mock public static T Parameter(Action configuration) { return default(T); } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.Class.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for class /// public class ClassExportBuilder : ClassOrInterfaceExportBuilder { internal ClassExportBuilder(TypeBlueprint blueprint) : base(blueprint) { if (Blueprint.TypeAttribute == null) Blueprint.TypeAttribute = new TsClassAttribute { AutoExportConstructors = false, AutoExportFields = false, AutoExportProperties = false, AutoExportMethods = false }; } internal TsClassAttribute Attr { get { return (TsClassAttribute)Blueprint.TypeAttribute; } } } /// /// Set of extensions for type export configuration /// public static partial class TypeConfigurationBuilderExtensions { /// /// Includes specified type to resulting typing exported as TypeScript class /// /// Type to include /// Configuration builder /// Fluent public static ClassExportBuilder ExportAsClass(this ConfigurationBuilder builder) { var bp = builder.GetCheckedBlueprint(typeof(T)); var conf = builder.TypeExportBuilders.GetOrCreate(typeof(T), () => new ClassExportBuilder(bp)) as ClassExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(typeof(T), "class"); } return conf; } /// /// Includes specified types to resulting typing exported as TypeScript classes /// /// Configuration builder /// Types to include /// Configuration to be applied to each type /// Fluent public static void ExportAsClasses(this ConfigurationBuilder builder, IEnumerable types, Action configuration = null) { foreach (var type in types) { var untypedConf = builder.TypeExportBuilders.GetOrCreate(type, () => { var bp = builder.GetCheckedBlueprint(type); if (!type._IsGenericTypeDefinition()) { var t = typeof(ClassExportBuilder<>).MakeGenericType(type); return (ClassExportBuilder)t.InstanceInternal(bp); } return new ClassExportBuilder(bp); }); var conf = untypedConf as ClassExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(type, "class"); } if (configuration != null) { try { configuration(conf); } catch (Exception ex) { ErrorMessages.RTE0006_FluentSingleError.Throw(ex.Message, "type", type.FullName); } } } } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.ClassOrInterface.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for class or interface /// public abstract class ClassOrInterfaceExportBuilder : TypeExportBuilder { internal ClassOrInterfaceExportBuilder(TypeBlueprint blueprint) : base(blueprint) { } /// /// Include specified methods to resulting typing. /// /// Methods to include /// Configuration to be applied to each method /// Fluent public void WithMethods(IEnumerable methods, Action configuration = null) { ApplyMethodsConfiguration(methods, configuration); } /// /// Include specified properties to resulting typing /// /// Properties to include /// Configuration to be applied to each property /// Fluent public void WithProperties(IEnumerable properties, Action configuration = null) { ApplyMembersConfiguration(properties, configuration); } /// /// Include specified fields to resulting typing /// /// Fields to include /// Configuration to be applied to each field /// Fluent public void WithFields(IEnumerable fields, Action configuration = null) { ApplyMembersConfiguration(fields, configuration); } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.Class`1.cs ================================================ using System; using System.Linq.Expressions; namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for class (generic) /// public class ClassExportBuilder : ClassExportBuilder, ITypedExportBuilder { internal ClassExportBuilder(TypeBlueprint blueprint) : base(blueprint) { } /// /// Include specified field to resulting typing /// /// Field to include /// Configuration to be applied to selected field /// Fluent public ClassExportBuilder WithField(Expression> field, Action configuration) { ApplyMembersConfiguration(new[] { LambdaHelpers.ParseFieldLambda(field) }, configuration); return this; } /// /// Include specified method to resulting typing. /// User to mock up method parameters or specify configuration for perticular method /// parameter /// /// Method to include /// configuration to be applied to method /// Fluent public ClassExportBuilder WithMethod(Expression> method, Action configuration) { WithMethods(new[] { LambdaHelpers.ParseMethodLambda(method) }, configuration); ExtractParameters(method); return this; } /// /// Include specified method to resulting typing. /// User to mock up method parameters or specify configuration for perticular method /// parameter /// /// Method to include /// configuration to be applied to method /// Fluent public ClassExportBuilder WithMethod(Expression> method, Action configuration) { WithMethods(new[] { LambdaHelpers.ParseMethodLambda(method) }, configuration); ExtractParameters(method); return this; } /// /// Include specified property to resulting typing /// /// Property to include /// Configuration to be applied to selected property /// Fluent public ClassExportBuilder WithProperty(Expression> property, Action configuration) { WithProperties(new[] { LambdaHelpers.ParsePropertyLambda(property) }, configuration); return this; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.Enum.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for enum /// public class EnumExportBuilder : TypeExportBuilder { internal EnumExportBuilder(TypeBlueprint blueprint) : base(blueprint) { if (Blueprint.TypeAttribute == null) Blueprint.TypeAttribute = new TsEnumAttribute(); } internal TsEnumAttribute Attr { get { return (TsEnumAttribute)Blueprint.TypeAttribute; } } /// /// Retrieves configuration builder for particular enumeration value /// /// String enum property name /// Configuration builder public EnumValueExportBuilder Value(string propertyName) { var field = Blueprint.Type._GetField(propertyName); var c = new EnumValueExportBuilder(Blueprint, field); return c; } } /// /// Fluent export configuration builder for enum (generic) /// public class EnumExportBuilder : EnumExportBuilder where T : struct { internal EnumExportBuilder(TypeBlueprint blueprint) : base(blueprint) { } /// /// Retrieves configuration builder for particular enumeration value /// /// Enum value /// Configuration builder public EnumValueExportBuilder Value(T value) { var n = Enum.GetName(typeof(T), value); var field = typeof(T)._GetField(n); var c = new EnumValueExportBuilder(Blueprint, field); return c; } /// /// Configures export of particular enumeration value /// /// Enum value /// Enum value export configuration /// Configuration builder public EnumExportBuilder Value(T value, Action valueConf) { var n = Enum.GetName(typeof(T), value); var field = typeof(T)._GetField(n); var c = new EnumValueExportBuilder(Blueprint, field); valueConf(c); return this; } } public static partial class TypeConfigurationBuilderExtensions { /// /// Configures export of particular enumeration value /// /// Configuration builder /// String enum property name /// Enum value export configuration /// Configuration builder public static T Value(this T conf, string propertyName, Action valueConf) where T : EnumExportBuilder { var ve = conf.Value(propertyName); valueConf(ve); return conf; } /// /// Overrides enum value's string initializer. Please escape quotes manually. /// /// /// /// public static EnumValueExportBuilder Initializer(this EnumValueExportBuilder conf, string initializer) { conf.Attr.Initializer = initializer; return conf; } /// /// Includes specified type to resulting typing exported as TypeScript enumeration /// /// Type to include /// Configuration builder /// Fluent public static EnumExportBuilder ExportAsEnum(this ConfigurationBuilder builder) where T : struct { var bp = builder.GetCheckedBlueprint(typeof(T)); var conf = builder.TypeExportBuilders.GetOrCreate(typeof(T), () => new EnumExportBuilder(bp)) as EnumExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(typeof(T), "enum"); } return conf; } /// /// Includes specified types to resulting typing exported as TypeScript enumerations /// /// Configuration builder /// Types to include /// Configuration to be applied to each type /// Fluent public static void ExportAsEnums(this ConfigurationBuilder builder, IEnumerable types, Action configuration = null) { foreach (var type in types) { var untypedConf = builder.TypeExportBuilders.GetOrCreate(type, () => { var bp = builder.GetCheckedBlueprint(type); var t = typeof(EnumExportBuilder<>).MakeGenericType(type); return (EnumExportBuilder)t.InstanceInternal(bp); }); var conf = untypedConf as EnumExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(type, "enum"); } if (configuration != null) { try { configuration(conf); } catch (Exception ex) { ErrorMessages.RTE0006_FluentSingleError.Throw(ex.Message, "enum", type.FullName); } } } } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.Interface.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for interface /// public class InterfaceExportBuilder : ClassOrInterfaceExportBuilder { internal InterfaceExportBuilder(TypeBlueprint blueprint) : base(blueprint) { if (Blueprint.TypeAttribute == null) Blueprint.TypeAttribute = new TsInterfaceAttribute { AutoExportProperties = false, AutoExportMethods = false }; } internal TsInterfaceAttribute Attr { get { return (TsInterfaceAttribute)Blueprint.TypeAttribute; } } } public static partial class TypeConfigurationBuilderExtensions { /// /// Includes specified type to resulting typing exported as TypeScript class /// /// Type to include /// Configuration builder /// Fluent public static InterfaceExportBuilder ExportAsInterface(this ConfigurationBuilder builder) { var bp = builder.GetCheckedBlueprint(typeof(T)); var conf = builder.TypeExportBuilders.GetOrCreate(typeof(T), () => new InterfaceExportBuilder(bp)) as InterfaceExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(typeof(T), "interface"); } return conf; } /// /// Includes specified types to resulting typing exported as TypeScript classes /// /// Configuration builder /// Types to include /// Configuration to be applied to each type /// Fluent public static void ExportAsInterfaces(this ConfigurationBuilder builder, IEnumerable types, Action configuration = null) { foreach (var type in types) { var untypedConf = builder.TypeExportBuilders.GetOrCreate(type, () => { var bp = builder.GetCheckedBlueprint(type); if (!type._IsGenericTypeDefinition()) { var t = typeof(InterfaceExportBuilder<>).MakeGenericType(type); return (InterfaceExportBuilder)t.InstanceInternal(bp); } return new InterfaceExportBuilder(bp); }); var conf = untypedConf as InterfaceExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(type, "interface"); } if (configuration != null) { try { configuration(conf); } catch (Exception ex) { ErrorMessages.RTE0006_FluentSingleError.Throw(ex.Message, "type", type.FullName); } } } } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.Interface`1.cs ================================================ using System; using System.Linq.Expressions; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for interface (generic) /// public class InterfaceExportBuilder : InterfaceExportBuilder, ITypedExportBuilder { internal InterfaceExportBuilder(TypeBlueprint blueprint) : base(blueprint) { } /// /// Include specified field to resulting typing /// /// Field to include /// Configuration to be applied to selected field /// Fluent public InterfaceExportBuilder WithField(Expression> field, Action configuration) { ApplyMembersConfiguration(new[] { LambdaHelpers.ParseFieldLambda(field) }, configuration); return this; } /// /// Include specified method to resulting typing. /// User to mock up method parameters or specify configuration for perticular method /// parameter /// /// Method to include /// configuration to be applied to method /// Fluent public InterfaceExportBuilder WithMethod(Expression> method, Action configuration) { this.WithMethods(new[] { LambdaHelpers.ParseMethodLambda(method) }, configuration); ExtractParameters(method); return this; } /// /// Include specified method to resulting typing. /// User to mock up method parameters or specify configuration for perticular method /// parameter /// /// Method to include /// configuration to be applied to method /// Fluent public InterfaceExportBuilder WithMethod(Expression> method, Action configuration) { this.WithMethods(new[] { LambdaHelpers.ParseMethodLambda(method) }, configuration); ExtractParameters(method); return this; } /// /// Include specified property to resulting typing /// /// Property to include /// Configuration to be applied to selected property /// Fluent public InterfaceExportBuilder WithProperty(Expression> property, Action configuration) { WithProperties(new[] { LambdaHelpers.ParsePropertyLambda(property) }, configuration); return this; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.ThirdParty.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for class /// public class ThirdPartyExportBuilder { internal TypeBlueprint Blueprint { get; private set; } internal ThirdPartyExportBuilder(TypeBlueprint blueprint) { Blueprint = blueprint; if (blueprint.ThirdParty == null) { blueprint.ThirdParty = new TsThirdPartyAttribute(Type.FullName); } } /// /// Gets type that is being configured for export /// public Type Type { get { return Blueprint.Type; } } internal TsThirdPartyAttribute Attr { get { return Blueprint.ThirdParty; } } } /// /// Set of extensions for type export configuration /// public static partial class TypeConfigurationBuilderExtensions { /// /// Makes RT to treat specified type as type from third-party library /// /// Type to include /// Configuration builder /// Fluent public static ThirdPartyExportBuilder ExportAsThirdParty(this ConfigurationBuilder builder) { var bp = builder.GetCheckedThirdPartyBlueprint(typeof(T)); if (builder.TypeExportBuilders.ContainsKey(typeof(T))) { ErrorMessages.RTE0017_FluentContradict.Throw(typeof(T), "third party"); } var conf = builder.ThirdPartyBuilders.GetOrCreate(typeof(T), () => new ThirdPartyExportBuilder(bp)) as ThirdPartyExportBuilder; if (conf == null) { ErrorMessages.RTE0017_FluentContradict.Throw(typeof(T), "third party"); } return conf; } /// /// Makes RT to treat specified types as types from third-party library /// /// Configuration builder /// Types to include /// Configuration to be applied to each type /// Fluent public static void ExportAsThirdParty(this ConfigurationBuilder builder, IEnumerable types, Action configuration = null) { foreach (var type in types) { if (builder.TypeExportBuilders.ContainsKey(type)) { ErrorMessages.RTE0017_FluentContradict.Throw(type, "third party"); } var conf = builder.ThirdPartyBuilders.GetOrCreate(type, () => { var bp = builder.GetCheckedThirdPartyBlueprint(type); if (!type._IsGenericTypeDefinition()) { var t = typeof(ThirdPartyExportBuilder<>).MakeGenericType(type); return (ThirdPartyExportBuilder)t.InstanceInternal(bp); } return new ThirdPartyExportBuilder(bp); }); if (configuration != null) { try { configuration(conf); } catch (Exception ex) { ErrorMessages.RTE0006_FluentSingleError.Throw(ex.Message, "type", type.FullName); } } } } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.ThirdParty`1.cs ================================================ using System; using System.Linq.Expressions; namespace Reinforced.Typings.Fluent { /// /// Fluent export configuration builder for class (generic) /// public class ThirdPartyExportBuilder : ThirdPartyExportBuilder { internal ThirdPartyExportBuilder(TypeBlueprint blueprint) : base(blueprint) { } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeBuilders/TypeExportBuilder.cs ================================================ using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace // ReSharper disable UnusedTypeParameter // ReSharper disable PossibleNullReferenceException #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member namespace Reinforced.Typings.Fluent { /// /// Generic fluent configuration builder /// public interface ITypedExportBuilder { } /// /// Fluent export configuration builder for type /// public abstract class TypeExportBuilder { internal TypeBlueprint Blueprint { get; private set; } internal TypeExportBuilder(TypeBlueprint blueprint) { Blueprint = blueprint; blueprint.IsExportedExplicitly = true; } /// /// Gets type that is being configured for export /// public Type Type { get { return Blueprint.Type; } } protected internal void ApplyMembersConfiguration(IEnumerable members, Action configuration = null) where T : MemberExportBuilder { Blueprint.NotifyFlattenTouched(); foreach (var member in members) { var conf = (T)typeof(T).InstanceInternal(Blueprint, member); if (configuration == null) continue; try { configuration(conf); } catch (Exception ex) { ErrorMessages.RTE0006_FluentSingleError.Throw(ex.Message, "property", string.Format("{0}.{1}", member.DeclaringType.FullName, member.Name)); } } } protected internal void ApplyMethodsConfiguration(IEnumerable methds, Action configuration = null) { Blueprint.NotifyFlattenTouched(); foreach (var methodInfo in methds) { var conf = new MethodExportBuilder(Blueprint, methodInfo); if (configuration == null) continue; try { configuration(conf); } catch (Exception ex) { ErrorMessages.RTE0006_FluentSingleError.Throw(ex.Message, "method", string.Format("{0}.{1}(...)", methodInfo.DeclaringType.FullName, methodInfo.Name)); } } } internal void ExtractParameters(LambdaExpression methodLambda) { var mex = methodLambda.Body as MethodCallExpression; if (mex == null) ErrorMessages.RTE0008_FluentWithMethodError.Throw(); var mi = mex.Method; var methodParameters = mi.GetParameters(); if (methodParameters.Length == 0) return; var i = 0; foreach (var expression in mex.Arguments) { var pi = methodParameters[i]; i++; var call = expression as MethodCallExpression; if (call != null) { if (call.Method.IsGenericMethod && call.Method.GetGenericMethodDefinition() == Ts.ParametrizedParameterMethod) { var pcb = new ParameterExportBuilder(Blueprint, pi); var parsed = false; var arg = call.Arguments[0] as LambdaExpression; if (arg != null) { var delg = arg.Compile(); delg.DynamicInvoke(pcb); parsed = true; } var uarg = call.Arguments[0] as UnaryExpression; // convert expression if (uarg != null) { var operand = uarg.Operand as MethodCallExpression; if (operand != null) { var actionArg = operand.Object as ConstantExpression; if (actionArg != null) { var value = actionArg.Value as MethodInfo; if (value != null) { var param = Expression.Parameter(typeof(ParameterExportBuilder)); var newCall = Expression.Call(value, param); var newLambda = Expression.Lambda(newCall, param); var delg = newLambda.Compile(); delg.DynamicInvoke(pcb); parsed = true; } } } if (!parsed) ErrorMessages.RTE0009_FluentWithMethodCouldNotParse.Throw(call.Arguments[0]); } } } } } } } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.All.NamesAndNamespaces.cs ================================================ // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { /// /// Set of extensions for types exporting configuration /// public static partial class TypeExportExtensions { /// /// Overrides name of exported type /// /// Configuration /// Custom name to be used public static TypeExportBuilder OverrideName(this TypeExportBuilder conf, string name) { conf.Blueprint.TypeAttribute.Name = name; return conf; } /// /// Configures exporter do not to export member to corresponding namespace /// public static T DontIncludeToNamespace(this T conf, bool include = false) where T : TypeExportBuilder { conf.Blueprint.TypeAttribute.IncludeNamespace = include; return conf; } /// /// Configures exporter to export type to specified namespace /// /// Configuration /// Namespace name public static T OverrideNamespace(this T conf, string nameSpace) where T : TypeExportBuilder { conf.Blueprint.TypeAttribute.Namespace = nameSpace; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.All.ReferencesAndImports.cs ================================================ using System; using Reinforced.Typings.Attributes; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Adds reference directive to file containing typing for current type /// This method is only used while splitting generated types to different files /// /// Configurator /// Path to referenced file public static T AddReference(this T configuration, string referenceFile) where T : TypeExportBuilder { configuration.Blueprint.References.Add(new TsAddTypeReferenceAttribute(referenceFile)); return configuration; } /// /// Adds reference directive to file containing typing for current type /// This method is only used while splitting generated types to different files /// /// Configurator /// Another generated type that should be referenced public static T AddReference(this T configuration, Type referencedType) where T : TypeExportBuilder { configuration.Blueprint.References.Add(new TsAddTypeReferenceAttribute(referencedType)); return configuration; } /// /// Adds import directive to file containing typing for current type /// This method is only used while splitting generated types to different files /// /// Configurator /// /// What we are importing from module. /// Everything that is placed after "import" keyword and before "from" or "= require(..)" /// Examples: /// - "import * as shape from './Shapes'" -> "* as shape" is target
/// - "import { Foo } from 'Bar'" -> "{ Foo }" is target
/// - "import { Bar2 as bar } from 'Baz'" -> "{ Bar2 as bar }" is target
/// If ImportTarget is null then side-effect import will be generated. /// /// /// Import source is everything that follows after "from" keyword. /// Please not the you do not have to specify quotes here! Quotes will be added automatically /// /// When true, import will be generated as "import ImportTarget = require('ImportSource')" public static T AddImport(this T conf, string target, string from, bool isRequire = false) where T : TypeExportBuilder { conf.Blueprint.Imports.Add(new TsAddTypeImportAttribute(target, @from, isRequire)); return conf; } /// /// Overrides target file name where specified name will be exported. /// This option will only be processed when RtDivideTypesAmongFiles is true. /// /// Configurator /// Target file path override. Related to RtTargetDirectory public static T ExportTo(this T configuration, string fileName) where T : TypeExportBuilder { configuration.Blueprint.PathToFile = fileName; return configuration; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.All.Substitutions.cs ================================================ using System; using Reinforced.Typings.Ast.TypeNames; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Defines local type substitution that will work only when exporting current class. /// Substituted type will be strictly replaced with substitution during export but this option will take effect only when /// exporting currently configurable type /// /// /// Type to substitute /// Substitution for type /// Fluent public static T Substitute(this T builder, Type substitute, RtTypeName substitution) where T : TypeExportBuilder { builder.Blueprint.Substitutions[substitute] = substitution; return builder; } /// /// Defines local generic type substitution that will work only when exporting current class. /// Substituted type will be strictly replaced with substitution during export but this option will take effect only when /// exporting currently configurable type /// /// /// Type to substitute /// Substitution for type /// Fluent public static T SubstituteGeneric(this T builder, Type genericType, Func substitutionFn) where T : TypeExportBuilder { if (!genericType._IsGenericTypeDefinition()) { if (!genericType._IsGenericType()) { throw new Exception(string.Format( "Type {0} does not appear to be generic type definition. Use typeof(MyType<>) to define generic substitution", genericType.FullName)); } genericType = genericType.GetGenericTypeDefinition(); } builder.Blueprint.GenericSubstitutions[genericType] = substitutionFn; return builder; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.All.ThirdParty.cs ================================================ using Reinforced.Typings.Ast.Dependency; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Overrides name of third-party type. Use full-qualified name. /// /// /// Full-qualified name of third-party type /// public static T WithName(this T builder, string fullQualifiedName) where T : ThirdPartyExportBuilder { builder.Blueprint.ThirdParty.Name = fullQualifiedName; return builder; } /// /// Specifies set of references that third-party type will add to each file it is being used in /// /// /// Set of references /// Fluent public static T References(this T builder, params RtReference[] references) where T : ThirdPartyExportBuilder { if (references != null) builder.Blueprint.ThirdPartyReferences.AddRange(references); return builder; } /// /// Specifies set of imports that third-party type will add to each file it is being used in /// /// /// Set of imports /// Fluent public static T Imports(this T builder, params RtImport[] imports) where T : ThirdPartyExportBuilder { if (imports != null) builder.Blueprint.ThirdPartyImports.AddRange(imports); return builder; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.Class.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Generators; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Specifies code generator for member /// public static ClassExportBuilder WithCodeGenerator(this ClassExportBuilder conf) where T : ITsCodeGenerator { conf.Attr.CodeGeneratorType = typeof(T); return conf; } /// /// Configures class to be exported as abstract or not. /// Pass null value to identify automatically /// public static T Abstract(this T conf, bool? isAbstract = true) where T : ClassExportBuilder { conf.Attr.IsAbstract = isAbstract; return conf; } /// /// Configures class to export constructor /// If constructor body is not specified, then default body will be generated. /// Default body is empty if there are no inheritance. /// If there is inheritance then RT will try to generate optimal super() call /// that can be controlled by /// /// /// /// When true, constructor will be exported /// Optional constructor body implementation /// public static T WithConstructor(this T conf, RtRaw constructorBody = null, bool exportConstructors = true) where T : ClassExportBuilder { conf.Attr.AutoExportConstructors = exportConstructors; conf.Blueprint.ConstructorBody = constructorBody; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.Enum.cs ================================================ using System; using Reinforced.Typings.Generators; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Specifies code generator for member /// public static EnumExportBuilder WithCodeGenerator(this EnumExportBuilder conf) where T : ITsCodeGenerator { conf.Attr.CodeGeneratorType = typeof(T); return conf; } /// /// Turns enum to constant enum /// /// /// Enum configurator /// When true, "const enum" will be generated. Regular enum otherwise /// Fluent public static T Const(this T conf, bool isConst = true) where T : EnumExportBuilder { conf.Attr.IsConst = isConst; return conf; } /// /// Makes enum to use string initializer for its values (TypeScript 2.4) /// /// /// Enum configurator /// When true, enum values will be exported with string initializers /// Fluent public static T UseString(this T conf, bool useString = true) where T : EnumExportBuilder { conf.Attr.UseString = useString; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.Interface.cs ================================================ using System; using Reinforced.Typings.Generators; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Specifies code generator for member /// public static InterfaceExportBuilder WithCodeGenerator(this InterfaceExportBuilder conf) where T : ITsCodeGenerator { conf.Attr.CodeGeneratorType = typeof(T); return conf; } /// /// Forces exporter to add I letter as interface prefix. /// /// Configuration /// Add I automatically or not public static T AutoI(this T conf, bool auto = true) where T: InterfaceExportBuilder { conf.Attr.AutoI = auto; return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/TypeExtensions/TypeExportExtensions.cs ================================================ using System; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace namespace Reinforced.Typings.Fluent { public static partial class TypeExportExtensions { /// /// Sets order this membter will be written to output file in /// /// Configurator /// Order of member /// Fluent public static TypeExportBuilder Order(this TypeExportBuilder conf, double order) { conf.Blueprint.TypeAttribute.Order = order; return conf; } /// /// Configures exporter to flatten inheritance hierarchy for supplied type /// /// Configuration /// /// All classes "deeper" than specified (including) will not be considered as exportable members donors. /// By default this parameter is equal to typeof(object) /// public static T FlattenHierarchy(this T conf, Type until = null) where T: TypeExportBuilder { if (!conf.Blueprint.TypeAttribute.FlattenHierarchy) { if (!conf.Blueprint.CanFlatten()) { ErrorMessages.RTE0015_CannotFlatten.Throw(conf.Blueprint.Type.FullName); } conf.Blueprint.NotifyFlattenTouched(); } conf.Blueprint.TypeAttribute.FlattenHierarchy = true; if (until != null) { conf.Blueprint.TypeAttribute.FlattenLimiter = until; } return conf; } /// /// Adds decorator to member /// /// Member configurator /// Decorator to add (everything that must follow after "@") /// Order of appearence /// Fluent public static TypeExportBuilder Decorator(this TypeExportBuilder conf, string decorator, double order = 0) { conf.Blueprint.Decorators.Add(new TsDecoratorAttribute(decorator, order)); return conf; } } } ================================================ FILE: Reinforced.Typings/Fluent/WithExtensions/WithExtensions.Fields.cs ================================================ using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace // ReSharper disable PossibleNullReferenceException namespace Reinforced.Typings.Fluent { /// /// Set of .With-extensions /// public static partial class WithExtensions { /// /// Include specified field to resulting typing /// /// Configuration builder /// Field to include /// Fluent public static FieldExportBuilder WithField(this ITypedExportBuilder tc, Expression> field) { var prop = LambdaHelpers.ParseFieldLambda(field); ClassOrInterfaceExportBuilder tcb = tc as ClassOrInterfaceExportBuilder; return new FieldExportBuilder(tcb.Blueprint, prop); } /// /// Include specified field to resulting typing /// /// Configuration builder /// Name of field to include /// Configuration to be applied to selected field /// Fluent public static T WithField(this T tc, string fieldName, Action configuration) where T : ClassOrInterfaceExportBuilder { var field = tc.Blueprint.Type._GetField(fieldName); if (field == null) { ErrorMessages.RTE0013_InvalidField.Throw(fieldName, tc.Blueprint.Type.FullName); } tc.WithFields(new[] { field }, configuration); return tc; } /// /// Include specified fields to resulting typing /// /// Configuration builder /// Predicate function that should mathc for fields to include /// Configuration to be applied to each field /// Fluent public static T WithFields(this T tc, Func predicate, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers((t, b) => t._GetFields(b)) .Where(predicate); tc.WithFields(prop, configuration); return tc; } /// /// Include all fields to resulting typing /// /// Configuration builder /// Configuration to be applied to each field /// Fluent public static T WithAllFields(this T tc, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers((t, b) => t._GetFields(b)); tc.WithFields(prop, configuration); return tc; } /// /// Include all public fields to resulting typing /// /// Configuration builder /// Configuration to be applied to each field /// Fluent public static T WithPublicFields(this T tc, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint .GetExportingMembers((t, b) => t._GetFields(b), true); tc.WithFields(prop, configuration); return tc; } /// /// Include specified fields to resulting typing /// /// Configuration builder /// BindingFlags describing fields to include /// Configuration to be applied to each field /// Fluent public static T WithFields(this T tc, BindingFlags bindingFlags, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.Type._GetFields(bindingFlags); tc.WithFields(prop, configuration); return tc; } } } ================================================ FILE: Reinforced.Typings/Fluent/WithExtensions/WithExtensions.Methods.cs ================================================ using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; // ReSharper disable CheckNamespace // ReSharper disable PossibleNullReferenceException namespace Reinforced.Typings.Fluent { public static partial class WithExtensions { /// /// Include specified method to resulting typing. /// User to mock up method parameters or specify configuration for perticular method /// parameter /// /// Configuration builder /// Method to include /// Fluent public static MethodExportBuilder WithMethod(this ITypedExportBuilder tc, Expression> method) { var prop = LambdaHelpers.ParseMethodLambda(method); ClassOrInterfaceExportBuilder tcb = tc as ClassOrInterfaceExportBuilder; var methodConf = new MethodExportBuilder(tcb.Blueprint, prop); tcb.ExtractParameters(method); return methodConf; } /// /// Include specified method to resulting typing. /// User to mock up method parameters or specify configuration for perticular method /// parameter /// /// Configuration builder /// Method to include /// Fluent public static MethodExportBuilder WithMethod(this ITypedExportBuilder tc, Expression> method) { var prop = LambdaHelpers.ParseMethodLambda(method); ClassOrInterfaceExportBuilder tcb = tc as ClassOrInterfaceExportBuilder; var methodConf = new MethodExportBuilder(tcb.Blueprint, prop); tcb.ExtractParameters(method); return methodConf; } /// /// Include specified methods to resulting typing. /// /// Configuration builder /// Predicate function that should mathc for methods to include /// Configuration to be applied to each method /// Fluent public static T WithMethods(this T tc, Func predicate, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers((t, b) => t._GetMethods(b)) .Where(predicate); tc.WithMethods(prop, configuration); return tc; } /// /// Include specified methods to resulting typing. /// /// Configuration builder /// BindingFlags describing methods to include /// Configuration to be applied to each method /// Fluent public static T WithMethods(this T tc, BindingFlags bindingFlags, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers((t, b) => t._GetMethods(bindingFlags)); tc.WithMethods(prop, configuration); return tc; } /// /// Include all methods to resulting typing /// /// Configuration builder /// Configuration to be applied to each method /// Fluent public static T WithAllMethods(this T tc, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers((t, b) => t._GetMethods(b)); tc.WithMethods(prop, configuration); return tc; } /// /// Include all methods to resulting typing /// /// Configuration builder /// Configuration to be applied to each method /// Fluent public static T WithPublicMethods(this T tc, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers((t, b) => t._GetMethods(b), true); tc.WithMethods(prop, configuration); return tc; } } } ================================================ FILE: Reinforced.Typings/Fluent/WithExtensions/WithExtensions.Properties.cs ================================================ using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Reinforced.Typings.Exceptions; // ReSharper disable CheckNamespace // ReSharper disable PossibleNullReferenceException namespace Reinforced.Typings.Fluent { public static partial class WithExtensions { /// /// Include specified property to resulting typing /// /// Configuration builder /// Property to include /// Fluent public static PropertyExportBuilder WithProperty(this ITypedExportBuilder tc, Expression> property) { var prop = LambdaHelpers.ParsePropertyLambda(property); ClassOrInterfaceExportBuilder tcb = tc as ClassOrInterfaceExportBuilder; return new PropertyExportBuilder(tcb.Blueprint, prop); } /// /// Include specified property to resulting typing /// /// Configuration builder /// Name of property to include /// Configuration to be applied to selected property /// Fluent public static T WithProperty(this T tc, string propertyName, Action configuration) where T:ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.Type._GetProperty(propertyName); if (prop == null) { ErrorMessages.RTE0014_InvalidProperty.Throw(propertyName, tc.Blueprint.Type.FullName); } tc.WithProperties(new[] { prop }, configuration); return tc; } /// /// Include specified properties to resulting typing /// /// Configuration builder /// Predicate function for properties to include /// Configuration to be applied to each property /// Fluent public static T WithProperties(this T tc, Func predicate, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers( (t, b) => t._GetProperties(b)).Where(predicate); tc.WithProperties(prop, configuration); return tc; } /// /// Include specified properties to resulting typing /// /// Configuration builder /// BindingFlags describing properties to include /// Configuration to be applied to each property /// Fluent public static T WithProperties(this T tc, BindingFlags bindingFlags, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers( (t, b) => t._GetProperties(bindingFlags)); tc.WithProperties(prop, configuration); return tc; } /// /// Include all properties to resulting typing /// /// Configuration builder /// Configuration to be applied to each property /// Fluent public static T WithAllProperties(this T tc, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint.GetExportingMembers( (t, b) => t._GetProperties(b)); tc.WithProperties(prop, configuration); return tc; } /// /// Include all public properties to resulting typing /// /// Configuration builder /// Configuration to be applied to each property /// Fluent public static T WithPublicProperties(this T tc, Action configuration = null) where T : ClassOrInterfaceExportBuilder { var prop = tc.Blueprint .GetExportingMembers( (t, b) => t._GetProperties(b), true); tc.WithProperties(prop, configuration); return tc; } } } ================================================ FILE: Reinforced.Typings/GeneratorManager.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; using Reinforced.Typings.Generators; namespace Reinforced.Typings { /// /// Class for managing and instantiating code generators /// public class GeneratorManager { private readonly ITsCodeGenerator _defaultClassGenerator; private readonly ITsCodeGenerator _defaultEnumGenerator; private readonly Dictionary _defaultGenerators = new Dictionary(); private readonly ITsCodeGenerator _defaultInterfaceGenerator; private readonly NamespaceCodeGenerator _defaultNsgenerator; private readonly ITsCodeGenerator _defaultParameterGenerator; private readonly Dictionary _generatorsCache = new Dictionary(); private readonly ExportContext _context; internal GeneratorManager(ExportContext context) { _defaultGenerators[MemberTypes.Property] = new PropertyCodeGenerator { Context = context }; _defaultGenerators[MemberTypes.Field] = new FieldCodeGenerator { Context = context }; _defaultGenerators[MemberTypes.Method] = new MethodCodeGenerator { Context = context }; _defaultGenerators[MemberTypes.Constructor] = new ConstructorCodeGenerator { Context = context }; _defaultParameterGenerator = new ParameterCodeGenerator { Context = context }; _defaultClassGenerator = new ClassCodeGenerator { Context = context }; _defaultInterfaceGenerator = new InterfaceCodeGenerator { Context = context }; _defaultEnumGenerator = new EnumGenerator { Context = context }; _defaultNsgenerator = new NamespaceCodeGenerator { Context = context }; _context = context; } /// /// Reteieves code generator instance for specified type member. /// Also this method considers Typings attribute and instantiates generator specified there if necessary /// /// Type member info type /// Type member info /// Code generator for specified type member public ITsCodeGenerator GeneratorFor(T member) where T : MemberInfo { var attr = _context.CurrentBlueprint.ForMember(member); var fromAttr = GetFromAttribute(attr); if (fromAttr != null) return fromAttr; if (member is MethodInfo) { var classAttr = _context.CurrentBlueprint.Attr(); if (classAttr != null && classAttr.DefaultMethodCodeGenerator != null) { return LazilyInstantiateGenerator(classAttr.DefaultMethodCodeGenerator); } } var gen = (ITsCodeGenerator)_defaultGenerators[member.MemberType]; gen.Context = _context; return gen; } /// /// Retrieves code generator for ParameterInfo (since ParameterInfo does not derive from MemberInfo). /// Also this method considers Typings attribute and instantiates generator specified there if necessary /// /// Parameter info /// Code generator for parameter info public ITsCodeGenerator GeneratorFor(ParameterInfo member) { var attr = _context.CurrentBlueprint.ForMember(member); var fromAttr = GetFromAttribute(attr); if (fromAttr != null) return fromAttr; return _defaultParameterGenerator; } /// /// Retrieves code generator for specified type /// Also this method considers Typings attribute and instantiates generator specified there if necessary /// /// Type info /// Code generator for specified type public ITsCodeGenerator GeneratorFor(Type member) { var attr = _context.Project.Blueprint(member).TypeAttribute; var fromAttr = GetFromAttribute(attr); if (fromAttr != null) return fromAttr; var isClass = attr is TsClassAttribute; var isInterface = attr is TsInterfaceAttribute; var isEnum = attr is TsEnumAttribute; if (isClass) return _defaultClassGenerator; if (isInterface) return _defaultInterfaceGenerator; if (isEnum) return _defaultEnumGenerator; return null; } /// /// Retrieves code generator for namespaces /// /// public NamespaceCodeGenerator GeneratorForNamespace() { _defaultNsgenerator.Context = _context; return _defaultNsgenerator; } private ITsCodeGenerator GetFromAttribute(TsAttributeBase attr) { if (attr != null) { var t = attr.CodeGeneratorType; if (t != null) return LazilyInstantiateGenerator(t); } return null; } private ITsCodeGenerator LazilyInstantiateGenerator(Type generatorType) { lock (_generatorsCache) { if (!_generatorsCache.ContainsKey(generatorType)) { try { _generatorsCache[generatorType] = Activator.CreateInstance(generatorType); var gen = (ITsCodeGenerator)_generatorsCache[generatorType]; gen.Context = _context; } catch (Exception ex) { ErrorMessages.RTE0003_GeneratorInstantiate.Throw(generatorType.FullName, ex.Message); } } return (ITsCodeGenerator)_generatorsCache[generatorType]; } } } } ================================================ FILE: Reinforced.Typings/Generators/ClassAndInterfaceGeneratorBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; using Reinforced.Typings.Xmldoc.Model; namespace Reinforced.Typings.Generators { /// /// Base code generator both for TypeScript class and interface /// /// Resulting node type (RtClass or RtInterface) public abstract class ClassAndInterfaceGeneratorBase : TsCodeGeneratorBase where TNode : RtNode, new() { /// /// Exports entire class to specified writer /// /// Exporting result /// Exporting class type /// Type resolver /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void Export(ITypeMember result, Type type, TypeResolver resolver, IAutoexportSwitchAttribute swtch) { var bp = Context.Project.Blueprint(type); result.Name = bp.GetName(); result.Order = bp.GetOrder(); var doc = Context.Documentation.GetDocumentationMember(type); if (doc != null) { RtJsdocNode docNode = new RtJsdocNode(); if (doc.HasInheritDoc()) docNode.AddTag(DocTag.Inheritdoc); if (doc.HasSummary()) docNode.Description = doc.Summary.Text; result.Documentation = docNode; } var materializedGenericParameters = type._GetGenericArguments() .Where(c => c.GetCustomAttribute() != null) .ToDictionary(c => c.Name, resolver.ResolveTypeName); if (materializedGenericParameters.Count == 0) materializedGenericParameters = null; if (!bp.IsFlatten()) { var baseType = type._BaseType(); var implementees = ExtractImplementees(type, resolver, materializedGenericParameters).ToList(); if (baseType != null && baseType != typeof(object)) { bool baseAsInterface = false; RtTypeName inferredBaseType = null; if (baseType._IsGenericType()) { var genericBase = baseType.GetGenericTypeDefinition(); var genericBaseBp = Context.Project.Blueprint(genericBase); if (genericBaseBp.TypeAttribute != null || genericBaseBp.ThirdParty != null) { inferredBaseType = resolver.ResolveTypeName(baseType, MergeMaterializedGenerics(baseType, resolver, materializedGenericParameters)); baseAsInterface = Context.Project.Blueprint(genericBase).IsExportingAsInterface(); } } if (inferredBaseType == null || !baseType._IsGenericType()) { var bsBp = Context.Project.Blueprint(baseType); if (bsBp.TypeAttribute != null || bsBp.ThirdParty != null) { baseAsInterface = Context.Project.Blueprint(baseType).IsExportingAsInterface(); inferredBaseType = resolver.ResolveTypeName(baseType, MergeMaterializedGenerics(baseType, resolver, materializedGenericParameters)); } } if (inferredBaseType != null) { if (baseAsInterface || result is RtInterface) { implementees.Add(inferredBaseType); } else { ((RtClass)result).Extendee = inferredBaseType; } } } result.Implementees.AddRange(implementees.OfType()); } ExportMembers(type, resolver, result, swtch); } private Dictionary MergeMaterializedGenerics(Type t, TypeResolver resovler, Dictionary existing) { if (!t._IsGenericType()) return existing; var args = t._GetGenericArguments(); if (args.All(c => c.IsGenericParameter)) return existing; var genDef = t.GetGenericTypeDefinition()._GetGenericArguments(); Dictionary result = new Dictionary(); if (existing != null) { foreach (var rtTypeName in existing) { result[rtTypeName.Key] = rtTypeName.Value; } } for (int i = 0; i < args.Length; i++) { if (!args[i].IsGenericParameter) { result[genDef[i].Name] = resovler.ResolveTypeName(args[i], MergeMaterializedGenerics(args[i], resovler, existing)); } else { if (args[i].Name != genDef[i].Name) { result[genDef[i].Name] = new RtSimpleTypeName(args[i].Name); } } } if (result.Count == 0) return null; return result; } private IEnumerable ExtractImplementees(Type type, TypeResolver resolver, Dictionary materializedGenericParameters) { var ifaces = type._GetInterfaces(); foreach (var iface in ifaces) { RtTypeName inferredBaseType = null; if (iface._IsGenericType()) { var genericBase = iface.GetGenericTypeDefinition(); var genericBaseBp = Context.Project.Blueprint(genericBase); if (genericBaseBp.TypeAttribute != null || genericBaseBp.ThirdParty != null) { inferredBaseType = resolver.ResolveTypeName(iface, MergeMaterializedGenerics(iface, resolver, materializedGenericParameters)); } } if (inferredBaseType == null || !iface._IsGenericType()) { var bsBp = Context.Project.Blueprint(iface); if (bsBp.TypeAttribute != null || bsBp.ThirdParty != null) { inferredBaseType = resolver.ResolveTypeName(iface, MergeMaterializedGenerics(iface, resolver, materializedGenericParameters)); } } if (inferredBaseType != null) yield return inferredBaseType; } } /// /// Exports all type members sequentially /// /// Type itself /// Type resolver /// Placeholder for members /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void ExportMembers(Type element, TypeResolver resolver, ITypeMember typeMember, IAutoexportSwitchAttribute swtch) { ExportConstructors(typeMember, element, resolver, swtch); ExportFields(typeMember, element, resolver, swtch); ExportProperties(typeMember, element, resolver, swtch); ExportMethods(typeMember, element, resolver, swtch); HandleBaseClassExportingAsInterface(typeMember, element, resolver, swtch); } /// /// Here you can customize what to export when base class is class but exporting as interface /// /// Output writer /// Type itself /// Type resolver /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void HandleBaseClassExportingAsInterface(ITypeMember sw, Type element, TypeResolver resolver, IAutoexportSwitchAttribute swtch) { if (element._BaseType() != null) { var baseBp = Context.Project.Blueprint(element._BaseType(), false); var bp = Context.Project.Blueprint(element); //if we cannot determine what is being exported - then.. well. okay if (baseBp == null) return; if (bp == null) return; if ((!bp.IsExportingAsInterface()) && baseBp.IsExportingAsInterface()) { // well.. bad but often case. // Here we should export members also for base class // we do not export methods - just properties and fields // but still. It is better thatn nothing if (sw.Documentation == null) sw.Documentation = new RtJsdocNode(); sw.Documentation.AddTag(DocTag.Todo, string.Format("Automatically implemented from {0}", resolver.ResolveTypeName(element._BaseType()))); var baseBlueprint = Context.Project.Blueprint(element._BaseType()); var basExSwtch = baseBlueprint.Attr(); Context.SpecialCase = true; ExportFields(sw, element._BaseType(), resolver, basExSwtch); ExportProperties(sw, element._BaseType(), resolver, basExSwtch); ExportMethods(sw, element._BaseType(), resolver, basExSwtch); Context.SpecialCase = false; Context.AddWarning(ErrorMessages.RTW0005_BaseClassExportingAsInterface.Warn(element._BaseType().FullName, element.FullName)); } } } /// /// Exports type fields /// /// Output writer /// Type itself /// Type resolver /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void ExportFields(ITypeMember typeMember, Type element, TypeResolver resolver, IAutoexportSwitchAttribute swtch) { GenerateMembers(element, resolver, typeMember, Context.Project.Blueprint(element).GetExportedFields()); } /// /// Exports type properties /// /// Output writer /// Type itself /// Type resolver /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void ExportProperties(ITypeMember typeMember, Type element, TypeResolver resolver, IAutoexportSwitchAttribute swtch) { GenerateMembers(element, resolver, typeMember, Context.Project.Blueprint(element).GetExportedProperties()); } /// /// Exports type methods /// /// Output writer /// Type itself /// Type resolver /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void ExportMethods(ITypeMember typeMember, Type element, TypeResolver resolver, IAutoexportSwitchAttribute swtch) { GenerateMembers(element, resolver, typeMember, Context.Project.Blueprint(element).GetExportedMethods()); } /// /// Exports type constructors /// /// Output writer /// Type itself /// Type resolver /// Pass here type attribute inherited from IAutoexportSwitchAttribute protected virtual void ExportConstructors(ITypeMember typeMember, Type element, TypeResolver resolver, IAutoexportSwitchAttribute swtch) { var bp = Context.Project.Blueprint(element); if (swtch.AutoExportConstructors) { if (!bp.IsExportingAsInterface()) // constructors are not allowed on interfaces { var constructors = element._GetConstructors(TypeExtensions.MembersFlags) .Where(c => (c.GetCustomAttribute() == null) && !bp.IsIgnored(c)); if (!constructors.Any()) constructors = element._GetConstructors(TypeExtensions.MembersFlags) .Where(c => !bp.IsIgnored(c)); GenerateMembers(element, resolver, typeMember, constructors.Take(1)); } } } /// /// Exports list of type members /// /// Type member type /// Exporting class /// Type resolver /// Output writer /// Type members to export protected virtual void GenerateMembers(Type element, TypeResolver resolver, ITypeMember typeMember, IEnumerable members) where T : MemberInfo { foreach (var m in members) { var generator = Context.Generators.GeneratorFor(m); var member = generator.Generate(m, resolver); if (member != null) typeMember.Members.Add(member); } } } } ================================================ FILE: Reinforced.Typings/Generators/ClassCodeGenerator.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; namespace Reinforced.Typings.Generators { /// /// Default code generator for CLR type (class) /// public class ClassCodeGenerator : ClassAndInterfaceGeneratorBase { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtClass GenerateNode(Type element, RtClass result, TypeResolver resolver) { var clsbp = Context.Project.Blueprint(element); var tc = Context.Project.Blueprint(element).Attr(); if (tc == null) throw new ArgumentException("TsClassAttribute is not present", "element"); Export(result, element, resolver, tc); AddDecorators(result, clsbp.GetDecorators()); if (!tc.IsAbstract.HasValue) { result.Abstract = element._IsAbstract() && !element._IsInterface(); } else { result.Abstract = tc.IsAbstract.Value; } return result; } } } ================================================ FILE: Reinforced.Typings/Generators/ConstructorCodeGenerator.cs ================================================ using System; using System.Linq; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; using Reinforced.Typings.Xmldoc.Model; namespace Reinforced.Typings.Generators { /// /// Default code generator for constructor /// public class ConstructorCodeGenerator : TsCodeGeneratorBase { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtConstructor GenerateNode(ConstructorInfo element, RtConstructor result, TypeResolver resolver) { if (Context.CurrentBlueprint.IsIgnored(element)) return null; var doc = Context.Documentation.GetDocumentationMember(element); if (doc != null) { RtJsdocNode jsdoc = new RtJsdocNode(); if (doc.HasInheritDoc()) jsdoc.AddTag(DocTag.Inheritdoc); if (doc.HasSummary()) jsdoc.Description = doc.Summary.Text; if (doc.Parameters != null) { foreach (var documentationParameter in doc.Parameters) { jsdoc.AddTag(DocTag.Param, documentationParameter.Name + " " + documentationParameter.Description); } } result.Documentation = jsdoc; } var p = element.GetParameters(); foreach (var param in p) { if (Context.CurrentBlueprint.IsIgnored(param)) continue; var generator = Context.Generators.GeneratorFor(param); var argument = generator.Generate(param, resolver); result.Arguments.Add((RtArgument)argument); } var bp = Context.Project.Blueprint(element.DeclaringType); if (bp.ConstructorBody != null) { result.SuperCallParameters.Clear(); result.Body = bp.ConstructorBody; }else SetupSuperCall(result, element, bp.ForMember(element)); return result; } private void SetupSuperCall(RtConstructor constructor, ConstructorInfo element, TsBaseParamAttribute attr) { constructor.SuperCallParameters.Clear(); // 1. Check presence of base type var bt = element.DeclaringType != null ? element.DeclaringType._BaseType() : null; var bp = Context.Project.Blueprint(bt); if ((bt == typeof(object) || bp.IsExportingAsInterface()) || !bp.IsExportingAsClass()) bt = null; if (bt == null) { // 1. If not present then generate empty constructor body return; } var parameters = element.GetParameters(); // 2. Check presence of [TsBaseParam] if (attr != null) { // 2. If present then generate super() call with supplied parameters constructor.SuperCallParameters.AddRange(attr.Values.Take(parameters.Length).ToList()); if (constructor.SuperCallParameters.Count > 0) { constructor.NeedsSuperCall = true; } return; } var baseConstructors = bt._GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); // 3. Trying to lookup constructor with same parameters var found = false; var paramTypes = parameters.Select(c => c.ParameterType).ToArray(); var corresponding = TypeExtensions.GetMethodWithSameParameters( baseConstructors.Cast().ToArray(), paramTypes); found = corresponding != null; if (found) { // 3.If constructor with same parameters found - just use it constructor.SuperCallParameters.AddRange(parameters.Select(c => Context.CurrentBlueprint.GetName(c))); if (constructor.SuperCallParameters.Count > 0) { constructor.NeedsSuperCall = true; } return; } // 4. Maybe parameterles constructor? if (baseConstructors.Any(c => c.GetParameters().Length == 0)) { // 4. If not present then generate empty super() call constructor.NeedsSuperCall = true; return; } // 5. If nothing found - well... we simply leave here super with all nulls supplied var maxParams = baseConstructors.Max(c => c.GetParameters().Length); var mockedCtorParams = Enumerable.Repeat("null", maxParams); constructor.NeedsSuperCall = true; constructor.SuperCallParameters.AddRange(mockedCtorParams); Context.AddWarning(ErrorMessages.RTW0004_DefaultSuperCall.Warn(element.DeclaringType.FullName)); } } } ================================================ FILE: Reinforced.Typings/Generators/ContextExtensions.cs ================================================ namespace Reinforced.Typings.Generators { /// /// Various extensions for settings /// public static class ContextExtensions { /// /// Conditionally (based on settings) turns method name to camelCase /// /// Settings object /// Regular method name /// Method name in camelCase if camelCasing enabled, initial string otherwise public static string ConditionallyConvertMethodNameToCamelCase(this ExportContext context, string regularName) { if (!context.Global.CamelCaseForMethods) return regularName; return TypeBlueprint.ConvertToCamelCase(regularName); } /// /// Conditionally (based on settings) turns method name to PascalCase /// /// Settings object /// Regular method name /// Method name in camelCase if camelCasing enabled, initial string otherwise public static string ConditionallyConvertMethodNameToPascalCase(this ExportContext context, string regularName) { if (!context.Global.CamelCaseForMethods) return regularName; return TypeBlueprint.ConvertToCamelCase(regularName); } /// /// Conditionally (based on settings) turns property name to camelCase /// /// Settings object /// Regular property name /// Property name in camelCase if camelCasing enabled, initial string otherwise public static string ConditionallyConvertPropertyNameToCamelCase(this ExportContext context, string regularName) { if (!context.Global.CamelCaseForProperties) return regularName; return TypeBlueprint.ConvertToCamelCase(regularName); } } } ================================================ FILE: Reinforced.Typings/Generators/EnumGenerator.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Xmldoc.Model; namespace Reinforced.Typings.Generators { /// /// Default code generator for enums /// public class EnumGenerator : TsCodeGeneratorBase { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtEnum GenerateNode(Type element, RtEnum result, TypeResolver resolver) { Context.Location.SetCurrentType(element); var names = Enum.GetNames(element); var bp = Context.Project.Blueprint(element); result.EnumName = bp.GetName(); result.Order = bp.GetOrder(); var fields = element._GetFields().Where(c => !c.IsSpecialName).ToDictionary(c => c.Name, c => c); var doc = Context.Documentation.GetDocumentationMember(element); if (doc != null) { RtJsdocNode docNode = new RtJsdocNode(); if (doc.HasInheritDoc()) docNode.AddTag(DocTag.Inheritdoc); if (doc.HasSummary()) docNode.Description = doc.Summary.Text; result.Documentation = docNode; } bool stringInit = false; var ea = Context.CurrentBlueprint.Attr(); if (ea != null) { result.IsConst = ea.IsConst; stringInit = ea.UseString; } List valuesResult = new List(); for (var index = 0; index < names.Length; index++) { var n = names.GetValue(index) as string; var v = Enum.Parse(element, n); if (fields.ContainsKey(n)) { var fieldItself = fields[n]; if (Context.CurrentBlueprint.Ignored.Contains(fieldItself)) continue; var attr = Context.CurrentBlueprint.ForEnumValue(fieldItself); if (attr != null) n = attr.Name; if (string.IsNullOrEmpty(n)) n = fieldItself.Name; RtEnumValue value = new RtEnumValue { EnumValueName = n, EnumValue = Convert.ToInt64(v).ToString() }; if (stringInit) { if (attr != null && !string.IsNullOrEmpty(attr.Initializer)) value.EnumValue = String.Concat("\"", attr.Initializer, "\""); else { value.EnumValue = String.Concat("\"", n, "\""); } } var valueDoc = Context.Documentation.GetDocumentationMember(fieldItself); if (valueDoc != null) { RtJsdocNode docNode = new RtJsdocNode(); if (valueDoc.HasInheritDoc()) docNode.AddTag(DocTag.Inheritdoc); if (valueDoc.HasSummary()) docNode.Description = valueDoc.Summary.Text; value.Documentation = docNode; } valuesResult.Add(value); } } result.Values.AddRange(valuesResult); AddDecorators(result, Context.CurrentBlueprint.GetDecorators()); Context.Location.ResetCurrentType(); return result; } } } ================================================ FILE: Reinforced.Typings/Generators/FieldCodeGenerator.cs ================================================ using System; using System.Reflection; namespace Reinforced.Typings.Generators { /// /// Default code generator for fields /// public class FieldCodeGenerator : PropertyCodeGenerator { /// /// That's it - overriden GetType for property since properties and fields are exported to TypeScript almost same way. /// /// Member info (Fields behind) /// Field type protected override Type GetType(MemberInfo mi) { var pi = (FieldInfo) mi; return pi.FieldType; } /// /// Retrieves static value /// /// /// protected override object GetStaticValue(MemberInfo element) { var fi = element as FieldInfo; return fi.GetValue(null) ?? fi.GetRawConstantValue(); } } } ================================================ FILE: Reinforced.Typings/Generators/ITsCodeGenerator.cs ================================================ using Reinforced.Typings.Ast; namespace Reinforced.Typings.Generators { /// /// TypeScript code generator interface /// /// public interface ITsCodeGenerator { /// /// Export settings /// ExportContext Context { get; set; } /// /// Main code generator method. This method should return corresponding AST node for provided /// reflection element using source Reflection element and RT's Type Resolver /// /// Element code to be generated to output /// Type resolver RtNode Generate(TElement element, TypeResolver resolver); } } ================================================ FILE: Reinforced.Typings/Generators/InterfaceCodeGenerator.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; namespace Reinforced.Typings.Generators { /// /// Default code generator for interfaces. Derived from class generator since interfaces are very similar to classes in /// TypeScript /// public class InterfaceCodeGenerator : ClassAndInterfaceGeneratorBase { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtInterface GenerateNode(Type element,RtInterface result, TypeResolver resolver) { var tc = Context.Project.Blueprint(element).Attr(); if (tc == null) throw new ArgumentException("TsInterfaceAttribute is not present", "element"); Export(result, element, resolver, tc); return result; } } } ================================================ FILE: Reinforced.Typings/Generators/MethodCodeGenerator.cs ================================================ using System; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; using Reinforced.Typings.Xmldoc.Model; namespace Reinforced.Typings.Generators { /// /// Default typescript code generator for method /// public class MethodCodeGenerator : TsCodeGeneratorBase { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtFunction GenerateNode(MethodInfo element, RtFunction result, TypeResolver resolver) { if (Context.CurrentBlueprint.IsIgnored(element)) return null; string name; RtTypeName type; GetFunctionNameAndReturnType(element, resolver, out name, out type); result.Identifier = new RtIdentifier(name); result.ReturnType = type; var doc = Context.Documentation.GetDocumentationMember(element); if (doc != null) { RtJsdocNode jsdoc = new RtJsdocNode(); if (doc.HasInheritDoc()) jsdoc.AddTag(DocTag.Inheritdoc); if (doc.HasSummary()) jsdoc.Description = doc.Summary.Text; if (doc.Parameters != null) { foreach (var documentationParameter in doc.Parameters) { jsdoc.AddTag(DocTag.Param, documentationParameter.Name + " " + documentationParameter.Description); } } if (doc.HasReturns()) { jsdoc.AddTag(DocTag.Returns, doc.Returns.Text); } result.Documentation = jsdoc; } result.Order = Context.CurrentBlueprint.GetOrder(element); result.AccessModifier = element.GetModifier(); if (Context.SpecialCase) result.AccessModifier = AccessModifier.Public; result.Identifier = new RtIdentifier(name); result.IsStatic = element.IsStatic; var p = element.GetParameters(); foreach (var param in p) { if (Context.CurrentBlueprint.IsIgnored(param)) continue; var generator = Context.Generators.GeneratorFor(param); var argument = generator.Generate(param, resolver); result.Arguments.Add((RtArgument)argument); } var fa = Context.CurrentBlueprint.ForMember(element); if (fa != null && !string.IsNullOrEmpty(fa.Implementation)) { result.Body = new RtRaw(fa.Implementation); } if (fa != null && fa.ForceAsync != null) { result.IsAsync = (bool)fa.ForceAsync; } else { if (Context.Global.AutoAsync) { result.IsAsync = element.IsAsync(); } } AddDecorators(result, Context.CurrentBlueprint.DecoratorsFor(element)); return result; } protected RtTypeName ResolveAsyncReturnType(TsFunctionAttribute fa, MethodInfo element, TypeResolver resolver) { bool needAsync = (fa != null && fa.ForceAsync == true) || (Context.Global.AutoAsync && element.IsAsync()); return resolver.ResolveTypeName(element.ReturnType, needAsync); } /// /// Retrieves function name corresponding to method and return type. Fell free to override it. /// /// Method info /// Type resolver /// Resulting method name /// Resulting return type name protected virtual void GetFunctionNameAndReturnType(MethodInfo element, TypeResolver resolver, out string name, out RtTypeName type) { name = element.Name; bool isNameOverridden = false; var fa = Context.CurrentBlueprint.ForMember(element); if (fa != null) { if (!string.IsNullOrEmpty(fa.Name)) { name = fa.Name; isNameOverridden = true; } if (!string.IsNullOrEmpty(fa.Type)) type = new RtSimpleTypeName(fa.Type); else if (fa.StrongType != null) type = resolver.ResolveTypeName(fa.StrongType); else { type = ResolveAsyncReturnType(fa, element, resolver); } type = fa.TypeInferers.Infer(element, resolver) ?? type; } else { type = ResolveAsyncReturnType(null, element, resolver); } if (!isNameOverridden) { name = Context.ConditionallyConvertMethodNameToCamelCase(name); name = Context.CurrentBlueprint.CamelCaseFromAttribute(element, name); name = Context.CurrentBlueprint.PascalCaseFromAttribute(element, name); } if (element.IsGenericMethod) { if (!(name.Contains("<") || name.Contains(">"))) { var args = element.GetGenericArguments(); var names = args.Select(resolver.ResolveTypeName); name = string.Concat(name, "<", string.Join(",", names), ">"); } } } } } ================================================ FILE: Reinforced.Typings/Generators/NamespaceCodeGenerator.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Ast; namespace Reinforced.Typings.Generators { /// /// Default code generator for namespace /// public class NamespaceCodeGenerator { /// /// Export settings /// public ExportContext Context { get; set; } /// /// Generates namespace source code /// /// Types list /// Namespace name /// Type resolver public virtual RtNamespace Generate(IEnumerable types, string namespaceName, TypeResolver resolver) { RtNamespace ns = new RtNamespace(); var needToDiscard = Context.Global.UseModules && Context.Global.DiscardNamespacesWhenUsingModules; if (string.IsNullOrEmpty(namespaceName) || needToDiscard) ns.IsAmbientNamespace = true; ns.Name = namespaceName; Context.Location.SetLocation(ns); foreach (var type in types) { var typeGenerator = Context.Generators.GeneratorFor(type); if (typeGenerator == null) continue; var member = typeGenerator.Generate(type, resolver); var m = member as RtCompilationUnit; if (m != null) { if (Context.Global.UseModules) { m.Export = true; } else { m.Export = !ns.IsAmbientNamespace; } } if (member!=null) ns.CompilationUnits.Add(member); #if DEBUG Console.WriteLine("Exported {0}", type); #endif } if (Context.Global.UseModules) ns.GenerationMode = NamespaceGenerationMode.Namespace; Context.Location.ResetLocation(ns); return ns; } } } ================================================ FILE: Reinforced.Typings/Generators/ParameterCodeGenerator.cs ================================================ using System; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; namespace Reinforced.Typings.Generators { /// /// Default code generator for method parameter /// public class ParameterCodeGenerator : TsCodeGeneratorBase { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtArgument GenerateNode(ParameterInfo element,RtArgument result, TypeResolver resolver) { if (Context.CurrentBlueprint.IsIgnored(element)) return null; var name = element.Name; RtTypeName type; var isNullable = false; var fa = Context.CurrentBlueprint.ForMember(element); var defaultValue = GetDefaultValue(element, fa); if (fa != null) { if (!string.IsNullOrEmpty(fa.Name)) name = fa.Name; if (!string.IsNullOrEmpty(fa.Type)) type = new RtSimpleTypeName(fa.Type); else if (fa.StrongType != null) { type = resolver.ResolveTypeName(fa.StrongType); isNullable = element.IsOptional || element.IsReferenceForcedNullable(); } else type = resolver.ResolveTypeName(element.ParameterType); type = fa.TypeInferers.Infer(element, resolver) ?? type; } else { type = resolver.ResolveTypeName(element.ParameterType); isNullable = element.IsOptional || element.IsReferenceForcedNullable(); } if (element.GetCustomAttribute() != null) { result.IsVariableParameters = true; } result.Identifier = new RtIdentifier(name); result.Type = type; if (isNullable && defaultValue == null) result.Identifier.IsNullable = true; if (defaultValue != null) { //if parameter is having enum type then simple string value assignment is now right //so for Enum type result.DefaultValue should be equal to ENUME_NAME+"."+DefaultValue if (element.ParameterType._IsEnum()) { result.DefaultValue = result.Type + "." + defaultValue; } else result.DefaultValue = defaultValue; } AddDecorators(result, Context.CurrentBlueprint.DecoratorsFor(element)); return result; } /// /// Returns default value for specified parameter info /// /// Parameter info /// Parameter attribute /// Serialized to string default value of type that is exposed by mentioned parameter protected virtual string GetDefaultValue(ParameterInfo element, TsParameterAttribute attr) { object defVal = null; if (attr != null) { defVal = attr.DefaultValue; } if (defVal == null) { defVal = element.DefaultValue; } if (defVal == null) return null; if (defVal is string) { return string.Format("\"{0}\"", defVal); } if (defVal is bool) { return ((bool) defVal) ? "true" : "false"; } var ts = defVal.ToString(); if (string.IsNullOrEmpty(ts)) return null; return ts; } } } ================================================ FILE: Reinforced.Typings/Generators/PropertyCodeGenerator.cs ================================================ using System; using System.Globalization; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; using Reinforced.Typings.Xmldoc.Model; namespace Reinforced.Typings.Generators { /// /// Default code generator for properties /// public class PropertyCodeGenerator : TsCodeGeneratorBase { private bool HasToBeNullable(TsPropertyAttribute tp, Type propType) { var hasNullable = tp != null && tp.NilForceNullable.HasValue; if (hasNullable) { return tp.NilForceNullable.Value; } if (Context.Global.AutoOptionalProperties) { return propType.IsNullable(); } return false; } /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtField GenerateNode(MemberInfo element, RtField result, TypeResolver resolver) { if (Context.CurrentBlueprint.IsIgnored(element)) return null; result.IsStatic = element.IsStatic(); result.Order = Context.CurrentBlueprint.GetOrder(element); var doc = Context.Documentation.GetDocumentationMember(element); if (doc != null) { RtJsdocNode jsdoc = new RtJsdocNode(); if (doc.HasInheritDoc()) jsdoc.AddTag(DocTag.Inheritdoc); if (doc.HasSummary()) jsdoc.Description = doc.Summary.Text; result.Documentation = jsdoc; } var t = GetType(element); RtTypeName type = null; var propName = new RtIdentifier(element.Name); bool isNameOverridden = false; var tp = Context.CurrentBlueprint.ForMember(element); if (tp != null) { if (tp.StrongType != null) { type = resolver.ResolveTypeName(tp.StrongType); } else if (!string.IsNullOrEmpty(tp.Type)) { type = new RtSimpleTypeName(tp.Type); } type = tp.TypeInferers.Infer(element, resolver) ?? type; if (!string.IsNullOrEmpty(tp.Name)) { propName.IdentifierName = tp.Name; isNameOverridden = true; } } if (!Context.SpecialCase) { propName.IsNullable = HasToBeNullable(tp, t) || Context.Global.AutoOptionalProperties && element.IsReferenceForcedNullable(); } if (type == null) type = resolver.ResolveTypeName(t); if (!isNameOverridden) { if (element is PropertyInfo) { propName.IdentifierName = Context.ConditionallyConvertPropertyNameToCamelCase(propName.IdentifierName); } propName.IdentifierName = Context.CurrentBlueprint.CamelCaseFromAttribute(element, propName.IdentifierName); propName.IdentifierName = Context.CurrentBlueprint.PascalCaseFromAttribute(element, propName.IdentifierName); } if (this.Context.Location.CurrentClass != null) { this.FillInitialization(element, result, resolver, t, tp); } result.Identifier = propName; result.AccessModifier = Context.SpecialCase ? AccessModifier.Public : element.GetModifier(); result.Type = type; AddDecorators(result, Context.CurrentBlueprint.DecoratorsFor(element)); return result; } private static readonly IFormatProvider JsNumberFormat = new NumberFormatInfo() { NumberDecimalSeparator = "." }; /// /// Fills in initialization expression /// /// Class member /// Resulting AST /// Type resolver /// Field/property type /// Attribute protected virtual void FillInitialization(MemberInfo element, RtField result, TypeResolver resolver, Type memberType, TsPropertyAttribute attr) { bool exportConstant = true; if (attr != null) exportConstant = attr.Constant; if (element.IsStatic() && exportConstant) { if (TypeResolver.NumericTypes.Contains(memberType)) { var val = GetStaticValue(element); if (val == null) result.InitializationExpression = "null"; else if (TypeResolver.IntegerTypes.Contains(memberType)) { result.InitializationExpression = val.ToString(); } else { double dVal = (double)val; result.InitializationExpression = dVal.ToString(JsNumberFormat); } } if (memberType == typeof(bool)) { var val = GetStaticValue(element); if (val == null) result.InitializationExpression = "null"; else result.InitializationExpression = (bool)val ? "true" : "false"; } if (memberType == typeof(string)) { var val = GetStaticValue(element); if (val == null) result.InitializationExpression = "null"; else { var sv = string.Format("`{0}`", val.ToString().Replace("'", "\\'").Replace("`", "\\`")); result.InitializationExpression = sv; } } if (memberType._IsEnum()) { var val = GetStaticValue(element); if (val == null) result.InitializationExpression = "null"; else { var bp = Context.Project.Blueprint(memberType, false); if (bp != null) { var tn = resolver.ResolveTypeName(memberType); var name = Enum.GetName(memberType, val); result.InitializationExpression = string.Format("{0}.{1}", tn, name); } else { var v = (int)val; result.InitializationExpression = v.ToString(); } } } } if (attr?.InitializerEvaluator != null) { var val = element.IsStatic() ? GetStaticValue(element) : null; result.InitializationExpression = attr.InitializerEvaluator(element, resolver, val); } } /// /// Retrieves static value /// /// /// protected virtual object GetStaticValue(MemberInfo element) { var pi = element as PropertyInfo; return (pi.GetValue(null) ?? pi.GetConstantValue()) ?? pi.GetRawConstantValue(); } /// /// Returns type of specified property. It is useful for overloads sometimes /// /// Method Info /// Property info type protected virtual Type GetType(MemberInfo mi) { var pi = (PropertyInfo)mi; return pi.PropertyType; } } } ================================================ FILE: Reinforced.Typings/Generators/TsCodeGeneratorBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; namespace Reinforced.Typings.Generators { /// /// Base for strongly-typed code generator with automatical Context.Location handling /// /// Source reflection [Something]Info type. Possible: Type, MethodInfo, PropertyInfo, ConstructorInfo, FieldInfo /// Resulting node type public abstract class TsCodeGeneratorBase : ITsCodeGenerator where TNode : RtNode, new() { /// /// Export settings /// public ExportContext Context { get; set; } /// /// Generate method implementation. /// Calls GenerateNode inside, creates node dummy, sets and resets location /// /// Reflection element instance /// Type resolver /// Generated node or null public RtNode Generate(T element, TypeResolver resolver) { try { TNode currentNode = new TNode(); Context.Location.SetLocation(currentNode); if (element is Type) { Context.Location.SetCurrentType((Type)(object)element); } var result = GenerateNode(element, currentNode, resolver); Context.Location.ResetLocation(currentNode); if (element is Type) { Context.Location.ResetCurrentType(); } return result; } catch (Exception ex) { ErrorMessages.RTE0004_GeneratorError.Throw(GetType().FullName, ex.Message); return null; // unreacheable } } /// /// Main entry point for resulting node generation. /// /// Reflection element /// Resulting node to be modified /// Type resolver /// Resulting node or null public abstract TNode GenerateNode(T element, TNode node, TypeResolver resolver); /// /// Appends decorators to decoratable node /// /// Decoratable syntax node /// Set of decorator attributes protected void AddDecorators(IDecoratable node, IEnumerable decorators) { var decs = decorators.Select(c => new RtDecorator(c.Decorator, c.Order)); node.Decorators.AddRange(decs); } } } ================================================ FILE: Reinforced.Typings/GlobalParameters.cs ================================================ using System; using System.Linq; using System.Reflection; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; using Reinforced.Typings.ReferencesInspection; namespace Reinforced.Typings { /// /// Collections of global TS generation parameters /// public class GlobalParameters { private bool _isLocked; private readonly TsGlobalAttribute _attr; internal GlobalParameters(Assembly[] sourceAssemblies) { var tsGlobal = sourceAssemblies.Select(c => c.GetCustomAttribute()) .Where(c => c != null) .OrderByDescending(c => c.Priority) .FirstOrDefault(); _attr = tsGlobal ?? new TsGlobalAttribute(); } /// /// Boolean parameter that controls writing of "auto-generated warning" comment to each generated file. /// It meant the comment like "// This code was generated blah blah blah..." /// 'true' (default) to write warning comment about auto-generated to every file. /// 'false' to do not. /// public bool WriteWarningComment { get { return _attr == null ? true : _attr.WriteWarningComment; } set { if (_isLocked) return; _attr.WriteWarningComment = value; } } /// /// Specifies root namespace for hierarchical export. /// Helps to avoid creating redundant directories when hierarchical export. /// public string RootNamespace { get { return _attr.RootNamespace; } set { if (_isLocked) return; _attr.RootNamespace = value; } } /// /// Use camelCase for methods naming /// public bool CamelCaseForMethods { get { return _attr.CamelCaseForMethods; } set { if (_isLocked) return; _attr.CamelCaseForMethods = value; } } /// /// Use camelCase for properties naming /// public bool CamelCaseForProperties { get { return _attr.CamelCaseForProperties; } set { if (_isLocked) return; _attr.CamelCaseForProperties = value; } } /// /// Enables or disables documentation generator /// public bool GenerateDocumentation { get { return _attr.GenerateDocumentation; } set { if (_isLocked) return; _attr.GenerateDocumentation = value; } } /// /// Gets or sets whether all nullable properties must be exported as optional /// public bool AutoOptionalProperties { get { return _attr.AutoOptionalProperties; } set { if (_isLocked) return; _attr.AutoOptionalProperties = value; } } ///// ///// Enables or disables documentation generator ///// //public bool StrictNullChecks //{ // get { return _strictNullChecks; } // set // { // if (_isLocked) return; // _strictNullChecks = value; // } //} internal void Lock() { _isLocked = true; } internal void Unlock() { _isLocked = false; } /// /// Specifies symbol used for tabulation /// public string TabSymbol { get { return _attr.TabSymbol; } set { if (_isLocked) return; _attr.TabSymbol = value; } } /// /// Specifies string used as the line terminator. /// public string NewLine { get { return _attr.NewLine; } set { if(_isLocked) return; _attr.NewLine = value; } } /// /// Switches RT to using TS modules system (--module) parameter and import references /// public bool UseModules { get { return _attr.UseModules; } set { if (_isLocked) return; _attr.UseModules = value; } } /// /// When true, RT will ignore classes' namespaces when arraging classes and interfaces among files. /// This parameter only makes difference when using (--module) /// public bool DiscardNamespacesWhenUsingModules { get { return _attr.DiscardNamespacesWhenUsingModules; } set { if (_isLocked) return; _attr.DiscardNamespacesWhenUsingModules = value; } } /// /// If true, export will be performed in .d.ts manner (only typings, declare module etc). /// Otherwise, export will be performed to regular .ts file /// public bool ExportPureTypings { get { return _attr.ExportPureTypings; } set { if (_isLocked) return; _attr.ExportPureTypings = value; } } /// /// Gets or sets type of to be used while exporting files /// public Type ReferencesProcessorType { get { return _attr.ReferenceProcessorType; } set { if (_isLocked) return; if (!typeof(ReferenceProcessorBase)._IsAssignableFrom(value)) { ErrorMessages.RTE0016_InvalidRefProcessorType.Throw(value); } _attr.ReferenceProcessorType = value; } } /// /// Gets or sets whether it is needed to sort exported members alphabetically /// public bool ReorderMembers { get { return _attr.ReorderMembers; } set { if (_isLocked) return; _attr.ReorderMembers = value; } } /// /// Gets or sets type of AST visitor that will be used to write code to output. /// Visitor has to be child class of /// public Type VisitorType { get { return _attr.VisitorType; } set { if (_isLocked) return; _attr.VisitorType = value; } } /// /// Gets or sets whether unresolved types must be exported as 'unknown' instead of 'any' /// public bool UnresolvedToUnknown { get { return _attr.UnresolvedToUnknown; } set { if (_isLocked) return; _attr.UnresolvedToUnknown = value; } } /// /// Gets or sets whether RT must automatically treat methods returning Task as async methods /// public bool AutoAsync { get { return _attr.AutoAsync; } set { if (_isLocked) return; _attr.AutoAsync = value; } } } } ================================================ FILE: Reinforced.Typings/IFilesOperations.cs ================================================ using Reinforced.Typings.ReferencesInspection; namespace Reinforced.Typings { /// /// Interface of files operator /// It has to be public for testing purposes /// public interface IFilesOperations { /// /// Export context /// ExportContext Context { set; } /// /// Writes temporary files contents to disk /// void DeployTempFiles(); /// /// Cleans up temporary files registry /// void ClearTempRegistry(); /// /// Exports specified syntax nodes to specified file /// /// File name /// File to be exported void Export(string fileName, ExportedFile file); } } ================================================ FILE: Reinforced.Typings/InlineTypeInferers.cs ================================================ using System; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings { /// /// Class holding inline type inferers for specified node /// /// public class InlineTypeInferers { internal Type StrongType { get; set; } internal string Type { get; set; } private Func _stringResolver; private Func _typenameResolver; private Func _stringSimpleResolver; private Func _typenameSimpleResolver; internal Func StringResolver { get { return _stringResolver; } set { _stringResolver = value; _typenameResolver = null; _stringSimpleResolver = null; _typenameSimpleResolver = null; } } internal Func TypenameResolver { get { return _typenameResolver; } set { _typenameResolver = value; _stringResolver = null; _stringSimpleResolver = null; _typenameSimpleResolver = null; } } internal Func StringSimpleResolver { get { return _stringSimpleResolver; } set { _stringSimpleResolver = value; _typenameResolver = null; _stringResolver = null; _typenameSimpleResolver = null; } } internal Func TypenameSimpleResolver { get { return _typenameSimpleResolver; } set { _typenameSimpleResolver = value; _stringSimpleResolver = null; _stringResolver = null; _typenameResolver = null; } } internal RtTypeName Infer(T src, TypeResolver resolver) { if (StringResolver != null) { var r = StringResolver(src, resolver); return new RtSimpleTypeName(r); } if (TypenameSimpleResolver != null) { var r = TypenameSimpleResolver(src); return r; } if (StringSimpleResolver != null) { var r = StringSimpleResolver(src); return new RtSimpleTypeName(r); } if (TypenameResolver != null) { var r = TypenameResolver(src, resolver); return r; } return null; } } /// /// Decorates member that supports inline type inferring /// /// Member Type public interface ISupportsInferring { /// /// Type inferers set instance /// InlineTypeInferers TypeInferers { get; } } } ================================================ FILE: Reinforced.Typings/Location.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Ast; namespace Reinforced.Typings { /// /// Identifies where current export is performed in terms of AST. /// Context.Location could be used to conditionally add members to different places of generated source code /// public class Location { private readonly ExportContext _exContext; /// /// Current Class /// public RtClass CurrentClass { get; private set; } /// /// Current Interface /// public RtInterface CurrentInterface { get; private set; } /// /// Current Enum /// public RtEnum CurrentEnum { get; private set; } /// /// Current Module /// public RtNamespace CurrentNamespace { get; private set; } /// /// References currently exported type /// public Type CurrentType { get { if (_typesStack.Count == 0) return null; return _typesStack.Peek().Type; } } /// /// Sets current location /// /// public void SetLocation(RtNode location) { if (location is RtClass) CurrentClass = (RtClass)location; if (location is RtInterface) CurrentInterface = (RtInterface)location; if (location is RtEnum) CurrentEnum = (RtEnum)location; if (location is RtNamespace) CurrentNamespace = (RtNamespace)location; } /// /// Sets current location /// /// public void ResetLocation(RtNode location) { if (location is RtClass) CurrentClass = null; if (location is RtInterface) CurrentInterface = null; if (location is RtEnum) CurrentEnum = null; if (location is RtNamespace) CurrentNamespace = null; } internal Stack _typesStack = new Stack(); internal Location(ExportContext exContext) { _exContext = exContext; } /// /// Sets currently exported type /// /// public void SetCurrentType(Type t) { _typesStack.Push(_exContext.Project.Blueprint(t)); } /// /// Resets currently exported type /// public void ResetCurrentType() { if (_typesStack.Count > 0) _typesStack.Pop(); } } } ================================================ FILE: Reinforced.Typings/ProjectBlueprint.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; namespace Reinforced.Typings { /// /// Class that holds information of all exported types' parameters and helper methods for it /// public class ProjectBlueprint { /// Initializes a new instance of the class. public ProjectBlueprint() { PathesToFiles = new Dictionary(); TypesInFiles = new Dictionary>(); AdditionalDocumentationPathes = new List(); References = new List(); Imports = new List(); GlobalGenericSubstitutions = new Dictionary>(); GlobalSubstitutions = new Dictionary(); } private readonly Dictionary _blueprints = new Dictionary(); internal IEnumerable BlueprintedTypes { get { return _blueprints.Keys; } } /// /// Returns blueprint for type. Never returns null /// /// Type /// Type blueprint public TypeBlueprint Blueprint(Type t) { if (t == null) return null; return _blueprints.GetOrCreate(t, () => new TypeBlueprint(t)); } /// /// Returns blueprint for type. /// /// Type /// True to create blueprint if it does not exist /// Type blueprint public TypeBlueprint Blueprint(Type t, bool create) { if (t == null) return null; if (create) return _blueprints.GetOrCreate(t, () => new TypeBlueprint(t)); if (!_blueprints.ContainsKey(t)) return null; return _blueprints[t]; } internal void AddFileSeparationSettings(Type type) { var bp = Blueprint(type); if (bp.ThirdParty != null) return; if (!string.IsNullOrEmpty(bp.PathToFile)) { TrackTypeFile(type, bp.PathToFile); } else { var fileAttr = type.GetCustomAttribute(); if (fileAttr != null) { TrackTypeFile(type, fileAttr.FileName); } } } internal void TrackTypeFile(Type t, string fileName) { if (string.IsNullOrEmpty(fileName)) return; var typesPerFile = TypesInFiles.GetOrCreate(fileName); if (!typesPerFile.Contains(t)) typesPerFile.Add(t); PathesToFiles[t] = fileName; } internal string GetPathForFile(Type t) { if (PathesToFiles.ContainsKey(t)) return PathesToFiles[t]; return null; } /// /// Dictionary holds pathes to files /// public Dictionary PathesToFiles { get; private set; } /// /// Dictionary that holds types within each file /// public Dictionary> TypesInFiles { get; private set; } /// /// Additional pathes to look up documentation for /// public List AdditionalDocumentationPathes { get; private set; } /// /// References that will be added to each exported file /// public List References { get; private set; } /// /// Imports that will be added to each exported file /// public List Imports { get; private set; } internal Dictionary GlobalSubstitutions { get; private set; } internal Dictionary> GlobalGenericSubstitutions { get; private set; } /// /// Obtains substitution for type /// /// Type to find substitution for /// Type resolver instance /// Substitution AST public RtTypeName Substitute(Type t, TypeResolver tr) { Type genericDef = t._IsGenericType() ? t.GetGenericTypeDefinition() : null; if (GlobalSubstitutions.ContainsKey(t)) return GlobalSubstitutions[t]; if (genericDef != null) { if (GlobalGenericSubstitutions.ContainsKey(genericDef)) { var ts = GlobalGenericSubstitutions[genericDef](t, tr); if (ts != null) return ts; } } return null; } } } ================================================ FILE: Reinforced.Typings/Properties/AssemblyInfo.cs ================================================ using System; using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("DynamicMvcTypings")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DynamicMvcTypings")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: CLSCompliant(true)] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("f05e4940-fa83-446c-97ff-b0d7fb56daee")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: Reinforced.Typings/ReferencesInspection/ImportComparer.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.ReferencesInspection { sealed class ImportComparer : IEqualityComparer { public bool Equals(RtImport x, RtImport y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(x, null)) return false; if (ReferenceEquals(y, null)) return false; if (x.GetType() != y.GetType()) return false; return string.Equals(x.Target, y.Target) && string.Equals(x.From, y.From) && x.IsRequire == y.IsRequire; } public int GetHashCode(RtImport obj) { unchecked { var hashCode = (obj.Target != null ? obj.Target.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (obj.From != null ? obj.From.GetHashCode() : 0); hashCode = (hashCode * 397) ^ obj.IsRequire.GetHashCode(); return hashCode; } } private static readonly ImportComparer _instance = new ImportComparer(); public static ImportComparer Instance { get { return _instance; } } } } ================================================ FILE: Reinforced.Typings/ReferencesInspection/InspectedReferences.cs ================================================ using System.Collections.Generic; using System.Linq; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.ReferencesInspection { /// /// Represents inspected references for type or global references /// public class InspectedReferences { private readonly HashSet _references = new HashSet(ReferenceComparer.Instance); private readonly HashSet _imports = new HashSet(ImportComparer.Instance); private readonly Dictionary _starImportsAs = new Dictionary(); /// /// References exposed via <reference path="..."> tag /// public IEnumerable References { get { return _references; } } /// /// References exposed via imports /// public IEnumerable Imports { get { return _imports; } } /// /// Cache of starred imports. Key is "from", value is star import alias /// public IReadOnlyDictionary StarImports { get { return _starImportsAs; } } /// /// Constructs new inspected references set /// /// References /// Imports public InspectedReferences(IEnumerable references, IEnumerable imports = null) { foreach (var rtReference in references) { _references.AddIfNotExists(rtReference); } if (imports != null) { foreach (var rtImport in imports.Where(c => c.IsWildcard)) { _imports.AddIfNotExists(rtImport); _starImportsAs[rtImport.From] = rtImport; } foreach (var rtImport in imports.Where(c => !c.IsWildcard)) { _imports.AddIfNotExists(rtImport); } } } /// /// Duplicates inspected references for further usage /// /// public InspectedReferences Duplicate() { return new InspectedReferences(_references, _imports); } /// /// Attaches new reference to existing ones /// /// New reference public void AddReference(RtReference reference) { _references.AddIfNotExists(reference); } /// /// Attaches new import to existing ones /// /// Import public void AddImport(RtImport import) { if (import.IsWildcard) { if (_starImportsAs.ContainsKey(import.From)) return; _imports.RemoveWhere(c => c.From == import.From); _imports.Add(import); _starImportsAs[import.From] = import; } else { _imports.AddIfNotExists(import); } } } } ================================================ FILE: Reinforced.Typings/ReferencesInspection/ReferenceComparer.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.ReferencesInspection { sealed class ReferenceComparer : IEqualityComparer { public bool Equals(RtReference x, RtReference y) { return x.Path == y.Path; } public int GetHashCode(RtReference obj) { return obj.Path.GetHashCode(); } private static readonly ReferenceComparer _instance = new ReferenceComparer(); public static ReferenceComparer Instance { get { return _instance; } } } } ================================================ FILE: Reinforced.Typings/ReferencesInspection/ReferenceProcessorBase.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Ast.Dependency; namespace Reinforced.Typings.ReferencesInspection { /// /// Base class for reference post-processor. /// public abstract class ReferenceProcessorBase { /// /// Returns refiltered and reordered import directives that must appear in resulting file. /// Return null to remain references list untouched /// /// Set on initially computed imports /// File that is being exported currently /// Set of refiltered/reordered imports public abstract IEnumerable FilterImports(IEnumerable imports, ExportedFile file); /// /// Returns refiltered and reordered reference directives that must appear in resulting file /// Return null to remain imports list untouched /// /// Set on initially computed references /// File that is being exported currently /// Set of refiltered/reordered references public abstract IEnumerable FilterReferences(IEnumerable references, ExportedFile file); } } ================================================ FILE: Reinforced.Typings/Reinforced.Typings.Dev.csproj ================================================ net5.0 Reinforced.Typings false false false None AnyCPU;x64;x86 Reinforced.Typings Reinforced Software Construction OSS Pavel B. Novikov 2019 $(AssemblyName) 1.5.9 1.5.9 1.5.9 $(DefineConstants);NETCORE; ================================================ FILE: Reinforced.Typings/Reinforced.Typings.NETCore.csproj ================================================ net10.0 Reinforced.Typings false false false None AnyCPU;x64;x86 Reinforced.Typings Reinforced Software Construction OSS Pavel B. Novikov 2019 $(AssemblyName) 1.6.7 1.6.7 1.6.7 $(DefineConstants);$(RtAdditionalConstants); ================================================ FILE: Reinforced.Typings/Reinforced.Typings.csproj ================================================  Debug AnyCPU {2A5CCD5C-E660-4088-8937-9632ABBBCDBB} Library Properties Reinforced.Typings Reinforced.Typings v4.5 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 false bin\Debug\Reinforced.Typings.XML pdbonly true bin\Release\ TRACE prompt 4 bin\Release\Reinforced.Typings.xml false Auto true ================================================ FILE: Reinforced.Typings/Sign.cs ================================================ using System.Reflection; [assembly: AssemblyKeyFile("Reinforced.snk")] ================================================ FILE: Reinforced.Typings/TsExporter.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Reinforced.Typings.Ast; using Reinforced.Typings.Fluent; using Reinforced.Typings.ReferencesInspection; namespace Reinforced.Typings { /// /// Facade for final TypeScript export. This class supplies assemblies names or assemblies itself as parameter and /// exports resulting TypeScript file to file or to string /// public sealed class TsExporter //: MarshalByRefObject { private readonly ExportContext _context; /// /// Obtains export context /// public ExportContext Context { get { return _context; } } private bool _isInitialized; #region Constructors /// /// Constructs new instance of TypeScript exporter /// /// public TsExporter(ExportContext context) { _context = context; } #endregion /// /// Initializes TS exporter. Reads all types configuration, applies fluent configuration, resolves references /// public void Initialize() { if (_isInitialized) return; _context.Initialize(); _isInitialized = true; } /// /// Exports TypeScript source to specified TextWriter according to settings /// /// File name to export files to private ExportedFile ExportTypes(string fileName = null) { var ef = _context.CreateExportedFile(fileName); var gen = _context.Generators.GeneratorForNamespace(); var grp = ef.TypesToExport.GroupBy(c => _context.Project.Blueprint(c).GetNamespace(true)); var nsp = grp.Where(g => !string.IsNullOrEmpty(g.Key)) // avoid anonymous types .ToDictionary(k => k.Key, v => v.ToList()); List result = new List(nsp.Count); foreach (var n in nsp) { var ns = n.Key; if (ns == "-") ns = string.Empty; var module = gen.Generate(n.Value, ns, ef.TypeResolver); result.Add(module); } ef.Namespaces = result.ToArray(); return ef; } /// /// Exports TypeScript source according to settings /// public void Export() { _context.FileOperations.ClearTempRegistry(); Initialize(); _context.Lock(); ReferenceProcessorBase refProc = null; if (_context.Global.ReferencesProcessorType != null) { refProc = (ReferenceProcessorBase)Activator.CreateInstance(_context.Global.ReferencesProcessorType); } if (!_context.Hierarchical) { var file = ExportTypes(); file.ApplyReferenceProcessor(refProc); _context.FileOperations.Export(_context.TargetFile, file); } else { foreach (var kv in _context.TypesToFilesMap) { var path = kv.Key; var file = ExportTypes(kv.Key); file.ApplyReferenceProcessor(refProc); _context.FileOperations.Export(path, file); } } _context.Unlock(); _context.FileOperations.DeployTempFiles(); } } } ================================================ FILE: Reinforced.Typings/TypeBlueprint.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; namespace Reinforced.Typings { /// /// Holds all information that is necessary to export particular type /// public class TypeBlueprint { /// Initializes a new instance of the class. internal TypeBlueprint(Type t) { _attributesForParameters = new Dictionary(); _attributesForProperties = new Dictionary(); _attributesForMethods = new Dictionary(); _attributesForFields = new Dictionary(); _attributesForEnumValues = new Dictionary(); Substitutions = new Dictionary(); GenericSubstitutions = new Dictionary>(); References = new List(); Imports = new List(); DecoratorsForMembers = new Dictionary>(); DecoratorsForParameters = new Dictionary>(); Decorators = new List(); Type = t; ThirdPartyImports = new List(); ThirdPartyReferences = new List(); TypeAttribute = Type.GetCustomAttribute(false) ?? Type.GetCustomAttribute(false) ?? (TsDeclarationAttributeBase)Type.GetCustomAttribute(false); IsExportedExplicitly = TypeAttribute != null; _thirdPartyAttribute = Type.GetCustomAttribute(); InitFromAttributes(); } /// /// Gets whether specified type is exported explicitly /// public bool IsExportedExplicitly { get; internal set; } private bool _flattenTouched = false; internal void NotifyFlattenTouched() { _flattenTouched = true; } /// /// Path to file that blueprinted type will be exported to /// public string PathToFile { get; internal set; } private void InitFromAttributes() { var typeRefs = Type.GetCustomAttributes(); References.AddRange(typeRefs); var typeImports = Type.GetCustomAttributes(); Imports.AddRange(typeImports); InitThirdPartyImports(); } private void InitThirdPartyImports() { if (ThirdParty != null) { ThirdPartyReferences.Clear(); ThirdPartyImports.Clear(); var tpRefs = Type.GetCustomAttributes(); foreach (var a in tpRefs) { ThirdPartyReferences.Add(a.ToReference()); } var tpImpots = Type.GetCustomAttributes(); foreach (var a in tpImpots) { ThirdPartyImports.Add(a.ToImport()); } } } /// /// Type is being exported /// public Type Type { get; private set; } /// /// Attribute for exporting class /// public TsDeclarationAttributeBase TypeAttribute { get { return _typeAttribute; } internal set { _typeAttribute = value; InitFromAttributes(); } } internal RtRaw ConstructorBody { get; set; } #region Third-Party type handling private TsThirdPartyAttribute _thirdPartyAttribute; internal List ThirdPartyImports { get; private set; } internal List ThirdPartyReferences { get; private set; } /// /// Gets whether type is used as third-party type only without export being performed /// public TsThirdPartyAttribute ThirdParty { get { return _thirdPartyAttribute; } set { _thirdPartyAttribute = value; InitFromAttributes(); } } #endregion private readonly HashSet _ignored = new HashSet(); /// /// Set of ignored members /// internal HashSet Ignored { get { return _ignored; } private set { } } private readonly Dictionary _attributesForProperties; private readonly Dictionary _attributesForMethods; private readonly Dictionary _attributesForParameters; private readonly Dictionary _attributesForFields; private readonly Dictionary _attributesForEnumValues; private TsDeclarationAttributeBase _typeAttribute; /// /// Substitutions /// public Dictionary Substitutions { get; private set; } /// /// Generic substitutions /// public Dictionary> GenericSubstitutions { get; private set; } /// /// References /// public List References { get; private set; } /// /// Imports /// public List Imports { get; private set; } /// /// Decorators /// public List Decorators { get; set; } /// /// Decorators for type members /// public Dictionary> DecoratorsForMembers { get; private set; } /// /// Decorators for parameters /// public Dictionary> DecoratorsForParameters { get; private set; } /// /// Retrieves configuration attribute for type member /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public TsTypedMemberAttributeBase ForMember(MemberInfo member, bool create = false) { if (member is PropertyInfo) return ForMember((PropertyInfo)member, create); if (member is MethodInfo) return ForMember((MethodInfo)member, create); if (member is FieldInfo) return ForMember((FieldInfo)member, create); return null; } /// /// Retrieves configuration attribute for type member /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public T ForMember(MemberInfo member, bool create = false) where T : TsTypedMemberAttributeBase { if (member is PropertyInfo) return (T)(object)ForMember((PropertyInfo)member, create); if (member is MethodInfo) return (T)(object)ForMember((MethodInfo)member, create); if (member is FieldInfo) return (T)(object)ForMember((FieldInfo)member, create); return null; } /// /// Retrieves configuration attribute for method /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public TsFunctionAttribute ForMember(MethodInfo member, bool create = false) { var v = _attributesForMethods.GetOr(member, () => member.GetCustomAttribute(false)); if (create && v == null) { return _attributesForMethods.GetOrCreate(member); } return v; } /// /// Retrieves configuration attribute for method parameter /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public TsParameterAttribute ForMember(ParameterInfo member, bool create = false) { var v = _attributesForParameters.GetOr(member, () => member.GetCustomAttribute(false)); if (create && v == null) { return _attributesForParameters.GetOrCreate(member); } return v; } /// /// Retrieves configuration attribute for property /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public TsPropertyAttribute ForMember(PropertyInfo member, bool create = false) { var v = _attributesForProperties.GetOr(member, () => member.GetCustomAttribute(false)); if (create && v == null) { return _attributesForProperties.GetOrCreate(member); } return v; } /// /// Retrieves configuration attribute for field /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public TsPropertyAttribute ForMember(FieldInfo member, bool create = false) { var v = _attributesForFields.GetOr(member, () => member.GetCustomAttribute(false)); if (create && v == null) { return _attributesForFields.GetOrCreate(member); } return v; } /// /// Retrieves configuration attribute for constructor /// /// Type member /// Configuration attribute public TsBaseParamAttribute ForMember(ConstructorInfo member) { return member.GetCustomAttribute(false); } /// /// Retrieves configuration attribute for enum value /// /// Type member /// When true, attribute will be created if not exists /// Configuration attribute public TsValueAttribute ForEnumValue(FieldInfo member, bool create = false) { var v = _attributesForEnumValues.GetOr(member, () => member.GetCustomAttribute(false)); if (create && v == null) { return _attributesForEnumValues.GetOrCreate(member); } return v; } /// /// Retrieves type's exported fields /// /// Array of exported fields public FieldInfo[] GetExportedFields() { var t = Type; if (IsIgnored()) return new FieldInfo[0]; if (t._IsEnum()) return new FieldInfo[0]; var typeAttr = TypeAttribute; var aexpSwith = typeAttr as IAutoexportSwitchAttribute; if (aexpSwith != null) { var allMembers = this.GetExportingMembers(typeAttr.FlattenHierarchy, (tp, b) => tp._GetFields(b), typeAttr.FlattenLimiter); if (!aexpSwith.AutoExportFields) { allMembers = allMembers.Where(c => ForMember(c) != null); } return allMembers.ToArray(); } return new FieldInfo[0]; } /// /// Retrieves type's exported properties /// /// Array of exported properties public PropertyInfo[] GetExportedProperties() { var t = Type; if (IsIgnored()) return new PropertyInfo[0]; if (t._IsEnum()) return new PropertyInfo[0]; var typeAttr = TypeAttribute; var aexpSwith = typeAttr as IAutoexportSwitchAttribute; if (aexpSwith != null) { var allMembers = this.GetExportingMembers(typeAttr.FlattenHierarchy, (tp, b) => tp._GetProperties(b), typeAttr.FlattenLimiter); if (!aexpSwith.AutoExportProperties) { allMembers = allMembers.Where(c => ForMember(c) != null); } return allMembers.ToArray(); } return new PropertyInfo[0]; } /// /// Retrieves type's exported methods /// /// Array of exported methods public MethodInfo[] GetExportedMethods() { var t = Type; if (IsIgnored()) return new MethodInfo[0]; if (t._IsEnum()) return new MethodInfo[0]; var typeAttr = TypeAttribute; var aexpSwith = typeAttr as IAutoexportSwitchAttribute; if (aexpSwith != null) { var allMembers = this.GetExportingMembers(typeAttr.FlattenHierarchy, (tp, b) => tp._GetMethods(b).Where(x => !x.IsSpecialName).ToArray(), typeAttr.FlattenLimiter); if (!aexpSwith.AutoExportMethods) { allMembers = allMembers.Where(c => ForMember(c) != null); } return allMembers.Where(c => !c.IsSpecialName).ToArray(); } return new MethodInfo[0]; } #region Ignorance tracking methods /// /// Checks whether type is ignored during export /// /// True, when type is ignored. False otherwise private bool IsIgnored() { return TypeAttribute == null; } /// /// Checks whether constructor is ignored during export /// /// True, when constructor is ignored. False otherwise public bool IsIgnored(ConstructorInfo member) { return (member.GetCustomAttribute(false) != null); } /// /// Checks whether field is ignored during export /// /// True, when field is ignored. False otherwise public bool IsIgnored(FieldInfo member) { return _ignored.Contains(member) || (member.GetCustomAttribute() != null); } /// /// Checks whether property is ignored during export /// /// True, when property is ignored. False otherwise public bool IsIgnored(PropertyInfo member) { return _ignored.Contains(member) || (member.GetCustomAttribute() != null); } /// /// Checks whether parameter is ignored during export /// /// True, when parameter is ignored. False otherwise public bool IsIgnored(ParameterInfo member) { return _ignored.Contains(member) || (member.GetCustomAttribute() != null); } /// /// Checks whether type member is ignored during export /// /// True, when type member is ignored. False otherwise public bool IsIgnored(MemberInfo member) { #if NETCORE #else //if (member is Type) return IsIgnored((Type)member); #endif if (member is PropertyInfo) return IsIgnored((PropertyInfo)member); if (member is MethodInfo) return IsIgnored((MethodInfo)member); if (member is FieldInfo) return IsIgnored((FieldInfo)member); return false; } /// /// Checks whether method is ignored during export /// /// True, when method is ignored. False otherwise public bool IsIgnored(MethodInfo member) { return _ignored.Contains(member) || (member.GetCustomAttribute(false) != null); } #endregion internal List DecoratorsListFor(MemberInfo t) { return DecoratorsForMembers.GetOrCreate(t); } internal List DecoratorsListFor(ParameterInfo t) { return DecoratorsForParameters.GetOrCreate(t); } /// /// Retrieves decorators for type /// /// Set of type's decorators public IEnumerable GetDecorators() { var inlineDecorators = Type.GetCustomAttributes(); return inlineDecorators.Union(Decorators); } /// /// Retrieves set of decorators for method parameter /// /// Method's parameter /// Set of decorators public IEnumerable DecoratorsFor(ParameterInfo t) { var inlineDecorators = t.GetCustomAttributes(); var fluentDecorators = DecoratorsForParameters.ContainsKey(t) ? DecoratorsForParameters[t] : null; if (fluentDecorators == null) return inlineDecorators; return inlineDecorators.Union(fluentDecorators); } /// /// Retrieves set of decorators for type's member /// /// Member's parameter /// Set of decorators public IEnumerable DecoratorsFor(MemberInfo t) { var inlineDecorators = t.GetCustomAttributes(); var fluentDecorators = DecoratorsForMembers.ContainsKey(t) ? DecoratorsForMembers[t] : null; if (fluentDecorators == null) return inlineDecorators; return inlineDecorators.Union(fluentDecorators); } /// /// Retrieves type's configuration attribute /// /// Attribute type. Subclass of /// Configuration attribute. May be null public T Attr() where T : TsDeclarationAttributeBase { return TypeAttribute as T; } /// /// Conditionally (based on attribute setting) turns member name to camelCase /// /// Member /// Regular property name /// Property name in camelCase if camelCasing enabled, initial string otherwise public string CamelCaseFromAttribute(MemberInfo member, string regularName) { var attr = ForMember(member); if (attr == null) return regularName; if (attr.ShouldBeCamelCased) return ConvertToCamelCase(regularName); return regularName; } /// /// Conditionally (based on attribute setting) turns member name to PascalCase /// /// Member /// Regular property name /// Property name in PascalCase if pascalCasing enabled, initial string otherwise public string PascalCaseFromAttribute(MemberInfo member, string regularName) { var attr = ForMember(member); if (attr == null) return regularName; if (attr.ShouldBePascalCased) return ConvertToPascalCase(regularName); return regularName; } /// /// Converts string to camelCase /// /// Source string in any case /// Resulting string in camelCase public static string ConvertToCamelCase(string s) { if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0])) { return s; } char[] chars = s.ToCharArray(); for (int i = 0; i < chars.Length; i++) { if (i == 1 && !char.IsUpper(chars[i])) { break; } bool hasNext = i + 1 < chars.Length; if (i > 0 && hasNext && !char.IsUpper(chars[i + 1])) { // ABCa -> abCa break; } chars[i] = char.ToLowerInvariant(chars[i]); } return new string(chars); } private string ConvertToPascalCase(string s) { if (!char.IsLetter(s[0])) return s; if (char.IsLower(s[0])) { return char.ToUpper(s[0]) + s.Substring(1); } return s; } #region Order /// /// Retrieves member order /// /// Method info /// Method order public double GetOrder(MemberInfo element) { if (element is MethodInfo) return GetOrder((MethodInfo)element); if (element is PropertyInfo) return GetOrder((PropertyInfo)element); if (element is FieldInfo) return GetOrder((FieldInfo)element); return 0; } /// /// Retrieves member order /// /// Method info /// Method order public double GetOrder(MethodInfo element) { var fa = ForMember(element); if (fa != null) return fa.Order; return 0; } /// /// Retrieves member order /// /// Method info /// Method order public double GetOrder(PropertyInfo element) { var fa = ForMember(element); if (fa != null) return fa.Order; return 0; } /// /// Retrieves member order /// /// Method info /// Method order public double GetOrder(FieldInfo element) { var fa = ForMember(element); if (fa != null) return fa.Order; return 0; } /// /// Retrieves type order to appear in results file /// /// Type name public double GetOrder() { if (Type._IsEnum()) { var te = Attr(); return te.Order; } var tc = Attr(); var ti = Attr(); var order = tc != null ? tc.Order : ti != null ? ti.Order : 0; return order; } #endregion #region Names /// /// Retrieves parameter name from corresponding attribute. If attribute not present then takes parameter name via /// reflection /// /// Parameter info /// Parameter name public string GetName(ParameterInfo element) { var fa = ForMember(element); if (fa != null && !string.IsNullOrEmpty(fa.Name)) return fa.Name; return element.Name; } /// /// Retrieves type name from type itself or from corresponding Reinforced.Typings attribute /// /// Generic arguments to be substituted to type /// Type name public RtSimpleTypeName GetName(RtTypeName[] genericArguments = null) { var t = Type; string name = null; if (ThirdParty == null) { if (t._IsEnum()) { var te = Attr(); var ns = t.Name; if (te != null && !string.IsNullOrEmpty(te.Name)) { ns = te.Name; } return new RtSimpleTypeName(ns); } var tc = Attr(); var ti = Attr(); var nameFromAttr = tc != null ? tc.Name : ti != null ? ti.Name : null; name = (!string.IsNullOrEmpty(nameFromAttr) ? nameFromAttr : t.CleanGenericName()); if (ti != null) { if (ti.AutoI) { if (t._IsClass()) name = "I" + name; else if (!name.StartsWith("I")) name = "I" + name; } } } else { name = ThirdParty.Name; } if (genericArguments == null) genericArguments = t.SerializeGenericArguments(); return new RtSimpleTypeName(name, genericArguments); } #endregion /// /// Gets whether type configuration required flattering inheritance hierarchy /// /// True, when hierarchy must be flatten, false otherwise public bool IsFlatten() { var tc = Attr(); var ti = Attr(); return tc != null ? tc.FlattenHierarchy : ti != null ? ti.FlattenHierarchy : false; } #region Is exported (as) /// /// Determines should type be exported as interface or not /// /// True, if supplied type should be exported as interface. False otherwise public bool IsExportingAsInterface() { return Attr() != null; } /// /// Determines should type be exported as class or not /// /// True, if supplied type should be exported as interface. False otherwise public bool IsExportingAsClass() { return Attr() != null; } #endregion /// /// Retrieves type namespace from type itself or from corresponding Typings attribute /// /// /// Forces GetNamespace to return "-" for interfaces with IncludeInterface = false and /// null for anonymous types /// /// Full-qualified namespace name internal string GetNamespace(bool distinguishAutoTypes = false) { var t = Type; if (t._IsEnum()) { var te = Attr(); if (te == null) return t.Namespace; var ns = te.Namespace; if (!te.IncludeNamespace) return distinguishAutoTypes ? "-" : string.Empty; if (!string.IsNullOrEmpty(ns)) return ns; return t.Namespace; } var tc = Attr(); var ti = Attr(); if (tc == null && ti == null) return t.Namespace; var nsFromAttr = tc != null ? tc.Namespace : ti.Namespace; var includeNamespace = tc != null ? tc.IncludeNamespace : ti.IncludeNamespace; if (!includeNamespace) return distinguishAutoTypes ? "-" : string.Empty; if (!string.IsNullOrEmpty(nsFromAttr)) return nsFromAttr; return t.Namespace; } /// /// Obtains substitution for type /// /// Type to find substitution for /// Type resolver instance /// Substitution AST public RtTypeName Substitute(Type t, TypeResolver tr) { Type genericDef = t._IsGenericType() ? t.GetGenericTypeDefinition() : null; if (Substitutions.ContainsKey(t)) return Substitutions[t]; if (genericDef != null) { if (GenericSubstitutions.ContainsKey(genericDef)) { var r = GenericSubstitutions[genericDef]; var ts = r(t, tr); if (ts != null) return ts; } } return null; } /// /// Gets whether type hierarchy can be flatten /// /// public bool CanFlatten() { if (_flattenTouched) return false; if (_attributesForProperties.Count > 0) return false; if (_attributesForParameters.Count > 0) return false; if (_attributesForFields.Count > 0) return false; if (_attributesForMethods.Count > 0) return false; if (_attributesForEnumValues.Count > 0) return false; return true; } } } ================================================ FILE: Reinforced.Typings/TypeExtensions.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; namespace Reinforced.Typings { internal static class HashSetExtensions { internal static void AddIfNotExists(this HashSet hashSet, T val) { if (hashSet.Contains(val)) return; hashSet.Add(val); } } /// /// Useful extensions for reflection /// public static class TypeExtensions { internal static object InstanceInternal(this Type t, params object[] parameters) { #if NETCOREAPP1_0 var dc = t.GetTypeInfo().DeclaredConstructors; var needed = dc.Where(d=>d.GetParameters().Length == parameters.Length).FirstOrDefault(); return needed.Invoke(parameters); #elif NETSTANDARD1_5 var dc = t.GetTypeInfo().DeclaredConstructors; var needed = dc.Where(d=>d.GetParameters().Length == parameters.Length).FirstOrDefault(); return needed.Invoke(parameters); #elif NETSTANDARD1_6 var dc = t.GetTypeInfo().DeclaredConstructors; var needed = dc.Where(d=>d.GetParameters().Length == parameters.Length).FirstOrDefault(); return needed.Invoke(parameters); #else return Activator.CreateInstance(t, BindingFlags.NonPublic | BindingFlags.Instance, null, parameters, null); #endif } internal static IEnumerable _GetTypes(this Assembly a, IWarningsCollector warnings) { try { return a.GetTypes(); } catch (ReflectionTypeLoadException e) { foreach (var elo in e.LoaderExceptions) { warnings.AddWarning(ErrorMessages.RTW0008_TypeloadException.Warn(elo.Message)); } return e.Types.Where(t => t != null); } } internal static T RetrieveOrCreateCustomAttribute(this ICustomAttributeProvider member) where T : Attribute, new() { T proto = null; var attrs = member.GetCustomAttributes(true); foreach (var attribute in attrs) { if (typeof(T)._IsAssignableFrom(attribute.GetType())) { proto = (T)attribute; } } if (proto == null) proto = new T(); return proto; } #if NETCORE internal static T GetCustomAttribute(this Type t, bool inherit = true) where T : Attribute { return CustomAttributeExtensions.GetCustomAttribute(t.GetTypeInfo(), inherit); } internal static IEnumerable GetCustomAttributes(this Type t, bool inherit = true) where T : Attribute { return CustomAttributeExtensions.GetCustomAttributes(t.GetTypeInfo(), inherit); } #endif internal static IEnumerable _GetCustomAttributes(this Type t, bool inherit = true) { #if NETCORE return t.GetTypeInfo().GetCustomAttributes(inherit); #else return t.GetCustomAttributes(inherit); #endif } public static bool IsReferenceForcedNullable(this MemberInfo member) { byte[] nullableFlag = GetNullableAttributeValue(member); return nullableFlag != null && nullableFlag.Length > 0 && nullableFlag[0] == 2; } public static bool IsReferenceForcedNullable(this ParameterInfo member) { byte[] nullableFlag = GetNullableAttributeValue(member); return nullableFlag != null && nullableFlag.Length > 0 && nullableFlag[0] == 2; } internal static bool _IsGenericType(this Type t) { #if NETCORE return t.GetTypeInfo().IsGenericType; #else return t.IsGenericType; #endif } internal static bool _IsGenericTypeDefinition(this Type t) { #if NETCORE return t.GetTypeInfo().IsGenericTypeDefinition; #else return t.IsGenericTypeDefinition; #endif } internal static Type _BaseType(this Type t) { #if NETCORE return t.GetTypeInfo().BaseType; #else return t.BaseType; #endif } internal static bool _IsEnum(this Type t) { #if NETCORE return t.GetTypeInfo().IsEnum; #else return t.IsEnum; #endif } internal static bool _IsClass(this Type t) { #if NETCORE return t.GetTypeInfo().IsClass; #else return t.IsClass; #endif } internal static bool _IsAssignableFrom(this Type t, Type t2) { #if NETCORE return t.GetTypeInfo().IsAssignableFrom(t2); #else return t.IsAssignableFrom(t2); #endif } internal static bool _IsAbstract(this Type t) { #if NETCORE return t.GetTypeInfo().IsAbstract; #else return t.IsAbstract; #endif } internal static bool _IsInterface(this Type t) { #if NETCORE return t.GetTypeInfo().IsInterface; #else return t.IsInterface; #endif } internal static bool _IsArray(this Type t) { #if NETCORE return t.GetTypeInfo().IsArray; #else return t.IsArray; #endif } internal static bool _IsReferenceType(this Type t) { return t._IsClass() || t._IsInterface() || t._IsArray() || typeof(string)._IsAssignableFrom(t); } internal static IEnumerable _GetInterfaces(this Type t) { #if NETCORE return t.GetTypeInfo().GetInterfaces(); #else return t.GetInterfaces(); #endif } internal static FieldInfo[] _GetFields(this Type t, BindingFlags flags) { #if NETCORE return t.GetTypeInfo().GetFields(flags); #else return t.GetFields(flags); #endif } internal static FieldInfo[] _GetFields(this Type t) { #if NETCORE return t.GetTypeInfo().GetFields(); #else return t.GetFields(); #endif } internal static FieldInfo _GetField(this Type t, string name) { #if NETCORE return t.GetTypeInfo().GetField(name, MembersFlags); #else return t.GetField(name, MembersFlags); #endif } internal static ConstructorInfo[] _GetConstructors(this Type t, BindingFlags flags) { #if NETCORE return t.GetTypeInfo().GetConstructors(flags); #else return t.GetConstructors(flags); #endif } internal static PropertyInfo[] _GetProperties(this Type t, BindingFlags flags) { #if NETCORE return t.GetTypeInfo().GetProperties(flags); #else return t.GetProperties(flags); #endif } internal static MethodInfo[] _GetMethods(this Type t, BindingFlags flags) { #if NETCORE return t.GetTypeInfo().GetMethods(flags); #else return t.GetMethods(flags); #endif } internal static MethodInfo _GetMethod(this Type t, string name) { #if NETCORE return t.GetTypeInfo().GetMethod(name, MembersFlags); #else return t.GetMethod(name, MembersFlags); #endif } internal static Type[] _GetGenericArguments(this Type t) { #if NETCORE return t.GetTypeInfo().GetGenericArguments(); #else return t.GetGenericArguments(); #endif } internal static PropertyInfo _GetProperty(this Type t, string name) { #if NETCORE return t.GetTypeInfo().GetProperty(name, MembersFlags); #else return t.GetProperty(name, MembersFlags | BindingFlags.GetProperty | BindingFlags.SetProperty); #endif } /// /// Binding flags for searching all members /// public const BindingFlags MembersFlags = PublicMembersFlags | BindingFlags.NonPublic; /// /// Binding flags for searching all members /// public const BindingFlags PublicMembersFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; #region Inheritance flatten /// /// Simple comparer to detect overridden methods /// private class MethodEqComparer : IEqualityComparer { public static readonly MethodEqComparer Instance = new MethodEqComparer(); public bool Equals(MethodInfo x, MethodInfo y) { if (x == null && y == null) return true; if (x == null && y != null) return false; if (y == null && x != null) return false; if (x.Name != y.Name) return false; var xparms = x.GetParameters(); var yparms = y.GetParameters(); if (xparms.Length != yparms.Length) return false; for (int i = 0; i < xparms.Length; i++) { if (xparms[i].Name != yparms[i].Name) return false; } return true; } public int GetHashCode(MethodInfo obj) { unchecked { int hashCode = obj.Name.GetHashCode(); var parms = obj.GetParameters(); hashCode = (hashCode * 397) ^ parms.Length; foreach (var pi in parms) { hashCode = (hashCode * 397) ^ pi.Name.GetHashCode(); } return hashCode; } } } private class NameEqComparer : IEqualityComparer where T : MemberInfo { public static readonly NameEqComparer Instance = new NameEqComparer(); public bool Equals(T x, T y) { if (x == null && y == null) return true; if (x == null && y != null) return false; if (y == null && x != null) return false; if (x.Name != y.Name) return false; return true; } public int GetHashCode(T obj) { return obj.Name.GetHashCode(); } } private static IEqualityComparer GetInheritanceEqComparer() where T : MemberInfo { if (typeof(T) == typeof(MethodInfo)) return (IEqualityComparer)MethodEqComparer.Instance; return NameEqComparer.Instance; } internal static T[] GetInheritedMembers(this Type type, Func membersGetter, Type limiter) where T : MemberInfo { var members = new HashSet(GetInheritanceEqComparer()); var considered = new List(); var queue = new Queue(); considered.Add(type); queue.Enqueue(type); bool limitReached = false; while (queue.Count > 0) { var subType = queue.Dequeue(); foreach (var subInterface in subType._GetInterfaces()) { if (considered.Contains(subInterface)) continue; considered.Add(subInterface); queue.Enqueue(subInterface); } if (!limitReached) { var bt = subType._BaseType(); if (bt != null) { if (bt == limiter) { limitReached = true; } else { if (considered.Contains(bt)) continue; considered.Add(bt); queue.Enqueue(bt); } } } var typeMembers = membersGetter(subType); foreach (var newMember in typeMembers) { if (!members.Contains(newMember)) members.Add(newMember); } } return members.ToArray(); } internal static IEnumerable GetExportingMembers(this TypeBlueprint t, bool flattenHierarchy, Func membersGetter, Type limiter, bool publicOnly = false) where T : MemberInfo { var declaredFlags = publicOnly ? PublicMembersFlags : MembersFlags; T[] baseSet = null; baseSet = flattenHierarchy ? GetInheritedMembers(t.Type, x => membersGetter(x, declaredFlags), limiter) : membersGetter(t.Type, declaredFlags); var allMembers = baseSet.Where(x => (x.GetCustomAttribute() == null) && !t.IsIgnored(x)).OfType(); return allMembers.ToArray(); } internal static IEnumerable GetExportingMembers(this TypeBlueprint t, Func membersGetter, bool publicOnly = false) where T : MemberInfo { var declaredFlags = publicOnly ? PublicMembersFlags : MembersFlags; var flattenHierarchy = t.TypeAttribute.FlattenHierarchy; var limiter = t.TypeAttribute.FlattenLimiter; T[] baseSet = null; baseSet = flattenHierarchy ? GetInheritedMembers(t.Type, x => membersGetter(x, declaredFlags), limiter) : membersGetter(t.Type, declaredFlags); var allMembers = baseSet.Where(x => (x.GetCustomAttribute() == null) && !t.IsIgnored(x)).OfType(); return allMembers.ToArray(); } #endregion #region IsStatic /// /// Determines is type is static /// /// Type /// True if type is static. False otherwise public static bool IsStatic(this Type t) { #if NETCORE return (t.GetTypeInfo().IsAbstract && t.GetTypeInfo().IsSealed); #else return (t.IsAbstract && t.IsSealed); #endif } /// /// Determines is member static or not /// /// Type member /// True if member is static. False otherwise public static bool IsStatic(this MemberInfo member) { if (member is PropertyInfo) return IsStatic((PropertyInfo)member); if (member is MethodInfo) return ((MethodInfo)member).IsStatic; if (member is FieldInfo) return ((FieldInfo)member).IsStatic; return false; } /// /// Determines is property static or not /// /// Property /// True if member is static. False otherwise public static bool IsStatic(this PropertyInfo propertyInfo) { if (propertyInfo.GetMethod != null) { return propertyInfo.GetMethod.IsStatic; } if (propertyInfo.SetMethod != null) { return propertyInfo.SetMethod.IsStatic; } return false; } #endregion #region Type distinguishing /// /// Determines is type derived from Nullable or not /// /// Type /// True if type is nullable value type. False otherwise public static bool IsNullable(this Type t) { return (t._IsGenericType() && (t.GetGenericTypeDefinition() == typeof(Nullable<>))); } /// /// Determines if type is one of System.Tuple types set /// /// Type to check /// True when type is tuple, false otherwise public static bool IsTuple(this Type t) { if (!t._IsGenericType()) return false; var gen = t.GetGenericTypeDefinition(); if (gen == typeof(System.Tuple<>)) return true; if (gen == typeof(System.Tuple<,>)) return true; if (gen == typeof(System.Tuple<,,>)) return true; if (gen == typeof(System.Tuple<,,,>)) return true; if (gen == typeof(System.Tuple<,,,,>)) return true; if (gen == typeof(System.Tuple<,,,,,>)) return true; if (gen == typeof(System.Tuple<,,,,,,>)) return true; if (gen == typeof(System.Tuple<,,,,,,,>)) return true; if (gen == typeof(System.Tuple<,,,,,,,>)) return true; if (gen.FullName != null && gen.FullName.StartsWith("System.ValueTuple`")) return true; return false; } /// /// Determines if type is Dictionary-like /// /// Type /// True if type is derived from dictionary type public static bool IsDictionary(this Type t) { if (t._IsGenericType()) { var tg = t.GetGenericTypeDefinition(); if (typeof(IDictionary<,>)._IsAssignableFrom(tg)) return true; if (typeof(IReadOnlyDictionary<,>)._IsAssignableFrom(tg)) return true; if (typeof(Dictionary<,>)._IsAssignableFrom(tg)) return true; if (typeof(IDictionary)._IsAssignableFrom(t)) return true; } else { if (typeof(IDictionary)._IsAssignableFrom(t)) return true; } return false; } /// /// Determines if type is enumerable regardless of generic spec /// /// Type /// True if type is enumerable (incl. array type). False otherwise. public static bool IsEnumerable(this Type t) { if (t.IsArray) return true; if (typeof(IEnumerable)._IsAssignableFrom(t)) return true; if (t._IsGenericType()) { var tg = t.GetGenericTypeDefinition(); if (typeof(IEnumerable<>)._IsAssignableFrom(tg)) return true; } return false; } /// /// Determines if supplied type is non-generic enumerable /// /// Type /// True if supplied type is nongeneric enumerable. False otherwise public static bool IsNongenericEnumerable(this Type t) { if (t._IsGenericType() && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)) return false; var interfaces = t._GetInterfaces(); var containsEnumerable = interfaces.Contains(typeof(IEnumerable)); var containsGenericEnumerable = interfaces.Any(c => c._IsGenericType() && c.GetGenericTypeDefinition() == typeof(IEnumerable<>)); return containsEnumerable && !containsGenericEnumerable; } /// /// Determines if supplied type is delegate type /// /// Type /// True, if supplied type is delegate, false otherwise public static bool IsDelegate(this Type t) { if (t._BaseType() == null) return false; return typeof(MulticastDelegate)._IsAssignableFrom(t._BaseType()); } /// /// Determines if type is one of System.Tuple types set /// /// Type to check /// True when type is tuple, false otherwise public static bool _IsAsyncType(this Type t) { return t._IsAssignableFrom(typeof(Task)) || ( t._IsGenericType() && t._BaseType() != null && t._BaseType()._IsAssignableFrom(typeof(Task)) // exclude "object" as "Task" is assignable to it, too && !t._BaseType()._IsAssignableFrom(typeof(Object)) ); } #endregion #region Modifiers /// /// Returns access modifier for specified field /// /// Field /// Access modifier string public static AccessModifier GetModifier(this FieldInfo fieldInfo) { if (fieldInfo.IsPrivate) return AccessModifier.Private; if (fieldInfo.IsFamily) return AccessModifier.Protected; return AccessModifier.Public; } /// /// Returns access modifier for specified method /// /// Method /// Access modifier string public static AccessModifier GetModifier(this MethodInfo methodInfo) { if (methodInfo.IsPrivate) return AccessModifier.Private; if (methodInfo.IsFamily) return AccessModifier.Protected; return AccessModifier.Public; } /// /// Returns access modifier for specified method /// /// Method /// Access modifier string public static bool IsAsync(this MethodInfo methodInfo) { var ret = methodInfo.ReturnType; return ret._IsAsyncType(); } /// /// Returns access modifier for specified constructor /// /// Constructor /// Access modifier string public static AccessModifier GetModifier(this ConstructorInfo constructorInfo) { if (constructorInfo.IsPrivate) return AccessModifier.Private; if (constructorInfo.IsFamily) return AccessModifier.Protected; return AccessModifier.Public; } /// /// Returns access modifier for specified constructor /// /// Property /// Access modifier string public static AccessModifier GetModifier(this PropertyInfo propertyInfo) { if (propertyInfo.GetMethod == null) { return GetModifier(propertyInfo.SetMethod); } if (propertyInfo.SetMethod == null) { return GetModifier(propertyInfo.GetMethod); } var getAccessor = GetModifier(propertyInfo.GetMethod); var setAccessor = GetModifier(propertyInfo.SetMethod); return getAccessor > setAccessor ? getAccessor : setAccessor; } /// /// Returns access modifier for specified type member /// /// Type member /// Access modifier string public static AccessModifier GetModifier(this MemberInfo member) { if (member is PropertyInfo) return GetModifier((PropertyInfo)member); if (member is MethodInfo) return GetModifier((MethodInfo)member); if (member is FieldInfo) return GetModifier((FieldInfo)member); return AccessModifier.Public; } /// /// Converts AccessModifier to corresponding TypeScript source text /// /// Access modifier /// Access modifier text public static string ToModifierText(this AccessModifier modifier) { switch (modifier) { case AccessModifier.Private: return "private"; case AccessModifier.Protected: return "protected"; } return "public"; } /// /// Converts AccessModifier to corresponding TypeScript source text /// /// Access modifier /// Access modifier text public static string ToModifierOmitPublic(this AccessModifier modifier) { switch (modifier) { case AccessModifier.Private: return "private"; case AccessModifier.Protected: return "protected"; } return string.Empty; } #endregion #region Utility methods /// /// Retrieves first type argument of type /// /// Type /// First type argument public static Type GetArg(this Type t) { return t._GetGenericArguments()[0]; } /// /// Removes generics postfix (all text after '`') from typename /// /// Type /// Clean, genericless name internal static string CleanGenericName(this Type t) { if (t._IsGenericType()) { var name = t.Name; var qidx = name.IndexOf('`'); return name.Substring(0, qidx); } return t.Name; } internal static RtTypeName[] SerializeGenericArguments(this Type t) { if (!t._IsGenericTypeDefinition()) return new RtTypeName[0]; if (t._IsGenericTypeDefinition()) { // arranged generic attribute means that generic type is replaced with real one var args = t._GetGenericArguments().Where(g => g.GetCustomAttribute() == null); var argsStr = args.Select(c => new RtSimpleTypeName(c.Name)).Cast().ToArray(); return argsStr; } return new RtTypeName[0]; } /// /// Determines if propercy is "bounced". /// It means property with different accesor's access level /// /// Property /// True if property has different access levels for accessor public static bool IsBounceProperty(this PropertyInfo propertyInfo) { var g = propertyInfo.GetMethod; var s = propertyInfo.SetMethod; if ((g == null) || (s == null)) return true; return g.IsPublic != s.IsPublic || g.IsFamily != s.IsFamily || g.IsPrivate != s.IsPrivate; } internal static MethodBase GetMethodWithSameParameters(MethodBase[] methodsSet, Type[] parameters) { MethodBase result = null; foreach (var method in methodsSet) { var methodParams = method.GetParameters(); if (methodParams.Length != parameters.Length) continue; var parametersMatch = true; for (var i = 0; i < parameters.Length; i++) { if (parameters[i] != methodParams[i].ParameterType) { parametersMatch = false; break; } } if (parametersMatch) { result = method; break; } } return result; } #endregion /// /// Reads the new compiler specific nullable attribute of the parameter or its parent scopes. /// /// The parameter to check for the availability of a nullable attribute. /// the value of the first attribute to find or null if none is available. public static byte[] GetNullableAttributeValue(this ParameterInfo member) { // non reference types will be converted to Nullable<> if they are nullable. // C# 8.0 nullable flag just changes the way reference types are handled. If enabled, then they are // not implicitly nullable anymore! if (member?.ParameterType == null || !member.ParameterType._IsReferenceType()) { return null; } return GetNullableAttributeValue(member.GetCustomAttributes(), false) ?? GetNullableAttributeValue(member.Member.GetCustomAttributes(), true) ?? GetNullableAttributeValue(member.Member.DeclaringType._GetCustomAttributes(true), true); } /// /// Reads the new compiler specific nullable attribute of a property or field or their parent scopes. /// /// The property or field to check for the availability of a nullable attribute. /// the value of the first attribute to find or null if none is available. public static byte[] GetNullableAttributeValue(this MemberInfo member) { Type memberType = member is PropertyInfo propertyInfo ? propertyInfo.PropertyType : ( member is FieldInfo fieldInfo ? fieldInfo.FieldType : null ); if (memberType == null || !memberType._IsReferenceType()) { return null; } return GetNullableAttributeValue(member.GetCustomAttributes(true), false) ?? GetNullableAttributeValue(member.DeclaringType._GetCustomAttributes(true), true); } private static byte[] GetNullableAttributeValue(IEnumerable attributes, bool fromParent) { if (attributes == null) return null; // need to retrieve all attributes and find by class name. // see: http://code.fitness/post/2019/02/nullableattribute.html // https://github.com/dotnet/roslyn/blob/master/docs/features/nullable-metadata.md foreach(var customAttribute in attributes) { if (customAttribute is Attribute nullableAttribute) { bool isNullableAttribute = string.Equals( customAttribute.GetType().FullName, "System.Runtime.CompilerServices.NullableAttribute", StringComparison.OrdinalIgnoreCase ); bool isNullableContextAttribute = fromParent && !isNullableAttribute && string.Equals( customAttribute.GetType().FullName, "System.Runtime.CompilerServices.NullableContextAttribute", StringComparison.OrdinalIgnoreCase ); if (!isNullableAttribute && !isNullableContextAttribute) { continue; } FieldInfo flagField = isNullableAttribute ? nullableAttribute.GetType().GetRuntimeField("NullableFlags") : nullableAttribute.GetType().GetRuntimeField("Flag"); object flagsData = flagField?.GetValue(nullableAttribute); byte[] flags = flagsData is byte[] flagsDataBytes ? flagsDataBytes : null; flags = flags is null && flagsData is byte flagsDataSingleByte ? new byte[] {flagsDataSingleByte} : flags; return flags != null && flags.Length > 0 ? flags : null; } } return null; } } } ================================================ FILE: Reinforced.Typings/TypeResolver.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; using Reinforced.Typings.Exceptions; namespace Reinforced.Typings { /// /// Type resolver. It is helper class to convert source types, members and parameter names to typescript ones /// public sealed class TypeResolver { private static readonly RtSimpleTypeName AnyType = new RtSimpleTypeName("any"); private static readonly RtSimpleTypeName NumberType = new RtSimpleTypeName("number"); private static readonly RtSimpleTypeName StringType = new RtSimpleTypeName("string"); private static readonly RtSimpleTypeName UnknownType = new RtSimpleTypeName("unknown"); /// /// Hash set of all numeric types /// public static readonly HashSet NumericTypes = new HashSet(new[] { typeof (byte), typeof (sbyte), typeof (short), typeof (ushort), typeof (int), typeof (uint), typeof (long), typeof (ulong), typeof (float), typeof (double), typeof (decimal), typeof (byte?), typeof (sbyte?), typeof (short?), typeof (ushort?), typeof (int?), typeof (uint?), typeof (long?), typeof (ulong?), typeof (float?), typeof (double?), typeof (decimal?) }); /// /// Hash set of all integer types /// public static readonly HashSet IntegerTypes = new HashSet(new[] { typeof (byte), typeof (sbyte), typeof (short), typeof (ushort), typeof (int), typeof (uint), typeof (long), typeof (ulong), typeof (byte?), typeof (sbyte?), typeof (short?), typeof (ushort?), typeof (int?), typeof (uint?), typeof (long?), typeof (ulong?) }); private readonly Dictionary _resolveCache = new Dictionary { {typeof (object), AnyType}, {typeof (void), new RtSimpleTypeName("void")}, {typeof (string), StringType}, {typeof (char),StringType}, {typeof (bool), new RtSimpleTypeName("boolean")}, {typeof (byte), NumberType}, {typeof (sbyte), NumberType}, {typeof (short), NumberType}, {typeof (ushort), NumberType}, {typeof (int), NumberType}, {typeof (uint), NumberType}, {typeof (long), NumberType}, {typeof (ulong), NumberType}, {typeof (float), NumberType}, {typeof (double), NumberType}, {typeof (decimal), NumberType} }; private readonly RtSimpleTypeName _anyOrUnknown; private ExportContext Context { get { return _file.Context; } } private readonly ExportedFile _file; /// /// Constructs new type resolver /// internal TypeResolver(ExportedFile file) { _file = file; _anyOrUnknown = _file.Context.Global.UnresolvedToUnknown ? UnknownType : AnyType; } private RtTypeName[] GetConcreteGenericArguments(Type t, Dictionary materializedGenerics = null) { if (!t._IsGenericType()) return new RtTypeName[0]; var args = t._GetGenericArguments(); if (materializedGenerics == null) return args.Select(ResolveTypeName).ToArray(); else { List result = new List(); foreach (var type in args) { if (materializedGenerics.ContainsKey(type.Name)) result.Add(materializedGenerics[type.Name]); else result.Add(ResolveTypeName(type)); } return result.ToArray(); } } private RtTypeName Cache(Type t, RtTypeName name) { _resolveCache[t] = name; return name; } internal RtTypeName ResolveTypeName(Type t, Dictionary materializedGenerics) { if (materializedGenerics == null) return ResolveTypeName(t); try { return ResolveTypeNameInner(t, materializedGenerics); } catch (Exception ex) { ErrorMessages.RTE0005_TypeResolvationError.Throw(t.FullName, ex.Message); return null; // unreacheable } } /// /// Returns typescript-friendly type name node for specified type. /// This method successfully handles dictionaries, IEnumerables, arrays, another TsExport-ed types, void, delegates, /// most of CLR built-in types, parametrized types etc. /// It also considers Ts*-attributes while resolving type names /// If it cannot handle anything then it will return "any" /// /// Specified type /// Typescript-friendly type name public RtTypeName ResolveTypeName(Type t) { return ResolveTypeName(t, true); } /// /// Returns typescript-friendly type name node for specified type. /// This method successfully handles dictionaries, IEnumerables, arrays, another TsExport-ed types, void, delegates, /// most of CLR built-in types, parametrized types etc. /// It also considers Ts*-attributes while resolving type names /// If it cannot handle anything then it will return "any" /// /// Specified type /// if true, then async types like "Task" are supported and translated to "Promise". /// Otherwise the generics value of "Task" is used or "void". /// Typescript-friendly type name public RtTypeName ResolveTypeName(Type t, bool usePromiseType) { try { return ResolveTypeNameInner(t, null, usePromiseType); } catch (Exception ex) { ErrorMessages.RTE0005_TypeResolvationError.Throw(t.FullName, ex.Message); return null; // unreacheable } } internal RtTypeName ResolveTypeNameInner(Type t, Dictionary materializedGenerics = null, bool usePromiseType = true) { var substitution = Context.Project.Substitute(t, this); if (substitution != null) return substitution; // order important! if (Context.CurrentBlueprint != null) { var localSubstitution = Context.CurrentBlueprint.Substitute(t, this); if (localSubstitution != null) return localSubstitution; } if (t.IsGenericParameter) { var genAt = t.GetCustomAttribute(false); if (genAt != null) { if (genAt.StrongType != null) return ResolveTypeName(genAt.StrongType); if (genAt.Type != null) return new RtSimpleTypeName(genAt.Type); } return new RtSimpleTypeName(t.Name); } if (materializedGenerics == null && _resolveCache.ContainsKey(t)) return _resolveCache[t]; var bp = Context.Project.Blueprint(t, false); if (bp != null && bp.ThirdParty != null) { var result = bp.GetName(bp.IsExportedExplicitly ? null : GetConcreteGenericArguments(t, materializedGenerics)); if (Context.Global.UseModules) _file.EnsureImport(t, result.TypeName); _file.EnsureReference(t); return Cache(t, result); } else { var declaration = bp == null ? null : bp.TypeAttribute; if (declaration != null) { var ns = t.Namespace; if (!string.IsNullOrEmpty(declaration.Namespace)) ns = declaration.Namespace; if (!declaration.IncludeNamespace) ns = string.Empty; var result = bp.GetName(bp.IsExportedExplicitly ? null : GetConcreteGenericArguments(t, materializedGenerics)); if (Context.Global.UseModules) { var import = _file.EnsureImport(t, result.TypeName); if (Context.Global.DiscardNamespacesWhenUsingModules) ns = string.Empty; if (import == null || !import.IsWildcard) { result.Prefix = ns; return Cache(t, result); } result.Prefix = string.IsNullOrEmpty(ns) ? import.WildcardAlias : string.Format("{0}.{1}", import.WildcardAlias, ns); return Cache(t, result); } else { _file.EnsureReference(t); if (!string.IsNullOrEmpty(declaration.Namespace)) ns = declaration.Namespace; result.Prefix = ns; return Cache(t, result); } } } if (t.IsNullable()) { return ResolveTypeName(t.GetArg()); } if (t.IsTuple()) { var args = t._GetGenericArguments().Select(ResolveTypeName); return Cache(t, new RtTuple(args)); } if (t.IsDictionary()) { if (!t._IsGenericType()) { Context.AddWarning(ErrorMessages.RTW0007_InvalidDictionaryKey.Warn(AnyType, typeof(object))); return Cache(t, new RtDictionaryType(AnyType, AnyType)); } var gargs = t._GetGenericArguments(); bool isKeyEnum = gargs[0]._IsEnum(); var key = ResolveTypeName(gargs[0]); if (!NumberType.Equals(key) && !StringType.Equals(key) && !isKeyEnum) { Context.AddWarning(ErrorMessages.RTW0007_InvalidDictionaryKey.Warn(key, gargs[0])); } var value = ResolveTypeName(gargs[1]); return Cache(t, new RtDictionaryType(key, value, isKeyEnum)); } if (t.IsNongenericEnumerable()) { return Cache(t, new RtArrayType(AnyType)); } if (t.IsEnumerable()) { if (t.IsArray) { return Cache(t, new RtArrayType(ResolveTypeName(t.GetElementType()))); } var enumerable = t._GetInterfaces() .FirstOrDefault(c => c._IsGenericType() && c.GetGenericTypeDefinition() == typeof(IEnumerable<>)); if (enumerable == null) { if (t._IsGenericType() && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)) enumerable = t; } if (enumerable == null) return Cache(t, new RtArrayType(AnyType)); return Cache(t, new RtArrayType(ResolveTypeName(enumerable.GetArg()))); } if (t._IsAsyncType()) { var deliveredTypeOfTask = t._IsGenericType() ? ResolveTypeName(t.GetArg(), usePromiseType) : ResolveTypeName(typeof(void)); if (usePromiseType || Context.Global.AutoAsync) { return Cache(t, new RtAsyncType(deliveredTypeOfTask)); } else { // Unfold the generics value of the task but do NOT cache. Caching would interfere with // parameter resolving, which always uses promise type. return deliveredTypeOfTask; } } if (typeof(MulticastDelegate)._IsAssignableFrom(t._BaseType())) { var methodInfo = t._GetMethod("Invoke"); return Cache(t, ConstructFunctionType(methodInfo, materializedGenerics)); } if (t._IsGenericType() && !t._IsGenericTypeDefinition()) { var def = t.GetGenericTypeDefinition(); var tsFriendly = ResolveTypeNameInner(def) as RtSimpleTypeName; if (tsFriendly != null && tsFriendly != AnyType && tsFriendly != UnknownType) { var parametrized = new RtSimpleTypeName(tsFriendly.TypeName, t._GetGenericArguments().Select(c => ResolveTypeNameInner(c, null)).ToArray()) { Prefix = tsFriendly.Prefix }; return Cache(t, parametrized); } } if (t._IsEnum()) { return Cache(t, NumberType); } Context.AddWarning(ErrorMessages.RTW0003_TypeUnknown.Warn(t.FullName, _anyOrUnknown)); return Cache(t, _anyOrUnknown); } private RtDelegateType ConstructFunctionType(MethodInfo methodInfo, Dictionary materializedGenerics = null) { var retType = ResolveTypeName(methodInfo.ReturnType, materializedGenerics); var result = retType; var argAggreagtor = 0; List arguments = new List(); foreach (var parameterInfo in methodInfo.GetParameters()) { var argName = argAggreagtor > 0 ? "arg" + argAggreagtor : "arg"; var typeName = ResolveTypeName(parameterInfo.ParameterType, materializedGenerics); arguments.Add(new RtArgument() { Identifier = new RtIdentifier(argName), Type = typeName }); argAggreagtor++; } return new RtDelegateType(arguments.ToArray(), result); } } } ================================================ FILE: Reinforced.Typings/Visitors/TextExportingVisitor.cs ================================================ using System.IO; using System.Text; using Reinforced.Typings.Ast.Dependency; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors { public abstract class TextExportingVisitor : VisitorBase { private readonly TextWriter _writer; private int _tabsCount; private string _tabsLine; private readonly string _tabulation; protected TextWriter Writer { get { return _writer; } } /// /// Gets current export context /// protected ExportContext ExportContext { get; private set; } protected TextExportingVisitor(TextWriter writer, ExportContext exportContext) { _writer = writer; _tabulation = exportContext.Global.TabSymbol; ExportContext = exportContext; } private string TabLine(int count) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < count; i++) { sb.Append(_tabulation); } return sb.ToString(); } protected void Tab() { _tabsCount++; _tabsLine = TabLine(_tabsCount); } protected void UnTab() { if (_tabsCount > 0) _tabsCount--; _tabsLine = TabLine(_tabsCount); } protected void Indent() { AppendTabs(); } protected void AppendTabs() { _writer.Write(_tabsLine); } public void Br() { _writer.WriteLine(); } protected void WriteLines(string str) { var result = str.Split('\n'); foreach (var s in result) { AppendTabs(); _writer.WriteLine(s.Replace("\n", null).Replace("\r", null)); } } protected void WriteLines(string format, params object[] args) { var formatted = string.Format(format, args); var result = formatted.Split('\n'); foreach (var s in result) { AppendTabs(); _writer.Write(s.Replace("\n", null).Replace("\r", null)); _writer.WriteLine(); } } protected void Write(string text) { _writer.Write(text); } protected void WriteLine(string text) { _writer.WriteLine(text); } public override void VisitFile(ExportedFile file) { bool hasReferences = false, hasImports = false; foreach (var rtReference in file.FinalReferences) { Visit(rtReference); hasReferences = true; } foreach (var rtImport in file.FinalImports) { Visit(rtImport); hasImports = true; } if (hasReferences || hasImports) Br(); foreach (var fileNamespace in file.Namespaces) { Visit(fileNamespace); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.Dependencies.cs ================================================ using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtImport node) { Write("import "); if (node.Target != null) { Write(node.Target); Write(" "); if (node.IsRequire) { WriteLine(string.Format("= require('{0}');", node.From)); } else { WriteLine(string.Format("from '{0}';", node.From)); } } else { WriteLine(string.Format("'{0}';", node.From)); } } public override void Visit(RtReference node) { WriteLine(string.Format("///", node.Path)); } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtArgument.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtArgument node) { if (node == null) return; Decorators(node); if (node.IsVariableParameters) Write("..."); Visit(node.Identifier); // if a default value is used, then the parameter may be omitted as the default value is in place. if (Context == WriterContext.Interface && !node.Identifier.IsNullable && !string.IsNullOrEmpty(node.DefaultValue)) { Write("?"); } Write(": "); Visit(node.Type); if (Context != WriterContext.Interface && !string.IsNullOrEmpty(node.DefaultValue)) { Write(" = "); Write(node.DefaultValue); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtClass.cs ================================================ using System.Linq; using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtClass node) { if (node == null) return; Visit(node.Documentation); var prev = Context; Context = WriterContext.Class; AppendTabs(); Decorators(node); if (node.Export) Write("export "); if (node.Abstract) Write("abstract "); Write("class "); Visit(node.Name); if (node.Extendee != null) { Write(" extends "); Visit(node.Extendee); } if (node.Implementees.Count > 0) { Write(" implements "); SequentialVisit(node.Implementees, ", "); } Br(); AppendTabs(); Write("{"); Br(); Tab(); var members = DoSortMembers(node.Members); foreach (var rtMember in members) { Visit(rtMember); } UnTab(); AppendTabs(); WriteLine("}"); Context = prev; } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtConstructor.cs ================================================ using System; using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtConstructor node) { if (node == null) return; if (Context == WriterContext.Interface) return; Visit(node.Documentation); AppendTabs(); Write("constructor ("); SequentialVisit(node.Arguments, ", "); Write(")"); if (node.NeedsSuperCall && node.Body == null) { string ncp = string.Empty; if (node.SuperCallParameters != null) ncp = string.Join(", ", node.SuperCallParameters); node.Body = new RtRaw(String.Format("super({0});", ncp)); } if (node.Body != null && !string.IsNullOrEmpty(node.Body.RawContent)) { CodeBlock(node.Body); } else { EmptyBody(null); } if (!string.IsNullOrEmpty(node.LineAfter)) { AppendTabs(); Write(node.LineAfter); Br(); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtEnum.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtEnum node) { if (node == null) return; Visit(node.Documentation); var prev = Context; Context = WriterContext.Enum; AppendTabs(); if (node.Export) Write("export "); if (node.IsConst) Write("const "); Write("enum "); Visit(node.EnumName); WriteLine(" {"); Tab(); var arr = node.Values.ToArray(); for (int i = 0; i < arr.Length; i++) { Visit(arr[i]); if (i != arr.Length - 1) WriteLine(","); if (!string.IsNullOrEmpty(arr[i].LineAfter)) { AppendTabs(); Write(arr[i].LineAfter); Br(); } } WriteLine(string.Empty); UnTab(); AppendTabs(); WriteLine("}"); Context = prev; } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtEnumValue.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtEnumValue node) { if (node == null) return; Visit(node.Documentation); AppendTabs(); Write(node.EnumValueName); if (!string.IsNullOrEmpty(node.EnumValue)) { Write(" = "); Write(node.EnumValue); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtField.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtField node) { if (node == null) return; Visit(node.Documentation); AppendTabs(); if (Context != WriterContext.Interface) { Decorators(node); Modifiers(node); } Visit(node.Identifier); Write(": "); Visit(node.Type); if (!string.IsNullOrEmpty(node.InitializationExpression)) { Write(" = "); Write(node.InitializationExpression); } Write(";"); Br(); if (!string.IsNullOrEmpty(node.LineAfter)) { AppendTabs(); Write(node.LineAfter); Br(); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtFunction.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtFunction node) { if (node == null) return; Visit(node.Documentation); AppendTabs(); if (Context != WriterContext.Interface) { Decorators(node); Modifiers(node); if (node.IsAsync) { Write("async "); } } Visit(node.Identifier); Write("("); SequentialVisit(node.Arguments, ", "); Write(") "); if (node.ReturnType != null) { Write(": "); Visit(node.ReturnType); } if (Context == WriterContext.Interface) { WriteLine(";"); } else { if (node.Body != null && !string.IsNullOrEmpty(node.Body.RawContent)) { CodeBlock(node.Body); } else { EmptyBody(node.ReturnType, node.IsAsync); } } if (!string.IsNullOrEmpty(node.LineAfter)) { AppendTabs(); Write(node.LineAfter); Br(); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtIdentifier.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtIdentifier node) { if (node == null) return; Write(node.IdentifierName); if (node.IsNullable) Write("?"); } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtInterface.cs ================================================ using System.Linq; using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtInterface node) { if (node == null) return; Visit(node.Documentation); var prev = Context; Context = WriterContext.Interface; AppendTabs(); if (node.Export) Write("export "); Write("interface "); Visit(node.Name); if (node.Implementees.Count > 0) { Write(" extends "); SequentialVisit(node.Implementees, ", "); } Br(); AppendTabs(); Write("{"); Br(); Tab(); foreach (var rtMember in DoSortMembers(node.Members)) { Visit(rtMember); } UnTab(); AppendTabs(); WriteLine("}"); Context = prev; } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtJsdocNode.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtJsdocNode node) { if (node == null) return; if (!string.IsNullOrEmpty(node.Description) && !node.Description.Contains("\n") && node.TagToDescription.Count == 0) { //handle single-line JSDOC AppendTabs(); Write("/** "); Write(node.Description); WriteLine(" */"); } else { AppendTabs(); WriteLine("/**"); if (!string.IsNullOrEmpty(node.Description)) { Summary(node.Description); if (node.TagToDescription.Count > 0) DocLine(); } foreach (var tuple in node.TagToDescription) { DocTag(tuple.Item1, tuple.Item2); } AppendTabs(); WriteLine("*/"); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtNamespace.cs ================================================ using System; using System.Linq; using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtNamespace node) { if (node == null) return; if (!node.IsAmbientNamespace) { Context = WriterContext.Module; AppendTabs(); if (node.GenerationMode == NamespaceGenerationMode.Module) { WriteLine(String.Format("module {0} {{", node.Name)); } else { if (node.Export) Write("export "); WriteLine(String.Format("namespace {0} {{", node.Name)); } Tab(); } foreach (var rtCompilationUnit in node.CompilationUnits.OrderBy(c => c is RtCompilationUnit ? ((RtCompilationUnit) c).Order : 0)) { Visit(rtCompilationUnit); } if (!node.IsAmbientNamespace) { Context = WriterContext.None; UnTab(); AppendTabs(); WriteLine("}"); } } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.RtRaw.cs ================================================ using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { public override void Visit(RtRaw node) { if (node == null) return; if (string.IsNullOrEmpty(node.RawContent)) return; WriteLines(node.RawContent); } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/TypeScriptExportVisitor.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { /// /// Visitor that generates TypeScript code (.ts) from existing model /// public partial class TypeScriptExportVisitor : TextExportingVisitor { protected WriterContext Context { get; set; } /// /// Writes modifiers for type member /// /// Type member protected void Modifiers(RtMember member) { if (member.AccessModifier != null) { Write(member.AccessModifier.Value.ToModifierText()); Write(" "); } if (member.IsStatic) { Write("static "); } } protected void Decorators(IDecoratable member) { foreach (var memberDecorator in member.Decorators.OrderBy(c => c.Order)) { Visit(memberDecorator); } } #region Documentation protected void DocTag(DocTag tag, string value) { var tagText = tag.Tagname(); if (string.IsNullOrEmpty(value)) { DocLine(tagText); } else { value = value.Replace("\r", null).Replace("\n", null); DocLine(String.Format("{0} {1}", tagText, value)); } } protected void DocLine(string line = null) { if (string.IsNullOrEmpty(line)) { AppendTabs(); WriteLine("*"); } else { AppendTabs(); WriteLine(String.Format("* {0}", line)); } } private void Summary(string summary) { if (string.IsNullOrEmpty(summary)) return; var summaryLines = summary.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var summaryLine in summaryLines) { DocLine(summaryLine); } } #endregion /// /// Writes empty method body of known return type /// /// Method return type /// Whether the method is tagged as "async", then no Promise need to be created /// directly. TypeScript compiler does it for us. protected void EmptyBody(RtTypeName returnType, bool isAsyncMethod = false) { // unfold the Promise return value if (returnType is RtAsyncType) { if (isAsyncMethod) { returnType = ((RtAsyncType) returnType).TypeNameOfAsync; } else { CodeBlock("return Promise.resolve(null);"); return; } } if (returnType == null || returnType.IsVoid()) { WriteLine(" { } "); } else { CodeBlock("return null;"); } } /// /// Writes code block with correct tabulation /// /// Code content protected void CodeBlock(string content) { Br(); AppendTabs(); WriteLine("{"); Tab(); WriteLines(content); UnTab(); AppendTabs(); WriteLine("}"); } /// /// Writes AST node as code block with correct tabulation /// /// Code content protected void CodeBlock(RtRaw content) { Br(); AppendTabs(); WriteLine("{"); Tab(); Visit(content); UnTab(); AppendTabs(); WriteLine("}"); } /// /// Performs sequential visiting of AST nodes inserting separator in between /// /// /// Nodes to visit /// Seperator string protected void SequentialVisit(IEnumerable nodes, string separator) where T : RtNode { var n = nodes.ToArray(); for (int index = 0; index < n.Length; index++) { var rtArgument = n[index]; Visit(rtArgument); if (index < n.Length - 1) Write(separator); } } public override void Visit(RtDecorator node) { if (node == null) return; Write("@"); Write(node.Decorator); Write(" "); } private bool IsKnownMember(RtNode n) { if (n is RtConstructor) return true; if (n is RtField) return true; if (n is RtFunction) return true; return false; } private IEnumerable DoNodesOrder(List nodes) { var constructors = nodes.Where(d => d is RtConstructor).OfType(); var fields = nodes.Where(d => d is RtField).OfType().OrderBy(d => d.Identifier.IdentifierName); var methods = nodes.Where(d => d is RtFunction).OfType().OrderBy(d => d.Identifier.IdentifierName); var rest = nodes.Where(d => !IsKnownMember(d)); return constructors.Cast() .Union(fields) .Union(methods) .Union(rest); } protected IEnumerable DoSortMembers(List nodes) { if (ExportContext.Global.ReorderMembers) { return DoNodesOrder(nodes); } else { if (nodes.Any(d => d._order != 0)) return nodes.OrderBy(c => c is RtConstructor ? int.MinValue : c._order); return nodes; } } public TypeScriptExportVisitor(TextWriter writer, ExportContext exportContext) : base(writer, exportContext) { Context = WriterContext.None; } } public enum WriterContext { None, Class, Interface, Enum, Module } internal static class ExportExtensions { public static bool IsVoid(this RtTypeName typeName) { if (typeName == null) return true; var tn = typeName as RtSimpleTypeName; if (tn == null) return false; return tn.TypeName == "void"; } } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/Types/TypeScriptExportVisitor.RtArrayType.cs ================================================ using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { #region Types public override void Visit(RtArrayType node) { if (node == null) return; Visit(node.ElementType); Write("[]"); } #endregion } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/Types/TypeScriptExportVisitor.RtAsyncType.cs ================================================ using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { #region Types public override void Visit(RtAsyncType node) { Write("Promise<"); if (node.TypeNameOfAsync != null) this.Visit(node.TypeNameOfAsync); else Write("void"); Write(">"); } #endregion } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/Types/TypeScriptExportVisitor.RtDelegateType.cs ================================================ using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { #region Types public override void Visit(RtDelegateType node) { if (node == null) return; Write("("); SequentialVisit(node.Arguments, ", "); Write(") => "); Visit(node.Result); } #endregion } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/Types/TypeScriptExportVisitor.RtDictionaryType.cs ================================================ using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { #region Types public override void Visit(RtDictionaryType node) { if (node == null) return; string keyTypeSpec = node.IsKeyEnum ? " in " : ":"; Write("{ [key"); Write(keyTypeSpec); Visit(node.KeyType); Write("]: "); Visit(node.ValueType); Write(" }"); } #endregion } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/Types/TypeScriptExportVisitor.RtSimpleTypeName.cs ================================================ using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { #region Types public override void Visit(RtSimpleTypeName node) { if (node.HasPrefix) { Write(node.Prefix); Write("."); } Write(node.TypeName); if (node.GenericArguments.Length > 0) { Write("<"); SequentialVisit(node.GenericArguments, ", "); Write(">"); } } #endregion } } ================================================ FILE: Reinforced.Typings/Visitors/TypeScript/Types/TypeScriptExportVisitor.RtTuple.cs ================================================ using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.TypeScript { partial class TypeScriptExportVisitor { #region Types public override void Visit(RtTuple node) { if (node==null) return; Write("["); SequentialVisit(node.TupleTypes,","); Write("]"); } #endregion } } ================================================ FILE: Reinforced.Typings/Visitors/TypedVisitorBase.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Visitors { abstract class TypedVisitorBase : IRtVisitor { public T Visit(RtNode node) { if (node is RtField) return Visit((RtField)node); if (node is RtInterface) return Visit((RtInterface)node); if (node is RtFunction) return Visit((RtFunction)node); if (node is RtArgument) return Visit((RtArgument)node); if (node is RtClass) return Visit((RtClass)node); if (node is RtIdentifier) return Visit((RtIdentifier)node); if (node is RtDelegateType) return Visit((RtDelegateType)node); if (node is RtSimpleTypeName) return Visit((RtSimpleTypeName)node); if (node is RtRaw) return Visit((RtRaw)node); if (node is RtJsdocNode) return Visit((RtJsdocNode)node); if (node is RtNamespace) return Visit((RtNamespace)node); if (node is RtEnumValue) return Visit((RtEnumValue)node); if (node is RtEnum) return Visit((RtEnum)node); if (node is RtDictionaryType) return Visit((RtDictionaryType)node); if (node is RtArrayType) return Visit((RtArrayType)node); if (node is RtConstructor) return Visit((RtConstructor)node); if (node is RtImport) return Visit((RtImport)node); if (node is RtDecorator) return Visit((RtDecorator)node); if (node is RtReference) return Visit((RtReference)node); if (node is RtTuple) return Visit((RtTuple)node); throw new Exception("Unknown node passed"); } public abstract T Visit(RtField node); public abstract T Visit(RtInterface node); public abstract T Visit(RtFunction node); public abstract T Visit(RtArgument node); public abstract T Visit(RtClass node); public abstract T Visit(RtIdentifier node); public abstract T Visit(RtDelegateType node); public abstract T Visit(RtSimpleTypeName node); public abstract T Visit(RtRaw node); public abstract T Visit(RtJsdocNode node); public abstract T Visit(RtNamespace node); public abstract T Visit(RtEnumValue node); public abstract T Visit(RtEnum node); public abstract T Visit(RtDictionaryType node); public abstract T Visit(RtArrayType node); public abstract T Visit(RtConstructor node); public abstract T Visit(RtImport node); public abstract T Visit(RtDecorator node); public abstract T Visit(RtReference node); public abstract T Visit(RtTuple node); public abstract T VisitFile(ExportedFile file); } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.RtClass.cs ================================================ using System.Linq; using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { partial class TypingsExportVisitor { public override void Visit(RtClass node) { if (node == null) return; Visit(node.Documentation); var prev = Context; Context = WriterContext.Class; AppendTabs(); if (prev == WriterContext.Module) Write("export "); else Write("declare "); if (node.Abstract) Write("abstract "); Write("class "); Visit(node.Name); if (node.Extendee != null) { Write(" extends "); Visit(node.Extendee); } if (node.Implementees.Count > 0) { Write(" implements "); SequentialVisit(node.Implementees, ", "); } Br(); AppendTabs(); Write("{"); Br(); Tab(); var members = DoSortMembers(node.Members); foreach (var rtMember in members) { Visit(rtMember); } UnTab(); AppendTabs(); WriteLine("}"); Context = prev; } } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.RtConstructor.cs ================================================ using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { partial class TypingsExportVisitor { public override void Visit(RtConstructor node) { if (node == null) return; Visit(node.Documentation); AppendTabs(); if (Context == WriterContext.Interface) { Write("new ("); } else { Write("constructor ("); } SequentialVisit(node.Arguments, ", "); WriteLine(");"); if (!string.IsNullOrEmpty(node.LineAfter)) { AppendTabs(); Write(node.LineAfter); Br(); } } } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.RtEnum.cs ================================================ using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { partial class TypingsExportVisitor { public override void Visit(RtEnum node) { if (node == null) return; Visit(node.Documentation); var prev = Context; Context = WriterContext.Enum; AppendTabs(); if (node.Export) { if (prev == WriterContext.Module) Write("export "); else Write("declare "); } if (node.IsConst) Write("const "); Write("enum "); Visit(node.EnumName); WriteLine(" {"); Tab(); var arr = node.Values.ToArray(); for (int i = 0; i < arr.Length; i++) { Visit(arr[i]); if (i != arr.Length - 1) WriteLine(","); if (!string.IsNullOrEmpty(arr[i].LineAfter)) { AppendTabs(); Write(arr[i].LineAfter); Br(); } } WriteLine(string.Empty); UnTab(); AppendTabs(); WriteLine("}"); Context = prev; } } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.RtField.cs ================================================ using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { partial class TypingsExportVisitor { public override void Visit(RtField node) { if (node == null) return; Visit(node.Documentation); AppendTabs(); if (Context == WriterContext.Module) Write("export var "); if (Context == WriterContext.None) Write("declare var "); if (Context == WriterContext.Class) Modifiers(node); Visit(node.Identifier); Write(": "); Visit(node.Type); WriteLine(";"); if (!string.IsNullOrEmpty(node.LineAfter)) { AppendTabs(); Write(node.LineAfter); Br(); } } } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.RtFunction.cs ================================================ using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { partial class TypingsExportVisitor { public override void Visit(RtFunction node) { if (node == null) return; Visit(node.Documentation); AppendTabs(); if (Context != WriterContext.Interface) Modifiers(node); if (Context == WriterContext.Module) Write("export function "); Visit(node.Identifier); Write("("); SequentialVisit(node.Arguments, ", "); Write(") "); if (node.ReturnType != null) { Write(": "); Visit(node.ReturnType); } WriteLine(";"); if (!string.IsNullOrEmpty(node.LineAfter)) { AppendTabs(); Write(node.LineAfter); Br(); } } } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.RtModule.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { partial class TypingsExportVisitor { public override void Visit(RtNamespace node) { if (node == null) return; if (!node.IsAmbientNamespace) { Context = WriterContext.Module; AppendTabs(); WriteLine(String.Format("declare module {0} {{", node.Name)); Tab(); } foreach (var rtCompilationUnit in node.CompilationUnits) { Visit(rtCompilationUnit); } if (!node.IsAmbientNamespace) { Context = WriterContext.None; UnTab(); AppendTabs(); WriteLine("}"); } } } } ================================================ FILE: Reinforced.Typings/Visitors/Typings/TypingsExportVisitor.cs ================================================ using System.IO; using Reinforced.Typings.Ast; using Reinforced.Typings.Visitors.TypeScript; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors.Typings { /// /// Visitor that is generating .d.ts from existing model /// public partial class TypingsExportVisitor : TypeScriptExportVisitor { public override void Visit(RtDecorator node) { //no decorators allowed in the .d.ts } public TypingsExportVisitor(TextWriter writer, ExportContext exportContext) : base(writer, exportContext) { } } } ================================================ FILE: Reinforced.Typings/Visitors/VisitorBase.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Ast.TypeNames; #pragma warning disable 1591 namespace Reinforced.Typings.Visitors { public abstract class VisitorBase : IRtVisitor { public void Visit(RtNode node) { if (node == null) return; if (node is RtField) { Visit((RtField)node); return; } if (node is RtInterface) { Visit((RtInterface)node); return; } if (node is RtFunction) { Visit((RtFunction)node); return; } if (node is RtArgument) { Visit((RtArgument)node); return; } if (node is RtClass) { Visit((RtClass)node); return; } if (node is RtIdentifier) { Visit((RtIdentifier)node); return; } if (node is RtDelegateType) { Visit((RtDelegateType)node); return; } if (node is RtSimpleTypeName) { Visit((RtSimpleTypeName)node); return; } if (node is RtRaw) { Visit((RtRaw)node); return; } if (node is RtJsdocNode) { Visit((RtJsdocNode)node); return; } if (node is RtNamespace) { Visit((RtNamespace)node); return; } if (node is RtEnumValue) { Visit((RtEnumValue)node); return; } if (node is RtEnum) { Visit((RtEnum)node); return; } if (node is RtDictionaryType) { Visit((RtDictionaryType)node); return; } if (node is RtArrayType) { Visit((RtArrayType)node); return; } if (node is RtConstructor) { Visit((RtConstructor)node); return; } if (node is RtImport) { Visit((RtImport)node); return; } if (node is RtDecorator) { Visit((RtDecorator)node); return; } if (node is RtReference) { Visit((RtReference)node); return; } if (node is RtTuple) { Visit((RtTuple)node); return; } if (node is RtAsyncType) { Visit((RtAsyncType)node); return; } throw new Exception("Unknown node passed"); } public abstract void Visit(RtField node); public abstract void Visit(RtInterface node); public abstract void Visit(RtFunction node); public abstract void Visit(RtArgument node); public abstract void Visit(RtClass node); public abstract void Visit(RtIdentifier node); public abstract void Visit(RtDelegateType node); public abstract void Visit(RtSimpleTypeName node); public abstract void Visit(RtRaw node); public abstract void Visit(RtJsdocNode node); public abstract void Visit(RtNamespace node); public abstract void Visit(RtEnumValue node); public abstract void Visit(RtEnum node); public abstract void Visit(RtDictionaryType node); public abstract void Visit(RtArrayType node); public abstract void Visit(RtConstructor node); public abstract void Visit(RtImport node); public abstract void Visit(RtDecorator node); public abstract void Visit(RtReference node); public abstract void Visit(RtTuple node); public abstract void Visit(RtAsyncType node); public abstract void VisitFile(ExportedFile file); } } ================================================ FILE: Reinforced.Typings/Xmldoc/DocumentationManager.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Xml.Serialization; using Reinforced.Typings.Exceptions; using Reinforced.Typings.Xmldoc.Model; // ReSharper disable PossibleNullReferenceException namespace Reinforced.Typings.Xmldoc { /// /// XMLDOC documentation manager /// public class DocumentationManager { private readonly Dictionary _documentationCache = new Dictionary(); private bool _isDocumentationExists; internal DocumentationManager(string docFilePath, IWarningsCollector warnings) { CacheDocumentation(docFilePath, warnings); } internal DocumentationManager(string[] docFilePath, IWarningsCollector warnings) { foreach (var s in docFilePath) { CacheDocumentation(s, warnings); } } internal void CacheDocumentation(string docFilePath, IWarningsCollector warnings) { if (string.IsNullOrEmpty(docFilePath)) { return; } if (!File.Exists(docFilePath)) { warnings.AddWarning(ErrorMessages.RTW0002_DocumentationNotFound.Warn(docFilePath)); return; } try { var ser = new XmlSerializer(typeof(Documentation)); Documentation documentation; using (var fs = File.OpenRead(docFilePath)) { documentation = (Documentation)ser.Deserialize(fs); } foreach (var documentationMember in documentation.Members) { _documentationCache[documentationMember.Name] = documentationMember; } _isDocumentationExists = true; } catch (Exception ex) { _isDocumentationExists = false; warnings.AddWarning(ErrorMessages.RTW0006_DocumentationParseringError.Warn(docFilePath, ex.Message)); } } private static string GetDocFriendlyParameterName(Type parameterType, Dictionary typeGenericsDict, Dictionary methodGenericArgsDict) { if (typeGenericsDict.ContainsKey(parameterType)) { return ("`" + typeGenericsDict[parameterType]); } if (methodGenericArgsDict.ContainsKey(parameterType)) { return ("``" + methodGenericArgsDict[parameterType]); } if (parameterType._IsGenericType()) { var gen = parameterType.GetGenericTypeDefinition(); var name = gen.FullName; var quote = name.IndexOf('`'); name = name.Substring(0, quote); var genericParams = parameterType._GetGenericArguments() .Select(c => GetDocFriendlyParameterName(c, typeGenericsDict, methodGenericArgsDict)).ToArray(); name = string.Format("{0}{{{1}}}", name, string.Join(",", genericParams)); return name; } return parameterType.FullName.Trim('&'); } private string GetIdentifierForMethod(MethodBase method, string name) { var isCtor = name == "#ctor"; var sb = new StringBuilder(string.Format("M:{0}.{1}", method.DeclaringType.FullName.Replace('+', '.'), name)); if (!isCtor) { var cnt = method.GetGenericArguments().Length; if (cnt > 0) sb.AppendFormat("``{0}", cnt); } var prs = method.GetParameters(); if (prs.Length > 0) { sb.Append('('); var typeGenericsDict = method.DeclaringType._GetGenericArguments() .Select((a, i) => new { a, i }) .ToDictionary(c => c.a, c => c.i); // type -> `0, type -> `1 var methodGenericArgsDict = isCtor ? new Dictionary() : method.GetGenericArguments() .Select((a, i) => new { a, i }) .ToDictionary(c => c.a, c => c.i); //type -> ``0, type -> ``1 var names = new List(); foreach (var param in prs) { var friendlyName = GetDocFriendlyParameterName(param.ParameterType, typeGenericsDict, methodGenericArgsDict); if (param.IsOut || param.ParameterType.IsByRef) friendlyName = friendlyName + "@"; names.Add(friendlyName); } sb.Append(string.Join(",", names)); sb.Append(')'); } return sb.ToString(); } private string GetPrefix(MemberTypes mt) { switch (mt) { case MemberTypes.Property: return "P"; case MemberTypes.Field: return "F"; case MemberTypes.Method: return "M"; case MemberTypes.Event: return "E"; } return string.Empty; } private string GetIdentifierForMember(MemberInfo member) { if (member is MethodInfo) return GetIdentifierForMethod((MethodBase)member, member.Name); var path = member.DeclaringType.FullName; if (string.IsNullOrEmpty(path)) { path = member.DeclaringType.Namespace + "." + member.DeclaringType.Name; } var id = string.Format("{0}:{1}.{2}", GetPrefix(member.MemberType), path.Replace('+', '.'), member.Name); return id; } private string GetIdentifierForType(Type type) { return string.Format("T:{0}", type.FullName.Replace('+', '.')); } private string GetIdentifierForConstructor(ConstructorInfo constructor) { return GetIdentifierForMethod(constructor, "#ctor"); } /// /// Returns documentation member for class member /// /// Class member public DocumentationMember GetDocumentationMember(MemberInfo member) { if (member == null) return null; if (!_isDocumentationExists) return null; var id = GetIdentifierForMember(member); if (!_documentationCache.ContainsKey(id)) return null; var info = member as MethodInfo; if (info != null) { return GetDocumentationMember(info); } var doc = _documentationCache[id]; if (!doc.HasInheritDoc() && !doc.HasSummary()) return null; return doc; } /// /// Returns documentation member for method /// /// /// public DocumentationMember GetDocumentationMember(MethodInfo method) { if (method == null) return null; if (!_isDocumentationExists) return null; var id = GetIdentifierForMethod(method, method.Name); if (!_documentationCache.ContainsKey(id)) return null; var doc = _documentationCache[id]; if (!doc.HasInheritDoc() && !doc.HasSummary() && !doc.HasParameters() && !doc.HasReturns()) return null; return doc; } /// /// Returns documentation for constructor /// /// Constructor public DocumentationMember GetDocumentationMember(ConstructorInfo constructor) { if (constructor == null) return null; if (!_isDocumentationExists) return null; var id = GetIdentifierForConstructor(constructor); if (!_documentationCache.ContainsKey(id)) return null; var doc = _documentationCache[id]; if (!doc.HasInheritDoc() && !doc.HasSummary() && !doc.HasParameters()) return null; return doc; } /// /// Returns documentation for type /// /// Type public DocumentationMember GetDocumentationMember(Type type) { if (type == null) return null; if (!_isDocumentationExists) return null; var id = GetIdentifierForType(type); if (!_documentationCache.ContainsKey(id)) return null; var typeDoc = _documentationCache[id]; if (!typeDoc.HasInheritDoc() && !typeDoc.HasSummary()) return null; return typeDoc; } } } ================================================ FILE: Reinforced.Typings/Xmldoc/Model/DocumentationMemberExtensions.cs ================================================ namespace Reinforced.Typings.Xmldoc.Model { internal static class DocumentationMemberExtensions { public static DocumentationMemberType MemberType(this string name) { if (string.IsNullOrEmpty(name)) return DocumentationMemberType.Unknown; if (name.Contains("#ctor")) return DocumentationMemberType.Constructor; if (name.StartsWith("M:")) return DocumentationMemberType.Method; if (name.StartsWith("T:")) return DocumentationMemberType.Type; if (name.StartsWith("P:")) return DocumentationMemberType.Property; if (name.StartsWith("E:")) return DocumentationMemberType.Event; if (name.StartsWith("N:")) return DocumentationMemberType.Namespace; if (name.StartsWith("F:")) return DocumentationMemberType.Field; return DocumentationMemberType.Unknown; } public static bool HasInheritDoc(this DocumentationMember dm) { return dm.InheritDoc != null; } public static bool HasSummary(this DocumentationMember dm) { return dm.Summary != null && !string.IsNullOrEmpty(dm.Summary.Text); } public static bool HasRemarks(this DocumentationMember dm) { return dm.Remarks != null && !string.IsNullOrEmpty(dm.Remarks.Text); } public static bool HasParameters(this DocumentationMember dm) { return dm.Parameters != null && dm.Parameters.Length > 0; } public static bool HasReturns(this DocumentationMember dm) { return dm.Returns != null && !string.IsNullOrEmpty(dm.Returns.Text); } } } ================================================ FILE: Reinforced.Typings/Xmldoc/Model/DocumentationMemberType.cs ================================================ #pragma warning disable 1591 namespace Reinforced.Typings.Xmldoc.Model { public enum DocumentationMemberType { Type, Property, Field, Event, Namespace, Method, Constructor, Unknown } } ================================================ FILE: Reinforced.Typings/Xmldoc/Model/Model.cs ================================================ using System; using System.Xml; using System.Xml.Serialization; using Reinforced.Typings.Ast; #pragma warning disable 1591 namespace Reinforced.Typings.Xmldoc.Model { [XmlRoot("doc")] [XmlType("doc")] [XmlInclude(typeof (DocumentationMember))] [XmlInclude(typeof (DocumentationParameter))] public class Documentation { [XmlArray("members")] [XmlArrayItem("member")] public DocumentationMember[] Members { get; set; } } public class DocumentationMember { private string _name; [XmlAttribute("name")] public string Name { get { return _name; } set { _name = value; MemberType = _name.MemberType(); } } [XmlIgnore] public DocumentationMemberType MemberType { get; private set; } [XmlElement(ElementName = "summary")] public DocumentationSummary Summary { get; set; } [XmlElement(ElementName = "remarks")] public DocumentationRemarks Remarks { get; set; } [XmlElement(ElementName = "inheritdoc")] public DocumentationInheritDoc InheritDoc { get; set; } [XmlElement(ElementName = "param")] public DocumentationParameter[] Parameters { get; set; } [XmlElement(ElementName = "returns")] public DocumentationReturns Returns { get; set; } public override string ToString() { return string.Format("({0}) {1}", MemberType, Name); } } public class DocumentationParameter : XmlIgnoreInner { public string Name { get; set; } public string Description { get; set; } public override void ReadXml(XmlReader reader) { Name = reader.GetAttribute("name"); Description = reader.ReadInnerXml().Trim(); if (Description.Contains("this method interface declaration")) { } } public override string ToString() { return Name; } } public class DocumentationSummary : XmlIgnoreInner { public string Text { get; set; } public string Cref { get; set; } public override string ToString() { return Text; } public override void ReadXml(XmlReader reader) { Cref = reader.GetAttribute("cref"); Text = reader.ReadInnerXml().Trim(); } } public class DocumentationRemarks : XmlIgnoreInner { public string Text { get; set; } public override string ToString() { return Text; } public override void ReadXml(XmlReader reader) { Text = reader.ReadInnerXml().Trim(); } } public class DocumentationInheritDoc : XmlIgnoreInner { /// /// TODO: Find a type by this cref and get its documentation? /// public string Cref { get; set; } public override string ToString() { return string.Empty; } public override void ReadXml(XmlReader reader) { Cref = reader.GetAttribute("cref"); } } public class DocumentationReturns : XmlIgnoreInner { [XmlText] public string Text { get; set; } public override void ReadXml(XmlReader reader) { Text = reader.ReadInnerXml().Trim(); } public override string ToString() { return Text; } } } ================================================ FILE: Reinforced.Typings/Xmldoc/Model/XmlIgnoreInner.cs ================================================ using System; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; #pragma warning disable 1591 namespace Reinforced.Typings.Xmldoc.Model { public abstract class XmlIgnoreInner : IXmlSerializable { public XmlSchema GetSchema() { throw new NotImplementedException(); } public abstract void ReadXml(XmlReader reader); public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); } } } ================================================ FILE: Reinforced.Typings.Cli/AssemblyManager.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Reinforced.Typings.Exceptions; #if NETCORE using System.Runtime.Loader; #endif namespace Reinforced.Typings.Cli { internal class AssemblyLocation { public AssemblyLocation(string assemblyName, string fileName) { AssemblyName = assemblyName; FileName = fileName; } public string FileName { get; private set; } public string AssemblyName { get; private set; } } internal class AssemblyManager { private readonly string[] _sourceAssemblies; private int _totalLoadedAssemblies; public int TotalLoadedAssemblies { get { return _totalLoadedAssemblies; } } private readonly HashSet _allAssembliesDirs = new HashSet(); private readonly string _referencesTmpFilePath; private readonly TextReader _profileReader; private readonly Dictionary _alreadyLoaded = new Dictionary(); private readonly List _referencesCache = new List(); private readonly Action BuildWarn; public AssemblyManager(string[] sourceAssemblies, TextReader profileReader, string referencesTmpFilePath, Action buildWarn) { _sourceAssemblies = sourceAssemblies; _profileReader = profileReader; _referencesTmpFilePath = referencesTmpFilePath; BuildWarn = buildWarn; } internal void TurnOffAdditionalResolvation() { #if NETCORE AssemblyLoadContext.Default.Resolving -= CurrentDomainOnAssemblyResolve; #else AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomainOnAssemblyResolve; #endif } public Assembly[] GetAssembliesFromArgs() { BuildReferencesCache(); #if NETCORE AssemblyLoadContext.Default.Resolving += CurrentDomainOnAssemblyResolve; #else AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve; #endif List assemblies = new List(); foreach (var assemblyPath in _sourceAssemblies) { var pathes = LookupPossibleAssemblyPath(assemblyPath); foreach (var path in pathes) { if (!Path.IsPathRooted(assemblyPath)) { BuildWarn(ErrorMessages.RTW0013_AssemblyMayNotBeResolvedIncorrectly, new object[] { assemblyPath }); } try { #if NETCORE var a = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); #else var a = Assembly.LoadFrom(path); #endif _totalLoadedAssemblies++; assemblies.Add(a); } catch (Exception ex) { BuildWarn(ErrorMessages.RTW0014_AssemblyFailedToLoad, new object[] { path, ex }); } } } return assemblies.ToArray(); } private void BuildReferencesCache() { _referencesCache.Clear(); if (string.IsNullOrEmpty(_referencesTmpFilePath) && _profileReader == null) return; TextReader tr = null; try { if (_profileReader == null) { tr = File.OpenText(_referencesTmpFilePath); } else { tr = _profileReader; } string reference; while ((reference = tr.ReadLine()) != null) { _referencesCache.Add(new AssemblyLocation(Path.GetFileName(reference), reference)); } } finally { if (tr != null) { if (_profileReader == null) tr.Dispose(); } } } #if NETCORE private Assembly CurrentDomainOnAssemblyResolve(AssemblyLoadContext context, AssemblyName assemblyName) { //AssemblyLoadContext.Default.Resolving -= CurrentDomainOnAssemblyResolve; if (assemblyName.Name.StartsWith("Reinforced.Typings.XmlSerializers")) return Assembly.GetEntryAssembly(); if (_alreadyLoaded.ContainsKey(assemblyName.FullName)) return _alreadyLoaded[assemblyName.FullName]; AssemblyName nm = new AssemblyName(assemblyName.Name); var paths = LookupPossibleAssemblyPath(nm.Name, false); Assembly a = null; foreach (var path in paths) { try { if (!Path.IsPathRooted(path)) { BuildWarn(ErrorMessages.RTW0013_AssemblyMayNotBeResolvedIncorrectly, new object[] { string.Format("{0} (from {1})",nm.Name, path) }); continue; } a = context.LoadFromAssemblyPath(path); } catch (Exception ex) { BuildWarn(ErrorMessages.RTW0014_AssemblyFailedToLoad, new object[] { string.Format("{0} (from {1})",nm.Name, path), ex }); continue; } _alreadyLoaded[assemblyName.FullName] = a; _totalLoadedAssemblies++; break; #if DEBUG Console.WriteLine("{0} additionally resolved", nm); #endif } //AssemblyLoadContext.Default.Resolving += CurrentDomainOnAssemblyResolve; return a; } #else private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) { if (args.Name.StartsWith("Reinforced.Typings.XmlSerializers")) return Assembly.GetExecutingAssembly(); if (_alreadyLoaded.ContainsKey(args.Name)) return _alreadyLoaded[args.Name]; AssemblyName nm = new AssemblyName(args.Name); var paths = LookupPossibleAssemblyPath(nm.Name, false); Assembly a = null; foreach (var path in paths) { try { if (!Path.IsPathRooted(path)) { BuildWarn(ErrorMessages.RTW0013_AssemblyMayNotBeResolvedIncorrectly, new object[] { string.Format("{0} (from {1})",nm.Name, path) }); continue; } a = Assembly.LoadFrom(path); } catch (Exception ex) { BuildWarn(ErrorMessages.RTW0014_AssemblyFailedToLoad, new object[] { string.Format("{0} (from {1})",nm.Name, path), ex }); continue; } _alreadyLoaded[args.Name] = a; _totalLoadedAssemblies++; #if DEBUG Console.WriteLine("{0} additionally resolved", nm); #endif } return a; } #endif private string[] LookupAssemblyPathInternal(string assemblyNameOrFullPath, bool storeIfFullName = true) { #if DEBUG Console.WriteLine("Looking up for assembly {0}", assemblyNameOrFullPath); #endif if (Path.IsPathRooted(assemblyNameOrFullPath) && File.Exists(assemblyNameOrFullPath)) { if (storeIfFullName) { var lastAssemblyLocalDir = Path.GetDirectoryName(assemblyNameOrFullPath) + Path.DirectorySeparatorChar; if (!_allAssembliesDirs.Contains(lastAssemblyLocalDir)) _allAssembliesDirs.Add(lastAssemblyLocalDir); } #if DEBUG Console.WriteLine("Already have full path to assembly {0}", assemblyNameOrFullPath); #endif return new[] { assemblyNameOrFullPath }; } var possiblePathes = _referencesCache.Where(d => d.AssemblyName == assemblyNameOrFullPath) .Select(d => d.FileName) .ToArray(); if (possiblePathes.Length > 0) { #if DEBUG Console.WriteLine("Assembly {0} could be found at:", assemblyNameOrFullPath); foreach (var assemblyLocation in possiblePathes) { Console.WriteLine("\t{0}", assemblyLocation); } #endif return possiblePathes; } List result = new List(); foreach (var dir in _allAssembliesDirs) { var p = Path.Combine(dir, assemblyNameOrFullPath); if (File.Exists(p)) { #if DEBUG Console.WriteLine("Assembly {0} found at {1}", assemblyNameOrFullPath, p); #endif result.Add(p); } } return result.ToArray(); } private IEnumerable LookupPossibleAssemblyPath(string assemblyNameOrFullPath, bool storeIfFullName = true) { string[] checkResult; if (!assemblyNameOrFullPath.EndsWith(".dll") && !assemblyNameOrFullPath.EndsWith(".exe")) { var check = assemblyNameOrFullPath + ".dll"; checkResult = LookupAssemblyPathInternal(check, storeIfFullName); if (checkResult.Length > 0 && checkResult.Any(d => !string.IsNullOrEmpty(d))) return checkResult.Where(d => !string.IsNullOrEmpty(d)); check = assemblyNameOrFullPath + ".exe"; checkResult = LookupAssemblyPathInternal(check, storeIfFullName); if (checkResult.Length > 0 && checkResult.Any(d => !string.IsNullOrEmpty(d))) return checkResult.Where(d => !string.IsNullOrEmpty(d)); } var p = assemblyNameOrFullPath; checkResult = LookupAssemblyPathInternal(p, storeIfFullName); if (checkResult.Length > 0 && checkResult.Any(d => !string.IsNullOrEmpty(d))) return checkResult.Where(d => !string.IsNullOrEmpty(d)); return new[] { assemblyNameOrFullPath }; } } } ================================================ FILE: Reinforced.Typings.Cli/Bootstrapper.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; #if NETCORE using System.Runtime.Loader; #endif using Reinforced.Typings.Exceptions; using Reinforced.Typings.Fluent; namespace Reinforced.Typings.Cli { internal static class CoreTypeExtensions { internal static PropertyInfo[] _GetProperties(this Type t, BindingFlags flags) { #if NETCORE return t.GetTypeInfo().GetProperties(flags); #else return t.GetProperties(flags); #endif } internal static PropertyInfo _GetProperty(this Type t, string name) { #if NETCORE return t.GetTypeInfo().GetProperty(name); #else return t.GetProperty(name); #endif } internal static MethodInfo _GetMethod(this Type t, string name) { #if NETCORE return t.GetTypeInfo().GetMethod(name); #else return t.GetMethod(name); #endif } } internal class ReferenceCacheEntry { } /// /// Class for CLI typescript typings utility /// public static class Bootstrapper { private static TextReader _profileReader; private static string _profilePath; private static AssemblyManager _assemblyManager; private static HashSet _suppressedWarnings = new HashSet(); /// /// Usage: rtcli.exe Assembly.dll [Assembly2.dll Assembly3.dll ... etc] file.ts /// /// public static void Main(string[] args) { Console.WriteLine("Reinforced.Typings CLI generator (c) 2015-2018 by Pavel B. Novikov"); ExporterConsoleParameters parameters = null; if (args.Length == 0) { PrintHelp(); return; } try { if (string.Compare(args[0], "profile", #if NETCORE StringComparison.CurrentCultureIgnoreCase #else StringComparison.InvariantCultureIgnoreCase #endif ) == 0) { if (!File.Exists(args[1])) { Console.WriteLine("Cannot find profile {0}, exiting", args[1]); return; } parameters = ExtractParametersFromFile(args[1]); } else { parameters = ExtractParametersFromArgs(args); } if (parameters == null) { Console.WriteLine("No valid parameters found. Exiting."); return; } _suppressedWarnings = ParseSuppressedWarnings(parameters.SuppressedWarnings); var settings = InstantiateExportContext(parameters); ResolveFluentMethod(settings,parameters); TsExporter exporter = new TsExporter(settings); exporter.Export(); _assemblyManager.TurnOffAdditionalResolvation(); foreach (var rtWarning in settings.Warnings) { var msg = VisualStudioFriendlyErrorMessage.Create(rtWarning); Console.WriteLine(msg.ToString()); } ReleaseReferencesTempFile(parameters); } catch (RtException rtException) { var error = VisualStudioFriendlyErrorMessage.Create(rtException); Console.WriteLine(error.ToString()); Console.WriteLine(rtException.StackTrace); ReleaseReferencesTempFile(parameters); Environment.Exit(1); } catch (TargetInvocationException ex) { var e = ex.InnerException; // ReSharper disable once PossibleNullReferenceException BuildError(e.Message); Console.WriteLine(e.StackTrace); Environment.Exit(1); } catch (ReflectionTypeLoadException ex) { BuildError(ex.Message); Console.WriteLine(ex.StackTrace); if (ex.LoaderExceptions != null) { foreach (var elo in ex.LoaderExceptions) { BuildError(elo.Message); Console.WriteLine(elo.StackTrace); } } Environment.Exit(1); } catch (Exception ex) { BuildError(ex.Message); Console.WriteLine(ex.StackTrace); Environment.Exit(1); } if (_assemblyManager != null) { Console.WriteLine("Reinforced.Typings generation finished with total {0} assemblies loaded", _assemblyManager.TotalLoadedAssemblies); } Console.WriteLine("Please build CompileTypeScript task to update javascript sources"); } private static void ReleaseReferencesTempFile(ExporterConsoleParameters parameters) { if (_profileReader != null) _profileReader.Dispose(); if (!string.IsNullOrEmpty(_profilePath)) File.Delete(_profilePath); if (parameters == null) return; if (!string.IsNullOrEmpty(parameters.ReferencesTmpFilePath)) File.Delete(parameters.ReferencesTmpFilePath); } private static void ResolveFluentMethod(ExportContext context, ExporterConsoleParameters parameters) { if (string.IsNullOrEmpty(parameters.ConfigurationMethod)) return; var methodPath = parameters.ConfigurationMethod; var path = new Stack(methodPath.Split('.')); var method = path.Pop(); var fullQualifiedType = string.Join(".", path.Reverse()); bool isFound = false; foreach (var sourceAssembly in context.SourceAssemblies) { var type = sourceAssembly.GetType(fullQualifiedType, false); if (type != null) { var constrMethod = type._GetMethod(method); if (constrMethod != null && constrMethod.IsStatic) { var pars = constrMethod.GetParameters(); if (pars.Length == 1/* && pars[0].ParameterType == typeof(ConfigurationBuilder)*/) { isFound = true; context.ConfigurationMethod = builder => constrMethod.Invoke(null, new object[] { builder }); break; } } } } if (!isFound) BuildWarn(ErrorMessages.RTW0009_CannotFindFluentMethod, methodPath); } public static ExportContext InstantiateExportContext(ExporterConsoleParameters parameters) { _assemblyManager = new AssemblyManager(parameters.SourceAssemblies,_profileReader,parameters.ReferencesTmpFilePath,BuildWarn); var srcAssemblies = _assemblyManager.GetAssembliesFromArgs(); ExportContext context = new ExportContext(srcAssemblies) { Hierarchical = parameters.Hierarchy, TargetDirectory = parameters.TargetDirectory, TargetFile = parameters.TargetFile, DocumentationFilePath = parameters.DocumentationFilePath, SuppressedWarningCodes = ParseSuppressedWarnings(parameters.SuppressedWarnings) }; return context; } public static void PrintHelp() { Console.WriteLine("Available parameters:"); Console.WriteLine(); var t = typeof(ExporterConsoleParameters); var props = t._GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var propertyInfo in props) { var attr = propertyInfo.GetCustomAttribute(); if (attr != null) { var req = attr.RequiredType; string requiredText = null; switch (req) { case Required.Not: requiredText = "(not required)"; break; case Required.Is: requiredText = "(required)"; break; case Required.Partially: requiredText = "(sometimes required)"; break; } Console.WriteLine(propertyInfo.Name + " " + requiredText); var lines = attr.HelpText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { Console.WriteLine("\t{0}", line); } Console.WriteLine(); } } } private static void BuildWarn(ErrorMessage msg, params object[] args) { if (_suppressedWarnings.Contains(msg.Code)) return; VisualStudioFriendlyErrorMessage vsm = VisualStudioFriendlyErrorMessage.Create(msg.Warn(args)); Console.WriteLine(vsm.ToString()); } private static void BuildError(string message, params object[] args) { var errorMessage = string.Format(message, args); VisualStudioFriendlyErrorMessage vsm = new VisualStudioFriendlyErrorMessage(999, errorMessage, VisualStudioFriendlyMessageType.Error, "Unexpected"); Console.WriteLine(vsm.ToString()); } public static HashSet ParseSuppressedWarnings(string input) { var result = new HashSet(); if (string.IsNullOrEmpty(input)) return result; var values = input.Split(';'); foreach (var warningCode in values) { //for some reason there is no StringSplitOptions for netcoreapp1.0 if (string.IsNullOrEmpty(warningCode)) continue; var filtered = new string(warningCode.Where(char.IsDigit).ToArray()); bool parsed = int.TryParse(filtered, out int intWarningCode); if (parsed) result.Add(intWarningCode); else { BuildWarn(ErrorMessages.RTW0010_CannotParseWarningCode,warningCode); } } return result; } private static ExporterConsoleParameters ExtractParametersFromFile(string fileName) { _profilePath = fileName; _profileReader = File.OpenText(fileName); return ExporterConsoleParameters.FromFile(_profileReader); } public static ExporterConsoleParameters ExtractParametersFromArgs(string[] args) { var t = typeof(ExporterConsoleParameters); var instance = new ExporterConsoleParameters(); foreach (var s in args) { var trimmed = s.TrimStart('-'); var kv = trimmed.Split('='); if (kv.Length != 2) { BuildWarn(ErrorMessages.RTW0011_UnrecognizedConfigurationParameter, s); continue; } var key = kv[0].Trim(); var value = kv[1].Trim().Trim('"'); var prop = t._GetProperty(key); if (prop == null) { BuildWarn(ErrorMessages.RTW0011_UnrecognizedConfigurationParameter, key); continue; } if (prop.PropertyType == typeof(bool)) { bool parsedValue = Boolean.Parse(value); prop.SetValue(instance, parsedValue); continue; } if (prop.PropertyType == typeof(string)) { prop.SetValue(instance, value); continue; } if (prop.PropertyType == typeof(string[])) { var parsedValue = value.Split(';'); prop.SetValue(instance, parsedValue); continue; } BuildWarn(ErrorMessages.RTW0012_UnrecognizedConfigurationParameterValue, key); } try { instance.Validate(); } catch (Exception ex) { BuildError("Parameter validation error: {0}", ex.Message); PrintHelp(); return null; } return instance; } } } ================================================ FILE: Reinforced.Typings.Cli/ConsoleHelpAttribute.cs ================================================ using System; namespace Reinforced.Typings.Cli { /// /// Denotes console help for parameter /// public class ConsoleHelpAttribute : Attribute { /// /// Help text /// public string HelpText { get; set; } public Required RequiredType { get; set; } public ConsoleHelpAttribute(string helpText,Required requiredType = Required.Not) { HelpText = helpText; RequiredType = requiredType; } } public enum Required { Is, Not, Partially } } ================================================ FILE: Reinforced.Typings.Cli/ErrorMessages.cs ================================================ using Reinforced.Typings.Exceptions; namespace Reinforced.Typings.Cli { class ErrorMessages { /// /// Error of fluent method loading /// public static readonly ErrorMessage RTW0009_CannotFindFluentMethod = new ErrorMessage(0009, "Cannot find configured fluent method '{0}'", "Type loading"); /// /// Error of suppressed warning code parsing /// public static readonly ErrorMessage RTW0010_CannotParseWarningCode = new ErrorMessage(0010, "Cannot parse warning code '{0}'", "Parameters parsering"); /// /// Error of configuration parameter parsing /// public static readonly ErrorMessage RTW0011_UnrecognizedConfigurationParameter = new ErrorMessage(0011, "Unrecognized configuration parameter: {0}", "Parameters parsering"); /// /// Error of configuration parameter value parsing /// public static readonly ErrorMessage RTW0012_UnrecognizedConfigurationParameterValue = new ErrorMessage(0012, "Unrecognized configuration parameter value: {0}", "Parameters parsering"); /// /// Warning of potentially incorrect assembly resolve /// public static readonly ErrorMessage RTW0013_AssemblyMayNotBeResolvedIncorrectly = new ErrorMessage(0013, "Assembly {0} may be resolved incorrectly", "Assembly loading"); /// /// Warning of failed assembly load /// public static readonly ErrorMessage RTW0014_AssemblyFailedToLoad = new ErrorMessage(0014, "Assembly {0} failed to load: {1}", "Assembly loading"); } } ================================================ FILE: Reinforced.Typings.Cli/ExporterConsoleParameters.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; namespace Reinforced.Typings.Cli { /// /// Reinforced.Typings generator CLI parameters /// public class ExporterConsoleParameters { /// /// Source assemblies. /// The assemblies to extract typings from /// [ConsoleHelp(@" The semicolon-separated list of assemblies to extract typings from. Example: rtcli.exe SourceAssemblies=""C:\TestProject\Assembly1.dll;C:\TestProject\Assembly2.dll"" ", Required.Is)] public string[] SourceAssemblies { get; set; } /// /// Target file where to store generated sources. /// This parameter is not used when Hierarchy is true /// [ConsoleHelp(@" Target file to store generated sources. Not required if Hierarchy=""true"" specified. Otherwise required. Example: rtcli.exe TargetFile=""C:\path\to\target\file.ts""", Required.Partially)] public string TargetFile { get; set; } /// /// Target directory where to store generated typing files. /// This parameter is not used when Hierarchy is false /// [ConsoleHelp(@" Target directory to store generated typing files. Not required if Hierarchy=""false"" or not specified. Otherwise required. Example: rtcli.exe TargetDirectory=""C:\path\to\project\"" (trailing slash optional)", Required.Partially)] public string TargetDirectory { get; set; } /// /// Full list of referenced assemblies. /// If not specified then the CLI will try to resolve reference assemblies from same directory as target assembly /// [ConsoleHelp(@" Path to temporary file containing all references for project. One reference per line. If not specified then the CLI will try to resolve reference assemblies from same directory as target assembly. Example: rtcli.exe References=""C:\Users\AppData\Local\Temp\ANGhgRuDPG.tmp"" ")] public string ReferencesTmpFilePath { get; set; } /// /// True to create project hierarchy in target folder. /// False to store generated typings in single file /// [ConsoleHelp(@" Boolean parameter that switches hierarchy generation ability. True to create project hierarchy in target folder. False (default) to store generated typings in single file. Example: rtcli.exe Hierarchy=""true"" ")] public bool Hierarchy { get; set; } /// /// Full path to assembly's XMLDOC file. /// If this parameter is not specified or contains invalid path then documentation will not be generated without any exception /// [ConsoleHelp(@" Full path to assembly's XMLDOC file. If this parameter is not specified or contains invalid path then documentation will not be generated without any exception Example: rtcli.exe DocumentationFilePath=""C:\MyAssembly\Assembly.XML"" ")] public string DocumentationFilePath { get; set; } /// /// Sets full-qualified name of configuration method to be applied to retrieve fluent configuration instead of attribute-based configuration. /// Configuration method should be static and consume Reinforced.Typings.Fluent.ConfigurationBuilder as first parameter. /// Warning! It is important for Configuration method to be full-qualified and it should be located in the one of referenced assemblies! /// [ConsoleHelp(@" Sets full-qualified name of configuration method to be applied to retrieve fluent configuration instead of attribute-based configuration. Configuration method should be static and consume ConfigurationBuilder as first parameter. Example: rtcli.exe ConfigurationMethod=""My.Assembly.Name.Configuration.ConfigureTypings"" ")] public string ConfigurationMethod { get; set; } /// /// Sets list of warnings to be suppressed. Semi-colon separated values. /// All letters will be discarded when parsing, so can be specified in any convenient format /// [ConsoleHelp(@" Sets list of warnings to be suppressed. Semi-colon separated values. All letters will be discarded when parsering, so can be specified in any convenient format Example: rtcli.exe SuppressedWarnings=""RTW0001;2;3"" ")] public string SuppressedWarnings { get; set; } /// /// Validates input parameters /// public void Validate() { if (!Hierarchy && string.IsNullOrEmpty(TargetFile)) throw new Exception("Target file must be specified in case of non-hierarchy generation"); if (Hierarchy && string.IsNullOrEmpty(TargetDirectory)) throw new Exception("Target directory must be specified in case of hierarchy generation"); if (SourceAssemblies == null || SourceAssemblies.Length == 0) throw new Exception("No source assemblies specified. Nothing to export"); } public ExporterConsoleParameters() { } public static ExporterConsoleParameters FromFile(TextReader tr) { ExporterConsoleParameters result = new ExporterConsoleParameters(); result.TargetFile = tr.ReadLine(); result.ReferencesTmpFilePath = tr.ReadLine(); result.TargetDirectory = tr.ReadLine(); result.Hierarchy = bool.Parse(tr.ReadLine()); result.DocumentationFilePath = tr.ReadLine(); result.ConfigurationMethod = tr.ReadLine(); result.SuppressedWarnings = tr.ReadLine(); result.SourceAssemblies = new string[int.Parse(tr.ReadLine())]; for (int i = 0; i < result.SourceAssemblies.Length; i++) { result.SourceAssemblies[i] = tr.ReadLine(); } return result; } public void ToFile(TextWriter tw) { tw.WriteLine(TargetFile); tw.WriteLine(ReferencesTmpFilePath); tw.WriteLine(TargetDirectory); tw.WriteLine(Hierarchy); tw.WriteLine(DocumentationFilePath); tw.WriteLine(ConfigurationMethod); tw.WriteLine(SuppressedWarnings); tw.WriteLine(SourceAssemblies.Length); foreach (var sourceAssembly in SourceAssemblies) { tw.WriteLine(sourceAssembly); } } /// /// Produces command line arguments suitable for rtcli.exe /// /// Command line arguments string public string ExportConsoleParameters() { List arguments = new List(); var props = typeof(ExporterConsoleParameters)._GetProperties(BindingFlags.Public | BindingFlags.Instance); const string propFormat = "{0}=\"{1}\""; foreach (var propertyInfo in props) { var pi = propertyInfo.GetValue(this); if (pi == null) continue; if (propertyInfo.PropertyType == (typeof(string[]))) { var strings = (string[])pi; if (strings.Length == 0) continue; pi = string.Join(";", strings); } arguments.Add(String.Format(propFormat, propertyInfo.Name, pi)); } return String.Join(" ", arguments); } } } ================================================ FILE: Reinforced.Typings.Cli/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Reinforced.WebTypings.Console")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Reinforced.WebTypings.Console")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("b1103c7e-f5a2-4ac5-a5bc-7107b4d0fd69")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: Reinforced.Typings.Cli/Properties/launchSettings.json ================================================ { "profiles": { "Reinforced.Typings.Cli.NETCore": { "commandName": "Project", "commandLineArgs": "profile \"w:\\Work\\Reinforced\\Typings\\testfile.txt\"" } } } ================================================ FILE: Reinforced.Typings.Cli/Reinforced.Typings.Cli.Dev.csproj ================================================ net5.0 Exe Reinforced.Typings.Cli false false None Reinforced.Typings.Cli.Bootstrapper true true AnyCPU;x64;x86 rtcli Reinforced Software Construction OSS Pavel B. Novikov 2019 $(AssemblyName) 1.5.9 1.5.9 1.5.9 $(DefineConstants);NETCORE; ================================================ FILE: Reinforced.Typings.Cli/Reinforced.Typings.Cli.NETCore.csproj ================================================ net10.0 Exe Reinforced.Typings.Cli false false None Reinforced.Typings.Cli.Bootstrapper true true AnyCPU;x64;x86 rtcli Reinforced Software Construction OSS Pavel B. Novikov 2019 $(AssemblyName) 1.6.7 1.6.7 1.6.7 $(DefineConstants);$(RtAdditionalConstants); ================================================ FILE: Reinforced.Typings.Cli/Reinforced.Typings.Cli.csproj ================================================  Debug AnyCPU {006290E6-CC0D-4222-87F8-9E67469AD2C9} Exe Properties Reinforced.Typings.Cli rtcli v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {2a5ccd5c-e660-4088-8937-9632abbbcdbb} Reinforced.Typings ================================================ FILE: Reinforced.Typings.Cli/VisualStudioFriendlyErrorMessage.cs ================================================ using Reinforced.Typings.Exceptions; namespace Reinforced.Typings.Cli { /// /// Class that formats messages in appropriate way to be shown at /// VisualStudio's errors list /// /// Explanation is taken from here: /// http://blogs.msdn.com/b/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx /// class VisualStudioFriendlyErrorMessage { public string Origin { get { return "Reinforced.Typings"; } } public string Subcategory { get; set; } public VisualStudioFriendlyMessageType Type { get; set; } public int Code { get; set; } public string CodeName { get { return string.Format("RT{0:0000}", Code); } } public string ErrorText { get; set; } public VisualStudioFriendlyErrorMessage(int code, string errorText, VisualStudioFriendlyMessageType type, string subcategory = "") { Code = code; ErrorText = errorText; Subcategory = subcategory; Type = type; } public override string ToString() { return string.Format("{0} : {1} {2} {3}: {4}", Origin, Subcategory, Type == VisualStudioFriendlyMessageType.Error ? "error" : "warning", CodeName, ErrorText); } public static VisualStudioFriendlyErrorMessage Create(RtWarning warning) { return new VisualStudioFriendlyErrorMessage(warning.Code,warning.Text,VisualStudioFriendlyMessageType.Warning,warning.Subcategory); } public static VisualStudioFriendlyErrorMessage Create(RtException error) { return new VisualStudioFriendlyErrorMessage(error.Code, error.Message, VisualStudioFriendlyMessageType.Error, error.Subcategory); } } } ================================================ FILE: Reinforced.Typings.Cli/VisualStudioFriendlyMessageType.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Reinforced.Typings.Cli { public enum VisualStudioFriendlyMessageType { Error, Warning } } ================================================ FILE: Reinforced.Typings.Cli/app.config ================================================ ================================================ FILE: Reinforced.Typings.Dev.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.Dev", "Reinforced.Typings\Reinforced.Typings.Dev.csproj", "{ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.Cli.Dev", "Reinforced.Typings.Cli\Reinforced.Typings.Cli.Dev.csproj", "{E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.Integrate.Dev", "Reinforced.Typings.Integrate\Reinforced.Typings.Integrate.Dev.csproj", "{836424C9-8003-4C0F-84E1-2C17FE498648}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cake", "cake", "{71091BA9-1588-4878-B1FA-3EF908CCD61C}" ProjectSection(SolutionItems) = preProject cake\build.cake = cake\build.cake EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.Tests.Dev", "Reinforced.Typings.Tests\Reinforced.Typings.Tests.Dev.csproj", "{6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestFluentAssembly.Dev", "TestFluentAssembly\TestFluentAssembly.Dev.csproj", "{D72B9639-9CC3-403E-8E7E-636115429A38}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x64.ActiveCfg = Debug|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x64.Build.0 = Debug|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x86.ActiveCfg = Debug|x86 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x86.Build.0 = Debug|x86 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|Any CPU.Build.0 = Release|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x64.ActiveCfg = Release|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x64.Build.0 = Release|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x86.ActiveCfg = Release|x86 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x86.Build.0 = Release|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x64.ActiveCfg = Debug|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x64.Build.0 = Debug|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x86.ActiveCfg = Debug|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x86.Build.0 = Debug|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|Any CPU.Build.0 = Release|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x64.ActiveCfg = Release|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x64.Build.0 = Release|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x86.ActiveCfg = Release|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x86.Build.0 = Release|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|Any CPU.Build.0 = Debug|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x64.ActiveCfg = Debug|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x64.Build.0 = Debug|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x86.ActiveCfg = Debug|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x86.Build.0 = Debug|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|Any CPU.ActiveCfg = Release|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|Any CPU.Build.0 = Release|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x64.ActiveCfg = Release|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x64.Build.0 = Release|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x86.ActiveCfg = Release|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x86.Build.0 = Release|x86 {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Debug|Any CPU.Build.0 = Debug|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Debug|x64.ActiveCfg = Debug|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Debug|x64.Build.0 = Debug|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Debug|x86.ActiveCfg = Debug|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Debug|x86.Build.0 = Debug|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Release|Any CPU.Build.0 = Release|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Release|x64.ActiveCfg = Release|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Release|x64.Build.0 = Release|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Release|x86.ActiveCfg = Release|Any CPU {6E812A62-42E1-4CBF-97A4-A1F73BB5E96E}.Release|x86.Build.0 = Release|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Debug|Any CPU.Build.0 = Debug|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Debug|x64.ActiveCfg = Debug|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Debug|x64.Build.0 = Debug|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Debug|x86.ActiveCfg = Debug|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Debug|x86.Build.0 = Debug|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Release|Any CPU.ActiveCfg = Release|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Release|Any CPU.Build.0 = Release|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Release|x64.ActiveCfg = Release|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Release|x64.Build.0 = Release|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Release|x86.ActiveCfg = Release|Any CPU {D72B9639-9CC3-403E-8E7E-636115429A38}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {222B89C5-FC73-4A1A-AF3C-8BEB9CEF8EB3} EndGlobalSection EndGlobal ================================================ FILE: Reinforced.Typings.Integrate/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Reinforced.Typings.Integrate")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Reinforced.Typings.Integrate")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("0e333cad-85ca-4636-88e8-f72a8ad9b8c5")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: Reinforced.Typings.Integrate/Reinforced.Typings.Integrate.Dev.csproj ================================================ net46;netstandard2.0 Reinforced.Typings.Integrate false false None AnyCPU;x64;x86 Reinforced.Typings.Integrate Reinforced Software Construction OSS Pavel B. Novikov 2019 $(AssemblyName) 1.5.9 1.5.9 1.5.9 $(DefineConstants);NETCORE; ================================================ FILE: Reinforced.Typings.Integrate/Reinforced.Typings.Integrate.NETCore.csproj ================================================ net46;netstandard2.0 Reinforced.Typings.Integrate false false None AnyCPU;x64;x86 Reinforced.Typings.Integrate Reinforced Software Construction OSS Pavel B. Novikov 2019 $(AssemblyName) 1.6.7 1.6.7 1.6.7 $(DefineConstants);$(RtAdditionalConstants); ================================================ FILE: Reinforced.Typings.Integrate/Reinforced.Typings.Integrate.csproj ================================================  Debug AnyCPU {F4830436-B660-4FAF-8F1B-4ADD0732AF02} Library Properties Reinforced.Typings.Integrate Reinforced.Typings.Integrate v4.6 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 ..\packages\Microsoft.Build.Framework.15.9.20\lib\net46\Microsoft.Build.Framework.dll True ..\packages\Microsoft.Build.Utilities.Core.15.9.20\lib\net46\Microsoft.Build.Utilities.Core.dll True ..\packages\Microsoft.VisualStudio.Setup.Configuration.Interop.1.16.30\lib\net35\Microsoft.VisualStudio.Setup.Configuration.Interop.dll True True ..\packages\System.Collections.Immutable.1.5.0\lib\netstandard1.3\System.Collections.Immutable.dll True ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll True {006290e6-cc0d-4222-87f8-9e67469ad2c9} Reinforced.Typings.Cli ================================================ FILE: Reinforced.Typings.Integrate/RemoveTypescriptStep.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Build.Framework; namespace Reinforced.Typings.Integrate { public class RemoveTypescriptStep : ITask { [Output] public string[] Fixed { get; set; } [Required] public string Original { get; set; } /// Executes a task. /// true if the task executed successfully; otherwise, false. public bool Execute() { Console.WriteLine("RT is fixing build tasks"); string[] targets = Original.Trim().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); List result = new List(); foreach (string s in targets) { string v = s.Trim(); bool isCompileTs = (v == "CompileTypeScript"); bool isCompileTsConfig = (v == "CompileTypeScriptWithTSConfig"); bool isGetTypeScriptOutputForPublishing = (v == "GetTypeScriptOutputForPublishing"); if ((!isCompileTs) && (!isCompileTsConfig) && (!isGetTypeScriptOutputForPublishing)) { result.Add(v); } else { Console.WriteLine(v + " task will be removed"); } } Fixed = result.ToArray(); Console.WriteLine("RT has fixed build tasks:" + string.Join(";", Fixed)); return true; } /// Gets or sets the build engine associated with the task. /// The build engine associated with the task. public IBuildEngine BuildEngine { get; set; } /// Gets or sets any host object that is associated with the task. /// The host object associated with the task. public ITaskHost HostObject { get; set; } } } ================================================ FILE: Reinforced.Typings.Integrate/RtCli.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Reinforced.Typings.Cli; namespace Reinforced.Typings.Cli { public static class TypeExtensions { internal static PropertyInfo[] _GetProperties(this Type t, BindingFlags flags) { #if NETCORE return t.GetTypeInfo().GetProperties(flags); #else return t.GetProperties(flags); #endif } } } namespace Reinforced.Typings.Integrate { /// /// Task for gathering dynamic typings /// public class RtCli : ToolTask { /// /// Framework version to invoke rtcli /// public string TargetFramework { get; set; } /// /// Forced usage of target framework /// public string RtForceTargetFramework { get; set; } /// /// Package's "build" directory /// [Required] public string BuildDirectory { get; set; } /// /// Additional library references /// [Required] public ITaskItem[] References { get; set; } /// /// Source assembly /// [Required] public ITaskItem[] SourceAssembly { get; set; } /// /// Target .td/.d.ts file /// public string TargetFile { get; set; } /// /// Target directory for hierarchical generation /// public string TargetDirectory { get; set; } /// /// Generate types to multiple files /// public bool Hierarchical { get; set; } /// /// Additional source assemblies to import /// public ITaskItem[] AdditionalSourceAssemblies { get; set; } /// /// ProjectDir variable /// public string ProjectRoot { get; set; } /// /// Path to documentation XML /// public string DocumentationFilePath { get; set; } /// /// Full-qualified name of fluent configuration method /// public string ConfigurationMethod { get; set; } /// /// Semicolon-separated list of warnings to be suppressed /// public string SuppressedWarnings { get; set; } /// Projects may set this to override a task's ToolName. Tasks may override this to prevent that. public override string ToolExe { get; set; } protected override string GenerateFullPathToTool() { if (IsCore) { #if NETCORE return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"; #else return "dotnet.exe"; #endif } return Path.Combine(GetProperRtcliPath(), ToolName); } private string GetProperRtcliPath() { var bd = new DirectoryInfo(BuildDirectory); var toolsPath = Path.Combine(bd.Parent.FullName, "tools"); var fwPath = Path.Combine(toolsPath, NormalizeFramework()); return fwPath; } private string NormalizeFramework() { if (!string.IsNullOrEmpty(RtForceTargetFramework)) return RtForceTargetFramework; if (string.IsNullOrEmpty(TargetFramework)) #if NETCORE return "netcoreapp2.0"; #else return "net45"; #endif if (TargetFramework.StartsWith("netstandard")) { var version = int.Parse(TargetFramework.Substring("netstandard".Length)[0].ToString()); if (version == 1) return "netcoreapp1.0"; return "netcoreapp2.0"; } if (TargetFramework.StartsWith("netcoreapp")) return TargetFramework; if (TargetFramework.StartsWith("net46")) return "net461"; if (TargetFramework.StartsWith("net47")) return "net461"; if (TargetFramework.StartsWith("net48")) return "net461"; return TargetFramework; } private bool IsCore { get { var fw = NormalizeFramework(); if (string.IsNullOrEmpty(fw)) return false; if (fw.StartsWith("netstandard")) return true; if (fw.StartsWith("netcoreapp")) return true; if (fw.StartsWith("net5")) return true; if (fw.StartsWith("net6")) return true; if (fw.StartsWith("net7")) return true; if (fw.StartsWith("net8")) return true; if (fw.StartsWith("net9")) return true; if (fw.StartsWith("net10")) return true; return false; } } protected override string ToolName { get { if (IsCore) { #if NETCORE return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"; #else return "dotnet.exe"; #endif } return "rtcli.exe"; } } protected override string GenerateCommandLineCommands() { ExporterConsoleParameters consoleParams = new ExporterConsoleParameters() { Hierarchy = Hierarchical, TargetDirectory = FixTargetPath(TargetDirectory), TargetFile = FixTargetPath(TargetFile), ReferencesTmpFilePath = string.Empty, SourceAssemblies = ExtractSourceAssemblies(), SuppressedWarnings = SuppressedWarnings, DocumentationFilePath = DocumentationFilePath.EndsWith(".xml", #if NETCORE StringComparison.CurrentCultureIgnoreCase #else StringComparison.InvariantCultureIgnoreCase #endif ) ? DocumentationFilePath : String.Empty, ConfigurationMethod = ConfigurationMethod }; var tmpFile = Path.GetTempFileName(); using (var fs = File.OpenWrite(tmpFile)) { using (var tw = new StreamWriter(fs)) { consoleParams.ToFile(tw); PutReferencesToTempFile(tw); tw.Flush(); } } if (IsCore) { var pth = Path.Combine(GetProperRtcliPath(), "rtcli.dll"); return string.Format("\"{1}\" profile \"{0}\"", tmpFile, pth); } return string.Format("profile \"{0}\"", tmpFile); } private string FixTargetPath(string path) { if (!string.IsNullOrEmpty(path)) { if (!Path.IsPathRooted(path)) { return Path.Combine(ProjectRoot, path); } } return path; } private void PutReferencesToTempFile(TextWriter tw) { if (References == null) return; foreach (var rf in References.Select(c => c.ItemSpec)) { tw.WriteLine(rf); } tw.Flush(); } private string[] ExtractSourceAssemblies() { List srcAssemblies = new List(); if (AdditionalSourceAssemblies != null) { srcAssemblies.AddRange(AdditionalSourceAssemblies.Select(c => c.ItemSpec)); } if (SourceAssembly != null) { srcAssemblies.AddRange(SourceAssembly.Select(c => Path.Combine(ProjectRoot, c.ItemSpec))); } return srcAssemblies.ToArray(); } } } ================================================ FILE: Reinforced.Typings.Integrate/packages.config ================================================  ================================================ FILE: Reinforced.Typings.NETCore.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.16 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.NETCore", "Reinforced.Typings\Reinforced.Typings.NETCore.csproj", "{ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.Cli.NETCore", "Reinforced.Typings.Cli\Reinforced.Typings.Cli.NETCore.csproj", "{E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reinforced.Typings.Integrate.NETCore", "Reinforced.Typings.Integrate\Reinforced.Typings.Integrate.NETCore.csproj", "{836424C9-8003-4C0F-84E1-2C17FE498648}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cake", "cake", "{71091BA9-1588-4878-B1FA-3EF908CCD61C}" ProjectSection(SolutionItems) = preProject cake\build.cake = cake\build.cake cake\build.ps1 = cake\build.ps1 cake\build.sh = cake\build.sh EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reinforced.Typings.Tests.NETCore", "Reinforced.Typings.Tests\Reinforced.Typings.Tests.NETCore.csproj", "{5D126898-7E5D-4967-8732-3FC8722F532E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestFluentAssembly.NETCore", "TestFluentAssembly\TestFluentAssembly.NETCore.csproj", "{E7E010D2-1CE5-4877-ABA7-36EA8EC62118}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x64.ActiveCfg = Debug|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x64.Build.0 = Debug|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x86.ActiveCfg = Debug|x86 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Debug|x86.Build.0 = Debug|x86 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|Any CPU.Build.0 = Release|Any CPU {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x64.ActiveCfg = Release|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x64.Build.0 = Release|x64 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x86.ActiveCfg = Release|x86 {ADDC2C7F-C429-4772-A00C-0587B9DEC2EB}.Release|x86.Build.0 = Release|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x64.ActiveCfg = Debug|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x64.Build.0 = Debug|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x86.ActiveCfg = Debug|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Debug|x86.Build.0 = Debug|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|Any CPU.Build.0 = Release|Any CPU {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x64.ActiveCfg = Release|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x64.Build.0 = Release|x64 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x86.ActiveCfg = Release|x86 {E69ACAC0-16DB-4AB9-BB4A-03EC33538D1E}.Release|x86.Build.0 = Release|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|Any CPU.Build.0 = Debug|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x64.ActiveCfg = Debug|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x64.Build.0 = Debug|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x86.ActiveCfg = Debug|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Debug|x86.Build.0 = Debug|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|Any CPU.ActiveCfg = Release|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|Any CPU.Build.0 = Release|Any CPU {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x64.ActiveCfg = Release|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x64.Build.0 = Release|x64 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x86.ActiveCfg = Release|x86 {836424C9-8003-4C0F-84E1-2C17FE498648}.Release|x86.Build.0 = Release|x86 {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|Any CPU.Build.0 = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|x64.ActiveCfg = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|x64.Build.0 = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|x86.ActiveCfg = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|x86.Build.0 = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|Any CPU.Build.0 = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|x64.ActiveCfg = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|x64.Build.0 = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|x86.ActiveCfg = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|x86.Build.0 = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|x64.ActiveCfg = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|x64.Build.0 = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|x86.ActiveCfg = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|x86.Build.0 = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|Any CPU.Build.0 = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|x64.ActiveCfg = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|x64.Build.0 = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|x86.ActiveCfg = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {222B89C5-FC73-4A1A-AF3C-8BEB9CEF8EB3} EndGlobalSection EndGlobal ================================================ FILE: Reinforced.Typings.Tests/BasicTypesResolvationTests.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using Reinforced.Typings.Ast.TypeNames; using Xunit; namespace Reinforced.Typings.Tests { public class BasicTypesResolvationTests { private readonly TypeResolver _tr; private readonly TypeNameEqualityComparer _comparer; private readonly ExportContext _context; private static readonly RtSimpleTypeName AnyType = new RtSimpleTypeName("any"); private static readonly RtSimpleTypeName NumberType = new RtSimpleTypeName("number"); private static readonly RtSimpleTypeName StringType = new RtSimpleTypeName("string"); private static readonly RtArrayType AnyArrayType = new RtArrayType(AnyType); public BasicTypesResolvationTests() { _context = new ExportContext(new[] { Assembly.GetExecutingAssembly() }) { TargetDirectory = "targetDir/" }; var exporter = new TsExporter(_context); exporter.Initialize(); _tr = _context.CreateExportedFile().TypeResolver; _comparer = new TypeNameEqualityComparer(); } [Fact] public void NumericsToNumber() { Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(int)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(uint)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(long)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(ulong)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(short)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(ushort)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(byte)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(double)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(float)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(decimal)), _comparer); } [Fact] public void StringsAndCharsToString() { Assert.Equal(StringType, _tr.ResolveTypeName(typeof(string)), _comparer); Assert.Equal(StringType, _tr.ResolveTypeName(typeof(char)), _comparer); } [Fact] public void NullableNumbersToNumber() { Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(int?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(uint?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(long?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(ulong?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(short?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(ushort?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(byte?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(double?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(float?)), _comparer); Assert.Equal(NumberType, _tr.ResolveTypeName(typeof(decimal?)), _comparer); } [Fact] public void VoidToVoid() { Assert.Equal(new RtSimpleTypeName("void"), _tr.ResolveTypeName(typeof(void)), _comparer); } [Fact] public void ObjectToAny() { Assert.Equal(AnyType, _tr.ResolveTypeName(typeof(object)), _comparer); } [Fact] public void NongenericCollectionsToAnyArray() { Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(IEnumerable)), _comparer); Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(IQueryable)), _comparer); Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(IList)), _comparer); Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(Stack)), _comparer); Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(Queue)), _comparer); Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(ArrayList)), _comparer); Assert.Equal(AnyArrayType, _tr.ResolveTypeName(typeof(CollectionBase)), _comparer); } [Fact] public void DictionaryToObject() { Assert.Equal(new RtDictionaryType(AnyType, AnyType), _tr.ResolveTypeName(typeof(IDictionary)), _comparer); Assert.True(_context.Warnings.Any(c => c.Code == 7)); _context.ClearWarnings(); Assert.Equal(new RtDictionaryType(AnyType, AnyType), _tr.ResolveTypeName(typeof(IDictionary)), _comparer); Assert.True(_context.Warnings.Any(c => c.Code == 7)); _context.ClearWarnings(); Assert.Equal(new RtDictionaryType(StringType, AnyType), _tr.ResolveTypeName(typeof(IDictionary)), _comparer); Assert.Equal(new RtDictionaryType(NumberType, AnyType), _tr.ResolveTypeName(typeof(IDictionary)), _comparer); Assert.Equal(new RtDictionaryType(AnyType, AnyType), _tr.ResolveTypeName(typeof(Dictionary)), _comparer); Assert.True(_context.Warnings.Any(c => c.Code == 7)); _context.ClearWarnings(); Assert.Equal(new RtDictionaryType(StringType, AnyType), _tr.ResolveTypeName(typeof(Dictionary)), _comparer); Assert.Equal(new RtDictionaryType(NumberType, AnyType), _tr.ResolveTypeName(typeof(Dictionary)), _comparer); } private void GenericCollectionsOfType(RtTypeName targetType) { Assert.Equal(targetType, _tr.ResolveTypeName(typeof(IEnumerable)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(IQueryable)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(IList)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(Stack)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(Queue)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(Collection)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(ICollection)), _comparer); Assert.Equal(targetType, _tr.ResolveTypeName(typeof(T[])), _comparer); } [Fact] public void CollectionsToCorrespondingArray() { var numArray = new RtArrayType(NumberType); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(numArray); GenericCollectionsOfType(new RtArrayType(StringType)); GenericCollectionsOfType(new RtArrayType(new RtSimpleTypeName("boolean"))); } [Fact] public void SystemTuplesToTsTuples() { for (int i = 1; i < 8; i++) { var expected = new RtTuple(); List args = new List(); for (int j = 0; j < i; j++) { expected.TupleTypes.Add(AnyType); args.Add(typeof(object)); } var correspondingTuple = Type.GetType("System.Tuple`" + i); var arrange = correspondingTuple.MakeGenericType(args.ToArray()); Assert.Equal(expected, _tr.ResolveTypeName(arrange), _comparer); } } } } ================================================ FILE: Reinforced.Typings.Tests/ClassicMultiFileResolvationTests.cs ================================================ using System; using System.IO; using System.Linq; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using Reinforced.Typings.Tests.Core; using Xunit; namespace Reinforced.Typings.Tests { public class ClassicMultiFileResolvationTests : RtExporterTestBase { private readonly TypeNameEqualityComparer _comparer = new TypeNameEqualityComparer(); protected ExportedFile Setup2Files(string filePath1, string filePath2, Action builder) { var setup = base.InitializeMultipleFiles(a => { builder(a); a.ExportAsInterface().ExportTo(filePath1); a.ExportAsInterface().ExportTo(filePath2); }); return setup.Exporter.Context.CreateExportedFile(Path.Combine(TargetDir, filePath1)); } [Fact] public void SimpleReferenceResolvationTestSingleDir() { var file = Setup2Files("File1.ts", "File2.ts", x => x.Global(a => a.UseModules(false))); var typeName = file.TypeResolver.ResolveTypeName(typeof(TestFluentAssembly.TwoInterfaces.IInterface2)); Assert.Equal(new RtSimpleTypeName("IInterface2") { Prefix = "TestFluentAssembly.TwoInterfaces" }, typeName, _comparer); Assert.Single(file.References.References); var rf = file.References.References.First(); Assert.Equal("File2.ts", rf.Path); } [Fact] public void SimpleModuleResolvationTestSingleDir() { var file = Setup2Files("File1.ts", "File2.ts", x => x.Global(a => a.UseModules())); //todo this fails in mono, the Prefix property of this below is "" - but Prefix of one below is null var typeName = file.TypeResolver.ResolveTypeName(typeof(TestFluentAssembly.TwoInterfaces.IInterface2)); Assert.Equal(new RtSimpleTypeName("IInterface2"), typeName, _comparer); Assert.Single(file.References.Imports); var rf = file.References.Imports.First(); Assert.Equal("./File2", rf.From); Assert.Equal("{ IInterface2 }", rf.Target); } [Fact] public void SimpleModuleWithNamespaceResolvationTestSingleDir() { var file = Setup2Files("File1.ts", "File2.ts", x => x.Global(a => a.UseModules(discardNamespaces: false))); var typeName = file.TypeResolver.ResolveTypeName(typeof(TestFluentAssembly.TwoInterfaces.IInterface2)); Assert.Equal(new RtSimpleTypeName("IInterface2") { Prefix = "File2.TestFluentAssembly.TwoInterfaces" }, typeName, _comparer); Assert.Single(file.References.Imports); var rf = file.References.Imports.First(); Assert.True(rf.IsWildcard); Assert.Equal("File2", rf.WildcardAlias); Assert.Equal("./File2", rf.From); Assert.Equal("* as File2", rf.Target); } [Fact] public void SimpleReferenceResolvationTestDifferentDirs() { var file = Setup2Files("File1.ts", "Another/File2.ts", x => x.Global(a => a.UseModules(false))); var typeName = file.TypeResolver.ResolveTypeName(typeof(TestFluentAssembly.TwoInterfaces.IInterface2)); Assert.Equal(new RtSimpleTypeName("IInterface2") { Prefix = "TestFluentAssembly.TwoInterfaces" }, typeName, _comparer); Assert.Single(file.References.References); var rf = file.References.References.First(); Assert.Equal("Another/File2.ts", rf.Path); } [Fact] public void SimpleModuleResolvationTestDifferentDirs() { var file = Setup2Files("File1.ts", "Another/File2.ts", x => x.Global(a => a.UseModules())); //todo this fails in mono, the Prefix property of this below is "" - but Prefix of one below is null var typeName = file.TypeResolver.ResolveTypeName(typeof(TestFluentAssembly.TwoInterfaces.IInterface2)); Assert.Equal(new RtSimpleTypeName("IInterface2"), typeName, _comparer); Assert.Single(file.References.Imports); var rf = file.References.Imports.First(); Assert.Equal("./Another/File2", rf.From); Assert.Equal("{ IInterface2 }", rf.Target); } } } ================================================ FILE: Reinforced.Typings.Tests/ConfigurationBuilderTestBase.cs ================================================ using System; using System.Reflection; using Reinforced.Typings.Fluent; using Reinforced.Typings.Tests.Core; namespace Reinforced.Typings.Tests { public abstract class ConfigurationBuilderTestBase { protected const string TargetDir = "targetDir"; protected const string Sample = "target.ts"; protected TestInitializationData InitializeSingleFile(Action configuration) { MockFileOperations mfo = new MockFileOperations(); ExportContext ec = new ExportContext(new Assembly[] { Assembly.GetExecutingAssembly(), typeof(TestFluentAssembly.TwoInterfaces.IInterface1).Assembly },mfo) { ConfigurationMethod = configuration, Hierarchical = false, TargetDirectory = TargetDir, TargetFile = Sample }; TsExporter te = new TsExporter(ec); te.Initialize(); return new TestInitializationData(mfo, te); } protected TestInitializationData InitializeMultipleFiles(Action configuration) { MockFileOperations mfo = new MockFileOperations(); ExportContext ec = new ExportContext(new Assembly[] { Assembly.GetExecutingAssembly(), typeof(TestFluentAssembly.TwoInterfaces.IInterface1).Assembly },mfo) { ConfigurationMethod = configuration, Hierarchical = true, TargetDirectory = TargetDir }; TsExporter te = new TsExporter(ec); te.Initialize(); return new TestInitializationData(mfo, te); } } public class TestInitializationData { public MockFileOperations Files { get; private set; } public TsExporter Exporter { get; private set; } public TestInitializationData(MockFileOperations files, TsExporter exporter) { Files = files; Exporter = exporter; } } } ================================================ FILE: Reinforced.Typings.Tests/Core/MockFileOperations.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.ReferencesInspection; using Reinforced.Typings.Visitors; using Reinforced.Typings.Visitors.TypeScript; using Reinforced.Typings.Visitors.Typings; namespace Reinforced.Typings.Tests.Core { public class MockFileOperations : IFilesOperations { public bool DeployCalled { get; private set; } public bool TempRegistryCleared { get; private set; } public ExportContext Context { get; set; } public Dictionary ExportedFiles { get; private set; } public MockFileOperations() { ExportedFiles = new Dictionary(); } public void DeployTempFiles() { DeployCalled = true; } public void ClearTempRegistry() { TempRegistryCleared = true; } public void Export(string fileName, ExportedFile file) { StringBuilder sb = new StringBuilder(); using (var sw = new StringWriter(sb)) { sw.NewLine = Context.Global.NewLine; ExportCore(sw, file); } ExportedFiles[fileName] = sb.ToString(); } protected virtual void ExportCore(TextWriter tw, ExportedFile file) { var visitor = Context.Global.VisitorType == null ? Context.Global.ExportPureTypings ? new TypingsExportVisitor(tw, Context) : new TypeScriptExportVisitor(tw, Context) : (TextExportingVisitor)Activator.CreateInstance(Context.Global.VisitorType, new object[] { tw, Context }); WriteWarning(tw); visitor.VisitFile(file); } private void WriteWarning(TextWriter tw) { if (Context.Global.WriteWarningComment) { tw.WriteLine("// This code was generated by a Reinforced.Typings tool. "); tw.WriteLine("// Changes to this file may cause incorrect behavior and will be lost if"); tw.WriteLine("// the code is regenerated."); tw.WriteLine(); } } } } ================================================ FILE: Reinforced.Typings.Tests/Core/RtExporterTestBase.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Fluent; using Reinforced.Typings.Tests.Tokenizing; using Xunit; namespace Reinforced.Typings.Tests.Core { public abstract class RtExporterTestBase : ConfigurationBuilderTestBase { protected string AssertConfiguration(Action configuration, string result, bool compareComments = false) { var data = InitializeSingleFile(configuration); var te = data.Exporter; var mfo = data.Files; te.Export(); Assert.True(mfo.DeployCalled); Assert.True(mfo.TempRegistryCleared); var actual = mfo.ExportedFiles[Sample]; //<--- variable to check in debugger Assert.True(actual.TokenizeCompare(result, compareComments)); //<--- best place to put breakpoint return actual; } protected string AssertConfiguration(Action configuration, string result, Action expAction, bool compareComments = false) { var data = InitializeSingleFile(configuration); var te = data.Exporter; var mfo = data.Files; te.Export(); expAction(te); Assert.True(mfo.DeployCalled); Assert.True(mfo.TempRegistryCleared); var actual = mfo.ExportedFiles[Sample]; //<--- variable to check in debugger Assert.True(actual.TokenizeCompare(result, compareComments)); //<--- best place to put breakpoint return actual; } protected void AssertConfiguration(Action configuration, Dictionary results, bool compareComments = false) { var data = InitializeMultipleFiles(configuration); var te = data.Exporter; var mfo = data.Files; te.Export(); Assert.True(mfo.DeployCalled); Assert.True(mfo.TempRegistryCleared); var exportedFiles = mfo.ExportedFiles; //<--- variable to check in debugger foreach (var mfoExportedFile in exportedFiles) { var generated = mfoExportedFile.Value; //<--- variable to check in debugger Assert.True(results.ContainsKey(mfoExportedFile.Key)); //<--- best place to put breakpoint var expected = results[mfoExportedFile.Key]; Assert.True(generated.TokenizeCompare(expected,compareComments)); } } } } ================================================ FILE: Reinforced.Typings.Tests/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Reinforced.Typings.Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Reinforced.Typings.Tests")] [assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("5d126898-7e5d-4967-8732-3fc8722f532e")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: Reinforced.Typings.Tests/Reinforced.Typings.Tests.Dev.csproj ================================================ net5.0 false Preview w:\Work\Reinforced\Typings\Reinforced.Typings\Reinforced.Typings.Tests\Reinforced.Typings.Tests.Dev.xml runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all ================================================ FILE: Reinforced.Typings.Tests/Reinforced.Typings.Tests.Dev.xml ================================================ Reinforced.Typings.Tests.Dev Initializes a new instance of the class. Some documentation for nested class Ctor comment Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to WriterWrapper (3rd argument) using TypeResolver if necessary Element code to be generated to output Resulting node Type resolver Example of implementation of custom reference processor Returns refiltered and reordered import directives that must appear in resulting file. Return null to remain references list untouched Set on initially computed imports File that is being exported currently Set of refiltered/reordered imports Returns refiltered and reordered reference directives that must appear in resulting file Return null to remain imports list untouched Set on initially computed references File that is being exported currently Set of refiltered/reordered references Simulate F# map C Value D Value E Value Some documentation for interface. Some documentation for interface property. Some documentation for interface method. Some documentation for class. Some documentation for constructor. Some documentation for property. Some documentation for method. Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to WriterWrapper (3rd argument) using TypeResolver if necessary Element code to be generated to output Resulting node Type resolver Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to WriterWrapper (3rd argument) using TypeResolver if necessary Element code to be generated to output Resulting node Type resolver Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to WriterWrapper (3rd argument) using TypeResolver if necessary Element code to be generated to output Resulting node Type resolver ================================================ FILE: Reinforced.Typings.Tests/Reinforced.Typings.Tests.NETCore.csproj ================================================ Debug AnyCPU {5D126898-7E5D-4967-8732-3FC8722F532E} Library Properties Reinforced.Typings.Tests Reinforced.Typings.Tests netstandard2.0;netstandard2.1;netcoreapp2.1;netcoreapp3.1;netcoreapp2.2 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 bin\Debug\Reinforced.Typings.Tests.XML pdbonly true bin\Release\ TRACE prompt 4 This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: Reinforced.Typings.Tests/Reinforced.Typings.Tests.csproj ================================================  Debug AnyCPU {5D126898-7E5D-4967-8732-3FC8722F532E} Library Properties Reinforced.Typings.Tests Reinforced.Typings.Tests v4.5 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 bin\Debug\Reinforced.Typings.Tests.XML pdbonly true bin\Release\ TRACE prompt 4 ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll True ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll True ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll True ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll True {006290E6-CC0D-4222-87F8-9E67469AD2C9} Reinforced.Typings.Cli {2A5CCD5C-E660-4088-8937-9632ABBBCDBB} Reinforced.Typings {e7e010d2-1ce5-4877-aba7-36ea8ec62118} TestFluentAssembly This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ADIXReadonlyDictionaryWorkaround.cs ================================================ using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Threading.Tasks; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { interface User { int Id { get; } string Name { get; } FSharpMap AccessRights { get; } FSharpMap> Privilegies { get; } } [Fact] public void ADIXReadonlyDictionaryWorkaround() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IUser { Id: number; Name: string; AccessRights: { [key:string]: number }; Privilegies: { [key:number]: { [key:string]: string } }; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.SubstituteGeneric(typeof(FSharpMap<,>), (t, tr) => { var args = t.GetGenericArguments(); return new RtDictionaryType(tr.ResolveTypeName(args[0]),tr.ResolveTypeName(args[1])); }); s.ExportAsInterface().WithAllProperties(); }, result); } } /// /// Simulate F# map /// class FSharpMap : IReadOnlyDictionary { public IEnumerator> GetEnumerator() { throw new System.NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public int Count { get; } public bool ContainsKey(T key) { throw new System.NotImplementedException(); } public bool TryGetValue(T key, out V value) { throw new System.NotImplementedException(); } public V this[T key] { get { throw new System.NotImplementedException(); } } public IEnumerable Keys { get; } public IEnumerable Values { get; } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.All.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Cli; using Reinforced.Typings.Fluent; using Reinforced.Typings.ReferencesInspection; using Reinforced.Typings.Tests.Core; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases : RtExporterTestBase { } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.AutoAsync.cs ================================================ using System.Threading.Tasks; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { class TestAsync { public async Task DoVoid() { } public async Task DoArgument() { return "aaa"; } } class TestAsync2 { public async Task DoVoid() { } public async Task DoArgument() { return "aaa"; } } interface ITestAsync { Task DoVoid(); Task DoArgument(); } interface ITestAsyncParameter { Task EvaluatePromise(Task taskParameter); } public partial class SpecificTestCases { [Fact] public void AutoAsyncWorks() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export class TestAsync { public async DoVoid() : Promise { } public async DoArgument() : Promise { return null; } } export interface ITestAsync2 { DoVoid() : Promise; DoArgument() : Promise; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().AutoAsync()); s.ExportAsClass().WithPublicMethods(); s.ExportAsInterface().WithPublicMethods(); }, result); } [Fact] public void AutoAsyncInterfaceWorks() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestAsync { DoVoid() : Promise; DoArgument() : Promise; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().AutoAsync()); s.ExportAsInterface().WithPublicMethods(); }, result); } [Fact] public void NoAutoAsyncInterfaceWorks() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestAsync { DoVoid() : void; DoArgument() : string; } }"; AssertConfiguration(s => { s.ExportAsInterface().WithPublicMethods(); }, result); } [Fact] public void PromiseTaskInParamterIsMaintained() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestAsyncParameter { EvaluatePromise(taskParameter: Promise) : string; } }"; AssertConfiguration(s => { s.ExportAsInterface().WithPublicMethods(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.AutoOptional.cs ================================================ using System; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { interface OptionalTestInterface { DateTime? Date { get; } int? Number { get; } string String { get; } } class OptionalTestClass { public DateTime? Date { get; } public int? Number { get; } public string String { get; } } [Fact] public void AutoOptional() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IOptionalTestInterface { Date?: any; Number?: number; String: string; } export interface IOptionalTestClass { Date?: any; Number?: number; String: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().AutoOptionalProperties()); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.AutoOptionalWithCompilerNullable.cs ================================================ #if CUSTOM_FLAG_NULLABLE_AVAILABLE using System; using System.Collections.Generic; using Reinforced.Typings.Fluent; using Xunit; #nullable enable namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { public interface OptionalTestInterfaceNullableAttribute { DateTime? Date { get; } int Number { get; } public int[]? Numbers { get; } string? String { get; set; } public IList? SomeList { get; } } public class OptionalTestClassNullableAttribute { public DateTime? Date { get; } public int? Number { get; } public int[] Numbers { get; } public string String { get; } public IList SomeList { get; } } [Fact] public void AutoOptionalIfCompilerNullableAttribute() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IOptionalTestInterfaceNullableAttribute { Date?: any; Number: number; Numbers?: number[]; String?: string; SomeList?: number[]; } export interface IOptionalTestClassNullableAttribute { Date?: any; Number?: number; Numbers: number[]; String: string; SomeList: number[]; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().AutoOptionalProperties()); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties(); }, result); } public interface OptionalTestParameterInterfaceNullableAttribute { public int TransformSomeValue(int mode, string? data); public string TransformSomeValueNonNullParameter(int mode, string data); } [Fact] public void AutoOptionalOfParameterIfCompilerNullableAttribute() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IOptionalTestParameterInterfaceNullableAttribute { TransformSomeValue(mode: number, data?: string) : number; TransformSomeValueNonNullParameter(mode: number, data: string) : string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().AutoOptionalProperties()); s.ExportAsInterface().WithPublicMethods(); }, result); } } } #endif ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ClassCodeGenerators.cs ================================================ using System; using System.CodeDom; using System.Text; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public class CodeGeneratedClass { public void DoSomething() { } public string GetName(int arg) { return string.Empty; } } public class FunClassCodeGenerator : ClassCodeGenerator { public override RtClass GenerateNode(Type element, RtClass result, TypeResolver resolver) { // obtain current namespace var ns = this.Context.Location.CurrentNamespace; var r = base.GenerateNode(element, result, resolver); foreach (var rMember in r.Members) { var m = rMember as RtFunction; if (m != null) { m.AccessModifier = null; ns.CompilationUnits.Add(m); } } // return null instead of result to // suppress writing AST of original class // to resulting file return null; } } public class AdditionalEnumGenerator : EnumGenerator { public override RtEnum GenerateNode(Type element, RtEnum result, TypeResolver resolver) { var resultEnum = base.GenerateNode(element, result, resolver); if (Context.Location.CurrentNamespace!=null) { Context.Location.CurrentNamespace.CompilationUnits.Add(resultEnum); StringBuilder enumdescriptor = new StringBuilder(); enumdescriptor.AppendLine(); enumdescriptor.AppendLine($"const {resultEnum.EnumName} = new Map(["); bool first = true; foreach (var resultEnumValue in resultEnum.Values) { if (!first) enumdescriptor.AppendLine(","); first = false; var enumDescription = resultEnumValue.EnumValueName.ToUpper(); //<- here you get your desired enum description string somehow enumdescriptor.Append($"[{resultEnum.EnumName}.{resultEnumValue.EnumValueName},'{enumDescription}']"); } enumdescriptor.AppendLine("]);"); Context.Location.CurrentNamespace.CompilationUnits.Add(new RtRaw(enumdescriptor.ToString())); } return null; } } public partial class SpecificTestCases { [Fact] public void ClassCodeGenerators() { const string result = @" DoSomething() : void { } GetName(arg: number) : string { return null; } enum SomeEnum { One = 0, Two = 1 } const SomeEnum = new Map([ [SomeEnum.One,'ONE'], [SomeEnum.Two,'TWO']]); "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsClass() .WithPublicMethods() .WithCodeGenerator() .DontIncludeToNamespace(); s.ExportAsEnum().WithCodeGenerator().DontIncludeToNamespace(); ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ConstantProperties.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { enum ExportedEnum { One = 1 } enum NotExportedEnum { Two = 2 } class ConstantTestA { public const string ConstantString = "a"; public static string StaticString = "b"; public static int StaticNumber = 42; public const int ConstantNumber = 42; public const ExportedEnum ConstExEnum = ExportedEnum.One; public static ExportedEnum StaticExEnum = ExportedEnum.One; public const NotExportedEnum ConstNotExEnum = NotExportedEnum.Two; public static NotExportedEnum StaticNotExEnum = NotExportedEnum.Two; } class ConstantTestB { public static string StaticString = "b"; public object MyObject { get; set; } } class ConstantTestC { public const string WillBeInitialized = "a"; public static string WillNotBeInitialized = "b"; } public partial class SpecificTestCases { [Fact] public void ConstantProperties() { // NB this test fails on Mono because the Members property of RtClass does not // order the tokens in the same order as the CLR on Windows (ie it's CLR-specific, relying on a certain order) // (Similar to the way that the order of attributes in C# code is CLR-dependent and shouldn't be relied on) const string result = @" module Test { export enum ExportedEnum { One = 1 } export class ConstantTestA { public static ConstantNumber: number = 42; public static ConstantString: string = `a`; public static ConstExEnum: Test.ExportedEnum = Test.ExportedEnum.One; public static ConstNotExEnum: number = 2; public static StaticExEnum: Test.ExportedEnum = Test.ExportedEnum.One; public static StaticNotExEnum: number = 2; public static StaticNumber: number = 42; public static StaticString: string = `b`; } export class ConstantTestB { public MyObject: any = { a: 10, b: 5 }; public static StaticString: string = 'Hello, I\'m string that originally was \'b\''; } export class ConstantTestC { public static WillBeInitialized: string = `a`; public static WillNotBeInitialized: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsEnum().OverrideNamespace("Test"); s.ExportAsClass() .WithAllFields() .WithAllProperties().OverrideNamespace("Test"); s.ExportAsClass() .OverrideNamespace("Test") .WithProperty(x => x.MyObject, x => x.InitializeWith((m, tr, v) => "{ a: 10, b: 5 }")) .WithField("StaticString", x => x.InitializeWith((m, tr, v) => $"'Hello, I\\'m string that originally was \\'{v}\\''")); s.ExportAsClass() .WithPublicFields() .OverrideNamespace("Test") .WithField("WillNotBeInitialized", c => c.Constant(false)); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.Constructor.cs ================================================ using Reinforced.Typings.Ast; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { class ClassWithDefaultConstructor { } class ClassWithDefaultConstructorWithBody { } class ClassWithParametersConstructor { /// Initializes a new instance of the class. public ClassWithParametersConstructor(int x, string y, bool z) { } } [Fact] public void GenerateConstructors() { const string result = @" export class ClassWithDefaultConstructor { constructor () { } } export class ClassWithDefaultConstructorWithBody { constructor () { this.invokeSomeMethod(); } } export class ClassWithParametersConstructor { constructor (x: number, y: string, z: boolean) { this.x = x; this.y = y; this.z = z; } } "; const string resultDts = @" declare class ClassWithDefaultConstructor { constructor (); } declare class ClassWithDefaultConstructorWithBody { constructor (); } declare class ClassWithParametersConstructor { constructor (x: number, y: string, z: boolean); } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules().ReorderMembers()); s.ExportAsClass() .WithPublicProperties() .WithPublicMethods() .WithConstructor() ; s.ExportAsClass() .WithPublicProperties() .WithPublicMethods() .WithConstructor(new RtRaw("this.invokeSomeMethod();")) ; s.ExportAsClass() .WithPublicProperties() .WithPublicMethods() .WithConstructor(new RtRaw("this.x = x; this.y = y; this.z = z;")) ; }, result, compareComments: true); AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules().ReorderMembers().ExportPureTypings()); s.ExportAsClass() .WithPublicProperties() .WithPublicMethods() .WithConstructor() ; s.ExportAsClass() .WithPublicProperties() .WithPublicMethods() .WithConstructor(new RtRaw("this.invokeSomeMethod();")) ; s.ExportAsClass() .WithPublicProperties() .WithPublicMethods() .WithConstructor(new RtRaw("this.x = x; this.y = y; this.z = z;")) ; }, resultDts, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.CrozinSubstitutions.cs ================================================ using System; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { #region Substitutions public class CrozinSubstitutionTest { public Guid GuidProperty { get; set; } public DateTime TimeProperty { get; set; } } public class CrozinLocalSubstitutionTest { public Guid OneMoreGuidProperty { get; set; } public DateTime OneMoreTimeProperty { get; set; } } #endregion [Fact] public void CrozinSubstitutions() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ICrozinSubstitutionTest { GuidProperty: string; TimeProperty: any; } export interface ICrozinLocalSubstitutionTest { OneMoreGuidProperty: string; OneMoreTimeProperty: Date; } }"; AssertConfiguration(s => { s.Global(x => x.DontWriteWarningComment().ReorderMembers()); s.Substitute(typeof(Guid), new RtSimpleTypeName("string")); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface() .WithPublicProperties() .Substitute(typeof(DateTime), new RtSimpleTypeName("Date")); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.DDanteInheritanceBug.cs ================================================ using System; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { #region DDante case public abstract class PolluxEntity { public Key EntityId { get; set; } public DateTime CreatedOn { get; set; } public DateTime? ModifiedOn { get; set; } public PolluxEntity() { this.CreatedOn = DateTime.Now; } } public class ContactData : PolluxEntity { public string Phone { get; set; } public string AlternatePhone { get; set; } public bool PhoneConfirmed { get; set; } public string Email { get; set; } public string AlternateEmail { get; set; } public bool EmailConfirmed { get; set; } public virtual string OwnerId { get; set; } public ContactData() { } } public class OtherData : PolluxEntity { public string Something { get; set; } } #endregion [Fact] public void DDanteInheritanceBug() { const string result = @" module Pollux.Models { export interface IPolluxEntity { CreatedOn: any; EntityId: Key; ModifiedOn?: any; } export interface IContactData extends Pollux.Models.IPolluxEntity { AlternateEmail: string; AlternatePhone: string; Email: string; EmailConfirmed: boolean; OwnerId: string; Phone: string; PhoneConfirmed: boolean; } export interface IOtherData extends Pollux.Models.IPolluxEntity { Something: string; } }"; AssertConfiguration(config => { config.Global(a => a.DontWriteWarningComment().ReorderMembers().AutoOptionalProperties()); var polluxBase = typeof(PolluxEntity<>); var types = new[] { polluxBase, typeof(ContactData), typeof(OtherData<>) }; // stripped to fit the test config.ExportAsInterfaces(types, _icb => { _icb.OverrideNamespace("Pollux.Models") .WithPublicProperties(); }); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.DGoncharovGenericsCase.cs ================================================ using System.Collections.Generic; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { #region DGoncharovGenericsTestCase public class SelectListItem { public string Text { get; set; } public string Value { get; set; } } public class TypedBasicResult { public int Status { get; set; } public string Message { get; set; } public T Data { get; set; } } public class RequestHandler { public TypedBasicResult> DoRequest() { return null; } } #endregion [Fact] public void DGoncharovGenericsCase() { const string result = @" export interface ITypedBasicResult { Data: T; Message: string; Status: number; } export interface ISelectListItem { Text: string; Value: string; } export class RequestHandler { public DoRequest() : ITypedBasicResult { return null; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules().ReorderMembers()); s.ExportAsInterfaces(new[] {typeof(TypedBasicResult<>)}, x => x.WithPublicProperties()); s.ExportAsInterface().WithPublicProperties(); s.ExportAsClass().WithPublicMethods(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.DaggmanoAutoIBug.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void DaggmanoAutoIBug() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IInternalUserDaggmano { Name: string; } export interface IExternalUserDaggmano { Name: string; } export interface IAlreadyContainsI { Name: string; } export interface IDoesntContainI { Name: string; } export class DoNotNeedIAtAll { public Name: string; } export class ICannotBeRemovedHere { public Name: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties(); s.ExportAsClass().WithPublicProperties(); s.ExportAsClass().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.DecoratorsTest.cs ================================================ using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { #region Decorators public class ClassWithMethods { public string String { get; set; } public int Int { get; set; } [TsDecorator("b()")] public void DoSomethinig() { } } #endregion [Fact] public void DecoratorsTest() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { @sealed export class ClassWithMethods { @bind public Int: number; @bind public String: string; @a() @b() public DoSomethinig() : void { } } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsClass() .WithPublicProperties(a => a.Decorator("bind")) .WithMethod(c => c.DoSomethinig(), c => c.Decorator("a()", -1)) .Decorator("sealed") ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.DocumentationForNestedTypes.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { /// /// Some documentation for nested class /// public class SomeReallyNestedClass { /// Ctor comment public SomeReallyNestedClass(int x) { } } [Fact] public void DocumentationForNestedTypes() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { /** Some documentation for nested class */ export class SomeReallyNestedClass { /** Ctor comment */ constructor (x: number) { } } } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().GenerateDocumentation()); s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsClass() .WithPublicProperties() .WithConstructor(); }, result, exp => { var doc = exp.Context.Documentation.GetDocumentationMember(typeof(SomeReallyNestedClass)); Assert.NotNull(doc); }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.DtsNoDeclareEnumWithoutAmbientScope.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Enum.Test { public enum Version { Current = 1 } } namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void DtsNoDeclareEnumWithoutAmbientScope() { const string result = @" declare module Enum.Test { export const enum Version { Current = 1 } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules(false, false) .ExportPureTypings(true)); s.ExportAsEnum().Const(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.EnumKeyedDictionary.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void EnumKeyedDictionary() { const string result = @" export enum SomeEnum { One = 0, Two = 1 } export interface IParametrizedGenericsInterface { Bag: { [key in SomeEnum]: string }; Bag2: { [key:string]: SomeEnum }[]; Bag3: { [key in SomeEnum]: SomeEnum }[][]; Bag4: { [key in SomeEnum]: { [key:string]: SomeEnum[][] } }; }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules()); s.ExportAsEnum(); s.ExportAsInterfaces( new[] {typeof(IParametrizedGenericsInterface)}, x => x.WithPublicProperties().WithPublicMethods()); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.EnumStringInitializerIgnoreManyValues.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { enum EnumToIgnoreSomeValues { Value1, Value2, Value3 } [Fact] public void EnumMultipleIgnoreValuesShouldPass() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export enum EnumToIgnoreSomeValues { Value3 = ""Value3"" } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsEnum() .Value(EnumToIgnoreSomeValues.Value1, d => d.Ignore()) .Value(EnumToIgnoreSomeValues.Value2, d => d.Ignore()) .UseString(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.EnumStringInitializers.cs ================================================ using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { enum SomeInitializerEnum { Value1, Value2, [TsValue(Initializer = "Three")] Value3 } [Fact] public void EnumStringInitializers() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export enum SomeInitializerEnum { Value1 = ""One"", Value2 = ""Two"", Value3 = ""Three"" } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsEnum() .Value(SomeInitializerEnum.Value1, d => d.Initializer("One")) .Value(SomeInitializerEnum.Value2, d => d.Initializer("Two")) .UseString(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ExportEnums.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public enum TestEnum1 { A, B, C } public enum TestEnum2 { /// /// C Value /// C, /// /// D Value /// D, /// /// E Value /// E } public partial class SpecificTestCases { [Fact] public void ExportEnums() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export enum TestEnum1 { A = 0, B = 1, C = 2 } export enum TestEnum2 { C = 0, D = 1, E = 2 } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsEnums(new[] { typeof(TestEnum1), typeof(TestEnum2) }); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ExportEnumsInDtsWithDeclareKeyword.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ExportEnumsInDtsWithDeclareKeyword() { const string result = @" declare module Reinforced.Typings.Tests.SpecificCases { export enum TestEnum1 { A = 0, B = 1, C = 2 } export enum TestEnum2 { C = 0, D = 1, E = 2 } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ExportPureTypings()); s.ExportAsEnums(new[] { typeof(TestEnum1), typeof(TestEnum2) }); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ExportOrderTest1.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ExportOrderTest1() { const string result1 = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestClass { String: string; Int: number; } export interface ITestInterface { String: string; Int: number; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties().Order(-1); }, result1); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ExportOrderTest2.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ExportOrderTest2() { const string result2 = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestInterface { Int: number; String: string; } export interface ITestClass { String: string; Int: number; } export class TestClass2 { public Int: number; public String: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface().WithPublicProperties().WithProperty(c=>c.String).Order(1); s.ExportAsInterface().WithPublicProperties(); s.ExportAsClass().WithPublicProperties().WithProperty(c => c.Int).Order(-1); }, result2); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.FQNs.cs ================================================ using System.Linq; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { namespace FqnTest.Ns1 { public class FqnClass1 { public int AnIntegerPropNs1 { get; set; } public string AStringPropNs1 { get; set; } } } namespace FqnTest.Ns2 { using FqnTest.Ns1; public class FqnClass2 : FqnClass1 { public int AnIntegerPropNs2 { get; set; } public string AStringPropNs2 { get; set; } } } namespace FqnTest.Ns3 { using FqnTest.Ns1; public class FqnClass3 { public int AnIntegerPropNs3 { get; set; } public string AStringPropNs3 { get; set; } public FqnClass1 AClass1PropNs3 { get; set; } } } public partial class SpecificTestCases { [Fact] public void FQNs() { const string result = @" export namespace Reinforced.Typings.Tests.SpecificCases.FqnTest.Ns1 { export class FqnClass1 { public AnIntegerPropNs1: number; public AStringPropNs1: string; } } export namespace Reinforced.Typings.Tests.SpecificCases.FqnTest.Ns2 { export class FqnClass2 extends Reinforced.Typings.Tests.SpecificCases.FqnTest.Ns1.FqnClass1 { public AnIntegerPropNs2: number; public AStringPropNs2: string; } } export namespace Reinforced.Typings.Tests.SpecificCases.FqnTest.Ns3 { export class FqnClass3 { public AClass1PropNs3: Reinforced.Typings.Tests.SpecificCases.FqnTest.Ns1.FqnClass1; public AnIntegerPropNs3: number; public AStringPropNs3: string; } } "; var types =new[] { typeof(FqnTest.Ns1.FqnClass1), typeof(FqnTest.Ns2.FqnClass2), typeof(FqnTest.Ns3.FqnClass3) }; AssertConfiguration(s => { s.ExportAsClasses(types.Where(x => x.IsClass), c => c.WithAllFields().WithAllMethods().WithAllProperties()); s.Global(c => c.UseModules(true, false).DontWriteWarningComment().ReorderMembers()); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.Fields.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { class TestExportWithFields { public string StringField; public int NumberField; } [Fact] public void FieldsWithBuilderConfig() { const string result = @" class TestExportWithFields { public StringField: string; public NumberField: number; } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsClass() .WithPublicFields((config) => { var fieldInfo = config.Member; }) .DontIncludeToNamespace() ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.FunctionWithParamInitialiser.cs ================================================ using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { private class MyFunctionTestClassWithParamInitializer { public string MyProperty { get; set; } public int MyNumber { get; set; } public string DoSomething(int a = 4) { return a == 4 ? "Hello World" : string.Empty; } } [Fact] public void FunctionWithParamInitializerAsInterface() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IMyFunctionTestClassWithParamInitializer { MyProperty: string; MyNumber: number; doSomething(a?: number) : string; } } "; AssertConfiguration(s => { s.Global(x=>x.DontWriteWarningComment()); s.ExportAsInterface() .WithPublicMethods(x=>x.CamelCase()) .WithPublicProperties(); }, result); } [Fact] public void FunctionWithParamInitializerAsClass() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export class MyFunctionTestClassWithParamInitializer { public MyProperty: string; public MyNumber: number; public doSomething(a: number = 4) : string { return null; } } } "; AssertConfiguration(s => { s.Global(x=>x.DontWriteWarningComment()); s.ExportAsClass() .WithPublicMethods(x=>x.CamelCase()) .WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.FunctionalNames.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void FunctionalNames() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestInterface { WoohooInt: number; WoohooString: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicProperties(c => c.OverrideName("Woohoo" + c.Member.Name)); s.ExportAsInterfaces(new List(), c => c.WithPublicProperties(x => x.OverrideName("_" + x.Member.Name))); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.GenericGuidDictionary.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { class A { public IDictionary GuidDictionary { get; set; } } [Fact] public void GenericGuidDictionary() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IA { GuidDictionary: { [key:string]: string }; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.Substitute(typeof(Guid), new RtSimpleTypeName("string")); s.ExportAsInterface().WithPublicProperties(); }, result, exp => { var warnings = exp.Context.Warnings.Count(); Assert.Equal(0, warnings); }); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.GenericSubstitutions.cs ================================================ using System.Linq; using System.Threading.Tasks; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { interface INotPromise { } class AsyncA { public async Task Do() { return string.Empty; } } class B { public INotPromise NotPromise { get; set; } public void MethodWithPromise(INotPromise p) { } } class C { public INotPromise NotPromise { get; set; } public void MethodWithPromise(INotPromise p) { } } class D { public INotPromise NotPromise { get; set; } public void MethodWithPromise(INotPromise p) { } } public partial class SpecificTestCases { [Fact] public void GenericSubstitutions() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IAsyncA { Do() : angular.Promise; } export interface IB { NotPromise: angular.Promise; MethodWithPromise(p: angular.Promise) : void; } export interface IC { NotPromise: angular.Promise; MethodWithPromise(p: angular.Promise) : void; } export interface ID { NotPromise: angular.Promise; MethodWithPromise(p: angular.Promise) : void; } } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.SubstituteGeneric(typeof(INotPromise<>), (t, tr) => new RtSimpleTypeName("angular.Promise", t.GetGenericArguments().Select(tr.ResolveTypeName).ToArray())); s.ExportAsInterface() .SubstituteGeneric(typeof(Task<>), (t, tr) => new RtSimpleTypeName("angular.Promise", t.GetGenericArguments().Select(tr.ResolveTypeName).ToArray())) .WithPublicProperties() .WithPublicMethods(); s.ExportAsInterface() .WithPublicProperties() .WithPublicMethods() ; s.ExportAsInterfaces(new[] { typeof(C<>) }, x => x.WithPublicProperties().WithPublicMethods()); s.ExportAsInterface>() .WithPublicProperties() .WithPublicMethods() ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.GenericsExport.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void GenericsExport() { const string result = @" export interface ISimpleGenericsInterface { Property: T; Method(param: T) : T; } export interface IParametrizedGenericsInterface { Bag: { [key:T]: T2 }; Bag2: { [key:T2]: T }[]; Bag3: { [key:T]: T }[][]; Bag4: { [key:T]: { [key:T2]: T[][] } }; } export interface IAttributeParametrization extends ISimpleGenericsInterface { } export interface IChildParametrized extends IParametrizedGenericsInterface { } export interface ITriforce { } export interface ITrimplementor1 extends ITriforce { } export interface ITrimplementor2 extends ITriforce { Property: TChild; } export interface ITrimplementor3 extends ITriforce { Property: [TMaster,TChild]; } export interface IParametrized { Bag: { [key:number]: string }; Bag2: { [key:string]: number }[]; Bag3: { [key:number]: number }[][]; Bag4: { [key:number]: { [key:string]: number[][] } }; }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules().ReorderMembers()); s.ExportAsInterfaces(new[] { typeof(ISimpleGenericsInterface<>), typeof(IParametrizedGenericsInterface<,>), typeof(IAttributeParametrization<>), typeof(IChildParametrized<>), typeof(ITriforce<,,>), typeof(ITrimplementor1<>), typeof(ITrimplementor2<,>), typeof(ITrimplementor3<,>), }, x => x.WithPublicProperties().WithPublicMethods()); s.ExportAsInterfaces(new[] {typeof(IParametrizedGenericsInterface)}, x => x.WithPublicProperties().WithPublicMethods().OverrideName("Parametrized")); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.GenericsExport2.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { class GenericModel { } public partial class SpecificTestCases { [Fact] public void GenericsExport2() { const string result = @" export class GenericModel { } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules()); s.ExportAsClasses(new[] { typeof(GenericModel<>) }, x => x.DontIncludeToNamespace().WithPublicProperties().WithPublicMethods()); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.GenericsExport3.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { class ExplicitGeneric { } class SomeOther { public ExplicitGeneric Prop { get; } public ExplicitGeneric Prop2 { get; } } public partial class SpecificTestCases { [Fact] public void GenericsExport3() { /* * Here we export type with materialized generics explicitly. So ExplicitGeneric becomes known type, but * generic definition ExpicitGeneric was exported differently so there are 2 different types */ const string result = @" export interface IExplicitGeneric { } export interface ISomeOther { Prop: IExplicitGeneric; Prop2: ICompletelyDifferentType; } export interface ICompletelyDifferentType { } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules()); s.ExportAsInterfaces(new[] { typeof(ExplicitGeneric), typeof(SomeOther), }, x => x.WithPublicProperties().WithPublicMethods()); s.ExportAsInterfaces(new [] {typeof(ExplicitGeneric<>)},d=>d.WithPublicProperties().OverrideName("CompletelyDifferentType")); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.HierarchyFlattening.cs ================================================ using System.Reflection; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public interface ITestFlatteningBase { string SomeProperty { get; } void DoSomething(); } public interface ITestFlatteningChild : ITestFlatteningBase { } public abstract class TestFlatteningBase { public string SomeProperty { get; set; } public abstract void DoSomething(); } public class TestFlatteningChild : TestFlatteningBase { public override void DoSomething() { } } public partial class SpecificTestCases { [Fact] public void HierarchyFlattening() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IA { SomeProperty: string; DoSomething() : void; } export interface IB { SomeProperty: string; DoSomething() : void; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface().FlattenHierarchy() .WithPublicProperties() .WithPublicMethods() .OverrideName("A"); s.ExportAsInterface().FlattenHierarchy() .WithPublicProperties() .WithPublicMethods() .OverrideName("B"); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.HierarchyFlattening2.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public class FlattenBase { public T1 Name { get; set; } public T2 Value { get; set; } public List Set { get; set; } } public interface IViewModel { string Name { get; } } public class FlattenChild1 : FlattenBase { } public class FlattenChild2 : FlattenBase { } public partial class SpecificTestCases { [Fact] public void HierarchyFlattening2() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IViewModel { Name: string; } export interface IFlattenChild1 { Name: number; Set: Reinforced.Typings.Tests.SpecificCases.IViewModel[]; Value: string; } export interface IFlattenChild2 { Name: number; Set: Reinforced.Typings.Tests.SpecificCases.IFlattenChild2[]; Value: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicProperties(); s.ExportAsInterface() .FlattenHierarchy() .WithPublicProperties(); s.ExportAsInterface() .FlattenHierarchy() .WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.HierarchyFlattening3.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public interface IFlattenBase { T1 Name { get; set; } T2 Value { get; set; } List Set { get; set; } } public interface IFlattenBase2 { int Id { get; set; } } public interface IViewModel2 { string Name { get; } } public interface IFlattenChild1 : IFlattenBase, IFlattenBase2 { } public interface IFlattenChild2 : IFlattenBase, IFlattenBase2 { } public partial class SpecificTestCases { [Fact] public void HierarchyFlattening3() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IViewModel { Name: string; } export interface IFlattenChild1 { Id: number; Name: number; Set: Reinforced.Typings.Tests.SpecificCases.IViewModel[]; Value: string; } export interface IFlattenChild2 { Id: number; Name: number; Set: Reinforced.Typings.Tests.SpecificCases.IFlattenChild2[]; Value: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicProperties(); s.ExportAsInterface() .FlattenHierarchy() .WithPublicProperties(); s.ExportAsInterface() .FlattenHierarchy() .WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.HierarchyFlattening4.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void HierarchyFlattening4() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IFlattenChild1 { Name_For_1: number; } export interface IFlattenChild2 { Name_For_2: number; } } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .FlattenHierarchy() .WithProperty(x => x.Name, x => x.OverrideName("Name_For_1")); s.ExportAsInterface() .FlattenHierarchy() .WithProperty(x => x.Name, x => x.OverrideName("Name_For_2")); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.InferTypeTest.cs ================================================ using System.Reflection; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void InferTypeTest() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestInterface { } export interface IInferringTestInterface { DateTime: Observable; Guid: Observable; Int: Observable; String: Observable; TestInterface: Observable; SomeMethod1(arg: Observable) : Observable; SomeMethod2(arg: Observable) : Observable; SomeMethod3(arg: Observable) : Observable; SomeMethod4(arg: Observable) : Observable; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface(); s.ExportAsInterface() .WithPublicProperties(x => x.InferType((m, t) => new RtSimpleTypeName("Observable", t.ResolveTypeName(((PropertyInfo)m).PropertyType)))) .WithProperty(x => x.Guid, x => x.InferType(_ => "Observable")) .WithProperty(x => x.Int, x => x.InferType(_ => new RtSimpleTypeName("Observable", new RtSimpleTypeName("number")))) .WithProperty(x => x.TestInterface, x => x.InferType((m, r) => new RtSimpleTypeName("Observable", r.ResolveTypeName(typeof(ITestInterface))))) .WithProperty(x => x.DateTime, x => x.InferType((m, r) => string.Format("Observable<{0}>", r.ResolveTypeName(((PropertyInfo)m).PropertyType)))) .WithProperty(x => x.String, x => x.InferType(_ => "Observable")) .WithMethod(x => x.SomeMethod1(Ts.Parameter(t => t.InferType(_ => "Observable"))), x => x.InferType(_ => "Observable")) .WithMethod(x => x.SomeMethod2(Ts.Parameter( t => t.InferType(_ => new RtSimpleTypeName("Observable", new RtSimpleTypeName("number"))))), x => x.InferType(_ => new RtSimpleTypeName("Observable", new RtSimpleTypeName("number")))) .WithMethod(x => x.SomeMethod3(Ts.Parameter(t => t.InferType((m, r) => new RtSimpleTypeName("Observable", r.ResolveTypeName(typeof(ITestInterface)))))), x => x.InferType((m, r) => new RtSimpleTypeName("Observable", r.ResolveTypeName(typeof(ITestInterface))))) .WithMethod(x => x.SomeMethod4(Ts.Parameter(t => t.InferType((m, r) => string.Format("Observable<{0}>", r.ResolveTypeName(m.ParameterType))))), x => x.InferType((m, r) => string.Format("Observable<{0}>", r.ResolveTypeName(m.ReturnType)))) ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.InheritDoc.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { /// /// Some documentation for interface. /// public interface ISomeInterfaceWithDocs { /// /// Some documentation for interface property. /// string InterfaceProp { get; set; } /// /// Some documentation for interface method. /// void InterfaceMethod(); } /// public interface ISomeInterfaceWithInheritDoc : ISomeInterfaceWithDocs { // TODO: Test with inheritdoc + cref, makes no sense without cref } /// public class SomeClassWithInterfaceInheritDoc : ISomeInterfaceWithDocs { /// public string InterfaceProp { get; set; } /// public void InterfaceMethod() { } } /// /// Some documentation for class. /// public class SomeClassWithDocs { /// /// Some documentation for constructor. /// public SomeClassWithDocs() { } /// /// Some documentation for property. /// public virtual string SomeProp { get; set; } /// /// Some documentation for method. /// public virtual void SomeMethod() { } } /// public class SomeClassWithInheritDoc : SomeClassWithDocs { /// public SomeClassWithInheritDoc() { } /// public override string SomeProp { get; set; } /// public override void SomeMethod() { } } /// public class SomeClassWithInheritDocCref { /// public SomeClassWithInheritDocCref() { } /// public virtual string AnotherProp { get; set; } /// public virtual void AnotherMethod() { } } public partial class SpecificTestCases { [Fact] public void InheritDocInterface() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { /** * @inheritdoc */ export interface ISomeInterfaceWithInheritDoc { } } "; AssertConfiguration( s => { s.Global(a => a.DontWriteWarningComment().GenerateDocumentation()); s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsInterface() .WithPublicProperties().WithPublicMethods(); }, result, exp => { var doc = exp.Context.Documentation.GetDocumentationMember(typeof(ISomeInterfaceWithInheritDoc)); Assert.NotNull(doc); }, compareComments: true); } [Fact] public void InheritDocInterfaceToClass() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { /** * @inheritdoc */ export class SomeClassWithInterfaceInheritDoc { /** * @inheritdoc */ public InterfaceProp: string; /** * @inheritdoc */ public InterfaceMethod() : void { } } } "; AssertConfiguration( s => { s.Global(a => a.DontWriteWarningComment().GenerateDocumentation()); s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsClass() .WithPublicProperties() .WithPublicMethods(); }, result, exp => { var doc = exp.Context.Documentation.GetDocumentationMember(typeof(SomeClassWithInterfaceInheritDoc)); Assert.NotNull(doc); }, compareComments: true); } [Fact] public void InheritDocClass() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { /** * @inheritdoc */ export class SomeClassWithInheritDoc { /** * @inheritdoc */ constructor () { } /** * @inheritdoc */ public SomeProp: string; /** * @inheritdoc */ public SomeMethod() : void { } } } "; AssertConfiguration( s => { s.Global(a => a.DontWriteWarningComment().GenerateDocumentation()); s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsClass() .WithConstructor() .WithPublicProperties() .WithPublicMethods(); }, result, exp => { var doc = exp.Context.Documentation.GetDocumentationMember(typeof(SomeClassWithInheritDoc)); Assert.NotNull(doc); }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.InlineFunctionImplementation.cs ================================================ using System; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void InlineFunctionImplementation() { string implementation1 = Guid.NewGuid().ToString() + ";"; string implementation2 = Guid.NewGuid().ToString() + ";"; string result = $@" module Reinforced.Typings.Tests.SpecificCases {{ export class ClassWithManyMethods {{ public DoSomethingElse() : void {{ {implementation1} }} public DoSomethingElseWithResult() : string {{ {implementation2} }} public DoSomethinig() : void {{ {implementation1} }} }} }}"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsClass() .WithPublicMethods(c => c.Implement(implementation1)) .WithMethod(c => c.DoSomethingElseWithResult(), c => c.Implement(implementation2)) ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.InvalidFlattenOrder.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Exceptions; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public class Flat1 { } public class Flat2 { } public class Flat3 { } public partial class SpecificTestCases { [Fact] public void InvalidFlattenOrder() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IFlat1 { } export interface IFlat2 { } export interface IFlat3 { } } "; Assert.Throws(() => { AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface() .WithPublicProperties() .FlattenHierarchy(); }, result); }); Assert.Throws(() => { AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface() .WithPublicMethods() .FlattenHierarchy(); }, result); }); Assert.Throws(() => { AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface() .WithPublicFields() .FlattenHierarchy(); }, result); }); AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterfaces(new[] {typeof(Flat1), typeof(Flat2), typeof(Flat3)}, x => x.FlattenHierarchy().WithPublicProperties()); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.JonsaCustomIndentationTest.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void JonsaCustomIndentationTest() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { #export interface ITestInterface #{ ##Int: number; ##String: string; #} }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().TabSymbol("#").ReorderMembers()); s.ExportAsInterface().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.JonsaEnumWithouNamespaceTest.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void JonsaEnumWithouNamespaceTest() { const string result = @" interface IJonsaModel { Enum: JonsaEnum; } enum JonsaEnum { Foo = 0, Bar = 1 }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface().WithPublicProperties().DontIncludeToNamespace(); s.ExportAsEnum().DontIncludeToNamespace(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.KpKozakIssueWithInheritance.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { //[TsInterface] public class ComponentProps { public T Model { get; set; } } //[TsInterface] public class AnotherComponentProps : ComponentProps { } //[TsInterface] public class TestComponentProps : ComponentProps { public int Number { get; set; } } //[TsInterface] public class TestComponentViewModel { } [Fact] public void KpKozakIssueWithInheritance() { Dictionary results = new Dictionary() { { "targetDir" + Path.DirectorySeparatorChar + "TestComponentViewModel.ts", @"export interface TestComponentViewModel { }" }, { "targetDir" + Path.DirectorySeparatorChar + "ComponentProps_1.ts", @"export interface ComponentProps { model: T; }" }, { "targetDir" + Path.DirectorySeparatorChar + "AnotherComponentProps.ts", @"import { TestComponentViewModel } from './TestComponentViewModel'; import { ComponentProps } from './ComponentProps_1'; export interface AnotherComponentProps extends ComponentProps { }" }, { "targetDir" + Path.DirectorySeparatorChar + "TestComponentProps.ts", @"import { TestComponentViewModel } from './TestComponentViewModel'; import { ComponentProps } from './ComponentProps_1'; export interface TestComponentProps extends ComponentProps { number: number; }" } }; var exportedTypes = new[] { typeof(TestComponentViewModel), typeof(ComponentProps<>), typeof(AnotherComponentProps), typeof(TestComponentProps) }; var componentViewModelType = typeof(TestComponentViewModel); AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().CamelCaseForProperties().UseModules().RootNamespace("TestProject")); foreach (var exportedType in exportedTypes) { s.ExportAsInterfaces(new[] { exportedType }, b => { b.AutoI(false); b.WithAllMethods(m => m.Ignore()) .WithAllProperties(); var fileName = exportedType.IsGenericType ? exportedType.Name.Substring(0, exportedType.Name.IndexOf('`')) : componentViewModelType.Name; b.ExportTo(exportedType.Name.Replace("`","_") + ".ts"); }); } }, results); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.LineAfterAnotherWay.cs ================================================ using System; using System.IO; using System.Linq; using Reinforced.Typings.Ast; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Reinforced.Typings.Visitors.TypeScript; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { class LineAfterVisitor : TypeScriptExportVisitor { public LineAfterVisitor(TextWriter writer, ExportContext exportContext) : base(writer, exportContext) { } public override void Visit(RtEnumValue node) { WriteLines(@" // Lick the belly! "); base.Visit(node); } public override void VisitFile(ExportedFile file) { base.VisitFile(file); var ns = file.Namespaces.FirstOrDefault(); if (ns != null) { WriteLines($@" export = {ns.Name}; "); } } } [Fact] public void LineAfterAnotherTest() { const string result = @"module Reinforced.Typings.Tests.SpecificCases { export enum TestEnum2 { // Lick the belly! /** C Value */ C = 0, // Lick the belly! /** D Value */ D = 1, // Lick the belly! /** E Value */ E = 2 } } export = Reinforced.Typings.Tests.SpecificCases; "; var str = AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().GenerateDocumentation().UseVisitor()); s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsEnum().WithCodeGenerator(); }, result); Assert.Equal(result,str); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.LineAfterTest.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { class LineAfterAddingGenerator : EnumGenerator { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtEnum GenerateNode(Type element, RtEnum result, TypeResolver resolver) { var r = base.GenerateNode(element, result, resolver); if (r == null) return null; foreach (var val in r.Values) { val.LineAfter = " "; } return r; } } [Fact] public void LineAfterTest() { const string result = @"module Reinforced.Typings.Tests.SpecificCases { export enum TestEnum2 { /** C Value */ C = 0, /** D Value */ D = 1, /** E Value */ E = 2 } } "; var str = AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().GenerateDocumentation()); s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsEnum().WithCodeGenerator(); }, result); Assert.Equal(result,str); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.NestedClassInheritance.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace TestA { public class TestParentClassA { public string Id { get; set; } public string Name { get; set; } } } namespace TestB { using TestA; public class SomeOtherClass { public class SomeDerivedClass : TestParentClassA { public int OtherId { get; set; } } } } namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void NestedClassInheritance() { const string result = @" module TestB { export interface ISomeDerivedClass extends TestB.ITestParentClassA { OtherId: number; } export interface ITestParentClassA { id: string; text: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicProperties(); s.ExportAsInterface() .WithProperty(c => c.Id, v => v.OverrideName("id")) .WithProperty(c => c.Name, v => v.OverrideName("text")) .OverrideNamespace("TestB"); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.NewForceNullable.cs ================================================ using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { #region New ForceNullable test public interface INewForceNullableTest { [TsProperty(ForceNullable = true)] int? NilInt { get; } int NotNilInt { get; } int? ForceNotNullableInt { get; } int ForceNullableInt { get; } } #endregion [Fact] public void NewForceNullable() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface INewForceNullableTest { ForceNotNullableInt: number; ForceNullableInt?: number; NilInt?: number; NotNilInt: number; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicProperties() .WithProperty(c => c.ForceNotNullableInt, c => c.ForceNullable(false)) .WithProperty(c => c.ForceNullableInt, c => c.ForceNullable()) ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.NewLineTest.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void NewLineTest_Default() { var newLine = Environment.NewLine; string result = $"module Reinforced.Typings.Tests.SpecificCases {{{newLine}export interface ITestInterface{newLine}{{{newLine}Int: number;{newLine}String: string;{newLine}}}{newLine}}}{newLine}"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().TabSymbol(string.Empty).ReorderMembers()); s.ExportAsInterface().WithPublicProperties(); }, result); } [Fact] public void NewLineTest_Explicit() { const string newLine = "\n"; string result = $"module Reinforced.Typings.Tests.SpecificCases {{{newLine}export interface ITestInterface{newLine}{{{newLine}Int: number;{newLine}String: string;{newLine}}}{newLine}}}{newLine}"; var actual = AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().TabSymbol(string.Empty).NewLine(newLine).ReorderMembers()); s.ExportAsInterface().WithPublicProperties(); }, result); Assert.Equal(result, actual); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.NvirthMultilineString.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { public class MyMultilineClass { public static string MyStaticProperty = @"My multiline string"; } [Fact] public void NvirthMultilineString() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export class MyMultilineClass { public static MyStaticProperty: string = `My multiline string`; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsClass().WithPublicFields().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.OverrideNamespaceWithModules.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace TypingsExample.Long.Namespace.Structure { class MyClass { public MyProperty Property { get; set; } } class MyProperty { public string Name { get; set; } } } namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void OverrideNamespaceWithModules() { const string result = @" export namespace server { export class MyClass { public Property: server.MyProperty; } export class MyProperty { public Name: string; } }"; var types = new[] { typeof(TypingsExample.Long.Namespace.Structure.MyClass), typeof(TypingsExample.Long.Namespace.Structure.MyProperty) }; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules(true, false)); s.ExportAsClasses( types, conf => conf .OverrideNamespace("server") .WithAllProperties() ); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.OverridenNamesNotCamelCased.cs ================================================ using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public class TestOverrides { [TsProperty(Name = "ID", ForceNullable = true)] public virtual int _id { get { return 0; } } [TsFunction(Name = "DO_DOMETHING")] public void DoSomething() { } public void AnotherMethod() { } public string AnotherProeprty { get; set; } } public partial class SpecificTestCases { [Fact] public void OverridenNamesNotCamelCased() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestOverrides { Another_Property: string; ID?: number; Another_Method() : void; DO_DOMETHING() : void; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().CamelCaseForMethods().CamelCaseForProperties().ReorderMembers()); s.ExportAsInterface() .WithPublicProperties() .WithPublicMethods() .WithMethod(x => x.AnotherMethod(), x => x.OverrideName("Another_Method")) .WithProperty(x => x.AnotherProeprty, x => x.OverrideName("Another_Property")) ; }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.PandaWoodCamelCase.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void PandaWoodCamelCase() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IPandaWoodCamelCaseTest { id: number; eta() : void; isoDate(date: any) : void; performRequest() : void; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().CamelCaseForMethods().CamelCaseForProperties().ReorderMembers()); s.ExportAsInterface().WithPublicProperties().WithPublicMethods(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.PandaWoodForceNullableTest.cs ================================================ using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { #region ForceNullable property public class PandaWoodForceNullableCase { [TsProperty(ForceNullable = true)] public string PandaWoodProperty { get; set; } } #endregion [Fact] public void PandaWoodForceNullableTest() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export class PandaWoodForceNullableCase { public PandaWoodProperty?: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsClass(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.Records.cs ================================================ using System.Threading.Tasks; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public record Person(string FirstName, string LastName); public partial class SpecificTestCases { [Fact] public void Records() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IPerson { FirstName: string; LastName: string; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesPart1.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ReferencesPart1() { /** * As we do not export any fields/methods/properties here - * imports must stay clean except explicitly specified references * * File1: * Reference to File3 appears as it is explicitly specified: .AddReference(typeof(SomeFluentReferencedType)) * Reference to jquery appears as it is explicitly specified via attribute * Imports does not appear as we are not using modules * Reference to File2 does not appear since we are not exporting any indirectly referenced members * Refernce to SomeFluentlyReferencedNotExported does not appear as it is not exported entirely */ const string file1 = @" /// /// module Reinforced.Typings.Tests.SpecificCases { export class SomeReferencingType { } }"; const string file2 = @" module Reinforced.Typings.Tests.SpecificCases { export class SomeIndirectlyReferencedClass { } }"; const string file3 = @" module Reinforced.Typings.Tests.SpecificCases { export class SomeFluentReferencedType { } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsClass() .AddReference(typeof(SomeFluentReferencedType)) .AddReference(typeof(SomeFluentlyReferencedNotExported)) .AddImport("* as React", "React") .ExportTo("Exported/File1.ts") .AddImport("sideeffects", "./sideeffects", true) ; s.ExportAsClass().ExportTo("Indirect/File2.ts"); s.ExportAsClass().ExportTo("Fluently/File3.ts"); }, new Dictionary { { Path.Combine(TargetDir, "Exported/File1.ts"), file1 }, { Path.Combine(TargetDir, "Indirect/File2.ts"), file2 }, { Path.Combine(TargetDir, "Fluently/File3.ts"), file3 } }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesPart2.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ReferencesPart2() { /** * File1: * Reference to File3 appears as it is explicitly specified: .AddReference(typeof(SomeFluentReferencedType)) * Reference to jquery appears as it is explicitly specified via attribute * Imports does not appear as we are not using modules * Reference to File2 appears as we are exporting method "Indirect" returning SomeIndirectlyReferencedClass * Refernce to SomeFluentlyReferencedNotExported does not appear as it is not exported entirely */ const string file1 = @" /// /// /// module Reinforced.Typings.Tests.SpecificCases { export class SomeReferencingType { public Indirect() : Reinforced.Typings.Tests.SpecificCases.SomeIndirectlyReferencedClass { return null; } } }"; const string file2 = @" module Reinforced.Typings.Tests.SpecificCases { export class SomeIndirectlyReferencedClass { } }"; const string file3 = @" module Reinforced.Typings.Tests.SpecificCases { export class SomeFluentReferencedType { } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsClass() .AddReference(typeof(SomeFluentReferencedType)) .AddReference(typeof(SomeFluentlyReferencedNotExported)) .AddImport("* as React", "React") .ExportTo("Exported/File1.ts") .AddImport("sideeffects", "./sideeffects", true) .WithPublicMethods() //<--- this line differs from references part 1 ; s.ExportAsClass().ExportTo("Indirect/File2.ts"); s.ExportAsClass().ExportTo("Fluently/File3.ts"); }, new Dictionary { { Path.Combine(TargetDir, "Exported/File1.ts"), file1 }, { Path.Combine(TargetDir, "Indirect/File2.ts"), file2 }, { Path.Combine(TargetDir, "Fluently/File3.ts"), file3 } }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesPart3.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ReferencesPart3() { /** * Here code significantly changed since we have switched to modules * File1: * Reference to File3 appears as import since we are using modules * Reference to jquery appears as it is explicitly specified via attribute * Import to jQuery appears as it has been explecitly specified via attribute * Import to React appears as it has been explicitly specified via fluent configuration * Required-import to sideeffects appears as it was explicitly specified in fluent configuration * * Reference to ../Indirect/File2 appears as we are exporting method "Indirect" returning SomeIndirectlyReferencedClass * * Refernce to SomeFluentlyReferencedNotExported does not appear as it is not exported entirely */ const string file1 = @" /// /// import * as 'react' from 'React'; import { SomeFluentReferencedType } from '../Fluently/File3'; import * as '$' from 'JQuery'; import sideeffects = require('./sideeffects'); import { SomeIndirectlyReferencedClass } from '../Indirect/File2'; export class SomeReferencingType { public Indirect() : SomeIndirectlyReferencedClass { return null; } }"; const string file2 = @" /// import * as 'react' from 'React'; export class SomeIndirectlyReferencedClass { }"; const string file3 = @" /// import * as 'react' from 'React'; export class SomeFluentReferencedType { }"; AssertConfiguration(s => { s.AddReference("../../bootstrap.d.ts"); s.AddImport("* as 'react'", "React"); s.Global(a => a.DontWriteWarningComment() .UseModules() //<--- this line differs from references part 2 ); s.ExportAsClass() .AddReference(typeof(SomeFluentReferencedType)) .AddReference(typeof(SomeFluentlyReferencedNotExported)) .AddImport("* as React", "React") .ExportTo("Exported/File1.ts") .AddImport("sideeffects", "./sideeffects", true) .WithPublicMethods() ; s.ExportAsClass().ExportTo("Indirect/File2.ts"); s.ExportAsClass().ExportTo("Fluently/File3.ts"); }, new Dictionary { { Path.Combine(TargetDir, "Exported/File1.ts"), file1 }, { Path.Combine(TargetDir, "Indirect/File2.ts"), file2 }, { Path.Combine(TargetDir, "Fluently/File3.ts"), file3 } }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesPart4.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ReferencesPart4() { /** * We have removed reference to React and require-import * Also we explicitly have added reference to Stuff.ts that exports other types * * File1: * Reference to jquery appears as it is explicitly specified via attribute * Import to jQuery appears as it has been explecitly specified via attribute * Import to React appears as it has been explicitly specified via fluent configuration * References to SomeIndirectlyReferencedClass and SomeFluentReferencedType does not appear since * we have explicitly mentioned containing file as import. * * Warning! This trick works only on RT exported types. If you already have predefined .ts file - it will not work * because RT does not know what types are being described there * * Refernce to SomeFluentlyReferencedNotExported does not appear as it is not exported entirely */ const string file1 = @" /// import * as Stuff from '../Stuff/Stuff'; import * as '$' from 'JQuery'; export class SomeReferencingType { public Indirect() : Stuff.SomeIndirectlyReferencedClass { return null; } }"; const string file2 = @" export class SomeIndirectlyReferencedClass { } export class SomeFluentReferencedType { }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules()); s.ExportAsClass() .AddReference(typeof(SomeFluentReferencedType)) .AddReference(typeof(SomeFluentlyReferencedNotExported)) .AddImport("* as Stuff", "../Stuff/Stuff") .ExportTo("Exported/File1.ts") .WithPublicMethods() ; s.ExportAsClass().ExportTo("Stuff/Stuff.ts"); s.ExportAsClass().ExportTo("Stuff/Stuff.ts"); }, new Dictionary { { Path.Combine(TargetDir, "Exported/File1.ts"), file1}, { Path.Combine(TargetDir, "Stuff/Stuff.ts"), file2} }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesPart5.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ReferencesPart5() { /** * How let's make some noise with discarding namespaces * * Import tu Stuff appeared as specified it explicitly * * SomeIndirectlyReferencedClass exported within its namespace as we are using modules without * discarding namespaces * * SomeFluentReferencedType is exported without namespace as we have explicitly specified it * * Also I've added nullable enum property just in case */ const string file1 = @" /// import * as Stuff from '../Stuff/Stuff'; import * as '$' from 'JQuery'; export namespace Reinforced.Typings.Tests.SpecificCases { export class AnothreReferencingType { public Property: Stuff.SomeFluentReferencedType; public Enum?: Stuff.SomeIndirectEnum; public Indirect() : Stuff.Reinforced.Typings.Tests.SpecificCases.SomeIndirectlyReferencedClass { return null; } } }"; const string file2 = @" export namespace Reinforced.Typings.Tests.SpecificCases { export class SomeIndirectlyReferencedClass { } } export class SomeFluentReferencedType { } export enum SomeIndirectEnum { One = 0, Two = 1, Three = 2 }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules(discardNamespaces: false)); s.ExportAsClass() .AddReference(typeof(SomeFluentReferencedType)) .AddReference(typeof(SomeFluentlyReferencedNotExported)) .AddImport("* as Stuff", "../Stuff/Stuff") .ExportTo("Exported/File1.ts") .WithPublicMethods() .WithPublicProperties() .WithProperty(c => c.Enum, c => c.ForceNullable()) ; s.ExportAsClass().ExportTo("Stuff/Stuff.ts"); s.ExportAsClass().DontIncludeToNamespace().ExportTo("Stuff/Stuff.ts"); s.ExportAsEnum().DontIncludeToNamespace().ExportTo("Stuff/Stuff.ts"); }, new Dictionary { { Path.Combine(TargetDir, "Exported/File1.ts"), file1}, { Path.Combine(TargetDir, "Stuff/Stuff.ts"), file2} }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesPart6ByDanielWest.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void ReferencesPart6ByDanielWest() { /** * Specific test case with equal folder names by Daniel West */ const string file1 = @" export namespace Reinforced.Typings.Tests.SpecificCases { export enum SomeEnum { One = 0, Two = 1 } }"; const string file2 = @" import * as Enum from '../../APIv2/Models/TimeAndAttendance/Enum'; export namespace Reinforced.Typings.Tests.SpecificCases { export class SomeViewModel { public Enum: Enum.Reinforced.Typings.Tests.SpecificCases.SomeEnum; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules(discardNamespaces: false)); s.ExportAsEnum().ExportTo("Areas/APIv2/Models/TimeAndAttendance/Enum.ts"); s.ExportAsClass().WithPublicProperties().ExportTo("Areas/Reporting/Models/Model.ts"); }, new Dictionary { { Path.Combine(TargetDir, "Areas/APIv2/Models/TimeAndAttendance/Enum.ts"), file1 }, { Path.Combine(TargetDir, "Areas/Reporting/Models/Model.ts"), file2 } }, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ReferencesProcessor.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.ReferencesInspection; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { /// /// Example of implementation of custom reference processor /// private class MyRefProcessor : ReferenceProcessorBase { /// /// Returns refiltered and reordered import directives that must appear in resulting file. /// Return null to remain references list untouched /// /// Set on initially computed imports /// File that is being exported currently /// Set of refiltered/reordered imports public override IEnumerable FilterImports(IEnumerable imports, ExportedFile file) { // here we also can return null to quickly reset references/imports list if (file.FileName.EndsWith("kendo.ts")) return imports; // modify imports only in meaningful file return FilterMainFileImports(imports); } private IEnumerable FilterMainFileImports(IEnumerable imports) { foreach (var rtImport in imports) { if (!string.IsNullOrEmpty(rtImport.From) && rtImport.From.Contains("./kendo")) { // let's... simply change import path rtImport.From = "../../vendor/kendo/kendo.core.ts"; } yield return rtImport; } } /// /// Returns refiltered and reordered reference directives that must appear in resulting file /// Return null to remain imports list untouched /// /// Set on initially computed references /// File that is being exported currently /// Set of refiltered/reordered references public override IEnumerable FilterReferences(IEnumerable references, ExportedFile file) { // same rules as for imports // keep in mind that references are ALWAYS being written // whereas imports are not being used until .UseModules set to true if (file.FileName.EndsWith("kendo.ts")) return references; return FilterMainFileReferences(references); } private IEnumerable FilterMainFileReferences(IEnumerable references) { // let's... add some references at the top yield return new RtReference() { Path = "some.dummy.reference.ts" }; foreach (var rtReference in references) { yield return rtReference; } } } interface KendoDataNode { } public class MyTreeNode : KendoDataNode { public int Id { get; set; } } [Fact] public void ReferencesProcessor() { const string file1 = @" /// import { kendo.data.Node } from '../../vendor/kendo/kendo.core.ts'; export interface IMyTreeNode extends kendo.data.Node { Id: number; }"; const string kendots = @" export interface kendo.data.Node { } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment() .UseModules() .ReorderMembers() .WithReferencesProcessor()); s.ExportAsInterface() .AutoI(false) .OverrideName("kendo.data.Node") .ExportTo("kendo.ts"); s.ExportAsInterface().WithPublicProperties().ExportTo("file1.ts"); } , new Dictionary { { Path.Combine(TargetDir, "file1.ts"), file1 }, { Path.Combine(TargetDir, "kendo.ts"), kendots }, }); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.RemarksDocs.cs ================================================ using System; using System.Threading.Tasks; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { /// /// dummy /// /// /// Class remark. /// public class SomeClassWithRemarks { /// /// dummy /// /// /// Ctor remark. /// public SomeClassWithRemarks() { } /// /// /// Property remark. /// public string ClassProp { get; set; } /// /// /// Method remark. /// public void Method() { } } [Fact] public void RemarksParsedFromDocs() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { /** dummy */ export class SomeClassWithRemarks { /** * @inheritdoc */ public ClassProp: string; /** * @inheritdoc */ public Method() : void { } } }"; AssertConfiguration( s => { s.TryLookupDocumentationForAssembly(typeof(SpecificTestCases).Assembly); s.ExportAsClass() .WithPublicProperties() .WithPublicMethods(); }, result, expAction => { // Currently the are just parsed into the DocumentationMember // but not used in the generated typings. Hence we use the action on // the ExportContext to perform the actual test. // To avoid surprises like empty docs are currently only valid // if there is a or tag. var type = typeof(SomeClassWithRemarks); var classDoc = expAction.Context.Documentation.GetDocumentationMember(type); Assert.NotNull(classDoc); Assert.Equal("Class remark.", classDoc.Remarks.Text); var memberDoc = expAction.Context.Documentation.GetDocumentationMember(type.GetProperty(nameof(SomeClassWithRemarks.ClassProp))); Assert.NotNull(memberDoc); Assert.Equal("Property remark.", memberDoc.Remarks.Text); var methodeDoc = expAction.Context.Documentation.GetDocumentationMember(type.GetMethod(nameof(SomeClassWithRemarks.Method))); Assert.NotNull(methodeDoc); Assert.Equal("Method remark.", methodeDoc.Remarks.Text); var ctorRemark = expAction.Context.Documentation.GetDocumentationMember(type.GetConstructor(Array.Empty())); Assert.NotNull(ctorRemark); Assert.Equal("Ctor remark.", ctorRemark.Remarks.Text); } ); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.RluitenConstEnums.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void RluitenConstEnums() { const string result = @" export const enum SomeEnum { One = 0, Two = 1 }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules()); s.ExportAsEnum().Const(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ThirdParty.cs ================================================ using System.Collections.Generic; using System.IO; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.ReferencesInspection; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { interface IGenericKendoDataNode { T GenericProperty1 { get; } } class GenericKendoNodeTest : IGenericKendoDataNode { public int Property { get; set; } public KendoDataNode Parent { get; set; } public string GenericProperty1 { get; } } class GenericKendoNodeTest2 : IGenericKendoDataNode { public TN GenericProperty1 { get; } } [Fact] public void ThirdPartyTests() { const string file1 = @" import { kendo.data.Node } from '../vendor/kendo.core.ts'; import { kendo.data.GenericNode } from '../vendor/kendo.core.ts'; export interface IMyTreeNode extends kendo.data.Node { Id: number; } export interface IGenericKendoNodeTest extends kendo.data.Node { GenericProperty1: string; Parent: kendo.data.Node; Property: number; } export interface IGenericKendoNodeTest2 extends kendo.data.Node { GenericProperty1: TN; } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment() .UseModules() .ReorderMembers()); s.ExportAsThirdParty().WithName("kendo.data.Node") .Imports(new RtImport() { From = "../vendor/kendo.core.ts", Target = "{ kendo.data.Node }" }); s.ExportAsThirdParty(new[] { typeof(IGenericKendoDataNode<>) }, d => d.WithName("kendo.data.Node") .Imports(new RtImport() { From = "../vendor/kendo.core.ts", Target = "{ kendo.data.GenericNode }" })); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterface().WithPublicProperties(); s.ExportAsInterfaces(new[] { typeof(GenericKendoNodeTest2<>) }, d => d.WithPublicProperties()); }, file1); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.ThirdPartyWithBaseClass.cs ================================================ using System; using System.Collections.Generic; using System.IO; using Reinforced.Typings.Ast.Dependency; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.ReferencesInspection; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { class ThirdPartyBaseClass { public string SomeProperty { get; set; } } class ExportedClass : ThirdPartyBaseClass { public int Property { get; set; } public string GenericProperty1 { get; set; } } [Fact] public void ExportAsInterfaceWithThirdPartyBaseClass() { const string file1 = @"import { IThirdPartyBaseInterface } from 'third-party'; export interface IExportedClass extends IThirdPartyBaseInterface { GenericProperty1: string; Property: number; } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment() .UseModules() .ReorderMembers()); s.ExportAsThirdParty() .WithName("IThirdPartyBaseInterface") .Imports(new RtImport() { From = "third-party", Target = "{ IThirdPartyBaseInterface }" }); s.ExportAsInterface().WithPublicProperties(); }, file1); } [Fact] public void ExportAsClassWithThirdPartyBaseClass() { const string file1 = @"import { ThirdPartyBaseClass } from 'third-party'; export class ExportedClass extends ThirdPartyBaseClass { public GenericProperty1: string; public Property: number; } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment() .UseModules() .ReorderMembers()); s.ExportAsThirdParty() .WithName("ThirdPartyBaseClass") .Imports(new RtImport() { From = "third-party", Target = "{ ThirdPartyBaseClass }" }); s.ExportAsClass().WithPublicProperties(); }, file1); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.TsFunctionWorks.cs ================================================ using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void TsFunctionWorks() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IMyFunctionTestClass { MyNumber: number; MyProperty: string; doSomething1(a: number) : string; } }"; AssertConfiguration(s => { s.Global(x=>x.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicMethods(x=>x.CamelCase()) .WithPublicProperties(); }, result); } } #region vmandic test with possibly not working TsProperty public class MyFunctionTestClass { public string MyProperty { get; set; } public int MyNumber { get; set; } [TestFunction] public string DoSomething(int a) { return string.Empty; } } public class TestFunctionAttribute : TsFunctionAttribute { public TestFunctionAttribute() { CodeGeneratorType = typeof(TestFunctionGenerator); } } public class TestFunctionGenerator : MethodCodeGenerator { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtFunction GenerateNode(MethodInfo element, RtFunction result, TypeResolver resolver) { var b = base.GenerateNode(element, result, resolver); if (b == null) return null; result.Identifier.IdentifierName = result.Identifier.IdentifierName + "1"; return b; } } #endregion } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.TsFunctionWorksWithEnum.cs ================================================ using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void TsFunctionWorksWithEnum() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IMyFunctionWithEnumTestClass { MyEnum: TestEnum; MyNumber: number; MyProperty: string; doSomething1(a: number) : string; doSomethingForEnum1(a: TestEnum) : TestEnum; doSomethingForEnumWithDefault1(a?: TestEnum) : TestEnum; } } enum TestEnum { One = 0 } "; AssertConfiguration(s => { s.Global(x => x.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface() .WithPublicMethods(x => x.CamelCase()) .WithPublicProperties(); s.ExportAsEnum() .DontIncludeToNamespace(); }, result); } } #region vmandic test with possibly not working TsProperty public class MyFunctionWithEnumTestClass { public string MyProperty { get; set; } public int MyNumber { get; set; } public TestEnum MyEnum { get; set; } [TestFunction] public string DoSomething(int a) { return string.Empty; } [TestFunction] public TestEnum DoSomethingForEnum(TestEnum a) { return MyEnum; } [TestFunction] public TestEnum DoSomethingForEnumWithDefault(TestEnum a = TestEnum.One) { this.MyEnum = a; return MyEnum; } } public enum TestEnum { One } public class TestFunctionWithEnumAttribute : TsFunctionAttribute { public TestFunctionWithEnumAttribute() { CodeGeneratorType = typeof(TestFunctionWithEnumAttribute); } } public class TestFunctionWithEnumGenerator : MethodCodeGenerator { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtFunction GenerateNode(MethodInfo element, RtFunction result, TypeResolver resolver) { var b = base.GenerateNode(element, result, resolver); if (b == null) return null; result.Identifier.IdentifierName = result.Identifier.IdentifierName + "1"; return b; } } #endregion } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.TsPropertyWorks.cs ================================================ using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.Generators; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void TsPropertyWorks() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IMyPropertyTestClass { myNumber: number; MyNumber: number; myProperty: string; } }"; AssertConfiguration(s => { s.Global(x=>x.DontWriteWarningComment().ReorderMembers()); s.ExportAsInterface().WithPublicProperties(); }, result); } } #region vmandic test with possibly not working TsProperty public class MyPropertyTestClass { [TsProperty(ShouldBeCamelCased = true)] public string MyProperty { get; set; } [TestProperty] public int MyNumber { get; set; } } public class TestPropertyAttribute : TsPropertyAttribute { public TestPropertyAttribute() { this.ShouldBeCamelCased = true; this.CodeGeneratorType = typeof(LegacyPropertyDuplicator); } } public class LegacyPropertyDuplicator : PropertyCodeGenerator { /// /// Main code generator method. This method should write corresponding TypeScript code for element (1st argument) to /// WriterWrapper (3rd argument) using TypeResolver if necessary /// /// Element code to be generated to output /// Resulting node /// Type resolver public override RtField GenerateNode(MemberInfo element, RtField result, TypeResolver resolver) { var b = base.GenerateNode(element, result, resolver); if (b == null) return null; var pascalCaseName = b.Identifier.IdentifierName.Substring(0, 1).ToUpperInvariant() + b.Identifier.IdentifierName.Substring(1); var newField = new RtField() { AccessModifier = b.AccessModifier, Identifier = new RtIdentifier(pascalCaseName), InitializationExpression = b.InitializationExpression, IsStatic = b.IsStatic, Documentation = b.Documentation, Order = b.Order, Type = b.Type }; if (Context.Location.CurrentClass != null) { Context.Location.CurrentClass.Members.Add(newField); } if (Context.Location.CurrentInterface != null) { Context.Location.CurrentInterface.Members.Add(newField); } return b; } } #endregion } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases.WeirdInheritanceCase.cs ================================================ using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void WeirdInheritanceCase() { const string result = @" export interface IBaseClass { Property: string; DoSomething() : void; } /** * @todo Automatically implemented from IBaseClass */ export class DerivedClass implements IBaseClass { public Property: string; public DoSomething() : void { } public GetName() : string { return null; } } "; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment().UseModules().ReorderMembers()); s.ExportAsInterface().WithPublicProperties().WithPublicMethods(); s.ExportAsClass().WithPublicProperties().WithPublicMethods(); }, result, compareComments: true); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecificTestCases._CopyMe_.cs ================================================ using System.Threading.Tasks; using Reinforced.Typings.Fluent; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { [Fact] public void InterfaceAsInterface() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface ITestInterface { String: string; Int: number; } }"; AssertConfiguration(s => { s.Global(a => a.DontWriteWarningComment()); s.ExportAsInterface().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/SpecifiicTestCases.UnresolvedToUnknown.cs ================================================ using Reinforced.Typings.Fluent; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Xunit; namespace Reinforced.Typings.Tests.SpecificCases { public partial class SpecificTestCases { interface IUnresolvedToUnknownInterface { DateTime? Date { get; } } [Fact] public void UnresolvedToUnknown() { const string result = @" module Reinforced.Typings.Tests.SpecificCases { export interface IUnresolvedToUnknownInterface { Date: unknown; } }"; AssertConfiguration(s => { s.Global(c => c.UnresolvedToUnknown(true)); s.ExportAsInterface().WithPublicProperties(); }, result); } } } ================================================ FILE: Reinforced.Typings.Tests/SpecificCases/TestCases.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Attributes; using Reinforced.Typings.Generators; //[assembly:TsGlobal(CamelCaseForProperties = true)] namespace Reinforced.Typings.Tests.SpecificCases { #region Basic test public interface ITestInterface { string String { get; } int Int { get; } } public class TestClass { public string String { get; set; } public int Int { get; set; } } public class TestClass2 { public string String { get; set; } public int Int { get; set; } } #endregion #region Enums in namespaces public class JonsaModel { public JonsaEnum Enum { get; set; } } public enum JonsaEnum { Foo, Bar } #endregion #region Camelcase public class PandaWoodCamelCaseTest { public int ID { get; set; } public void ETA() { } public void ISODate(DateTime date) { } public void PerformRequest() { } } #endregion #region Daggmano AutoI bug public class ExternalUserDaggmano { public string Name { get; set; } } public class InternalUserDaggmano { public string Name { get; set; } } public interface IAlreadyContainsI { string Name { get; } } public interface DoesntContainI { string Name { get; } } public class DoNotNeedIAtAll { public string Name { get; set; } } public interface ICannotBeRemovedHere { string Name { get; } } #endregion #region Type references public class SomeIndirectlyReferencedClass { } public class SomeOtherReferencedType { } public class SomeFluentReferencedType { } public class SomeFluentlyReferencedNotExported { } [TsAddTypeImport("* as '$'", "JQuery")] [TsAddTypeReference(typeof(SomeOtherReferencedType))] [TsAddTypeReference("../../jquery.d.ts")] public class SomeReferencingType { public SomeIndirectlyReferencedClass Indirect() { return null; } } [TsAddTypeImport("* as '$'", "JQuery")] [TsAddTypeReference(typeof(SomeOtherReferencedType))] [TsAddTypeReference("../../jquery.d.ts")] public class AnothreReferencingType { public SomeIndirectlyReferencedClass Indirect() { return null; } public SomeFluentReferencedType Property { get; set; } public SomeIndirectEnum Enum { get; set; } } public enum SomeIndirectEnum { One, Two, Three } #endregion #region Inline functions public class ClassWithManyMethods { public string String { get; set; } public int Int { get; set; } public void DoSomethinig() { } public void DoSomethingElse() { } public string DoSomethingElseWithResult() { return null; } } #endregion #region Generics public interface ISimpleGenericsInterface { T Property { get; } T Method(T param); } public interface IParametrizedGenericsInterface { Dictionary Bag { get; } IEnumerable> Bag2 { get; } IEnumerable>> Bag3 { get; } Dictionary>>> Bag4 { get; } } public interface IAttributeParametrization<[TsGeneric("any")]T> : ISimpleGenericsInterface { } public interface IChildParametrized : IParametrizedGenericsInterface { } public interface ITriforce { } public interface ITrimplementor1 : ITriforce, Dictionary>> { } public interface ITrimplementor2 : ITriforce, Dictionary>> { TChild Property { get; } } public interface ITrimplementor3 : ITriforce, Dictionary>> { Tuple Property { get; } } #endregion #region Weird inheritance public class BaseClass { public string Property { get; set; } public void DoSomething() { } } public class DerivedClass : BaseClass { public string GetName() { return null; } } #endregion #region Inline inferring test public interface IInferringTestInterface { string String { get; } int Int { get; } Guid Guid { get; } DateTime DateTime { get; } ITestInterface TestInterface { get; } void VoidMethod1(int arg); void VoidMethod2(int arg); void VoidMethod3(int arg); void VoidMethod4(int arg); int SomeMethod1(int arg); int SomeMethod2(int arg); int SomeMethod3(int arg); int SomeMethod4(int arg); } #endregion #region Daniel West Ref. Files test public enum SomeEnum { One, Two } public class SomeViewModel { public SomeEnum Enum { get; set; } } #endregion } ================================================ FILE: Reinforced.Typings.Tests/SuppressedWarningsParseringTests.cs ================================================ using Reinforced.Typings.Cli; using Xunit; namespace Reinforced.Typings.Tests { public class SuppressedWarningsParseringTests { [Fact] public void SuppressedWarningsParseringWorks_Case1() { var result = Bootstrapper.ParseSuppressedWarnings("1;2;3;4"); Assert.Collection(result, x => Assert.Equal(1, x), x => Assert.Equal(2, x), x => Assert.Equal(3, x), x => Assert.Equal(4, x)); } [Fact] public void SuppressedWarningsParseringWorks_Case2() { var result = Bootstrapper.ParseSuppressedWarnings("001;00002;0030;04"); Assert.Collection(result, x => Assert.Equal(1, x), x => Assert.Equal(2, x), x => Assert.Equal(30, x), x => Assert.Equal(4, x)); } [Fact] public void SuppressedWarningsParseringWorks_Case3() { var result = Bootstrapper.ParseSuppressedWarnings("RTW001;RTW00002;RTW0030;RTW4"); Assert.Collection(result, x => Assert.Equal(1, x), x => Assert.Equal(2, x), x => Assert.Equal(30, x), x => Assert.Equal(4, x)); } [Fact] public void SuppressedWarningsParseringWorks_Case4() { var result = Bootstrapper.ParseSuppressedWarnings("RTW0001_DocumentationNotSupplied;RTW0002_DocumentationNotFound;RTW0003_TypeUnknown;RTW4"); Assert.Collection(result, x => Assert.Equal(1, x), x => Assert.Equal(2, x), x => Assert.Equal(3, x), x => Assert.Equal(4, x)); } } } ================================================ FILE: Reinforced.Typings.Tests/Tokenizing/SimpleTokenizer.cs ================================================ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Reinforced.Typings.Tests.Tokenizing { sealed class SimpleTokenizer { private const string CommentSyntax = "//"; private const string TokenSeparators = ".,;:{[()]}=,+-/*%@!&|"; private readonly TextReader _reader; private readonly bool _tokenizeComments; private bool _inComment; private readonly StringBuilder _buffer = new StringBuilder(); public SimpleTokenizer(TextReader reader,bool tokenizeComments = false) { _reader = reader; _tokenizeComments = tokenizeComments; } public IEnumerable Tokenize() { var line = _reader.ReadLine(); while (line != null) { foreach (var token in TokenizeLine(line)) { if (!_tokenizeComments && token.StartsWith(CommentSyntax)) continue; yield return token; } line = _reader.ReadLine(); } } private IEnumerable TokenizeLine(string s) { if (s.Length == 1) { yield return s; yield break; } bool readingToken = false; for (int i = 0; i < s.Length; i++) { if (Ahead(s, CommentSyntax, i)) { if (_buffer.Length > 0) yield return _buffer.ToString(); _buffer.Clear(); yield return s.Substring(i); yield break; } if (!_inComment) { var commentAhead = Ahead(s, "/*", i); _inComment = commentAhead; if (commentAhead) { if (_tokenizeComments) _buffer.Append(s[i]); continue; } } if (_inComment) { var commentEndAhead = Ahead(s, "*/", i); if (_tokenizeComments) _buffer.Append(s[i]); if (!commentEndAhead) continue; _inComment = false; if (_tokenizeComments) { _buffer.Append("*/"); yield return _buffer.ToString(); _buffer.Clear(); } i+=2; continue; } if (!char.IsWhiteSpace(s[i])) { readingToken = true; _buffer.Append(s[i]); } else { if (readingToken) { yield return _buffer.ToString(); _buffer.Clear(); readingToken = false; } } if (IsTokenSeparator(s[i])) { yield return _buffer.ToString(); _buffer.Clear(); readingToken = false; } } if (_buffer.Length != 0) { var r = _buffer.ToString(); _buffer.Clear(); yield return r; } } private bool Ahead(string s, string lookup,int pos) { if (s.Length - pos < lookup.Length) return false; if (lookup.Length == 1) return s[pos] == lookup[0]; int lp = 0; while (lp < lookup.Length && lp + pos < s.Length) { if (s[lp + pos] != lookup[lp]) return false; lp++; } return true; } private bool IsTokenSeparator(char c) { return TokenSeparators.Contains(c); } } } ================================================ FILE: Reinforced.Typings.Tests/Tokenizing/TokenizingComparer.cs ================================================ using System.Collections.Generic; using System.IO; namespace Reinforced.Typings.Tests.Tokenizing { public static class TokenizingComparer { public static bool TokenizeCompare(this string s, string to, bool tokenizeComments = false) { using (var stringReader1 = new StringReader(s)) { using (var stringReader2 = new StringReader(to)) { var t1 = new SimpleTokenizer(stringReader1, tokenizeComments); var t2 = new SimpleTokenizer(stringReader2, tokenizeComments); IEnumerator en1 = null; IEnumerator en2 = null; try { en1 = t1.Tokenize().GetEnumerator(); en2 = t2.Tokenize().GetEnumerator(); while (true) { var canNext1 = en1.MoveNext(); var canNext2 = en2.MoveNext(); if (canNext1 != canNext2) { return false; } if (!canNext1) break; var token1 = en1.Current; var token2 = en2.Current; if (token1 != token2) return false; } return true; } finally { if (en1 != null) en1.Dispose(); if (en2 != null) en2.Dispose(); } } } } } } ================================================ FILE: Reinforced.Typings.Tests/TokenizingComparerTests.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Reinforced.Typings.Tests.Tokenizing; using Xunit; namespace Reinforced.Typings.Tests { public class TokenizingComparerTests { [Fact] public void BasicTest() { string s1 = "interface ISometing { _field:number; }"; string s2 = @"interface ISometing { _field:number; }"; var equal = s1.TokenizeCompare(s2); Assert.True(equal); } [Fact] public void NotEqualBasicTest() { string s1 = "interface ISometing { _field:number; }"; string s2 = @"interface ISometing2 { _field2: string; }"; var equal = s1.TokenizeCompare(s2); Assert.False(equal); } [Fact] public void InlineCommentTest() { string s1 = "interface ISometing /* a = 1 + 1 */ { _field:number; }"; string s2 = @"interface ISometing { _field: number; // hello }"; var equal = s1.TokenizeCompare(s2); Assert.True(equal); } [Fact] public void TokenizingTest() { var source = new[] { "export", "interface", "ISomething", "{", "private", "field:", "number;", "}" }; StringBuilder sb = new StringBuilder(); Random r = new Random(); foreach (var s in source) { if (r.Next(10) > 5) { sb.Append("\t"); } sb.Append(s); var num = r.Next(1, 10); sb.Append(new string(' ', num)); if (r.Next() > 5) sb.Append('\n'); } string[] result = null; using (var ss = new StringReader(sb.ToString())) { SimpleTokenizer st = new SimpleTokenizer(ss); result = st.Tokenize().ToArray(); } Assert.Equal(result.Length, source.Length); for (int i = 0; i < source.Length; i++) { Assert.Equal(source[i], result[i]); } } } } ================================================ FILE: Reinforced.Typings.Tests/TypeNameEqualityComparer.cs ================================================ using System; using System.Collections.Generic; using Reinforced.Typings.Ast.TypeNames; namespace Reinforced.Typings.Tests { public class TypeNameEqualityComparer : IEqualityComparer { public bool Equals(RtTypeName x, RtTypeName y) { if (x.GetType() != y.GetType()) return false; if (x is RtSimpleTypeName) return CompareSimple((RtSimpleTypeName)x, (RtSimpleTypeName)y); if (x is RtArrayType) return CompareArray((RtArrayType)x, (RtArrayType)y); if (x is RtDelegateType) return CompareDelegate((RtDelegateType)x, (RtDelegateType)y); if (x is RtDictionaryType) return CompareDictionary((RtDictionaryType)x, (RtDictionaryType)y); if (x is RtTuple) return CompareTuple((RtTuple)x, (RtTuple)y); throw new Exception(x.GetType().FullName + " is not valid type for comparison"); } private bool CompareSimple(RtSimpleTypeName x, RtSimpleTypeName y) { if (x.TypeName != y.TypeName) return false; if ((x.HasPrefix || y.HasPrefix) && x.Prefix != y.Prefix) return false; if (x.GenericArguments.Length != y.GenericArguments.Length) return false; for (int i = 0; i < x.GenericArguments.Length; i++) { if (!Equals(x.GenericArguments[i], y.GenericArguments[i])) return false; } return true; } private bool CompareArray(RtArrayType x, RtArrayType y) { return Equals(x.ElementType, y.ElementType); } private bool CompareTuple(RtTuple x, RtTuple y) { if (x.TupleTypes.Count != y.TupleTypes.Count) return false; for (int i = 0; i < x.TupleTypes.Count; i++) { if (!Equals(x.TupleTypes[i], y.TupleTypes[i])) return false; } return true; } private bool CompareDelegate(RtDelegateType x, RtDelegateType y) { if (x.Arguments.Length != y.Arguments.Length) return false; if (!Equals(x.Result, y.Result)) return false; for (int i = 0; i < x.Arguments.Length; i++) { if (!Equals(x.Arguments[i], y.Arguments[i])) return false; } return true; } private bool CompareDictionary(RtDictionaryType x, RtDictionaryType y) { if (!Equals(x.KeyType, y.KeyType)) return false; return Equals(x.ValueType, y.ValueType); } public int GetHashCode(RtTypeName obj) { return obj.GetHashCode(); } } } ================================================ FILE: Reinforced.Typings.Tests/packages.config ================================================  ================================================ FILE: Reinforced.Typings.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reinforced.Typings", "Reinforced.Typings\Reinforced.Typings.csproj", "{2A5CCD5C-E660-4088-8937-9632ABBBCDBB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reinforced.Typings.Cli", "Reinforced.Typings.Cli\Reinforced.Typings.Cli.csproj", "{006290E6-CC0D-4222-87F8-9E67469AD2C9}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reinforced.Typings.Integrate", "Reinforced.Typings.Integrate\Reinforced.Typings.Integrate.csproj", "{F4830436-B660-4FAF-8F1B-4ADD0732AF02}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{4AFAD24C-908C-42B9-9D2C-99BB6F8243B7}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config .nuget\NuGet.exe = .nuget\NuGet.exe .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reinforced.Typings.Tests", "Reinforced.Typings.Tests\Reinforced.Typings.Tests.csproj", "{5D126898-7E5D-4967-8732-3FC8722F532E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestFluentAssembly", "TestFluentAssembly\TestFluentAssembly.csproj", "{E7E010D2-1CE5-4877-ABA7-36EA8EC62118}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2A5CCD5C-E660-4088-8937-9632ABBBCDBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A5CCD5C-E660-4088-8937-9632ABBBCDBB}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A5CCD5C-E660-4088-8937-9632ABBBCDBB}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A5CCD5C-E660-4088-8937-9632ABBBCDBB}.Release|Any CPU.Build.0 = Release|Any CPU {006290E6-CC0D-4222-87F8-9E67469AD2C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {006290E6-CC0D-4222-87F8-9E67469AD2C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {006290E6-CC0D-4222-87F8-9E67469AD2C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {006290E6-CC0D-4222-87F8-9E67469AD2C9}.Release|Any CPU.Build.0 = Release|Any CPU {F4830436-B660-4FAF-8F1B-4ADD0732AF02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F4830436-B660-4FAF-8F1B-4ADD0732AF02}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4830436-B660-4FAF-8F1B-4ADD0732AF02}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4830436-B660-4FAF-8F1B-4ADD0732AF02}.Release|Any CPU.Build.0 = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Debug|Any CPU.Build.0 = Debug|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D126898-7E5D-4967-8732-3FC8722F532E}.Release|Any CPU.Build.0 = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7E010D2-1CE5-4877-ABA7-36EA8EC62118}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/App_Start/BundleConfig.cs ================================================ using System.Web.Optimization; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators { public class BundleConfig { // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.validate*")); // Use the development version of Modernizr to develop with and learn from. Then, when you're // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( "~/Scripts/modernizr-*")); bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( "~/Scripts/bootstrap.js", "~/Scripts/respond.js")); bundles.Add(new StyleBundle("~/Content/css").Include( "~/Content/bootstrap.css", "~/Content/site.css")); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/App_Start/FilterConfig.cs ================================================ using System.Web.Mvc; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators { public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/App_Start/RouteConfig.cs ================================================ using System.Web.Mvc; using System.Web.Routing; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Content/Site.css ================================================ body { padding-top: 50px; padding-bottom: 20px; } /* Set padding to keep content from hitting the edges */ .body-content { padding-left: 15px; padding-right: 15px; } /* Override the default bootstrap behavior where horizontal description lists will truncate terms that are too long to fit in the left column */ .dl-horizontal dt { white-space: normal; } /* Set width on the form input elements since they're 100% wide by default */ input, select, textarea { max-width: 280px; } .spin { -webkit-animation: 2s infinite linear; animation: 2s infinite linear; } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Content/prismjs/cshtml.css ================================================ .razor_comment{ color:#53c175;; } .razor_comment_begin{ color: darkgreen; } .razor_comment_end{ color: darkgreen; } .razor_pageclass{ color:#00cf8c } .razor_inline_key { color:#00cf8c; } .razor_borders{ background-color: #e8e86f; color:black; } .razor_block { background-color:#535645; } .razor_inline_method{ color:#7ee895; } .razor_inline{ background-color:#535645; } .razor_keyword{ background-color: #41412b; color:#7895ff; } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Content/prismjs/cshtml.js ================================================ Prism.languages.cshtml = Prism.languages.extend('markup', { 'razor_comment': { pattern: /@\*[\w\W]*?\*@/, greedy:false, inside: { razor_comment_begin: /@\*/, razor_comment_end: /\*@/ } }, 'razor_block': { pattern: /@\{[\w\W]*?\}(?=[\s\S]*(@|\<))/, greedy:true, inside :{ 'razor_borders': /@\{/, 'razor_end': { pattern: /\}$/ , alias:'razor_borders' } } }, 'razor_keyword': /@(model|using|section|if|foreach)/, 'razor_inline': { greedy:false, pattern: /@[\w]([\w\.]|\([\w\"\~\\\/\s\,\:\(\$\.\)]*\))+/, inside: { 'razor_borders': /^@/, } } }); Prism.languages.cshtml['razor_block'].inside.rest = Prism.util.clone(Prism.languages.csharp); Prism.languages.cshtml['razor_inline'].inside.rest = Prism.util.clone(Prism.languages.csharp); Prism.languages.cshtml['razor_inline'].inside['razor_pageclass'] = /\b(Html|Url|Ajax|this|Model|ViewBag|Styles|Scripts)\b/; Prism.languages.cshtml['razor_block'].inside['razor_pageclass'] = /\b(Html|Url|Ajax|this|Model|ViewBag|Styles|Scripts)\b/; ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Content/prismjs/prism.css ================================================ /* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript+aspnet+csharp+json+typescript&plugins=file-highlight+toolbar+copy-to-clipboard */ code[class*="language-"],pre[class*="language-"]{font-size: 14px;color:#f8f8f2;background:none;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*="language-"]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre) > code[class*="language-"], pre[class*="language-"] {background:#272822}:not(pre) > code[class*="language-"] {padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:#708090}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.property,.token.tag,.token.constant,.token.symbol,.token.deleted{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:#a6e22e}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.regex,.token.important{color:#fd971f}.token.important,.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help} pre.code-toolbar{position:relative}pre.code-toolbar>.toolbar{position:absolute;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}pre.code-toolbar:hover>.toolbar{opacity:1}pre.code-toolbar>.toolbar .toolbar-item{display:inline-block}pre.code-toolbar>.toolbar a{cursor:pointer}pre.code-toolbar>.toolbar button{background:none;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}pre.code-toolbar>.toolbar a,pre.code-toolbar>.toolbar button,pre.code-toolbar>.toolbar span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}pre.code-toolbar>.toolbar a:hover,pre.code-toolbar>.toolbar a:focus,pre.code-toolbar>.toolbar button:hover,pre.code-toolbar>.toolbar button:focus,pre.code-toolbar>.toolbar span:hover,pre.code-toolbar>.toolbar span:focus{color:inherit;text-decoration:none} ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Content/prismjs/prism.js ================================================ /* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript+aspnet+csharp+json+typescript&plugins=file-highlight+toolbar+copy-to-clipboard */ var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(v instanceof a)){u.lastIndex=0;var b=u.exec(v),k=1;if(!b&&h&&m!=r.length-1){if(u.lastIndex=y,b=u.exec(e),!b)break;for(var w=b.index+(c?b[1].length:0),_=b.index+b[0].length,P=m,A=y,j=r.length;j>P&&_>A;++P)A+=r[P].length,w>=A&&(++m,y=A);if(r[m]instanceof a||r[P-1].greedy)continue;k=P-m,v=e.slice(y,A),b.index-=y}if(b){c&&(f=b[1].length);var w=b.index+f,b=b[0].slice(f),_=w+b.length,x=v.slice(0,w),O=v.slice(_),S=[m,k];x&&S.push(x);var N=new a(i,g?n.tokenize(b,g):b,d,b,h);S.push(N),O&&S.push(O),Array.prototype.splice.apply(r,S)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.length=0|(a||"").length,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var l={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+""},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,l=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,!document.addEventListener||n.manual||r.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)); Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*\*?|\/|~|\^|%|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript; Prism.languages.aspnet=Prism.languages.extend("markup",{"page-directive tag":{pattern:/<%\s*@.*%>/i,inside:{"page-directive tag":/<%\s*@\s*(?:Assembly|Control|Implements|Import|Master(?:Type)?|OutputCache|Page|PreviousPageType|Reference|Register)?|%>/i,rest:Prism.languages.markup.tag.inside}},"directive tag":{pattern:/<%.*%>/i,inside:{"directive tag":/<%\s*?[$=%#:]{0,2}|%>/i,rest:Prism.languages.csharp}}}),Prism.languages.aspnet.tag.pattern=/<(?!%)\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,Prism.languages.insertBefore("inside","punctuation",{"directive tag":Prism.languages.aspnet["directive tag"]},Prism.languages.aspnet.tag.inside["attr-value"]),Prism.languages.insertBefore("aspnet","comment",{"asp comment":/<%--[\w\W]*?--%>/}),Prism.languages.insertBefore("aspnet",Prism.languages.javascript?"script":"tag",{"asp script":{pattern:/()[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.csharp||{}}}); Prism.languages.csharp=Prism.languages.extend("clike",{keyword:/\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,string:[{pattern:/@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,greedy:!0},{pattern:/("|')(\\?.)*?\1/,greedy:!0}],number:/\b-?(0x[\da-f]+|\d*\.?\d+f?)\b/i}),Prism.languages.insertBefore("csharp","keyword",{"generic-method":{pattern:/[a-z0-9_]+\s*<[^>\r\n]+?>\s*(?=\()/i,alias:"function",inside:{keyword:Prism.languages.csharp.keyword,punctuation:/[<>(),.:]/}},preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(\s*#)\b(define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}}); Prism.languages.json={property:/"(?:\\.|[^\\"])*"(?=\s*:)/gi,string:/"(?!:)(?:\\.|[^\\"])*"(?!:)/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?)\b/g,punctuation:/[{}[\]);,]/g,operator:/:/g,"boolean":/\b(true|false)\b/gi,"null":/\bnull\b/gi},Prism.languages.jsonp=Prism.languages.json; Prism.languages.typescript=Prism.languages.extend("javascript",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield|false|true|module|declare|constructor|string|Function|any|number|boolean|Array|enum|symbol|namespace|abstract|require|type)\b/}),Prism.languages.ts=Prism.languages.typescript; !function(){"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var e={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.forEach&&Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(t){for(var a,s=t.getAttribute("data-src"),n=t,r=/\blang(?:uage)?-(?!\*)(\w+)\b/i;n&&!r.test(n.className);)n=n.parentNode;if(n&&(a=(t.className.match(r)||[,""])[1]),!a){var o=(s.match(/\.(\w+)$/)||[,""])[1];a=e[o]||o}var l=document.createElement("code");l.className="language-"+a,t.textContent="",l.textContent="Loading…",t.appendChild(l);var i=new XMLHttpRequest;i.open("GET",s,!0),i.onreadystatechange=function(){4==i.readyState&&(i.status<400&&i.responseText?(l.textContent=i.responseText,Prism.highlightElement(l)):l.textContent=i.status>=400?"✖ Error "+i.status+" while fetching file: "+i.statusText:"✖ Error: File does not exist or is empty")},i.send(null)})},document.addEventListener("DOMContentLoaded",self.Prism.fileHighlight))}(); !function(){if("undefined"!=typeof self&&self.Prism&&self.document){var t=[],e={},n=function(){};Prism.plugins.toolbar={};var a=Prism.plugins.toolbar.registerButton=function(n,a){var o;o="function"==typeof a?a:function(t){var e;return"function"==typeof a.onClick?(e=document.createElement("button"),e.type="button",e.addEventListener("click",function(){a.onClick.call(this,t)})):"string"==typeof a.url?(e=document.createElement("a"),e.href=a.url):e=document.createElement("span"),e.textContent=a.text,e},t.push(e[n]=o)},o=Prism.plugins.toolbar.hook=function(a){var o=a.element.parentNode;if(o&&/pre/i.test(o.nodeName)&&!o.classList.contains("code-toolbar")){o.classList.add("code-toolbar");var r=document.createElement("div");r.classList.add("toolbar"),document.body.hasAttribute("data-toolbar-order")&&(t=document.body.getAttribute("data-toolbar-order").split(",").map(function(t){return e[t]||n})),t.forEach(function(t){var e=t(a);if(e){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(e),r.appendChild(n)}}),o.appendChild(r)}};a("label",function(t){var e=t.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&e.hasAttribute("data-label")){var n,a,o=e.getAttribute("data-label");try{a=document.querySelector("template#"+o)}catch(r){}return a?n=a.content:(e.hasAttribute("data-url")?(n=document.createElement("a"),n.href=e.getAttribute("data-url")):n=document.createElement("span"),n.textContent=o),n}}),Prism.hooks.add("complete",o)}}(); !function(){if("undefined"!=typeof self&&self.Prism&&self.document){if(!Prism.plugins.toolbar)return console.warn("Copy to Clipboard plugin loaded before Toolbar plugin."),void 0;var o=window.Clipboard||void 0;o||"function"!=typeof require||(o=require("clipboard"));var e=[];if(!o){var t=document.createElement("script"),n=document.querySelector("head");t.onload=function(){if(o=window.Clipboard)for(;e.length;)e.pop()()},t.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.8/clipboard.min.js",n.appendChild(t)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(t){function n(){var e=new o(i,{text:function(){return t.code}});e.on("success",function(){i.textContent="Copied!",r()}),e.on("error",function(){i.textContent="Press Ctrl+C to copy",r()})}function r(){setTimeout(function(){i.textContent="Copy"},5e3)}var i=document.createElement("a");return i.textContent="Copy",o?n():e.push(n),i})}}(); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Controllers/AngularController.cs ================================================ using System; using System.Web.Mvc; using Reinforced.Typings.Samples.Difficult.CodeGenerators.Models; using Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.Angular; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers { /// /// Controller containig methods to be invoked from AngularJS /// public class AngularController : Controller { /// /// Simple controller action that returns integer method /// /// JSON-ed random integer value [AngularMethod(typeof(int))] public ActionResult SimpleIntMethod() { return Json(new Random().Next(100)); } /// /// Controller action that returns /// /// Number value /// String value /// Boolean value /// JSON-ed string containing concatenated values [AngularMethod(typeof(string))] public ActionResult MethodWithParameters(int num, string s, bool boolValue) { return Json(string.Format("{0}-{1}-{2}", num, s, boolValue)); } /// /// Controller action that returns our simple object /// /// JSON-ed simple object [AngularMethod(typeof(SampleResponseModel))] public ActionResult ReturningObject() { var result = new SampleResponseModel() { CurrentTime = DateTime.Now.ToLongTimeString(), Message = "Hello!", Success = true }; return Json(result); } /// /// Controller action that returns our simple object and consimes parameters /// /// Sample parameter /// JSON-ed simple object [AngularMethod(typeof(SampleResponseModel))] public ActionResult ReturningObjectWithParameters(string echo) { var result = new SampleResponseModel() { CurrentTime = DateTime.Now.ToLongTimeString(), Message = echo, Success = true }; return Json(result); } /// /// Controller action that does not return anything but consumes object as parameter /// /// Object parameter /// Nothing [AngularMethod(typeof(void))] public ActionResult VoidMethodWithParameters(SampleResponseModel model) { return null; } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Controllers/HomeController.cs ================================================ using System.Web.Mvc; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult JQuery() { return View(); } public ActionResult Angular() { return View(); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Controllers/JQueryController.cs ================================================ using System; using System.Web.Mvc; using Reinforced.Typings.Samples.Difficult.CodeGenerators.Models; using Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.jQuery; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers { /// /// Our sample controller for testing queries made through jQuery /// public class JQueryController : Controller { [JQueryMethod(typeof(int))] public ActionResult SimpleIntMethod() { return Json(new Random().Next(100)); } [JQueryMethod(typeof(string))] public ActionResult MethodWithParameters(int num, string s, bool boolValue) { return Json(string.Format("{0}-{1}-{2}", num, s, boolValue)); } [JQueryMethod(typeof(SampleResponseModel))] public ActionResult ReturningObject() { var result = new SampleResponseModel() { CurrentTime = DateTime.Now.ToLongTimeString(), Message = "Hello!", Success = true }; return Json(result); } [JQueryMethod(typeof(SampleResponseModel))] public ActionResult ReturningObjectWithParameters(string echo) { var result = new SampleResponseModel() { CurrentTime = DateTime.Now.ToLongTimeString(), Message = echo, Success = true }; return Json(result); } [JQueryMethod(typeof(void))] public ActionResult VoidMethodWithParameters(SampleResponseModel model) { return Json(true); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Global.asax ================================================ <%@ Application Codebehind="Global.asax.cs" Inherits="Reinforced.Typings.Samples.Difficult.CodeGenerators.MvcApplication" Language="C#" %> ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Global.asax.cs ================================================ using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Models/SampleResponseModel.cs ================================================ namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.Models { /// /// Sample model that we will use for tests /// public class SampleResponseModel { /// /// String property - message /// public string Message { get; set; } /// /// Boolean flag /// public bool Success { get; set; } /// /// String containing date /// public string CurrentTime { get; set; } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Reinforced.Typings.Samples.Difficult.CodeGenerators")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Reinforced.Typings.Samples.Difficult.CodeGenerators")] [assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("3ea8aeee-b88c-406e-8686-72127ee1bf7c")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Reinforced.Typings.Samples.Difficult.CodeGenerators.csproj ================================================  Debug AnyCPU 2.0 {8014B424-7ADF-4FA3-8772-7271861B6CB3} {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties Reinforced.Typings.Samples.Difficult.CodeGenerators Reinforced.Typings.Samples.Difficult.CodeGenerators v4.5 false true 2.1 true full false bin\ DEBUG;TRACE prompt 4 bin\Reinforced.Typings.Samples.Difficult.CodeGenerators.XML pdbonly true bin\ TRACE prompt 4 ..\..\packages\Reinforced.Typings.1.3.5\lib\net45\Reinforced.Typings.dll True True ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll True ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll True ..\..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll ..\..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll True ..\..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll True ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll True ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll True ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll True ..\..\packages\WebGrease.1.5.2\lib\WebGrease.dll True ..\..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll ..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll ..\..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll ..\..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll ..\..\packages\Microsoft.AspNet.Identity.Core.2.1.0\lib\net45\Microsoft.AspNet.Identity.Core.dll ..\..\packages\Microsoft.AspNet.Identity.Owin.2.1.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll ..\..\packages\Microsoft.AspNet.Identity.EntityFramework.2.1.0\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll ..\..\packages\Owin.1.0\lib\net40\Owin.dll ..\..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll ..\..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll ..\..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll ..\..\packages\Microsoft.Owin.Security.Facebook.3.0.0\lib\net45\Microsoft.Owin.Security.Facebook.dll ..\..\packages\Microsoft.Owin.Security.Cookies.3.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll ..\..\packages\Microsoft.Owin.Security.OAuth.3.0.0\lib\net45\Microsoft.Owin.Security.OAuth.dll ..\..\packages\Microsoft.Owin.Security.Google.3.0.0\lib\net45\Microsoft.Owin.Security.Google.dll ..\..\packages\Microsoft.Owin.Security.Twitter.3.0.0\lib\net45\Microsoft.Owin.Security.Twitter.dll ..\..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.0.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll Global.asax Web.config Web.config 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) True True 48213 / http://localhost:48213/ False False False This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Reinforced.Typings.settings.xml ================================================  Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.Configuration.Configure true $(ProjectDir)Scripts\ReinforcedTypings\Generated false false ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/ReinforcedTypings/Angular/AngularActionCallGenerator.cs ================================================ using System; using System.Linq; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Generators; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.Angular { /// /// Action call generator for controller method inside angularjs glue-class is quite similar /// to jQuery's one. /// public class AngularActionCallGenerator : MethodCodeGenerator { public override RtFuncion GenerateNode(MethodInfo element, RtFuncion result, TypeResolver resolver) { result = base.GenerateNode(element, result, resolver); if (result == null) return null; // here we are overriding return type to corresponding promise var retType = result.ReturnType; bool isVoid = (retType is RtSimpleTypeName) && (((RtSimpleTypeName)retType).TypeName == "void"); // we use TypeResolver to get "any" type to avoid redundant type name construction // (or because I'm too lazy to manually construct "any" type) if (isVoid) retType = resolver.ResolveTypeName(typeof(object)); // Here we override TS method return type to make it angular.IPromise // We are using RtSimpleType with generig parameter of existing method type result.ReturnType = new RtSimpleTypeName(new[] { retType }, "angular", "IPromise"); // Here we retrieve method parameters // We are using .GetName() extension method to retrieve parameter name // It is supplied within Reinforced.Typings and retrieves parameter name // including possible name override with Fluent configuration or // [TsParameter] attribute var p = element.GetParameters().Select(c => string.Format("'{0}': {0}", c.GetName())); // Joining parameters for method body code var dataParameters = string.Join(", ", p); // Here we get path to controller // It is quite simple solution requiring /{controller}/{action} route string controller = element.DeclaringType.Name.Replace("Controller", String.Empty); string path = String.Format("/{0}/{1}", controller, element.Name); const string code = @"var params = {{ {1} }}; return this.http.post('{0}', params) .then((response) => {{ response.data['requestParams'] = params; return response.data; }});"; RtRaw body = new RtRaw(String.Format(code, path, dataParameters)); result.Body = body; // That's all. here we return node that will be written to target file. // Check result in /Scripts/ReinforcedTypings/GeneratedTypings.ts return result; } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/ReinforcedTypings/Angular/AngularControllerGenerator.cs ================================================ using System; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Generators; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.Angular { /// /// We have to add some fields and constructor to Angular service /// public class AngularControllerGenerator : ClassCodeGenerator { /// /// We override GenerateNode method here /// /// Type that we generate typings for (our controller) /// Resulting AST node /// Reinforced.Typings Type Resolver /// Generated node public override RtClass GenerateNode(Type element, RtClass result, TypeResolver resolver) { // First of all, we fetch original AST node that is being generated by default result = base.GenerateNode(element, result, resolver); if (result == null) return null; // We add some docs to keep you oriented result.Documentation = new RtJsdocNode(){Description = "Result of AngularControllerGenerator activity"}; // Here we just create ng.IHttpService type name because it is used several times var httpServiceType = new RtSimpleTypeName("IHttpService") { Prefix = "angular" }; // Here we are declaring constructor for our angular service using $http as parameter // It is quite simple so no more details RtConstructor constructor = new RtConstructor(); constructor.Arguments.Add(new RtArgument(){Type = httpServiceType,Identifier = new RtIdentifier("$http")}); constructor.Body = new RtRaw("this.http = $http;"); // Here we declaring class field for storing $http instance RtField httpServiceField = new RtField() { Type = httpServiceType, Identifier = new RtIdentifier("http"), AccessModifier = AccessModifier.Private, Documentation = new RtJsdocNode() { Description = "Keeps $http instance received on construction"} }; // Here we are adding our constructor and field to resulting class result.Members.Add(httpServiceField); result.Members.Add(constructor); // Also we will add controller registration to our app instance // To automatically get it registered in Angular's IoC const string initializerFormat = "if (window['app']) window['app'].factory('Api.{0}', ['$http', ($http: angular.IHttpService) => new {1}($http)]);"; RtRaw registration = new RtRaw(String.Format(initializerFormat,element.Name,result.Name)); // Since RtModule.compilationUnits is not typed and could contain any type then we // simply add RtRaw node here with registration glue code // app variable is declared in /Scripts/ReinforcedTypings/App.ts since it is used in // corresponding client script Context.Location.CurrentNamespace.CompilationUnits.Add(registration); // That's all. here we return node that will be written to target file. // Check result in /Scripts/ReinforcedTypings/GeneratedTypings.ts return result; } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/ReinforcedTypings/Angular/AngularMethodAttribute.cs ================================================ using System; using Reinforced.Typings.Attributes; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.Angular { /// /// Attribute that we place above out controller's methods /// public class AngularMethodAttribute : TsFunctionAttribute { /// /// Constructor /// /// public AngularMethodAttribute(Type returnType) { // Here we override method return type for TypeScript export StrongType = returnType; // Here we are specifying code generator for particular method CodeGeneratorType = typeof (AngularActionCallGenerator); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/ReinforcedTypings/Configuration.cs ================================================ using Reinforced.Typings.Attributes; using Reinforced.Typings.Fluent; using Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers; using Reinforced.Typings.Samples.Difficult.CodeGenerators.Models; using Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.Angular; [assembly: TsGlobal(GenerateDocumentation = true)] namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings { public class Configuration { public static void Configure(ConfigurationBuilder builder) { // --- For both tutorials // Configuration exporting test model class as interface builder.ExportAsInterface().WithPublicProperties().ExportTo("models.ts"); // --- For jQuery Tutorial // Configuration for JQueryController // Setting code generator for each method performed in JQueryMethodAttribute builder.ExportAsClass().ExportTo("JQueryController.ts"); // --- For Angular tutorial // Configuration for Angular.js-firndly controller // Setting code generator for methods also performed in attribute - see AngularMethodAttribute builder.ExportAsClass() .ExportTo("AngularController.ts") .WithCodeGenerator(); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/ReinforcedTypings/jQuery/JQueryActionCallGenerator.cs ================================================ using System; using System.Linq; using System.Reflection; using Reinforced.Typings.Ast; using Reinforced.Typings.Ast.TypeNames; using Reinforced.Typings.Generators; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.jQuery { /// /// This is our code generator. Its purpose is to consume MethodInfo as source /// and produce RtFunction TypeScript AST node as result. /// We will inherit regular Method Code generator and slilghtly adjust its result /// for convinence. /// public class JQueryActionCallGenerator : MethodCodeGenerator { /// /// We override GenerateNode method (since it is almost single method of code generator). /// /// Method of controller that we generate code for /// /// Resulting node - we do not have to create resulting node by ourselfs. /// But wi still can return null from GenerateNode method /// /// /// TypeResolver object that we will use to safely convert CLR types to TypeScript types names /// /// AST node for method declaration public override RtFuncion GenerateNode(MethodInfo element, RtFuncion result, TypeResolver resolver) { // Here we get default result of method export result = base.GenerateNode(element, result, resolver); if (result == null) return null; // We make method static since we will call it like JQueryController.Method result.IsStatic = true; // Below we will add special arguments for specifying element that should be // disabled during query (disable element) and element placeholder for // loading inidicator result.Arguments.Add( new RtArgument() { Identifier = new RtIdentifier("loadingPlaceholderSelector"), Type = resolver.ResolveTypeName(typeof(string)), DefaultValue = "''" }); result.Arguments.Add( new RtArgument() { Identifier = new RtIdentifier("disableElement"), Type = resolver.ResolveTypeName(typeof(string)), DefaultValue = "''" }); // We save original type name var retType = result.ReturnType; // ... and in case of void we just replace it with "any" bool isVoid = (retType is RtSimpleTypeName) && (((RtSimpleTypeName) retType).TypeName == "void"); // we use TypeResolver to get "any" type to avoid redundant type name construction // (or because I'm too lazy to manually construct "any" type) if (isVoid) retType = resolver.ResolveTypeName(typeof (object)); // Here we override TS method return type to make it JQueryPromise // We are using RtSimpleType with generig parameter of existing method type result.ReturnType = new RtSimpleTypeName("JQueryPromise", new[] { retType }); // Here we retrieve method parameters // We are using .GetName() extension method to retrieve parameter name // It is supplied within Reinforced.Typings and retrieves parameter name // including possible name override with Fluent configuration or // [TsParameter] attribute var p = element.GetParameters().Select(c => string.Format("'{0}': {0}", c.GetName())); // Joining parameters for method body code var dataParameters = string.Join(", ", p); // Here we get path to controller // It is quite simple solution requiring /{controller}/{action} route string controller = element.DeclaringType.Name.Replace("Controller", String.Empty); string path = String.Format("/{0}/{1}", controller, element.Name); // Here we are constructing our glue code // Please refer to /Scripts/ReinforcedTypings/query.ts for implementation of QueryController.query method string code = String.Format( @"return QueryController.query<{2}>( '{0}', {{ {1} }}, loadingPlaceholderSelector, disableElement );", path, dataParameters, retType); // Here we just set method body and return method node result.Body = new RtRaw(code); // Also here we will add some JSDOC result.Documentation = new RtJsdocNode(){Description = String.Format("Wrapper method for call {0} of {1}",element.Name,element.DeclaringType.Name)}; // That's all. here we return node that will be written to target file. // Check result in /Scripts/ReinforcedTypings/GeneratedTypings.ts return result; } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/ReinforcedTypings/jQuery/JQueryMethodAttribute.cs ================================================ using System; using Reinforced.Typings.Attributes; namespace Reinforced.Typings.Samples.Difficult.CodeGenerators.ReinforcedTypings.jQuery { /// /// Since controller method only can return ActionResult and /// there is no way to programmaticaly determine action result then /// we need special attribute to describe controller method return. /// We will inherit this attribute from TsFunction attribute since we /// anyway have to specify exported methods in fluent configuration either /// via attributes. /// public class JQueryMethodAttribute : TsFunctionAttribute { public JQueryMethodAttribute(Type returnType) { // Here we override method return type for TypeScript export StrongType = returnType; // Here we are specifying code generator for particular method CodeGeneratorType = typeof (JQueryActionCallGenerator); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/AngularDemoController.js ================================================ var Reinforced; (function (Reinforced) { var Typings; (function (Typings) { var Samples; (function (Samples) { var Difficult; (function (Difficult) { var CodeGenerators; (function (CodeGenerators) { var Pages; (function (Pages) { var AngularDemoController = (function () { function AngularDemoController(scope, angularControllerService) { this.voidMethodCalledCount = 0; this._controller = angularControllerService; this.simpleNum = 42; this.simpleS = 'Ni hao'; this.simpleBoolValue = false; } AngularDemoController.prototype.refreshRandomValue = function () { var _this = this; this._controller.SimpleIntMethod().then(function (c) { return _this.RandomValue = c; }); }; AngularDemoController.prototype.parametrizedMethod = function () { var _this = this; this._controller.MethodWithParameters(this.simpleNum, this.simpleS, this.simpleBoolValue) .then(function (c) { return _this.simpleResult = c; }); }; AngularDemoController.prototype.retrieveComplex = function () { var _this = this; this._controller.ReturningObject().then(function (c) { _this.objectResult = c; }); }; AngularDemoController.prototype.parametrizedMethodWithObject = function () { var _this = this; this._controller.ReturningObjectWithParameters(this.inputEcho).then(function (c) { return _this.echoResult = c; }); }; AngularDemoController.prototype.voidMethod = function () { var _this = this; this._controller.VoidMethodWithParameters({ CurrentTime: null, Message: 'Hello!', Success: true }).then(function (c) { return _this.voidMethodCalledCount++; }); }; return AngularDemoController; }()); Pages.AngularDemoController = AngularDemoController; app.controller('AngularDemoController', ['$scope', 'Api.AngularController', AngularDemoController]); })(Pages = CodeGenerators.Pages || (CodeGenerators.Pages = {})); })(CodeGenerators = Difficult.CodeGenerators || (Difficult.CodeGenerators = {})); })(Difficult = Samples.Difficult || (Samples.Difficult = {})); })(Samples = Typings.Samples || (Typings.Samples = {})); })(Typings = Reinforced.Typings || (Reinforced.Typings = {})); })(Reinforced || (Reinforced = {})); //# sourceMappingURL=AngularDemoController.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/AngularDemoController.ts ================================================ module Reinforced.Typings.Samples.Difficult.CodeGenerators.Pages { import AngularController = Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers.AngularController; export class AngularDemoController { private _controller: AngularController; private _scope: angular.IScope; public RandomValue: number; // model for simple method public simpleNum: number; public simpleS: string; public simpleBoolValue: boolean; public simpleResult: string; // end of model for simple method public objectResult: {}; public inputEcho:string; public echoResult: {}; public voidMethodCalledCount:number = 0; constructor(scope: angular.IScope, angularControllerService: AngularController) { this._controller = angularControllerService; this.simpleNum = 42; this.simpleS = 'Ni hao'; this.simpleBoolValue = false; } public refreshRandomValue() { this._controller.SimpleIntMethod().then(c => this.RandomValue = c); } public parametrizedMethod() { this._controller.MethodWithParameters(this.simpleNum, this.simpleS, this.simpleBoolValue) .then(c => this.simpleResult = c); } public retrieveComplex() { this._controller.ReturningObject().then(c => { this.objectResult = c; }); } public parametrizedMethodWithObject() { this._controller.ReturningObjectWithParameters(this.inputEcho).then(c => this.echoResult = c); } public voidMethod() { this._controller.VoidMethodWithParameters({ CurrentTime: null, Message: 'Hello!', Success: true }).then(c => this.voidMethodCalledCount++); } } app.controller('AngularDemoController', ['$scope', 'Api.AngularController', AngularDemoController]); } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/Generated/AngularController.js ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. /// var Reinforced; (function (Reinforced) { var Typings; (function (Typings) { var Samples; (function (Samples) { var Difficult; (function (Difficult) { var CodeGenerators; (function (CodeGenerators) { var Controllers; (function (Controllers) { if (window['app']) window['app'].factory('Api.AngularController', ['$http', function ($http) { return new AngularController($http); }]); /** Result of AngularControllerGenerator activity */ var AngularController = (function () { function AngularController($http) { this.http = $http; } /** * Simple controller action that returns integer method * * @returns JSON-ed random integer value */ AngularController.prototype.SimpleIntMethod = function () { var params = {}; return this.http.post('/Angular/SimpleIntMethod', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that returns * * @param num Number value * @param s String value * @param boolValue Boolean value * @returns JSON-ed string containing concatenated values */ AngularController.prototype.MethodWithParameters = function (num, s, boolValue) { var params = { 'num': num, 's': s, 'boolValue': boolValue }; return this.http.post('/Angular/MethodWithParameters', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that returns our simple object * * @returns JSON-ed simple object */ AngularController.prototype.ReturningObject = function () { var params = {}; return this.http.post('/Angular/ReturningObject', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that returns our simple object and consimes parameters * * @param echo Sample parameter * @returns JSON-ed simple object */ AngularController.prototype.ReturningObjectWithParameters = function (echo) { var params = { 'echo': echo }; return this.http.post('/Angular/ReturningObjectWithParameters', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that does not return anything but consumes object as parameter * * @param model Object parameter * @returns Nothing */ AngularController.prototype.VoidMethodWithParameters = function (model) { var params = { 'model': model }; return this.http.post('/Angular/VoidMethodWithParameters', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; return AngularController; }()); Controllers.AngularController = AngularController; })(Controllers = CodeGenerators.Controllers || (CodeGenerators.Controllers = {})); })(CodeGenerators = Difficult.CodeGenerators || (Difficult.CodeGenerators = {})); })(Difficult = Samples.Difficult || (Samples.Difficult = {})); })(Samples = Typings.Samples || (Typings.Samples = {})); })(Typings = Reinforced.Typings || (Reinforced.Typings = {})); })(Reinforced || (Reinforced = {})); //# sourceMappingURL=AngularController.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/Generated/AngularController.ts ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. /// module Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers { if (window['app']) window['app'].factory('Api.AngularController', ['$http', ($http: angular.IHttpService) => new AngularController($http)]); /** Result of AngularControllerGenerator activity */ export class AngularController { constructor ($http: angular.IHttpService) { this.http = $http; } /** * Simple controller action that returns integer method * * @returns JSON-ed random integer value */ public SimpleIntMethod() : angular.IPromise { var params = { }; return this.http.post('/Angular/SimpleIntMethod', params) .then((response) => { response.data['requestParams'] = params; return response.data; }); } /** * Controller action that returns * * @param num Number value * @param s String value * @param boolValue Boolean value * @returns JSON-ed string containing concatenated values */ public MethodWithParameters(num: number, s: string, boolValue: boolean) : angular.IPromise { var params = { 'num': num, 's': s, 'boolValue': boolValue }; return this.http.post('/Angular/MethodWithParameters', params) .then((response) => { response.data['requestParams'] = params; return response.data; }); } /** * Controller action that returns our simple object * * @returns JSON-ed simple object */ public ReturningObject() : angular.IPromise { var params = { }; return this.http.post('/Angular/ReturningObject', params) .then((response) => { response.data['requestParams'] = params; return response.data; }); } /** * Controller action that returns our simple object and consimes parameters * * @param echo Sample parameter * @returns JSON-ed simple object */ public ReturningObjectWithParameters(echo: string) : angular.IPromise { var params = { 'echo': echo }; return this.http.post('/Angular/ReturningObjectWithParameters', params) .then((response) => { response.data['requestParams'] = params; return response.data; }); } /** * Controller action that does not return anything but consumes object as parameter * * @param model Object parameter * @returns Nothing */ public VoidMethodWithParameters(model: Reinforced.Typings.Samples.Difficult.CodeGenerators.Models.ISampleResponseModel) : angular.IPromise { var params = { 'model': model }; return this.http.post('/Angular/VoidMethodWithParameters', params) .then((response) => { response.data['requestParams'] = params; return response.data; }); } /** Keeps $http instance received on construction */ private http: angular.IHttpService; } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/Generated/JQueryController.js ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. /// var Reinforced; (function (Reinforced) { var Typings; (function (Typings) { var Samples; (function (Samples) { var Difficult; (function (Difficult) { var CodeGenerators; (function (CodeGenerators) { var Controllers; (function (Controllers) { /** Our sample controller for testing queries made through jQuery */ var JQueryController = (function () { function JQueryController() { } /** Wrapper method for call SimpleIntMethod of JQueryController */ JQueryController.SimpleIntMethod = function (loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/SimpleIntMethod', {}, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call MethodWithParameters of JQueryController */ JQueryController.MethodWithParameters = function (num, s, boolValue, loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/MethodWithParameters', { 'num': num, 's': s, 'boolValue': boolValue }, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call ReturningObject of JQueryController */ JQueryController.ReturningObject = function (loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/ReturningObject', {}, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call ReturningObjectWithParameters of JQueryController */ JQueryController.ReturningObjectWithParameters = function (echo, loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/ReturningObjectWithParameters', { 'echo': echo }, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call VoidMethodWithParameters of JQueryController */ JQueryController.VoidMethodWithParameters = function (model, loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/VoidMethodWithParameters', { 'model': model }, loadingPlaceholderSelector, disableElement); }; return JQueryController; }()); Controllers.JQueryController = JQueryController; })(Controllers = CodeGenerators.Controllers || (CodeGenerators.Controllers = {})); })(CodeGenerators = Difficult.CodeGenerators || (Difficult.CodeGenerators = {})); })(Difficult = Samples.Difficult || (Samples.Difficult = {})); })(Samples = Typings.Samples || (Typings.Samples = {})); })(Typings = Reinforced.Typings || (Reinforced.Typings = {})); })(Reinforced || (Reinforced = {})); //# sourceMappingURL=JQueryController.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/Generated/JQueryController.ts ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. /// module Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers { /** Our sample controller for testing queries made through jQuery */ export class JQueryController { /** Wrapper method for call SimpleIntMethod of JQueryController */ public static SimpleIntMethod(loadingPlaceholderSelector: string = '', disableElement: string = '') : JQueryPromise { return QueryController.query( '/JQuery/SimpleIntMethod', { }, loadingPlaceholderSelector, disableElement ); } /** Wrapper method for call MethodWithParameters of JQueryController */ public static MethodWithParameters(num: number, s: string, boolValue: boolean, loadingPlaceholderSelector: string = '', disableElement: string = '') : JQueryPromise { return QueryController.query( '/JQuery/MethodWithParameters', { 'num': num, 's': s, 'boolValue': boolValue }, loadingPlaceholderSelector, disableElement ); } /** Wrapper method for call ReturningObject of JQueryController */ public static ReturningObject(loadingPlaceholderSelector: string = '', disableElement: string = '') : JQueryPromise { return QueryController.query( '/JQuery/ReturningObject', { }, loadingPlaceholderSelector, disableElement ); } /** Wrapper method for call ReturningObjectWithParameters of JQueryController */ public static ReturningObjectWithParameters(echo: string, loadingPlaceholderSelector: string = '', disableElement: string = '') : JQueryPromise { return QueryController.query( '/JQuery/ReturningObjectWithParameters', { 'echo': echo }, loadingPlaceholderSelector, disableElement ); } /** Wrapper method for call VoidMethodWithParameters of JQueryController */ public static VoidMethodWithParameters(model: Reinforced.Typings.Samples.Difficult.CodeGenerators.Models.ISampleResponseModel, loadingPlaceholderSelector: string = '', disableElement: string = '') : JQueryPromise { return QueryController.query( '/JQuery/VoidMethodWithParameters', { 'model': model }, loadingPlaceholderSelector, disableElement ); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/Generated/models.js ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. //# sourceMappingURL=models.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/Generated/models.ts ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. module Reinforced.Typings.Samples.Difficult.CodeGenerators.Models { /** Sample model that we will use for tests */ export interface ISampleResponseModel { /** String property - message */ Message: string; /** Boolean flag */ Success: boolean; /** String containing date */ CurrentTime: string; } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/GeneratedTypings.js ================================================ // This code was generated by a Reinforced.Typings tool. // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. var Reinforced; (function (Reinforced) { var Typings; (function (Typings) { var Samples; (function (Samples) { var Difficult; (function (Difficult) { var CodeGenerators; (function (CodeGenerators) { var Controllers; (function (Controllers) { /** Our sample controller for testing queries made through jQuery */ var JQueryController = (function () { function JQueryController() { } /** Wrapper method for call SimpleIntMethod of JQueryController */ JQueryController.SimpleIntMethod = function (loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/SimpleIntMethod', {}, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call MethodWithParameters of JQueryController */ JQueryController.MethodWithParameters = function (num, s, boolValue, loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/MethodWithParameters', { 'num': num, 's': s, 'boolValue': boolValue }, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call ReturningObject of JQueryController */ JQueryController.ReturningObject = function (loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/ReturningObject', {}, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call ReturningObjectWithParameters of JQueryController */ JQueryController.ReturningObjectWithParameters = function (echo, loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/ReturningObjectWithParameters', { 'echo': echo }, loadingPlaceholderSelector, disableElement); }; /** Wrapper method for call VoidMethodWithParameters of JQueryController */ JQueryController.VoidMethodWithParameters = function (model, loadingPlaceholderSelector, disableElement) { if (loadingPlaceholderSelector === void 0) { loadingPlaceholderSelector = ''; } if (disableElement === void 0) { disableElement = ''; } return QueryController.query('/JQuery/VoidMethodWithParameters', { 'model': model }, loadingPlaceholderSelector, disableElement); }; return JQueryController; }()); Controllers.JQueryController = JQueryController; if (window['app']) window['app'].factory('Api.AngularController', ['$http', function ($http) { return new AngularController($http); }]); /** Result of AngularControllerGenerator activity */ var AngularController = (function () { function AngularController($http) { this.http = $http; } /** * Simple controller action that returns integer method * * @returns JSON-ed random integer value */ AngularController.prototype.SimpleIntMethod = function () { var params = {}; return this.http.post('/Angular/SimpleIntMethod', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that returns * * @param num Number value * @param s String value * @param boolValue Boolean value * @returns JSON-ed string containing concatenated values */ AngularController.prototype.MethodWithParameters = function (num, s, boolValue) { var params = { 'num': num, 's': s, 'boolValue': boolValue }; return this.http.post('/Angular/MethodWithParameters', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that returns our simple object * * @returns JSON-ed simple object */ AngularController.prototype.ReturningObject = function () { var params = {}; return this.http.post('/Angular/ReturningObject', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that returns our simple object and consimes parameters * * @param echo Sample parameter * @returns JSON-ed simple object */ AngularController.prototype.ReturningObjectWithParameters = function (echo) { var params = { 'echo': echo }; return this.http.post('/Angular/ReturningObjectWithParameters', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; /** * Controller action that does not return anything but consumes object as parameter * * @param model Object parameter * @returns Nothing */ AngularController.prototype.VoidMethodWithParameters = function (model) { var params = { 'model': model }; return this.http.post('/Angular/VoidMethodWithParameters', params) .then(function (response) { response.data['requestParams'] = params; return response.data; }); }; return AngularController; }()); Controllers.AngularController = AngularController; })(Controllers = CodeGenerators.Controllers || (CodeGenerators.Controllers = {})); })(CodeGenerators = Difficult.CodeGenerators || (Difficult.CodeGenerators = {})); })(Difficult = Samples.Difficult || (Samples.Difficult = {})); })(Samples = Typings.Samples || (Typings.Samples = {})); })(Typings = Reinforced.Typings || (Reinforced.Typings = {})); })(Reinforced || (Reinforced = {})); //# sourceMappingURL=GeneratedTypings.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/IndexPage.js ================================================ var Reinforced; (function (Reinforced) { var Typings; (function (Typings) { var Samples; (function (Samples) { var Difficult; (function (Difficult) { var CodeGenerators; (function (CodeGenerators) { var Pages; (function (Pages) { var JQueryController = Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers.JQueryController; var IndexPage = (function () { function IndexPage() { $('#btnSimpleInt').click(this.btnSimpleIntClick.bind(this)); $('#btnMethodWithParameters').click(this.btnMethodWithParametersClick.bind(this)); $('#btnReturningObject').click(this.btnReturningObjectClick.bind(this)); $('#btnReturningObjectWithParameters').click(this.btnReturningObjectWithParametersClick.bind(this)); $('#btnVoidMethodWithParameters').click(this.btnVoidMethodWithParametersClick.bind(this)); } IndexPage.prototype.btnSimpleIntClick = function () { JQueryController.SimpleIntMethod('#loading', '#btnSimpleInt') .then(function (r) { return $('#result').html('Server tells us ' + r); }); }; IndexPage.prototype.btnMethodWithParametersClick = function () { JQueryController.MethodWithParameters(Math.random(), 'string' + Math.random(), Math.random() > 0.5, '#loading', '#btnMethodWithParameters') .then(function (r) { $('#result').html(r); }); }; IndexPage.prototype.btnReturningObjectClick = function () { JQueryController.ReturningObject('#loading', '#btnReturningObject') .then(function (r) { var s = "
 { 
"; for (var key in r) { s += " " + key + ": " + r[key] + ",\n"; } s += '}
'; $('#result').html(s); }); }; IndexPage.prototype.btnReturningObjectWithParametersClick = function () { var str = 'Random number: ' + Math.random() * 100; JQueryController.ReturningObjectWithParameters(str, '#loading', '#btnReturningObjectWithParameters') .then(function (r) { var s = "
 { 
"; for (var key in r) { s += " " + key + ": " + r[key] + ",\n"; } s += '}
'; $('#result').html(s); }); }; IndexPage.prototype.btnVoidMethodWithParametersClick = function () { JQueryController.VoidMethodWithParameters({ Message: 'Hello', Success: true, CurrentTime: null }, '#loading', '#btnVoidMethodWithParameters') .then(function () { $('#result').html('Void method executed but it does not return result'); }); }; return IndexPage; }()); Pages.IndexPage = IndexPage; })(Pages = CodeGenerators.Pages || (CodeGenerators.Pages = {})); })(CodeGenerators = Difficult.CodeGenerators || (Difficult.CodeGenerators = {})); })(Difficult = Samples.Difficult || (Samples.Difficult = {})); })(Samples = Typings.Samples || (Typings.Samples = {})); })(Typings = Reinforced.Typings || (Reinforced.Typings = {})); })(Reinforced || (Reinforced = {})); //# sourceMappingURL=IndexPage.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/IndexPage.ts ================================================ module Reinforced.Typings.Samples.Difficult.CodeGenerators.Pages { import JQueryController = Reinforced.Typings.Samples.Difficult.CodeGenerators.Controllers.JQueryController; export class IndexPage { constructor() { $('#btnSimpleInt').click(this.btnSimpleIntClick.bind(this)); $('#btnMethodWithParameters').click(this.btnMethodWithParametersClick.bind(this)); $('#btnReturningObject').click(this.btnReturningObjectClick.bind(this)); $('#btnReturningObjectWithParameters').click(this.btnReturningObjectWithParametersClick.bind(this)); $('#btnVoidMethodWithParameters').click(this.btnVoidMethodWithParametersClick.bind(this)); } private btnSimpleIntClick() { JQueryController.SimpleIntMethod('#loading', '#btnSimpleInt') .then(r => $('#result').html('Server tells us ' + r)); } private btnMethodWithParametersClick() { JQueryController.MethodWithParameters(Math.random(), 'string' + Math.random(), Math.random() > 0.5, '#loading', '#btnMethodWithParameters') .then(r => { $('#result').html(r); }); } private btnReturningObjectClick() { JQueryController.ReturningObject('#loading', '#btnReturningObject') .then(r => { var s = "
 { 
"; for (var key in r) { s += ` ${key}: ${r[key]},\n`; } s += '}
'; $('#result').html(s); }); } private btnReturningObjectWithParametersClick() { var str = 'Random number: ' + Math.random() * 100; JQueryController.ReturningObjectWithParameters(str, '#loading', '#btnReturningObjectWithParameters') .then(r => { var s = "
 { 
"; for (var key in r) { s += ` ${key}: ${r[key]},\n`; } s += '}
'; $('#result').html(s); }); } private btnVoidMethodWithParametersClick() { JQueryController.VoidMethodWithParameters({ Message: 'Hello', Success: true, CurrentTime: null }, '#loading', '#btnVoidMethodWithParameters') .then(() => { $('#result').html('Void method executed but it does not return result'); }); } } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/app.js ================================================ /// var app = angular.module('app', []); //# sourceMappingURL=app.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/app.ts ================================================ /// var app = angular.module('app', []); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/query.js ================================================ /** * Simple intermediate class for jQuery to easily perform AJAX requests with disabling elements */ var QueryController = (function () { function QueryController() { } /** * Main query method that we will use to perform AJAX calls from jQuery middleware controller * @param url URL to query * @param data Data to send * @param progressSelector Element selector to add progress indicator to * @param disableSelector Selector of element that is needed to be disabled while request */ QueryController.query = function (url, data, progressSelector, disableSelector) { if (disableSelector === void 0) { disableSelector = ''; } var promise = jQuery.Deferred(); var query = { data: JSON.stringify(data), type: 'post', dataType: 'json', contentType: 'application/json', timeout: 9000000, traditional: false, complete: function () { if (progressSelector && progressSelector.length > 0) { $(progressSelector).find('i[data-role="progressContainer"]').remove(); } if (disableSelector && disableSelector.length > 0) { $(disableSelector).prop('disabled', false); } }, success: function (response) { promise.resolve(response); }, error: function (request, status, error) { promise.reject({ Success: false, Message: error.toString(), Data: error }); } }; if (progressSelector && progressSelector.length > 0) { $(progressSelector).append(' Loading ... '); } if (disableSelector && disableSelector.length > 0) { $(disableSelector).prop('disabled', true); } $.ajax(url, query); return promise; }; return QueryController; }()); //# sourceMappingURL=query.js.map ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/ReinforcedTypings/query.ts ================================================ /** * Simple intermediate class for jQuery to easily perform AJAX requests with disabling elements */ class QueryController { /** * Main query method that we will use to perform AJAX calls from jQuery middleware controller * @param url URL to query * @param data Data to send * @param progressSelector Element selector to add progress indicator to * @param disableSelector Selector of element that is needed to be disabled while request */ public static query(url: string, data: any, progressSelector: string, disableSelector:string = ''): JQueryPromise { var promise = jQuery.Deferred(); var query = { data: JSON.stringify(data), type: 'post', dataType: 'json', contentType:'application/json', timeout: 9000000, traditional: false, complete: () => { if (progressSelector && progressSelector.length > 0) { $(progressSelector).find('i[data-role="progressContainer"]').remove(); } if (disableSelector && disableSelector.length > 0) { $(disableSelector).prop('disabled', false); } }, success: (response: T) => { promise.resolve(response); }, error: (request, status, error) => { promise.reject({ Success: false, Message: error.toString(), Data: error }); } }; if (progressSelector && progressSelector.length > 0) { $(progressSelector).append(' Loading ... '); } if (disableSelector && disableSelector.length > 0) { $(disableSelector).prop('disabled',true); } $.ajax(url,query); return promise; } } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-animate.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /* jshint ignore:start */ var noop = angular.noop; var extend = angular.extend; var jqLite = angular.element; var forEach = angular.forEach; var isArray = angular.isArray; var isString = angular.isString; var isObject = angular.isObject; var isUndefined = angular.isUndefined; var isDefined = angular.isDefined; var isFunction = angular.isFunction; var isElement = angular.isElement; var ELEMENT_NODE = 1; var COMMENT_NODE = 8; var ADD_CLASS_SUFFIX = '-add'; var REMOVE_CLASS_SUFFIX = '-remove'; var EVENT_CLASS_PREFIX = 'ng-'; var ACTIVE_CLASS_SUFFIX = '-active'; var NG_ANIMATE_CLASSNAME = 'ng-animate'; var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren'; // Detect proper transitionend/animationend event names. var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT; // If unprefixed events are not supported but webkit-prefixed are, use the latter. // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them. // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend` // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`. // Register both events in case `window.onanimationend` is not supported because of that, // do the same for `transitionend` as Safari is likely to exhibit similar behavior. // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit // therefore there is no reason to test anymore for other vendor prefixes: // http://caniuse.com/#search=transition if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) { CSS_PREFIX = '-webkit-'; TRANSITION_PROP = 'WebkitTransition'; TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; } else { TRANSITION_PROP = 'transition'; TRANSITIONEND_EVENT = 'transitionend'; } if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) { CSS_PREFIX = '-webkit-'; ANIMATION_PROP = 'WebkitAnimation'; ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend'; } else { ANIMATION_PROP = 'animation'; ANIMATIONEND_EVENT = 'animationend'; } var DURATION_KEY = 'Duration'; var PROPERTY_KEY = 'Property'; var DELAY_KEY = 'Delay'; var TIMING_KEY = 'TimingFunction'; var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount'; var ANIMATION_PLAYSTATE_KEY = 'PlayState'; var SAFE_FAST_FORWARD_DURATION_VALUE = 9999; var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY; var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY; var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY; var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY; var isPromiseLike = function(p) { return p && p.then ? true : false; }; function assertArg(arg, name, reason) { if (!arg) { throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); } return arg; } function mergeClasses(a,b) { if (!a && !b) return ''; if (!a) return b; if (!b) return a; if (isArray(a)) a = a.join(' '); if (isArray(b)) b = b.join(' '); return a + ' ' + b; } function packageStyles(options) { var styles = {}; if (options && (options.to || options.from)) { styles.to = options.to; styles.from = options.from; } return styles; } function pendClasses(classes, fix, isPrefix) { var className = ''; classes = isArray(classes) ? classes : classes && isString(classes) && classes.length ? classes.split(/\s+/) : []; forEach(classes, function(klass, i) { if (klass && klass.length > 0) { className += (i > 0) ? ' ' : ''; className += isPrefix ? fix + klass : klass + fix; } }); return className; } function removeFromArray(arr, val) { var index = arr.indexOf(val); if (val >= 0) { arr.splice(index, 1); } } function stripCommentsFromElement(element) { if (element instanceof jqLite) { switch (element.length) { case 0: return []; break; case 1: // there is no point of stripping anything if the element // is the only element within the jqLite wrapper. // (it's important that we retain the element instance.) if (element[0].nodeType === ELEMENT_NODE) { return element; } break; default: return jqLite(extractElementNode(element)); break; } } if (element.nodeType === ELEMENT_NODE) { return jqLite(element); } } function extractElementNode(element) { if (!element[0]) return element; for (var i = 0; i < element.length; i++) { var elm = element[i]; if (elm.nodeType == ELEMENT_NODE) { return elm; } } } function $$addClass($$jqLite, element, className) { forEach(element, function(elm) { $$jqLite.addClass(elm, className); }); } function $$removeClass($$jqLite, element, className) { forEach(element, function(elm) { $$jqLite.removeClass(elm, className); }); } function applyAnimationClassesFactory($$jqLite) { return function(element, options) { if (options.addClass) { $$addClass($$jqLite, element, options.addClass); options.addClass = null; } if (options.removeClass) { $$removeClass($$jqLite, element, options.removeClass); options.removeClass = null; } } } function prepareAnimationOptions(options) { options = options || {}; if (!options.$$prepared) { var domOperation = options.domOperation || noop; options.domOperation = function() { options.$$domOperationFired = true; domOperation(); domOperation = noop; }; options.$$prepared = true; } return options; } function applyAnimationStyles(element, options) { applyAnimationFromStyles(element, options); applyAnimationToStyles(element, options); } function applyAnimationFromStyles(element, options) { if (options.from) { element.css(options.from); options.from = null; } } function applyAnimationToStyles(element, options) { if (options.to) { element.css(options.to); options.to = null; } } function mergeAnimationOptions(element, target, newOptions) { var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || ''); var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || ''); var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove); if (newOptions.preparationClasses) { target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses); delete newOptions.preparationClasses; } // noop is basically when there is no callback; otherwise something has been set var realDomOperation = target.domOperation !== noop ? target.domOperation : null; extend(target, newOptions); // TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this. if (realDomOperation) { target.domOperation = realDomOperation; } if (classes.addClass) { target.addClass = classes.addClass; } else { target.addClass = null; } if (classes.removeClass) { target.removeClass = classes.removeClass; } else { target.removeClass = null; } return target; } function resolveElementClasses(existing, toAdd, toRemove) { var ADD_CLASS = 1; var REMOVE_CLASS = -1; var flags = {}; existing = splitClassesToLookup(existing); toAdd = splitClassesToLookup(toAdd); forEach(toAdd, function(value, key) { flags[key] = ADD_CLASS; }); toRemove = splitClassesToLookup(toRemove); forEach(toRemove, function(value, key) { flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS; }); var classes = { addClass: '', removeClass: '' }; forEach(flags, function(val, klass) { var prop, allow; if (val === ADD_CLASS) { prop = 'addClass'; allow = !existing[klass]; } else if (val === REMOVE_CLASS) { prop = 'removeClass'; allow = existing[klass]; } if (allow) { if (classes[prop].length) { classes[prop] += ' '; } classes[prop] += klass; } }); function splitClassesToLookup(classes) { if (isString(classes)) { classes = classes.split(' '); } var obj = {}; forEach(classes, function(klass) { // sometimes the split leaves empty string values // incase extra spaces were applied to the options if (klass.length) { obj[klass] = true; } }); return obj; } return classes; } function getDomNode(element) { return (element instanceof angular.element) ? element[0] : element; } function applyGeneratedPreparationClasses(element, event, options) { var classes = ''; if (event) { classes = pendClasses(event, EVENT_CLASS_PREFIX, true); } if (options.addClass) { classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX)); } if (options.removeClass) { classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX)); } if (classes.length) { options.preparationClasses = classes; element.addClass(classes); } } function clearGeneratedClasses(element, options) { if (options.preparationClasses) { element.removeClass(options.preparationClasses); options.preparationClasses = null; } if (options.activeClasses) { element.removeClass(options.activeClasses); options.activeClasses = null; } } function blockTransitions(node, duration) { // we use a negative delay value since it performs blocking // yet it doesn't kill any existing transitions running on the // same element which makes this safe for class-based animations var value = duration ? '-' + duration + 's' : ''; applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]); return [TRANSITION_DELAY_PROP, value]; } function blockKeyframeAnimations(node, applyBlock) { var value = applyBlock ? 'paused' : ''; var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY; applyInlineStyle(node, [key, value]); return [key, value]; } function applyInlineStyle(node, styleTuple) { var prop = styleTuple[0]; var value = styleTuple[1]; node.style[prop] = value; } function concatWithSpace(a,b) { if (!a) return b; if (!b) return a; return a + ' ' + b; } var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { var queue, cancelFn; function scheduler(tasks) { // we make a copy since RAFScheduler mutates the state // of the passed in array variable and this would be difficult // to track down on the outside code queue = queue.concat(tasks); nextTick(); } queue = scheduler.queue = []; /* waitUntilQuiet does two things: * 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through * 2. It will delay the next wave of tasks from running until the quiet `fn` has run. * * The motivation here is that animation code can request more time from the scheduler * before the next wave runs. This allows for certain DOM properties such as classes to * be resolved in time for the next animation to run. */ scheduler.waitUntilQuiet = function(fn) { if (cancelFn) cancelFn(); cancelFn = $$rAF(function() { cancelFn = null; fn(); nextTick(); }); }; return scheduler; function nextTick() { if (!queue.length) return; var items = queue.shift(); for (var i = 0; i < items.length; i++) { items[i](); } if (!cancelFn) { $$rAF(function() { if (!cancelFn) nextTick(); }); } } }]; var $$AnimateChildrenDirective = [function() { return function(scope, element, attrs) { var val = attrs.ngAnimateChildren; if (angular.isString(val) && val.length === 0) { //empty attribute element.data(NG_ANIMATE_CHILDREN_DATA, true); } else { attrs.$observe('ngAnimateChildren', function(value) { value = value === 'on' || value === 'true'; element.data(NG_ANIMATE_CHILDREN_DATA, value); }); } }; }]; var ANIMATE_TIMER_KEY = '$$animateCss'; /** * @ngdoc service * @name $animateCss * @kind object * * @description * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or * directives to create more complex animations that can be purely driven using CSS code. * * Note that only browsers that support CSS transitions and/or keyframe animations are capable of * rendering animations triggered via `$animateCss` (bad news for IE9 and lower). * * ## Usage * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however, * any automatic control over cancelling animations and/or preventing animations from being run on * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger * the CSS animation. * * The example below shows how we can create a folding animation on an element using `ng-if`: * * ```html * *
* This element will go BOOM *
* * ``` * * Now we create the **JavaScript animation** that will trigger the CSS transition: * * ```js * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) { * return { * enter: function(element, doneFn) { * var height = element[0].offsetHeight; * return $animateCss(element, { * from: { height:'0px' }, * to: { height:height + 'px' }, * duration: 1 // one second * }); * } * } * }]); * ``` * * ## More Advanced Uses * * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code. * * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation, * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order * to provide a working animation that will run in CSS. * * The example below showcases a more advanced version of the `.fold-animation` from the example above: * * ```js * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) { * return { * enter: function(element, doneFn) { * var height = element[0].offsetHeight; * return $animateCss(element, { * addClass: 'red large-text pulse-twice', * easing: 'ease-out', * from: { height:'0px' }, * to: { height:height + 'px' }, * duration: 1 // one second * }); * } * } * }]); * ``` * * Since we're adding/removing CSS classes then the CSS transition will also pick those up: * * ```css * /* since a hardcoded duration value of 1 was provided in the JavaScript animation code, * the CSS classes below will be transitioned despite them being defined as regular CSS classes */ * .red { background:red; } * .large-text { font-size:20px; } * * /* we can also use a keyframe animation and $animateCss will make it work alongside the transition */ * .pulse-twice { * animation: 0.5s pulse linear 2; * -webkit-animation: 0.5s pulse linear 2; * } * * @keyframes pulse { * from { transform: scale(0.5); } * to { transform: scale(1.5); } * } * * @-webkit-keyframes pulse { * from { -webkit-transform: scale(0.5); } * to { -webkit-transform: scale(1.5); } * } * ``` * * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen. * * ## How the Options are handled * * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline * styles using the `from` and `to` properties. * * ```js * var animator = $animateCss(element, { * from: { background:'red' }, * to: { background:'blue' } * }); * animator.start(); * ``` * * ```css * .rotating-animation { * animation:0.5s rotate linear; * -webkit-animation:0.5s rotate linear; * } * * @keyframes rotate { * from { transform: rotate(0deg); } * to { transform: rotate(360deg); } * } * * @-webkit-keyframes rotate { * from { -webkit-transform: rotate(0deg); } * to { -webkit-transform: rotate(360deg); } * } * ``` * * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied * and spread across the transition and keyframe animation. * * ## What is returned * * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties: * * ```js * var animator = $animateCss(element, { ... }); * ``` * * Now what do the contents of our `animator` variable look like: * * ```js * { * // starts the animation * start: Function, * * // ends (aborts) the animation * end: Function * } * ``` * * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends. * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and stlyes may have been * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties * and that changing them will not reconfigure the parameters of the animation. * * ### runner.done() vs runner.then() * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**. * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()` * unless you really need a digest to kick off afterwards. * * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code). * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works. * * @param {DOMElement} element the element that will be animated * @param {object} options the animation-related options that will be applied during the animation * * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.) * * `structural` - Indicates that the `ng-` prefix will be added to the event class. Setting to `false` or omitting will turn `ng-EVENT` and * `ng-EVENT-active` in `EVENT` and `EVENT-active`. Unused if `event` is omitted. * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both). * * `transitionStyle` - The raw CSS transition style that will be used (e.g. `1s linear all`). * * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`). * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation. * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition. * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation. * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation. * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0` * is provided then the animation will be skipped entirely. * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same * CSS delay value. * * `stagger` - A numeric time value representing the delay between successively animated elements * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.}) * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a * * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`) * * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.) * * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once * the animation is closed. This is useful for when the styles are used purely for the sake of * the animation and do not have a lasting visual effect on the element (e.g. a colapse and open animation). * By default this value is set to `false`. * * @return {object} an object with start and end methods and details about the animation. * * * `start` - The method to start the animation. This will return a `Promise` when called. * * `end` - This method will cancel the animation and remove all applied CSS classes and styles. */ var ONE_SECOND = 1000; var BASE_TEN = 10; var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; var CLOSING_TIME_BUFFER = 1.5; var DETECT_CSS_PROPERTIES = { transitionDuration: TRANSITION_DURATION_PROP, transitionDelay: TRANSITION_DELAY_PROP, transitionProperty: TRANSITION_PROP + PROPERTY_KEY, animationDuration: ANIMATION_DURATION_PROP, animationDelay: ANIMATION_DELAY_PROP, animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY }; var DETECT_STAGGER_CSS_PROPERTIES = { transitionDuration: TRANSITION_DURATION_PROP, transitionDelay: TRANSITION_DELAY_PROP, animationDuration: ANIMATION_DURATION_PROP, animationDelay: ANIMATION_DELAY_PROP }; function getCssKeyframeDurationStyle(duration) { return [ANIMATION_DURATION_PROP, duration + 's']; } function getCssDelayStyle(delay, isKeyframeAnimation) { var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP; return [prop, delay + 's']; } function computeCssStyles($window, element, properties) { var styles = Object.create(null); var detectedStyles = $window.getComputedStyle(element) || {}; forEach(properties, function(formalStyleName, actualStyleName) { var val = detectedStyles[formalStyleName]; if (val) { var c = val.charAt(0); // only numerical-based values have a negative sign or digit as the first value if (c === '-' || c === '+' || c >= 0) { val = parseMaxTime(val); } // by setting this to null in the event that the delay is not set or is set directly as 0 // then we can still allow for zegative values to be used later on and not mistake this // value for being greater than any other negative value. if (val === 0) { val = null; } styles[actualStyleName] = val; } }); return styles; } function parseMaxTime(str) { var maxValue = 0; var values = str.split(/\s*,\s*/); forEach(values, function(value) { // it's always safe to consider only second values and omit `ms` values since // getComputedStyle will always handle the conversion for us if (value.charAt(value.length - 1) == 's') { value = value.substring(0, value.length - 1); } value = parseFloat(value) || 0; maxValue = maxValue ? Math.max(value, maxValue) : value; }); return maxValue; } function truthyTimingValue(val) { return val === 0 || val != null; } function getCssTransitionDurationStyle(duration, applyOnlyDuration) { var style = TRANSITION_PROP; var value = duration + 's'; if (applyOnlyDuration) { style += DURATION_KEY; } else { value += ' linear all'; } return [style, value]; } function createLocalCacheLookup() { var cache = Object.create(null); return { flush: function() { cache = Object.create(null); }, count: function(key) { var entry = cache[key]; return entry ? entry.total : 0; }, get: function(key) { var entry = cache[key]; return entry && entry.value; }, put: function(key, value) { if (!cache[key]) { cache[key] = { total: 1, value: value }; } else { cache[key].total++; } } }; } // we do not reassign an already present style value since // if we detect the style property value again we may be // detecting styles that were added via the `from` styles. // We make use of `isDefined` here since an empty string // or null value (which is what getPropertyValue will return // for a non-existing style) will still be marked as a valid // value for the style (a falsy value implies that the style // is to be removed at the end of the animation). If we had a simple // "OR" statement then it would not be enough to catch that. function registerRestorableStyles(backup, node, properties) { forEach(properties, function(prop) { backup[prop] = isDefined(backup[prop]) ? backup[prop] : node.style.getPropertyValue(prop); }); } var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { var gcsLookup = createLocalCacheLookup(); var gcsStaggerLookup = createLocalCacheLookup(); this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$forceReflow', '$sniffer', '$$rAFScheduler', '$animate', function($window, $$jqLite, $$AnimateRunner, $timeout, $$forceReflow, $sniffer, $$rAFScheduler, $animate) { var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); var parentCounter = 0; function gcsHashFn(node, extraClasses) { var KEY = "$$ngAnimateParentKey"; var parentNode = node.parentNode; var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter); return parentID + '-' + node.getAttribute('class') + '-' + extraClasses; } function computeCachedCssStyles(node, className, cacheKey, properties) { var timings = gcsLookup.get(cacheKey); if (!timings) { timings = computeCssStyles($window, node, properties); if (timings.animationIterationCount === 'infinite') { timings.animationIterationCount = 1; } } // we keep putting this in multiple times even though the value and the cacheKey are the same // because we're keeping an interal tally of how many duplicate animations are detected. gcsLookup.put(cacheKey, timings); return timings; } function computeCachedCssStaggerStyles(node, className, cacheKey, properties) { var stagger; // if we have one or more existing matches of matching elements // containing the same parent + CSS styles (which is how cacheKey works) // then staggering is possible if (gcsLookup.count(cacheKey) > 0) { stagger = gcsStaggerLookup.get(cacheKey); if (!stagger) { var staggerClassName = pendClasses(className, '-stagger'); $$jqLite.addClass(node, staggerClassName); stagger = computeCssStyles($window, node, properties); // force the conversion of a null value to zero incase not set stagger.animationDuration = Math.max(stagger.animationDuration, 0); stagger.transitionDuration = Math.max(stagger.transitionDuration, 0); $$jqLite.removeClass(node, staggerClassName); gcsStaggerLookup.put(cacheKey, stagger); } } return stagger || {}; } var cancelLastRAFRequest; var rafWaitQueue = []; function waitUntilQuiet(callback) { rafWaitQueue.push(callback); $$rAFScheduler.waitUntilQuiet(function() { gcsLookup.flush(); gcsStaggerLookup.flush(); // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable. // PLEASE EXAMINE THE `$$forceReflow` service to understand why. var pageWidth = $$forceReflow(); // we use a for loop to ensure that if the queue is changed // during this looping then it will consider new requests for (var i = 0; i < rafWaitQueue.length; i++) { rafWaitQueue[i](pageWidth); } rafWaitQueue.length = 0; }); } function computeTimings(node, className, cacheKey) { var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES); var aD = timings.animationDelay; var tD = timings.transitionDelay; timings.maxDelay = aD && tD ? Math.max(aD, tD) : (aD || tD); timings.maxDuration = Math.max( timings.animationDuration * timings.animationIterationCount, timings.transitionDuration); return timings; } return function init(element, options) { var restoreStyles = {}; var node = getDomNode(element); if (!node || !node.parentNode || !$animate.enabled()) { return closeAndReturnNoopAnimator(); } options = prepareAnimationOptions(options); var temporaryStyles = []; var classes = element.attr('class'); var styles = packageStyles(options); var animationClosed; var animationPaused; var animationCompleted; var runner; var runnerHost; var maxDelay; var maxDelayTime; var maxDuration; var maxDurationTime; if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) { return closeAndReturnNoopAnimator(); } var method = options.event && isArray(options.event) ? options.event.join(' ') : options.event; var isStructural = method && options.structural; var structuralClassName = ''; var addRemoveClassName = ''; if (isStructural) { structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true); } else if (method) { structuralClassName = method; } if (options.addClass) { addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX); } if (options.removeClass) { if (addRemoveClassName.length) { addRemoveClassName += ' '; } addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX); } // there may be a situation where a structural animation is combined together // with CSS classes that need to resolve before the animation is computed. // However this means that there is no explicit CSS code to block the animation // from happening (by setting 0s none in the class name). If this is the case // we need to apply the classes before the first rAF so we know to continue if // there actually is a detected transition or keyframe animation if (options.applyClassesEarly && addRemoveClassName.length) { applyAnimationClasses(element, options); } var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim(); var fullClassName = classes + ' ' + preparationClasses; var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX); var hasToStyles = styles.to && Object.keys(styles.to).length > 0; var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0; // there is no way we can trigger an animation if no styles and // no classes are being applied which would then trigger a transition, // unless there a is raw keyframe value that is applied to the element. if (!containsKeyframeAnimation && !hasToStyles && !preparationClasses) { return closeAndReturnNoopAnimator(); } var cacheKey, stagger; if (options.stagger > 0) { var staggerVal = parseFloat(options.stagger); stagger = { transitionDelay: staggerVal, animationDelay: staggerVal, transitionDuration: 0, animationDuration: 0 }; } else { cacheKey = gcsHashFn(node, fullClassName); stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES); } if (!options.$$skipPreparationClasses) { $$jqLite.addClass(element, preparationClasses); } var applyOnlyDuration; if (options.transitionStyle) { var transitionStyle = [TRANSITION_PROP, options.transitionStyle]; applyInlineStyle(node, transitionStyle); temporaryStyles.push(transitionStyle); } if (options.duration >= 0) { applyOnlyDuration = node.style[TRANSITION_PROP].length > 0; var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration); // we set the duration so that it will be picked up by getComputedStyle later applyInlineStyle(node, durationStyle); temporaryStyles.push(durationStyle); } if (options.keyframeStyle) { var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle]; applyInlineStyle(node, keyframeStyle); temporaryStyles.push(keyframeStyle); } var itemIndex = stagger ? options.staggerIndex >= 0 ? options.staggerIndex : gcsLookup.count(cacheKey) : 0; var isFirst = itemIndex === 0; // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY // without causing any combination of transitions to kick in. By adding a negative delay value // it forces the setup class' transition to end immediately. We later then remove the negative // transition delay to allow for the transition to naturally do it's thing. The beauty here is // that if there is no transition defined then nothing will happen and this will also allow // other transitions to be stacked on top of each other without any chopping them out. if (isFirst && !options.skipBlocking) { blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE); } var timings = computeTimings(node, fullClassName, cacheKey); var relativeDelay = timings.maxDelay; maxDelay = Math.max(relativeDelay, 0); maxDuration = timings.maxDuration; var flags = {}; flags.hasTransitions = timings.transitionDuration > 0; flags.hasAnimations = timings.animationDuration > 0; flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all'; flags.applyTransitionDuration = hasToStyles && ( (flags.hasTransitions && !flags.hasTransitionAll) || (flags.hasAnimations && !flags.hasTransitions)); flags.applyAnimationDuration = options.duration && flags.hasAnimations; flags.applyTransitionDelay = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions); flags.applyAnimationDelay = truthyTimingValue(options.delay) && flags.hasAnimations; flags.recalculateTimingStyles = addRemoveClassName.length > 0; if (flags.applyTransitionDuration || flags.applyAnimationDuration) { maxDuration = options.duration ? parseFloat(options.duration) : maxDuration; if (flags.applyTransitionDuration) { flags.hasTransitions = true; timings.transitionDuration = maxDuration; applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0; temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration)); } if (flags.applyAnimationDuration) { flags.hasAnimations = true; timings.animationDuration = maxDuration; temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration)); } } if (maxDuration === 0 && !flags.recalculateTimingStyles) { return closeAndReturnNoopAnimator(); } if (options.delay != null) { var delayStyle = parseFloat(options.delay); if (flags.applyTransitionDelay) { temporaryStyles.push(getCssDelayStyle(delayStyle)); } if (flags.applyAnimationDelay) { temporaryStyles.push(getCssDelayStyle(delayStyle, true)); } } // we need to recalculate the delay value since we used a pre-emptive negative // delay value and the delay value is required for the final event checking. This // property will ensure that this will happen after the RAF phase has passed. if (options.duration == null && timings.transitionDuration > 0) { flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst; } maxDelayTime = maxDelay * ONE_SECOND; maxDurationTime = maxDuration * ONE_SECOND; if (!options.skipBlocking) { flags.blockTransition = timings.transitionDuration > 0; flags.blockKeyframeAnimation = timings.animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0; } if (options.from) { if (options.cleanupStyles) { registerRestorableStyles(restoreStyles, node, Object.keys(options.from)); } applyAnimationFromStyles(element, options); } if (flags.blockTransition || flags.blockKeyframeAnimation) { applyBlocking(maxDuration); } else if (!options.skipBlocking) { blockTransitions(node, false); } // TODO(matsko): for 1.5 change this code to have an animator object for better debugging return { $$willAnimate: true, end: endFn, start: function() { if (animationClosed) return; runnerHost = { end: endFn, cancel: cancelFn, resume: null, //this will be set during the start() phase pause: null }; runner = new $$AnimateRunner(runnerHost); waitUntilQuiet(start); // we don't have access to pause/resume the animation // since it hasn't run yet. AnimateRunner will therefore // set noop functions for resume and pause and they will // later be overridden once the animation is triggered return runner; } }; function endFn() { close(); } function cancelFn() { close(true); } function close(rejected) { // jshint ignore:line // if the promise has been called already then we shouldn't close // the animation again if (animationClosed || (animationCompleted && animationPaused)) return; animationClosed = true; animationPaused = false; if (!options.$$skipPreparationClasses) { $$jqLite.removeClass(element, preparationClasses); } $$jqLite.removeClass(element, activeClasses); blockKeyframeAnimations(node, false); blockTransitions(node, false); forEach(temporaryStyles, function(entry) { // There is only one way to remove inline style properties entirely from elements. // By using `removeProperty` this works, but we need to convert camel-cased CSS // styles down to hyphenated values. node.style[entry[0]] = ''; }); applyAnimationClasses(element, options); applyAnimationStyles(element, options); if (Object.keys(restoreStyles).length) { forEach(restoreStyles, function(value, prop) { value ? node.style.setProperty(prop, value) : node.style.removeProperty(prop); }); } // the reason why we have this option is to allow a synchronous closing callback // that is fired as SOON as the animation ends (when the CSS is removed) or if // the animation never takes off at all. A good example is a leave animation since // the element must be removed just after the animation is over or else the element // will appear on screen for one animation frame causing an overbearing flicker. if (options.onDone) { options.onDone(); } // if the preparation function fails then the promise is not setup if (runner) { runner.complete(!rejected); } } function applyBlocking(duration) { if (flags.blockTransition) { blockTransitions(node, duration); } if (flags.blockKeyframeAnimation) { blockKeyframeAnimations(node, !!duration); } } function closeAndReturnNoopAnimator() { runner = new $$AnimateRunner({ end: endFn, cancel: cancelFn }); // should flush the cache animation waitUntilQuiet(noop); close(); return { $$willAnimate: false, start: function() { return runner; }, end: endFn }; } function start() { if (animationClosed) return; if (!node.parentNode) { close(); return; } var startTime, events = []; // even though we only pause keyframe animations here the pause flag // will still happen when transitions are used. Only the transition will // not be paused since that is not possible. If the animation ends when // paused then it will not complete until unpaused or cancelled. var playPause = function(playAnimation) { if (!animationCompleted) { animationPaused = !playAnimation; if (timings.animationDuration) { var value = blockKeyframeAnimations(node, animationPaused); animationPaused ? temporaryStyles.push(value) : removeFromArray(temporaryStyles, value); } } else if (animationPaused && playAnimation) { animationPaused = false; close(); } }; // checking the stagger duration prevents an accidently cascade of the CSS delay style // being inherited from the parent. If the transition duration is zero then we can safely // rely that the delay value is an intential stagger delay style. var maxStagger = itemIndex > 0 && ((timings.transitionDuration && stagger.transitionDuration === 0) || (timings.animationDuration && stagger.animationDuration === 0)) && Math.max(stagger.animationDelay, stagger.transitionDelay); if (maxStagger) { $timeout(triggerAnimationStart, Math.floor(maxStagger * itemIndex * ONE_SECOND), false); } else { triggerAnimationStart(); } // this will decorate the existing promise runner with pause/resume methods runnerHost.resume = function() { playPause(true); }; runnerHost.pause = function() { playPause(false); }; function triggerAnimationStart() { // just incase a stagger animation kicks in when the animation // itself was cancelled entirely if (animationClosed) return; applyBlocking(false); forEach(temporaryStyles, function(entry) { var key = entry[0]; var value = entry[1]; node.style[key] = value; }); applyAnimationClasses(element, options); $$jqLite.addClass(element, activeClasses); if (flags.recalculateTimingStyles) { fullClassName = node.className + ' ' + preparationClasses; cacheKey = gcsHashFn(node, fullClassName); timings = computeTimings(node, fullClassName, cacheKey); relativeDelay = timings.maxDelay; maxDelay = Math.max(relativeDelay, 0); maxDuration = timings.maxDuration; if (maxDuration === 0) { close(); return; } flags.hasTransitions = timings.transitionDuration > 0; flags.hasAnimations = timings.animationDuration > 0; } if (flags.applyAnimationDelay) { relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay) ? parseFloat(options.delay) : relativeDelay; maxDelay = Math.max(relativeDelay, 0); timings.animationDelay = relativeDelay; delayStyle = getCssDelayStyle(relativeDelay, true); temporaryStyles.push(delayStyle); node.style[delayStyle[0]] = delayStyle[1]; } maxDelayTime = maxDelay * ONE_SECOND; maxDurationTime = maxDuration * ONE_SECOND; if (options.easing) { var easeProp, easeVal = options.easing; if (flags.hasTransitions) { easeProp = TRANSITION_PROP + TIMING_KEY; temporaryStyles.push([easeProp, easeVal]); node.style[easeProp] = easeVal; } if (flags.hasAnimations) { easeProp = ANIMATION_PROP + TIMING_KEY; temporaryStyles.push([easeProp, easeVal]); node.style[easeProp] = easeVal; } } if (timings.transitionDuration) { events.push(TRANSITIONEND_EVENT); } if (timings.animationDuration) { events.push(ANIMATIONEND_EVENT); } startTime = Date.now(); var timerTime = maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime; var endTime = startTime + timerTime; var animationsData = element.data(ANIMATE_TIMER_KEY) || []; var setupFallbackTimer = true; if (animationsData.length) { var currentTimerData = animationsData[0]; setupFallbackTimer = endTime > currentTimerData.expectedEndTime; if (setupFallbackTimer) { $timeout.cancel(currentTimerData.timer); } else { animationsData.push(close); } } if (setupFallbackTimer) { var timer = $timeout(onAnimationExpired, timerTime, false); animationsData[0] = { timer: timer, expectedEndTime: endTime }; animationsData.push(close); element.data(ANIMATE_TIMER_KEY, animationsData); } element.on(events.join(' '), onAnimationProgress); if (options.to) { if (options.cleanupStyles) { registerRestorableStyles(restoreStyles, node, Object.keys(options.to)); } applyAnimationToStyles(element, options); } } function onAnimationExpired() { var animationsData = element.data(ANIMATE_TIMER_KEY); // this will be false in the event that the element was // removed from the DOM (via a leave animation or something // similar) if (animationsData) { for (var i = 1; i < animationsData.length; i++) { animationsData[i](); } element.removeData(ANIMATE_TIMER_KEY); } } function onAnimationProgress(event) { event.stopPropagation(); var ev = event.originalEvent || event; var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now(); /* Firefox (or possibly just Gecko) likes to not round values up * when a ms measurement is used for the animation */ var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES)); /* $manualTimeStamp is a mocked timeStamp value which is set * within browserTrigger(). This is only here so that tests can * mock animations properly. Real events fallback to event.timeStamp, * or, if they don't, then a timeStamp is automatically created for them. * We're checking to see if the timeStamp surpasses the expected delay, * but we're using elapsedTime instead of the timeStamp on the 2nd * pre-condition since animations sometimes close off early */ if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) { // we set this flag to ensure that if the transition is paused then, when resumed, // the animation will automatically close itself since transitions cannot be paused. animationCompleted = true; close(); } } } }; }]; }]; var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationProvider) { $$animationProvider.drivers.push('$$animateCssDriver'); var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim'; var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor'; var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out'; var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in'; function isDocumentFragment(node) { return node.parentNode && node.parentNode.nodeType === 11; } this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$sniffer', '$$jqLite', '$document', function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $sniffer, $$jqLite, $document) { // only browsers that support these properties can render animations if (!$sniffer.animations && !$sniffer.transitions) return noop; var bodyNode = $document[0].body; var rootNode = getDomNode($rootElement); var rootBodyElement = jqLite( // this is to avoid using something that exists outside of the body // we also special case the doc fragement case because our unit test code // appends the $rootElement to the body after the app has been bootstrapped isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode ); var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); return function initDriverFn(animationDetails) { return animationDetails.from && animationDetails.to ? prepareFromToAnchorAnimation(animationDetails.from, animationDetails.to, animationDetails.classes, animationDetails.anchors) : prepareRegularAnimation(animationDetails); }; function filterCssClasses(classes) { //remove all the `ng-` stuff return classes.replace(/\bng-\S+\b/g, ''); } function getUniqueValues(a, b) { if (isString(a)) a = a.split(' '); if (isString(b)) b = b.split(' '); return a.filter(function(val) { return b.indexOf(val) === -1; }).join(' '); } function prepareAnchoredAnimation(classes, outAnchor, inAnchor) { var clone = jqLite(getDomNode(outAnchor).cloneNode(true)); var startingClasses = filterCssClasses(getClassVal(clone)); outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME); inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME); clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME); rootBodyElement.append(clone); var animatorIn, animatorOut = prepareOutAnimation(); // the user may not end up using the `out` animation and // only making use of the `in` animation or vice-versa. // In either case we should allow this and not assume the // animation is over unless both animations are not used. if (!animatorOut) { animatorIn = prepareInAnimation(); if (!animatorIn) { return end(); } } var startingAnimator = animatorOut || animatorIn; return { start: function() { var runner; var currentAnimation = startingAnimator.start(); currentAnimation.done(function() { currentAnimation = null; if (!animatorIn) { animatorIn = prepareInAnimation(); if (animatorIn) { currentAnimation = animatorIn.start(); currentAnimation.done(function() { currentAnimation = null; end(); runner.complete(); }); return currentAnimation; } } // in the event that there is no `in` animation end(); runner.complete(); }); runner = new $$AnimateRunner({ end: endFn, cancel: endFn }); return runner; function endFn() { if (currentAnimation) { currentAnimation.end(); } } } }; function calculateAnchorStyles(anchor) { var styles = {}; var coords = getDomNode(anchor).getBoundingClientRect(); // we iterate directly since safari messes up and doesn't return // all the keys for the coods object when iterated forEach(['width','height','top','left'], function(key) { var value = coords[key]; switch (key) { case 'top': value += bodyNode.scrollTop; break; case 'left': value += bodyNode.scrollLeft; break; } styles[key] = Math.floor(value) + 'px'; }); return styles; } function prepareOutAnimation() { var animator = $animateCss(clone, { addClass: NG_OUT_ANCHOR_CLASS_NAME, delay: true, from: calculateAnchorStyles(outAnchor) }); // read the comment within `prepareRegularAnimation` to understand // why this check is necessary return animator.$$willAnimate ? animator : null; } function getClassVal(element) { return element.attr('class') || ''; } function prepareInAnimation() { var endingClasses = filterCssClasses(getClassVal(inAnchor)); var toAdd = getUniqueValues(endingClasses, startingClasses); var toRemove = getUniqueValues(startingClasses, endingClasses); var animator = $animateCss(clone, { to: calculateAnchorStyles(inAnchor), addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd, removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove, delay: true }); // read the comment within `prepareRegularAnimation` to understand // why this check is necessary return animator.$$willAnimate ? animator : null; } function end() { clone.remove(); outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME); inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME); } } function prepareFromToAnchorAnimation(from, to, classes, anchors) { var fromAnimation = prepareRegularAnimation(from, noop); var toAnimation = prepareRegularAnimation(to, noop); var anchorAnimations = []; forEach(anchors, function(anchor) { var outElement = anchor['out']; var inElement = anchor['in']; var animator = prepareAnchoredAnimation(classes, outElement, inElement); if (animator) { anchorAnimations.push(animator); } }); // no point in doing anything when there are no elements to animate if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return; return { start: function() { var animationRunners = []; if (fromAnimation) { animationRunners.push(fromAnimation.start()); } if (toAnimation) { animationRunners.push(toAnimation.start()); } forEach(anchorAnimations, function(animation) { animationRunners.push(animation.start()); }); var runner = new $$AnimateRunner({ end: endFn, cancel: endFn // CSS-driven animations cannot be cancelled, only ended }); $$AnimateRunner.all(animationRunners, function(status) { runner.complete(status); }); return runner; function endFn() { forEach(animationRunners, function(runner) { runner.end(); }); } } }; } function prepareRegularAnimation(animationDetails) { var element = animationDetails.element; var options = animationDetails.options || {}; if (animationDetails.structural) { options.event = animationDetails.event; options.structural = true; options.applyClassesEarly = true; // we special case the leave animation since we want to ensure that // the element is removed as soon as the animation is over. Otherwise // a flicker might appear or the element may not be removed at all if (animationDetails.event === 'leave') { options.onDone = options.domOperation; } } // We assign the preparationClasses as the actual animation event since // the internals of $animateCss will just suffix the event token values // with `-active` to trigger the animation. if (options.preparationClasses) { options.event = concatWithSpace(options.event, options.preparationClasses); } var animator = $animateCss(element, options); // the driver lookup code inside of $$animation attempts to spawn a // driver one by one until a driver returns a.$$willAnimate animator object. // $animateCss will always return an object, however, it will pass in // a flag as a hint as to whether an animation was detected or not return animator.$$willAnimate ? animator : null; } }]; }]; // TODO(matsko): use caching here to speed things up for detection // TODO(matsko): add documentation // by the time... var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { this.$get = ['$injector', '$$AnimateRunner', '$$jqLite', function($injector, $$AnimateRunner, $$jqLite) { var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); // $animateJs(element, 'enter'); return function(element, event, classes, options) { // the `classes` argument is optional and if it is not used // then the classes will be resolved from the element's className // property as well as options.addClass/options.removeClass. if (arguments.length === 3 && isObject(classes)) { options = classes; classes = null; } options = prepareAnimationOptions(options); if (!classes) { classes = element.attr('class') || ''; if (options.addClass) { classes += ' ' + options.addClass; } if (options.removeClass) { classes += ' ' + options.removeClass; } } var classesToAdd = options.addClass; var classesToRemove = options.removeClass; // the lookupAnimations function returns a series of animation objects that are // matched up with one or more of the CSS classes. These animation objects are // defined via the module.animation factory function. If nothing is detected then // we don't return anything which then makes $animation query the next driver. var animations = lookupAnimations(classes); var before, after; if (animations.length) { var afterFn, beforeFn; if (event == 'leave') { beforeFn = 'leave'; afterFn = 'afterLeave'; // TODO(matsko): get rid of this } else { beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1); afterFn = event; } if (event !== 'enter' && event !== 'move') { before = packageAnimations(element, event, options, animations, beforeFn); } after = packageAnimations(element, event, options, animations, afterFn); } // no matching animations if (!before && !after) return; function applyOptions() { options.domOperation(); applyAnimationClasses(element, options); } return { start: function() { var closeActiveAnimations; var chain = []; if (before) { chain.push(function(fn) { closeActiveAnimations = before(fn); }); } if (chain.length) { chain.push(function(fn) { applyOptions(); fn(true); }); } else { applyOptions(); } if (after) { chain.push(function(fn) { closeActiveAnimations = after(fn); }); } var animationClosed = false; var runner = new $$AnimateRunner({ end: function() { endAnimations(); }, cancel: function() { endAnimations(true); } }); $$AnimateRunner.chain(chain, onComplete); return runner; function onComplete(success) { animationClosed = true; applyOptions(); applyAnimationStyles(element, options); runner.complete(success); } function endAnimations(cancelled) { if (!animationClosed) { (closeActiveAnimations || noop)(cancelled); onComplete(cancelled); } } } }; function executeAnimationFn(fn, element, event, options, onDone) { var args; switch (event) { case 'animate': args = [element, options.from, options.to, onDone]; break; case 'setClass': args = [element, classesToAdd, classesToRemove, onDone]; break; case 'addClass': args = [element, classesToAdd, onDone]; break; case 'removeClass': args = [element, classesToRemove, onDone]; break; default: args = [element, onDone]; break; } args.push(options); var value = fn.apply(fn, args); if (value) { if (isFunction(value.start)) { value = value.start(); } if (value instanceof $$AnimateRunner) { value.done(onDone); } else if (isFunction(value)) { // optional onEnd / onCancel callback return value; } } return noop; } function groupEventedAnimations(element, event, options, animations, fnName) { var operations = []; forEach(animations, function(ani) { var animation = ani[fnName]; if (!animation) return; // note that all of these animations will run in parallel operations.push(function() { var runner; var endProgressCb; var resolved = false; var onAnimationComplete = function(rejected) { if (!resolved) { resolved = true; (endProgressCb || noop)(rejected); runner.complete(!rejected); } }; runner = new $$AnimateRunner({ end: function() { onAnimationComplete(); }, cancel: function() { onAnimationComplete(true); } }); endProgressCb = executeAnimationFn(animation, element, event, options, function(result) { var cancelled = result === false; onAnimationComplete(cancelled); }); return runner; }); }); return operations; } function packageAnimations(element, event, options, animations, fnName) { var operations = groupEventedAnimations(element, event, options, animations, fnName); if (operations.length === 0) { var a,b; if (fnName === 'beforeSetClass') { a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass'); b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass'); } else if (fnName === 'setClass') { a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass'); b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass'); } if (a) { operations = operations.concat(a); } if (b) { operations = operations.concat(b); } } if (operations.length === 0) return; // TODO(matsko): add documentation return function startAnimation(callback) { var runners = []; if (operations.length) { forEach(operations, function(animateFn) { runners.push(animateFn()); }); } runners.length ? $$AnimateRunner.all(runners, callback) : callback(); return function endFn(reject) { forEach(runners, function(runner) { reject ? runner.cancel() : runner.end(); }); }; }; } }; function lookupAnimations(classes) { classes = isArray(classes) ? classes : classes.split(' '); var matches = [], flagMap = {}; for (var i=0; i < classes.length; i++) { var klass = classes[i], animationFactory = $animateProvider.$$registeredAnimations[klass]; if (animationFactory && !flagMap[klass]) { matches.push($injector.get(animationFactory)); flagMap[klass] = true; } } return matches; } }]; }]; var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProvider) { $$animationProvider.drivers.push('$$animateJsDriver'); this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) { return function initDriverFn(animationDetails) { if (animationDetails.from && animationDetails.to) { var fromAnimation = prepareAnimation(animationDetails.from); var toAnimation = prepareAnimation(animationDetails.to); if (!fromAnimation && !toAnimation) return; return { start: function() { var animationRunners = []; if (fromAnimation) { animationRunners.push(fromAnimation.start()); } if (toAnimation) { animationRunners.push(toAnimation.start()); } $$AnimateRunner.all(animationRunners, done); var runner = new $$AnimateRunner({ end: endFnFactory(), cancel: endFnFactory() }); return runner; function endFnFactory() { return function() { forEach(animationRunners, function(runner) { // at this point we cannot cancel animations for groups just yet. 1.5+ runner.end(); }); }; } function done(status) { runner.complete(status); } } }; } else { return prepareAnimation(animationDetails); } }; function prepareAnimation(animationDetails) { // TODO(matsko): make sure to check for grouped animations and delegate down to normal animations var element = animationDetails.element; var event = animationDetails.event; var options = animationDetails.options; var classes = animationDetails.classes; return $$animateJs(element, event, classes, options); } }]; }]; var NG_ANIMATE_ATTR_NAME = 'data-ng-animate'; var NG_ANIMATE_PIN_DATA = '$ngAnimatePin'; var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { var PRE_DIGEST_STATE = 1; var RUNNING_STATE = 2; var rules = this.rules = { skip: [], cancel: [], join: [] }; function isAllowed(ruleType, element, currentAnimation, previousAnimation) { return rules[ruleType].some(function(fn) { return fn(element, currentAnimation, previousAnimation); }); } function hasAnimationClasses(options, and) { options = options || {}; var a = (options.addClass || '').length > 0; var b = (options.removeClass || '').length > 0; return and ? a && b : a || b; } rules.join.push(function(element, newAnimation, currentAnimation) { // if the new animation is class-based then we can just tack that on return !newAnimation.structural && hasAnimationClasses(newAnimation.options); }); rules.skip.push(function(element, newAnimation, currentAnimation) { // there is no need to animate anything if no classes are being added and // there is no structural animation that will be triggered return !newAnimation.structural && !hasAnimationClasses(newAnimation.options); }); rules.skip.push(function(element, newAnimation, currentAnimation) { // why should we trigger a new structural animation if the element will // be removed from the DOM anyway? return currentAnimation.event == 'leave' && newAnimation.structural; }); rules.skip.push(function(element, newAnimation, currentAnimation) { // if there is an ongoing current animation then don't even bother running the class-based animation return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural; }); rules.cancel.push(function(element, newAnimation, currentAnimation) { // there can never be two structural animations running at the same time return currentAnimation.structural && newAnimation.structural; }); rules.cancel.push(function(element, newAnimation, currentAnimation) { // if the previous animation is already running, but the new animation will // be triggered, but the new animation is structural return currentAnimation.state === RUNNING_STATE && newAnimation.structural; }); rules.cancel.push(function(element, newAnimation, currentAnimation) { var nO = newAnimation.options; var cO = currentAnimation.options; // if the exact same CSS class is added/removed then it's safe to cancel it return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass); }); this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap', '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow', function($$rAF, $rootScope, $rootElement, $document, $$HashMap, $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) { var activeAnimationsLookup = new $$HashMap(); var disabledElementsLookup = new $$HashMap(); var animationsEnabled = null; function postDigestTaskFactory() { var postDigestCalled = false; return function(fn) { // we only issue a call to postDigest before // it has first passed. This prevents any callbacks // from not firing once the animation has completed // since it will be out of the digest cycle. if (postDigestCalled) { fn(); } else { $rootScope.$$postDigest(function() { postDigestCalled = true; fn(); }); } }; } // Wait until all directive and route-related templates are downloaded and // compiled. The $templateRequest.totalPendingRequests variable keeps track of // all of the remote templates being currently downloaded. If there are no // templates currently downloading then the watcher will still fire anyway. var deregisterWatch = $rootScope.$watch( function() { return $templateRequest.totalPendingRequests === 0; }, function(isEmpty) { if (!isEmpty) return; deregisterWatch(); // Now that all templates have been downloaded, $animate will wait until // the post digest queue is empty before enabling animations. By having two // calls to $postDigest calls we can ensure that the flag is enabled at the // very end of the post digest queue. Since all of the animations in $animate // use $postDigest, it's important that the code below executes at the end. // This basically means that the page is fully downloaded and compiled before // any animations are triggered. $rootScope.$$postDigest(function() { $rootScope.$$postDigest(function() { // we check for null directly in the event that the application already called // .enabled() with whatever arguments that it provided it with if (animationsEnabled === null) { animationsEnabled = true; } }); }); } ); var callbackRegistry = {}; // remember that the classNameFilter is set during the provider/config // stage therefore we can optimize here and setup a helper function var classNameFilter = $animateProvider.classNameFilter(); var isAnimatableClassName = !classNameFilter ? function() { return true; } : function(className) { return classNameFilter.test(className); }; var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); function normalizeAnimationOptions(element, options) { return mergeAnimationOptions(element, options, {}); } function findCallbacks(parent, element, event) { var targetNode = getDomNode(element); var targetParentNode = getDomNode(parent); var matches = []; var entries = callbackRegistry[event]; if (entries) { forEach(entries, function(entry) { if (entry.node.contains(targetNode)) { matches.push(entry.callback); } else if (event === 'leave' && entry.node.contains(targetParentNode)) { matches.push(entry.callback); } }); } return matches; } return { on: function(event, container, callback) { var node = extractElementNode(container); callbackRegistry[event] = callbackRegistry[event] || []; callbackRegistry[event].push({ node: node, callback: callback }); }, off: function(event, container, callback) { var entries = callbackRegistry[event]; if (!entries) return; callbackRegistry[event] = arguments.length === 1 ? null : filterFromRegistry(entries, container, callback); function filterFromRegistry(list, matchContainer, matchCallback) { var containerNode = extractElementNode(matchContainer); return list.filter(function(entry) { var isMatch = entry.node === containerNode && (!matchCallback || entry.callback === matchCallback); return !isMatch; }); } }, pin: function(element, parentElement) { assertArg(isElement(element), 'element', 'not an element'); assertArg(isElement(parentElement), 'parentElement', 'not an element'); element.data(NG_ANIMATE_PIN_DATA, parentElement); }, push: function(element, event, options, domOperation) { options = options || {}; options.domOperation = domOperation; return queueAnimation(element, event, options); }, // this method has four signatures: // () - global getter // (bool) - global setter // (element) - element getter // (element, bool) - element setter enabled: function(element, bool) { var argCount = arguments.length; if (argCount === 0) { // () - Global getter bool = !!animationsEnabled; } else { var hasElement = isElement(element); if (!hasElement) { // (bool) - Global setter bool = animationsEnabled = !!element; } else { var node = getDomNode(element); var recordExists = disabledElementsLookup.get(node); if (argCount === 1) { // (element) - Element getter bool = !recordExists; } else { // (element, bool) - Element setter bool = !!bool; if (!bool) { disabledElementsLookup.put(node, true); } else if (recordExists) { disabledElementsLookup.remove(node); } } } } return bool; } }; function queueAnimation(element, event, options) { var node, parent; element = stripCommentsFromElement(element); if (element) { node = getDomNode(element); parent = element.parent(); } options = prepareAnimationOptions(options); // we create a fake runner with a working promise. // These methods will become available after the digest has passed var runner = new $$AnimateRunner(); // this is used to trigger callbacks in postDigest mode var runInNextPostDigestOrNow = postDigestTaskFactory(); if (isArray(options.addClass)) { options.addClass = options.addClass.join(' '); } if (options.addClass && !isString(options.addClass)) { options.addClass = null; } if (isArray(options.removeClass)) { options.removeClass = options.removeClass.join(' '); } if (options.removeClass && !isString(options.removeClass)) { options.removeClass = null; } if (options.from && !isObject(options.from)) { options.from = null; } if (options.to && !isObject(options.to)) { options.to = null; } // there are situations where a directive issues an animation for // a jqLite wrapper that contains only comment nodes... If this // happens then there is no way we can perform an animation if (!node) { close(); return runner; } var className = [node.className, options.addClass, options.removeClass].join(' '); if (!isAnimatableClassName(className)) { close(); return runner; } var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0; // this is a hard disable of all animations for the application or on // the element itself, therefore there is no need to continue further // past this point if not enabled var skipAnimations = !animationsEnabled || disabledElementsLookup.get(node); var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {}; var hasExistingAnimation = !!existingAnimation.state; // there is no point in traversing the same collection of parent ancestors if a followup // animation will be run on the same element that already did all that checking work if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state != PRE_DIGEST_STATE)) { skipAnimations = !areAnimationsAllowed(element, parent, event); } if (skipAnimations) { close(); return runner; } if (isStructural) { closeChildAnimations(element); } var newAnimation = { structural: isStructural, element: element, event: event, close: close, options: options, runner: runner }; if (hasExistingAnimation) { var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation); if (skipAnimationFlag) { if (existingAnimation.state === RUNNING_STATE) { close(); return runner; } else { mergeAnimationOptions(element, existingAnimation.options, options); return existingAnimation.runner; } } var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation); if (cancelAnimationFlag) { if (existingAnimation.state === RUNNING_STATE) { // this will end the animation right away and it is safe // to do so since the animation is already running and the // runner callback code will run in async existingAnimation.runner.end(); } else if (existingAnimation.structural) { // this means that the animation is queued into a digest, but // hasn't started yet. Therefore it is safe to run the close // method which will call the runner methods in async. existingAnimation.close(); } else { // this will merge the new animation options into existing animation options mergeAnimationOptions(element, existingAnimation.options, newAnimation.options); return existingAnimation.runner; } } else { // a joined animation means that this animation will take over the existing one // so an example would involve a leave animation taking over an enter. Then when // the postDigest kicks in the enter will be ignored. var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation); if (joinAnimationFlag) { if (existingAnimation.state === RUNNING_STATE) { normalizeAnimationOptions(element, options); } else { applyGeneratedPreparationClasses(element, isStructural ? event : null, options); event = newAnimation.event = existingAnimation.event; options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options); //we return the same runner since only the option values of this animation will //be fed into the `existingAnimation`. return existingAnimation.runner; } } } } else { // normalization in this case means that it removes redundant CSS classes that // already exist (addClass) or do not exist (removeClass) on the element normalizeAnimationOptions(element, options); } // when the options are merged and cleaned up we may end up not having to do // an animation at all, therefore we should check this before issuing a post // digest callback. Structural animations will always run no matter what. var isValidAnimation = newAnimation.structural; if (!isValidAnimation) { // animate (from/to) can be quickly checked first, otherwise we check if any classes are present isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0) || hasAnimationClasses(newAnimation.options); } if (!isValidAnimation) { close(); clearElementAnimationState(element); return runner; } // the counter keeps track of cancelled animations var counter = (existingAnimation.counter || 0) + 1; newAnimation.counter = counter; markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation); $rootScope.$$postDigest(function() { var animationDetails = activeAnimationsLookup.get(node); var animationCancelled = !animationDetails; animationDetails = animationDetails || {}; // if addClass/removeClass is called before something like enter then the // registered parent element may not be present. The code below will ensure // that a final value for parent element is obtained var parentElement = element.parent() || []; // animate/structural/class-based animations all have requirements. Otherwise there // is no point in performing an animation. The parent node must also be set. var isValidAnimation = parentElement.length > 0 && (animationDetails.event === 'animate' || animationDetails.structural || hasAnimationClasses(animationDetails.options)); // this means that the previous animation was cancelled // even if the follow-up animation is the same event if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) { // if another animation did not take over then we need // to make sure that the domOperation and options are // handled accordingly if (animationCancelled) { applyAnimationClasses(element, options); applyAnimationStyles(element, options); } // if the event changed from something like enter to leave then we do // it, otherwise if it's the same then the end result will be the same too if (animationCancelled || (isStructural && animationDetails.event !== event)) { options.domOperation(); runner.end(); } // in the event that the element animation was not cancelled or a follow-up animation // isn't allowed to animate from here then we need to clear the state of the element // so that any future animations won't read the expired animation data. if (!isValidAnimation) { clearElementAnimationState(element); } return; } // this combined multiple class to addClass / removeClass into a setClass event // so long as a structural event did not take over the animation event = !animationDetails.structural && hasAnimationClasses(animationDetails.options, true) ? 'setClass' : animationDetails.event; markElementAnimationState(element, RUNNING_STATE); var realRunner = $$animation(element, event, animationDetails.options); realRunner.done(function(status) { close(!status); var animationDetails = activeAnimationsLookup.get(node); if (animationDetails && animationDetails.counter === counter) { clearElementAnimationState(getDomNode(element)); } notifyProgress(runner, event, 'close', {}); }); // this will update the runner's flow-control events based on // the `realRunner` object. runner.setHost(realRunner); notifyProgress(runner, event, 'start', {}); }); return runner; function notifyProgress(runner, event, phase, data) { runInNextPostDigestOrNow(function() { var callbacks = findCallbacks(parent, element, event); if (callbacks.length) { // do not optimize this call here to RAF because // we don't know how heavy the callback code here will // be and if this code is buffered then this can // lead to a performance regression. $$rAF(function() { forEach(callbacks, function(callback) { callback(element, phase, data); }); }); } }); runner.progress(event, phase, data); } function close(reject) { // jshint ignore:line clearGeneratedClasses(element, options); applyAnimationClasses(element, options); applyAnimationStyles(element, options); options.domOperation(); runner.complete(!reject); } } function closeChildAnimations(element) { var node = getDomNode(element); var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']'); forEach(children, function(child) { var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME)); var animationDetails = activeAnimationsLookup.get(child); switch (state) { case RUNNING_STATE: animationDetails.runner.end(); /* falls through */ case PRE_DIGEST_STATE: if (animationDetails) { activeAnimationsLookup.remove(child); } break; } }); } function clearElementAnimationState(element) { var node = getDomNode(element); node.removeAttribute(NG_ANIMATE_ATTR_NAME); activeAnimationsLookup.remove(node); } function isMatchingElement(nodeOrElmA, nodeOrElmB) { return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB); } function areAnimationsAllowed(element, parentElement, event) { var bodyElement = jqLite($document[0].body); var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML'; var rootElementDetected = isMatchingElement(element, $rootElement); var parentAnimationDetected = false; var animateChildren; var parentHost = element.data(NG_ANIMATE_PIN_DATA); if (parentHost) { parentElement = parentHost; } while (parentElement && parentElement.length) { if (!rootElementDetected) { // angular doesn't want to attempt to animate elements outside of the application // therefore we need to ensure that the rootElement is an ancestor of the current element rootElementDetected = isMatchingElement(parentElement, $rootElement); } var parentNode = parentElement[0]; if (parentNode.nodeType !== ELEMENT_NODE) { // no point in inspecting the #document element break; } var details = activeAnimationsLookup.get(parentNode) || {}; // either an enter, leave or move animation will commence // therefore we can't allow any animations to take place // but if a parent animation is class-based then that's ok if (!parentAnimationDetected) { parentAnimationDetected = details.structural || disabledElementsLookup.get(parentNode); } if (isUndefined(animateChildren) || animateChildren === true) { var value = parentElement.data(NG_ANIMATE_CHILDREN_DATA); if (isDefined(value)) { animateChildren = value; } } // there is no need to continue traversing at this point if (parentAnimationDetected && animateChildren === false) break; if (!rootElementDetected) { // angular doesn't want to attempt to animate elements outside of the application // therefore we need to ensure that the rootElement is an ancestor of the current element rootElementDetected = isMatchingElement(parentElement, $rootElement); if (!rootElementDetected) { parentHost = parentElement.data(NG_ANIMATE_PIN_DATA); if (parentHost) { parentElement = parentHost; } } } if (!bodyElementDetected) { // we also need to ensure that the element is or will be apart of the body element // otherwise it is pointless to even issue an animation to be rendered bodyElementDetected = isMatchingElement(parentElement, bodyElement); } parentElement = parentElement.parent(); } var allowAnimation = !parentAnimationDetected || animateChildren; return allowAnimation && rootElementDetected && bodyElementDetected; } function markElementAnimationState(element, state, details) { details = details || {}; details.state = state; var node = getDomNode(element); node.setAttribute(NG_ANIMATE_ATTR_NAME, state); var oldValue = activeAnimationsLookup.get(node); var newValue = oldValue ? extend(oldValue, details) : details; activeAnimationsLookup.put(node, newValue); } }]; }]; var $$AnimateAsyncRunFactory = ['$$rAF', function($$rAF) { var waitQueue = []; function waitForTick(fn) { waitQueue.push(fn); if (waitQueue.length > 1) return; $$rAF(function() { for (var i = 0; i < waitQueue.length; i++) { waitQueue[i](); } waitQueue = []; }); } return function() { var passed = false; waitForTick(function() { passed = true; }); return function(callback) { passed ? callback() : waitForTick(callback); }; }; }]; var $$AnimateRunnerFactory = ['$q', '$sniffer', '$$animateAsyncRun', function($q, $sniffer, $$animateAsyncRun) { var INITIAL_STATE = 0; var DONE_PENDING_STATE = 1; var DONE_COMPLETE_STATE = 2; AnimateRunner.chain = function(chain, callback) { var index = 0; next(); function next() { if (index === chain.length) { callback(true); return; } chain[index](function(response) { if (response === false) { callback(false); return; } index++; next(); }); } }; AnimateRunner.all = function(runners, callback) { var count = 0; var status = true; forEach(runners, function(runner) { runner.done(onProgress); }); function onProgress(response) { status = status && response; if (++count === runners.length) { callback(status); } } }; function AnimateRunner(host) { this.setHost(host); this._doneCallbacks = []; this._runInAnimationFrame = $$animateAsyncRun(); this._state = 0; } AnimateRunner.prototype = { setHost: function(host) { this.host = host || {}; }, done: function(fn) { if (this._state === DONE_COMPLETE_STATE) { fn(); } else { this._doneCallbacks.push(fn); } }, progress: noop, getPromise: function() { if (!this.promise) { var self = this; this.promise = $q(function(resolve, reject) { self.done(function(status) { status === false ? reject() : resolve(); }); }); } return this.promise; }, then: function(resolveHandler, rejectHandler) { return this.getPromise().then(resolveHandler, rejectHandler); }, 'catch': function(handler) { return this.getPromise()['catch'](handler); }, 'finally': function(handler) { return this.getPromise()['finally'](handler); }, pause: function() { if (this.host.pause) { this.host.pause(); } }, resume: function() { if (this.host.resume) { this.host.resume(); } }, end: function() { if (this.host.end) { this.host.end(); } this._resolve(true); }, cancel: function() { if (this.host.cancel) { this.host.cancel(); } this._resolve(false); }, complete: function(response) { var self = this; if (self._state === INITIAL_STATE) { self._state = DONE_PENDING_STATE; self._runInAnimationFrame(function() { self._resolve(response); }); } }, _resolve: function(response) { if (this._state !== DONE_COMPLETE_STATE) { forEach(this._doneCallbacks, function(fn) { fn(response); }); this._doneCallbacks.length = 0; this._state = DONE_COMPLETE_STATE; } } }; return AnimateRunner; }]; var $$AnimationProvider = ['$animateProvider', function($animateProvider) { var NG_ANIMATE_REF_ATTR = 'ng-animate-ref'; var drivers = this.drivers = []; var RUNNER_STORAGE_KEY = '$$animationRunner'; function setRunner(element, runner) { element.data(RUNNER_STORAGE_KEY, runner); } function removeRunner(element) { element.removeData(RUNNER_STORAGE_KEY); } function getRunner(element) { return element.data(RUNNER_STORAGE_KEY); } this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap', '$$rAFScheduler', function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap, $$rAFScheduler) { var animationQueue = []; var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); function sortAnimations(animations) { var tree = { children: [] }; var i, lookup = new $$HashMap(); // this is done first beforehand so that the hashmap // is filled with a list of the elements that will be animated for (i = 0; i < animations.length; i++) { var animation = animations[i]; lookup.put(animation.domNode, animations[i] = { domNode: animation.domNode, fn: animation.fn, children: [] }); } for (i = 0; i < animations.length; i++) { processNode(animations[i]); } return flatten(tree); function processNode(entry) { if (entry.processed) return entry; entry.processed = true; var elementNode = entry.domNode; var parentNode = elementNode.parentNode; lookup.put(elementNode, entry); var parentEntry; while (parentNode) { parentEntry = lookup.get(parentNode); if (parentEntry) { if (!parentEntry.processed) { parentEntry = processNode(parentEntry); } break; } parentNode = parentNode.parentNode; } (parentEntry || tree).children.push(entry); return entry; } function flatten(tree) { var result = []; var queue = []; var i; for (i = 0; i < tree.children.length; i++) { queue.push(tree.children[i]); } var remainingLevelEntries = queue.length; var nextLevelEntries = 0; var row = []; for (i = 0; i < queue.length; i++) { var entry = queue[i]; if (remainingLevelEntries <= 0) { remainingLevelEntries = nextLevelEntries; nextLevelEntries = 0; result.push(row); row = []; } row.push(entry.fn); entry.children.forEach(function(childEntry) { nextLevelEntries++; queue.push(childEntry); }); remainingLevelEntries--; } if (row.length) { result.push(row); } return result; } } // TODO(matsko): document the signature in a better way return function(element, event, options) { options = prepareAnimationOptions(options); var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0; // there is no animation at the current moment, however // these runner methods will get later updated with the // methods leading into the driver's end/cancel methods // for now they just stop the animation from starting var runner = new $$AnimateRunner({ end: function() { close(); }, cancel: function() { close(true); } }); if (!drivers.length) { close(); return runner; } setRunner(element, runner); var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass)); var tempClasses = options.tempClasses; if (tempClasses) { classes += ' ' + tempClasses; options.tempClasses = null; } animationQueue.push({ // this data is used by the postDigest code and passed into // the driver step function element: element, classes: classes, event: event, structural: isStructural, options: options, beforeStart: beforeStart, close: close }); element.on('$destroy', handleDestroyedElement); // we only want there to be one function called within the post digest // block. This way we can group animations for all the animations that // were apart of the same postDigest flush call. if (animationQueue.length > 1) return runner; $rootScope.$$postDigest(function() { var animations = []; forEach(animationQueue, function(entry) { // the element was destroyed early on which removed the runner // form its storage. This means we can't animate this element // at all and it already has been closed due to destruction. if (getRunner(entry.element)) { animations.push(entry); } else { entry.close(); } }); // now any future animations will be in another postDigest animationQueue.length = 0; var groupedAnimations = groupAnimations(animations); var toBeSortedAnimations = []; forEach(groupedAnimations, function(animationEntry) { toBeSortedAnimations.push({ domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element), fn: function triggerAnimationStart() { // it's important that we apply the `ng-animate` CSS class and the // temporary classes before we do any driver invoking since these // CSS classes may be required for proper CSS detection. animationEntry.beforeStart(); var startAnimationFn, closeFn = animationEntry.close; // in the event that the element was removed before the digest runs or // during the RAF sequencing then we should not trigger the animation. var targetElement = animationEntry.anchors ? (animationEntry.from.element || animationEntry.to.element) : animationEntry.element; if (getRunner(targetElement)) { var operation = invokeFirstDriver(animationEntry); if (operation) { startAnimationFn = operation.start; } } if (!startAnimationFn) { closeFn(); } else { var animationRunner = startAnimationFn(); animationRunner.done(function(status) { closeFn(!status); }); updateAnimationRunners(animationEntry, animationRunner); } } }); }); // we need to sort each of the animations in order of parent to child // relationships. This ensures that the child classes are applied at the // right time. $$rAFScheduler(sortAnimations(toBeSortedAnimations)); }); return runner; // TODO(matsko): change to reference nodes function getAnchorNodes(node) { var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']'; var items = node.hasAttribute(NG_ANIMATE_REF_ATTR) ? [node] : node.querySelectorAll(SELECTOR); var anchors = []; forEach(items, function(node) { var attr = node.getAttribute(NG_ANIMATE_REF_ATTR); if (attr && attr.length) { anchors.push(node); } }); return anchors; } function groupAnimations(animations) { var preparedAnimations = []; var refLookup = {}; forEach(animations, function(animation, index) { var element = animation.element; var node = getDomNode(element); var event = animation.event; var enterOrMove = ['enter', 'move'].indexOf(event) >= 0; var anchorNodes = animation.structural ? getAnchorNodes(node) : []; if (anchorNodes.length) { var direction = enterOrMove ? 'to' : 'from'; forEach(anchorNodes, function(anchor) { var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR); refLookup[key] = refLookup[key] || {}; refLookup[key][direction] = { animationID: index, element: jqLite(anchor) }; }); } else { preparedAnimations.push(animation); } }); var usedIndicesLookup = {}; var anchorGroups = {}; forEach(refLookup, function(operations, key) { var from = operations.from; var to = operations.to; if (!from || !to) { // only one of these is set therefore we can't have an // anchor animation since all three pieces are required var index = from ? from.animationID : to.animationID; var indexKey = index.toString(); if (!usedIndicesLookup[indexKey]) { usedIndicesLookup[indexKey] = true; preparedAnimations.push(animations[index]); } return; } var fromAnimation = animations[from.animationID]; var toAnimation = animations[to.animationID]; var lookupKey = from.animationID.toString(); if (!anchorGroups[lookupKey]) { var group = anchorGroups[lookupKey] = { structural: true, beforeStart: function() { fromAnimation.beforeStart(); toAnimation.beforeStart(); }, close: function() { fromAnimation.close(); toAnimation.close(); }, classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes), from: fromAnimation, to: toAnimation, anchors: [] // TODO(matsko): change to reference nodes }; // the anchor animations require that the from and to elements both have at least // one shared CSS class which effictively marries the two elements together to use // the same animation driver and to properly sequence the anchor animation. if (group.classes.length) { preparedAnimations.push(group); } else { preparedAnimations.push(fromAnimation); preparedAnimations.push(toAnimation); } } anchorGroups[lookupKey].anchors.push({ 'out': from.element, 'in': to.element }); }); return preparedAnimations; } function cssClassesIntersection(a,b) { a = a.split(' '); b = b.split(' '); var matches = []; for (var i = 0; i < a.length; i++) { var aa = a[i]; if (aa.substring(0,3) === 'ng-') continue; for (var j = 0; j < b.length; j++) { if (aa === b[j]) { matches.push(aa); break; } } } return matches.join(' '); } function invokeFirstDriver(animationDetails) { // we loop in reverse order since the more general drivers (like CSS and JS) // may attempt more elements, but custom drivers are more particular for (var i = drivers.length - 1; i >= 0; i--) { var driverName = drivers[i]; if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check var factory = $injector.get(driverName); var driver = factory(animationDetails); if (driver) { return driver; } } } function beforeStart() { element.addClass(NG_ANIMATE_CLASSNAME); if (tempClasses) { $$jqLite.addClass(element, tempClasses); } } function updateAnimationRunners(animation, newRunner) { if (animation.from && animation.to) { update(animation.from.element); update(animation.to.element); } else { update(animation.element); } function update(element) { getRunner(element).setHost(newRunner); } } function handleDestroyedElement() { var runner = getRunner(element); if (runner && (event !== 'leave' || !options.$$domOperationFired)) { runner.end(); } } function close(rejected) { // jshint ignore:line element.off('$destroy', handleDestroyedElement); removeRunner(element); applyAnimationClasses(element, options); applyAnimationStyles(element, options); options.domOperation(); if (tempClasses) { $$jqLite.removeClass(element, tempClasses); } element.removeClass(NG_ANIMATE_CLASSNAME); runner.complete(!rejected); } }; }]; }]; /* global angularAnimateModule: true, $$AnimateAsyncRunFactory, $$rAFSchedulerFactory, $$AnimateChildrenDirective, $$AnimateRunnerFactory, $$AnimateQueueProvider, $$AnimationProvider, $AnimateCssProvider, $$AnimateCssDriverProvider, $$AnimateJsProvider, $$AnimateJsDriverProvider, */ /** * @ngdoc module * @name ngAnimate * @description * * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an Angular app. * *
* * # Usage * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within * the HTML element that the animation will be triggered on. * * ## Directive Support * The following directives are "animation aware": * * | Directive | Supported Animations | * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move | * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave | * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave | * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave | * | {@link ng.directive:ngIf#animations ngIf} | enter and leave | * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) | * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) | * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) | * | {@link module:ngMessages#animations ngMessage} | enter and leave | * * (More information can be found by visiting each the documentation associated with each directive.) * * ## CSS-based Animations * * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML * and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation. * * The example below shows how an `enter` animation can be made possible on an element using `ng-if`: * * ```html *
* Fade me in out *
* * * ``` * * Notice the CSS class **fade**? We can now create the CSS transition code that references this class: * * ```css * /* The starting CSS styles for the enter animation */ * .fade.ng-enter { * transition:0.5s linear all; * opacity:0; * } * * /* The finishing CSS styles for the enter animation */ * .fade.ng-enter.ng-enter-active { * opacity:1; * } * ``` * * The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two * generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition * code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards. * * If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions: * * ```css * /* now the element will fade out before it is removed from the DOM */ * .fade.ng-leave { * transition:0.5s linear all; * opacity:1; * } * .fade.ng-leave.ng-leave-active { * opacity:0; * } * ``` * * We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class: * * ```css * /* there is no need to define anything inside of the destination * CSS class since the keyframe will take charge of the animation */ * .fade.ng-leave { * animation: my_fade_animation 0.5s linear; * -webkit-animation: my_fade_animation 0.5s linear; * } * * @keyframes my_fade_animation { * from { opacity:1; } * to { opacity:0; } * } * * @-webkit-keyframes my_fade_animation { * from { opacity:1; } * to { opacity:0; } * } * ``` * * Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element. * * ### CSS Class-based Animations * * Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different * naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added * and removed. * * For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class: * * ```html *
* Show and hide me *
* * * * ``` * * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest. * * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation * with CSS styles. * * ```html *
* Highlight this box *
* * * * ``` * * We can also make use of CSS keyframes by placing them within the CSS classes. * * * ### CSS Staggering Animations * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for * the animation. The style property expected within the stagger class can either be a **transition-delay** or an * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). * * ```css * .my-animation.ng-enter { * /* standard transition code */ * transition: 1s linear all; * opacity:0; * } * .my-animation.ng-enter-stagger { * /* this will have a 100ms delay between each successive leave animation */ * transition-delay: 0.1s; * * /* As of 1.4.4, this must always be set: it signals ngAnimate * to not accidentally inherit a delay property from another CSS class */ * transition-duration: 0s; * } * .my-animation.ng-enter.ng-enter-active { * /* standard transition styles */ * opacity:1; * } * ``` * * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired. * * The following code will issue the **ng-leave-stagger** event on the element provided: * * ```js * var kids = parent.children(); * * $animate.leave(kids[0]); //stagger index=0 * $animate.leave(kids[1]); //stagger index=1 * $animate.leave(kids[2]); //stagger index=2 * $animate.leave(kids[3]); //stagger index=3 * $animate.leave(kids[4]); //stagger index=4 * * window.requestAnimationFrame(function() { * //stagger has reset itself * $animate.leave(kids[5]); //stagger index=0 * $animate.leave(kids[6]); //stagger index=1 * * $scope.$digest(); * }); * ``` * * Stagger animations are currently only supported within CSS-defined animations. * * ### The `ng-animate` CSS class * * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation. * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations). * * Therefore, animations can be applied to an element using this temporary class directly via CSS. * * ```css * .zipper.ng-animate { * transition:0.5s linear all; * } * .zipper.ng-enter { * opacity:0; * } * .zipper.ng-enter.ng-enter-active { * opacity:1; * } * .zipper.ng-leave { * opacity:1; * } * .zipper.ng-leave.ng-leave-active { * opacity:0; * } * ``` * * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove * the CSS class once an animation has completed.) * * * ## JavaScript-based Animations * * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the * `module.animation()` module function we can register the ainmation. * * Let's see an example of a enter/leave animation using `ngRepeat`: * * ```html *
* {{ item }} *
* ``` * * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`: * * ```js * myModule.animation('.slide', [function() { * return { * // make note that other events (like addClass/removeClass) * // have different function input parameters * enter: function(element, doneFn) { * jQuery(element).fadeIn(1000, doneFn); * * // remember to call doneFn so that angular * // knows that the animation has concluded * }, * * move: function(element, doneFn) { * jQuery(element).fadeIn(1000, doneFn); * }, * * leave: function(element, doneFn) { * jQuery(element).fadeOut(1000, doneFn); * } * } * }]); * ``` * * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as * greensock.js and velocity.js. * * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define * our animations inside of the same registered animation, however, the function input arguments are a bit different: * * ```html *
* this box is moody *
* * * * ``` * * ```js * myModule.animation('.colorful', [function() { * return { * addClass: function(element, className, doneFn) { * // do some cool animation and call the doneFn * }, * removeClass: function(element, className, doneFn) { * // do some cool animation and call the doneFn * }, * setClass: function(element, addedClass, removedClass, doneFn) { * // do some cool animation and call the doneFn * } * } * }]); * ``` * * ## CSS + JS Animations Together * * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular, * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking * charge of the animation**: * * ```html *
* Slide in and out *
* ``` * * ```js * myModule.animation('.slide', [function() { * return { * enter: function(element, doneFn) { * jQuery(element).slideIn(1000, doneFn); * } * } * }]); * ``` * * ```css * .slide.ng-enter { * transition:0.5s linear all; * transform:translateY(-100px); * } * .slide.ng-enter.ng-enter-active { * transform:translateY(0); * } * ``` * * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from * our own JS-based animation code: * * ```js * myModule.animation('.slide', ['$animateCss', function($animateCss) { * return { * enter: function(element) { * // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`. * return $animateCss(element, { * event: 'enter', * structural: true * }); * } * } * }]); * ``` * * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework. * * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that * data into `$animateCss` directly: * * ```js * myModule.animation('.slide', ['$animateCss', function($animateCss) { * return { * enter: function(element) { * return $animateCss(element, { * event: 'enter', * structural: true, * addClass: 'maroon-setting', * from: { height:0 }, * to: { height: 200 } * }); * } * } * }]); * ``` * * Now we can fill in the rest via our transition CSS code: * * ```css * /* the transition tells ngAnimate to make the animation happen */ * .slide.ng-enter { transition:0.5s linear all; } * * /* this extra CSS class will be absorbed into the transition * since the $animateCss code is adding the class */ * .maroon-setting { background:red; } * ``` * * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over. * * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}. * * ## Animation Anchoring (via `ng-animate-ref`) * * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between * structural areas of an application (like views) by pairing up elements using an attribute * called `ng-animate-ref`. * * Let's say for example we have two views that are managed by `ng-view` and we want to show * that there is a relationship between two components situated in within these views. By using the * `ng-animate-ref` attribute we can identify that the two components are paired together and we * can then attach an animation, which is triggered when the view changes. * * Say for example we have the following template code: * * ```html * *
*
* * * * * * * * * ``` * * Now, when the view changes (once the link is clicked), ngAnimate will examine the * HTML contents to see if there is a match reference between any components in the view * that is leaving and the view that is entering. It will scan both the view which is being * removed (leave) and inserted (enter) to see if there are any paired DOM elements that * contain a matching ref value. * * The two images match since they share the same ref value. ngAnimate will now create a * transport element (which is a clone of the first image element) and it will then attempt * to animate to the position of the second image element in the next view. For the animation to * work a special CSS class called `ng-anchor` will be added to the transported element. * * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then * ngAnimate will handle the entire transition for us as well as the addition and removal of * any changes of CSS classes between the elements: * * ```css * .banner.ng-anchor { * /* this animation will last for 1 second since there are * two phases to the animation (an `in` and an `out` phase) */ * transition:0.5s linear all; * } * ``` * * We also **must** include animations for the views that are being entered and removed * (otherwise anchoring wouldn't be possible since the new view would be inserted right away). * * ```css * .view-animation.ng-enter, .view-animation.ng-leave { * transition:0.5s linear all; * position:fixed; * left:0; * top:0; * width:100%; * } * .view-animation.ng-enter { * transform:translateX(100%); * } * .view-animation.ng-leave, * .view-animation.ng-enter.ng-enter-active { * transform:translateX(0%); * } * .view-animation.ng-leave.ng-leave-active { * transform:translateX(-100%); * } * ``` * * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur: * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away * from its origin. Once that animation is over then the `in` stage occurs which animates the * element to its destination. The reason why there are two animations is to give enough time * for the enter animation on the new element to be ready. * * The example above sets up a transition for both the in and out phases, but we can also target the out or * in phases directly via `ng-anchor-out` and `ng-anchor-in`. * * ```css * .banner.ng-anchor-out { * transition: 0.5s linear all; * * /* the scale will be applied during the out animation, * but will be animated away when the in animation runs */ * transform: scale(1.2); * } * * .banner.ng-anchor-in { * transition: 1s linear all; * } * ``` * * * * * ### Anchoring Demo * Home
angular.module('anchoringExample', ['ngAnimate', 'ngRoute']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/', { templateUrl: 'home.html', controller: 'HomeController as home' }); $routeProvider.when('/profile/:id', { templateUrl: 'profile.html', controller: 'ProfileController as profile' }); }]) .run(['$rootScope', function($rootScope) { $rootScope.records = [ { id:1, title: "Miss Beulah Roob" }, { id:2, title: "Trent Morissette" }, { id:3, title: "Miss Ava Pouros" }, { id:4, title: "Rod Pouros" }, { id:5, title: "Abdul Rice" }, { id:6, title: "Laurie Rutherford Sr." }, { id:7, title: "Nakia McLaughlin" }, { id:8, title: "Jordon Blanda DVM" }, { id:9, title: "Rhoda Hand" }, { id:10, title: "Alexandrea Sauer" } ]; }]) .controller('HomeController', [function() { //empty }]) .controller('ProfileController', ['$rootScope', '$routeParams', function($rootScope, $routeParams) { var index = parseInt($routeParams.id, 10); var record = $rootScope.records[index - 1]; this.title = record.title; this.id = record.id; }]);

Welcome to the home page

Please click on an element

{{ record.title }}
{{ profile.title }}
.record { display:block; font-size:20px; } .profile { background:black; color:white; font-size:100px; } .view-container { position:relative; } .view-container > .view.ng-animate { position:absolute; top:0; left:0; width:100%; min-height:500px; } .view.ng-enter, .view.ng-leave, .record.ng-anchor { transition:0.5s linear all; } .view.ng-enter { transform:translateX(100%); } .view.ng-enter.ng-enter-active, .view.ng-leave { transform:translateX(0%); } .view.ng-leave.ng-leave-active { transform:translateX(-100%); } .record.ng-anchor-out { background:red; }
* * ### How is the element transported? * * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element * will become visible since the shim class will be removed. * * ### How is the morphing handled? * * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out * what CSS classes differ between the starting element and the destination element. These different CSS classes * will be added/removed on the anchor element and a transition will be applied (the transition that is provided * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since * the cloned element is placed inside of root element which is likely close to the body element). * * Note that if the root element is on the `` element then the cloned node will be placed inside of body. * * * ## Using $animate in your directive code * * So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application? * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's * imagine we have a greeting box that shows and hides itself when the data changes * * ```html * Hi there * ``` * * ```js * ngModule.directive('greetingBox', ['$animate', function($animate) { * return function(scope, element, attrs) { * attrs.$observe('active', function(value) { * value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on'); * }); * }); * }]); * ``` * * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element * in our HTML code then we can trigger a CSS or JS animation to happen. * * ```css * /* normally we would create a CSS class to reference on the element */ * greeting-box.on { transition:0.5s linear all; background:green; color:white; } * ``` * * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's * possible be sure to visit the {@link ng.$animate $animate service API page}. * * * ### Preventing Collisions With Third Party Libraries * * Some third-party frameworks place animation duration defaults across many element or className * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which * is expecting actual animations on these elements and has to wait for their completion. * * You can prevent this unwanted behavior by using a prefix on all your animation classes: * * ```css * /* prefixed with animate- */ * .animate-fade-add.animate-fade-add-active { * transition:1s linear all; * opacity:0; * } * ``` * * You then configure `$animate` to enforce this prefix: * * ```js * $animateProvider.classNameFilter(/animate-/); * ``` * * This also may provide your application with a speed boost since only specific elements containing CSS class prefix * will be evaluated for animation when any DOM changes occur in the application. * * ## Callbacks and Promises * * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has * ended by chaining onto the returned promise that animation method returns. * * ```js * // somewhere within the depths of the directive * $animate.enter(element, parent).then(function() { * //the animation has completed * }); * ``` * * (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case * anymore.) * * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view * routing controller to hook into that: * * ```js * ngModule.controller('HomePageController', ['$animate', function($animate) { * $animate.on('enter', ngViewElement, function(element) { * // the animation for this route has completed * }]); * }]) * ``` * * (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.) */ /** * @ngdoc service * @name $animate * @kind object * * @description * The ngAnimate `$animate` service documentation is the same for the core `$animate` service. * * Click here {@link ng.$animate to learn more about animations with `$animate`}. */ angular.module('ngAnimate', []) .directive('ngAnimateChildren', $$AnimateChildrenDirective) .factory('$$rAFScheduler', $$rAFSchedulerFactory) .factory('$$AnimateRunner', $$AnimateRunnerFactory) .factory('$$animateAsyncRun', $$AnimateAsyncRunFactory) .provider('$$animateQueue', $$AnimateQueueProvider) .provider('$$animation', $$AnimationProvider) .provider('$animateCss', $AnimateCssProvider) .provider('$$animateCssDriver', $$AnimateCssDriverProvider) .provider('$$animateJs', $$AnimateJsProvider) .provider('$$animateJsDriver', $$AnimateJsDriverProvider); })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-aria.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /** * @ngdoc module * @name ngAria * @description * * The `ngAria` module provides support for common * [ARIA](http://www.w3.org/TR/wai-aria/) * attributes that convey state or semantic information about the application for users * of assistive technologies, such as screen readers. * *
* * ## Usage * * For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following * directives are supported: * `ngModel`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`, `ngDblClick`, and `ngMessages`. * * Below is a more detailed breakdown of the attributes handled by ngAria: * * | Directive | Supported Attributes | * |---------------------------------------------|----------------------------------------------------------------------------------------| * | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled | * | {@link ng.directive:ngShow ngShow} | aria-hidden | * | {@link ng.directive:ngHide ngHide} | aria-hidden | * | {@link ng.directive:ngDblclick ngDblclick} | tabindex | * | {@link module:ngMessages ngMessages} | aria-live | * | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles | * | {@link ng.directive:ngClick ngClick} | tabindex, keypress event, button role | * * Find out more information about each directive by reading the * {@link guide/accessibility ngAria Developer Guide}. * * ##Example * Using ngDisabled with ngAria: * ```html * * ``` * Becomes: * ```html * * ``` * * ##Disabling Attributes * It's possible to disable individual attributes added by ngAria with the * {@link ngAria.$ariaProvider#config config} method. For more details, see the * {@link guide/accessibility Developer Guide}. */ /* global -ngAriaModule */ var ngAriaModule = angular.module('ngAria', ['ng']). provider('$aria', $AriaProvider); /** * Internal Utilities */ var nodeBlackList = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY']; var isNodeOneOf = function(elem, nodeTypeArray) { if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) { return true; } }; /** * @ngdoc provider * @name $ariaProvider * * @description * * Used for configuring the ARIA attributes injected and managed by ngAria. * * ```js * angular.module('myApp', ['ngAria'], function config($ariaProvider) { * $ariaProvider.config({ * ariaValue: true, * tabindex: false * }); * }); *``` * * ## Dependencies * Requires the {@link ngAria} module to be installed. * */ function $AriaProvider() { var config = { ariaHidden: true, ariaChecked: true, ariaDisabled: true, ariaRequired: true, ariaInvalid: true, ariaMultiline: true, ariaValue: true, tabindex: true, bindKeypress: true, bindRoleForClick: true }; /** * @ngdoc method * @name $ariaProvider#config * * @param {object} config object to enable/disable specific ARIA attributes * * - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags * - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags * - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags * - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags * - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags * - **ariaMultiline** – `{boolean}` – Enables/disables aria-multiline tags * - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags * - **tabindex** – `{boolean}` – Enables/disables tabindex tags * - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `<div>` and * `<li>` elements with ng-click * - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements like `div` * using ng-click, making them more accessible to users of assistive technologies * * @description * Enables/disables various ARIA attributes */ this.config = function(newConfig) { config = angular.extend(config, newConfig); }; function watchExpr(attrName, ariaAttr, nodeBlackList, negate) { return function(scope, elem, attr) { var ariaCamelName = attr.$normalize(ariaAttr); if (config[ariaCamelName] && !isNodeOneOf(elem, nodeBlackList) && !attr[ariaCamelName]) { scope.$watch(attr[attrName], function(boolVal) { // ensure boolean value boolVal = negate ? !boolVal : !!boolVal; elem.attr(ariaAttr, boolVal); }); } }; } /** * @ngdoc service * @name $aria * * @description * @priority 200 * * The $aria service contains helper methods for applying common * [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives. * * ngAria injects common accessibility attributes that tell assistive technologies when HTML * elements are enabled, selected, hidden, and more. To see how this is performed with ngAria, * let's review a code snippet from ngAria itself: * *```js * ngAriaModule.directive('ngDisabled', ['$aria', function($aria) { * return $aria.$$watchExpr('ngDisabled', 'aria-disabled'); * }]) *``` * Shown above, the ngAria module creates a directive with the same signature as the * traditional `ng-disabled` directive. But this ngAria version is dedicated to * solely managing accessibility attributes. The internal `$aria` service is used to watch the * boolean attribute `ngDisabled`. If it has not been explicitly set by the developer, * `aria-disabled` is injected as an attribute with its value synchronized to the value in * `ngDisabled`. * * Because ngAria hooks into the `ng-disabled` directive, developers do not have to do * anything to enable this feature. The `aria-disabled` attribute is automatically managed * simply as a silent side-effect of using `ng-disabled` with the ngAria module. * * The full list of directives that interface with ngAria: * * **ngModel** * * **ngShow** * * **ngHide** * * **ngClick** * * **ngDblclick** * * **ngMessages** * * **ngDisabled** * * Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each * directive. * * * ## Dependencies * Requires the {@link ngAria} module to be installed. */ this.$get = function() { return { config: function(key) { return config[key]; }, $$watchExpr: watchExpr }; }; } ngAriaModule.directive('ngShow', ['$aria', function($aria) { return $aria.$$watchExpr('ngShow', 'aria-hidden', [], true); }]) .directive('ngHide', ['$aria', function($aria) { return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false); }]) .directive('ngModel', ['$aria', function($aria) { function shouldAttachAttr(attr, normalizedAttr, elem) { return $aria.config(normalizedAttr) && !elem.attr(attr); } function shouldAttachRole(role, elem) { return !elem.attr('role') && (elem.attr('type') === role) && (elem[0].nodeName !== 'INPUT'); } function getShape(attr, elem) { var type = attr.type, role = attr.role; return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' : ((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' : (type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' : (type || role) === 'textbox' || elem[0].nodeName === 'TEXTAREA' ? 'multiline' : ''; } return { restrict: 'A', require: '?ngModel', priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value compile: function(elem, attr) { var shape = getShape(attr, elem); return { pre: function(scope, elem, attr, ngModel) { if (shape === 'checkbox' && attr.type !== 'checkbox') { //Use the input[checkbox] $isEmpty implementation for elements with checkbox roles ngModel.$isEmpty = function(value) { return value === false; }; } }, post: function(scope, elem, attr, ngModel) { var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem) && !isNodeOneOf(elem, nodeBlackList); function ngAriaWatchModelValue() { return ngModel.$modelValue; } function getRadioReaction() { if (needsTabIndex) { needsTabIndex = false; return function ngAriaRadioReaction(newVal) { var boolVal = (attr.value == ngModel.$viewValue); elem.attr('aria-checked', boolVal); elem.attr('tabindex', 0 - !boolVal); }; } else { return function ngAriaRadioReaction(newVal) { elem.attr('aria-checked', (attr.value == ngModel.$viewValue)); }; } } function ngAriaCheckboxReaction() { elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue)); } switch (shape) { case 'radio': case 'checkbox': if (shouldAttachRole(shape, elem)) { elem.attr('role', shape); } if (shouldAttachAttr('aria-checked', 'ariaChecked', elem)) { scope.$watch(ngAriaWatchModelValue, shape === 'radio' ? getRadioReaction() : ngAriaCheckboxReaction); } if (needsTabIndex) { elem.attr('tabindex', 0); } break; case 'range': if (shouldAttachRole(shape, elem)) { elem.attr('role', 'slider'); } if ($aria.config('ariaValue')) { var needsAriaValuemin = !elem.attr('aria-valuemin') && (attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin')); var needsAriaValuemax = !elem.attr('aria-valuemax') && (attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax')); var needsAriaValuenow = !elem.attr('aria-valuenow'); if (needsAriaValuemin) { attr.$observe('min', function ngAriaValueMinReaction(newVal) { elem.attr('aria-valuemin', newVal); }); } if (needsAriaValuemax) { attr.$observe('max', function ngAriaValueMinReaction(newVal) { elem.attr('aria-valuemax', newVal); }); } if (needsAriaValuenow) { scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) { elem.attr('aria-valuenow', newVal); }); } } if (needsTabIndex) { elem.attr('tabindex', 0); } break; case 'multiline': if (shouldAttachAttr('aria-multiline', 'ariaMultiline', elem)) { elem.attr('aria-multiline', true); } break; } if (ngModel.$validators.required && shouldAttachAttr('aria-required', 'ariaRequired', elem)) { scope.$watch(function ngAriaRequiredWatch() { return ngModel.$error.required; }, function ngAriaRequiredReaction(newVal) { elem.attr('aria-required', !!newVal); }); } if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem)) { scope.$watch(function ngAriaInvalidWatch() { return ngModel.$invalid; }, function ngAriaInvalidReaction(newVal) { elem.attr('aria-invalid', !!newVal); }); } } }; } }; }]) .directive('ngDisabled', ['$aria', function($aria) { return $aria.$$watchExpr('ngDisabled', 'aria-disabled', []); }]) .directive('ngMessages', function() { return { restrict: 'A', require: '?ngMessages', link: function(scope, elem, attr, ngMessages) { if (!elem.attr('aria-live')) { elem.attr('aria-live', 'assertive'); } } }; }) .directive('ngClick',['$aria', '$parse', function($aria, $parse) { return { restrict: 'A', compile: function(elem, attr) { var fn = $parse(attr.ngClick, /* interceptorFn */ null, /* expensiveChecks */ true); return function(scope, elem, attr) { if (!isNodeOneOf(elem, nodeBlackList)) { if ($aria.config('bindRoleForClick') && !elem.attr('role')) { elem.attr('role', 'button'); } if ($aria.config('tabindex') && !elem.attr('tabindex')) { elem.attr('tabindex', 0); } if ($aria.config('bindKeypress') && !attr.ngKeypress) { elem.on('keypress', function(event) { var keyCode = event.which || event.keyCode; if (keyCode === 32 || keyCode === 13) { scope.$apply(callback); } function callback() { fn(scope, { $event: event }); } }); } } }; } }; }]) .directive('ngDblclick', ['$aria', function($aria) { return function(scope, elem, attr) { if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nodeBlackList)) { elem.attr('tabindex', 0); } }; }]); })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-cookies.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /** * @ngdoc module * @name ngCookies * @description * * # ngCookies * * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies. * * *
* * See {@link ngCookies.$cookies `$cookies`} for usage. */ angular.module('ngCookies', ['ng']). /** * @ngdoc provider * @name $cookiesProvider * @description * Use `$cookiesProvider` to change the default behavior of the {@link ngCookies.$cookies $cookies} service. * */ provider('$cookies', [function $CookiesProvider() { /** * @ngdoc property * @name $cookiesProvider#defaults * @description * * Object containing default options to pass when setting cookies. * * The object may have following properties: * * - **path** - `{string}` - The cookie will be available only for this path and its * sub-paths. By default, this would be the URL that appears in your base tag. * - **domain** - `{string}` - The cookie will be available only for this domain and * its sub-domains. For obvious security reasons the user agent will not accept the * cookie if the current domain is not a sub domain or equals to the requested domain. * - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT" * or a Date object indicating the exact date/time this cookie will expire. * - **secure** - `{boolean}` - The cookie will be available only in secured connection. * * Note: by default the address that appears in your `` tag will be used as path. * This is important so that cookies will be visible for all routes in case html5mode is enabled * **/ var defaults = this.defaults = {}; function calcOptions(options) { return options ? angular.extend({}, defaults, options) : defaults; } /** * @ngdoc service * @name $cookies * * @description * Provides read/write access to browser's cookies. * *
* Up until Angular 1.3, `$cookies` exposed properties that represented the * current browser cookie values. In version 1.4, this behavior has changed, and * `$cookies` now provides a standard api of getters, setters etc. *
* * Requires the {@link ngCookies `ngCookies`} module to be installed. * * @example * * ```js * angular.module('cookiesExample', ['ngCookies']) * .controller('ExampleController', ['$cookies', function($cookies) { * // Retrieving a cookie * var favoriteCookie = $cookies.get('myFavorite'); * // Setting a cookie * $cookies.put('myFavorite', 'oatmeal'); * }]); * ``` */ this.$get = ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) { return { /** * @ngdoc method * @name $cookies#get * * @description * Returns the value of given cookie key * * @param {string} key Id to use for lookup. * @returns {string} Raw cookie value. */ get: function(key) { return $$cookieReader()[key]; }, /** * @ngdoc method * @name $cookies#getObject * * @description * Returns the deserialized value of given cookie key * * @param {string} key Id to use for lookup. * @returns {Object} Deserialized cookie value. */ getObject: function(key) { var value = this.get(key); return value ? angular.fromJson(value) : value; }, /** * @ngdoc method * @name $cookies#getAll * * @description * Returns a key value object with all the cookies * * @returns {Object} All cookies */ getAll: function() { return $$cookieReader(); }, /** * @ngdoc method * @name $cookies#put * * @description * Sets a value for given cookie key * * @param {string} key Id for the `value`. * @param {string} value Raw value to be stored. * @param {Object=} options Options object. * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults} */ put: function(key, value, options) { $$cookieWriter(key, value, calcOptions(options)); }, /** * @ngdoc method * @name $cookies#putObject * * @description * Serializes and sets a value for given cookie key * * @param {string} key Id for the `value`. * @param {Object} value Value to be stored. * @param {Object=} options Options object. * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults} */ putObject: function(key, value, options) { this.put(key, angular.toJson(value), options); }, /** * @ngdoc method * @name $cookies#remove * * @description * Remove given cookie * * @param {string} key Id of the key-value pair to delete. * @param {Object=} options Options object. * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults} */ remove: function(key, options) { $$cookieWriter(key, undefined, calcOptions(options)); } }; }]; }]); angular.module('ngCookies'). /** * @ngdoc service * @name $cookieStore * @deprecated * @requires $cookies * * @description * Provides a key-value (string-object) storage, that is backed by session cookies. * Objects put or retrieved from this storage are automatically serialized or * deserialized by angular's toJson/fromJson. * * Requires the {@link ngCookies `ngCookies`} module to be installed. * *
* **Note:** The $cookieStore service is **deprecated**. * Please use the {@link ngCookies.$cookies `$cookies`} service instead. *
* * @example * * ```js * angular.module('cookieStoreExample', ['ngCookies']) * .controller('ExampleController', ['$cookieStore', function($cookieStore) { * // Put cookie * $cookieStore.put('myFavorite','oatmeal'); * // Get cookie * var favoriteCookie = $cookieStore.get('myFavorite'); * // Removing a cookie * $cookieStore.remove('myFavorite'); * }]); * ``` */ factory('$cookieStore', ['$cookies', function($cookies) { return { /** * @ngdoc method * @name $cookieStore#get * * @description * Returns the value of given cookie key * * @param {string} key Id to use for lookup. * @returns {Object} Deserialized cookie value, undefined if the cookie does not exist. */ get: function(key) { return $cookies.getObject(key); }, /** * @ngdoc method * @name $cookieStore#put * * @description * Sets a value for given cookie key * * @param {string} key Id for the `value`. * @param {Object} value Value to be stored. */ put: function(key, value) { $cookies.putObject(key, value); }, /** * @ngdoc method * @name $cookieStore#remove * * @description * Remove given cookie * * @param {string} key Id of the key-value pair to delete. */ remove: function(key) { $cookies.remove(key); } }; }]); /** * @name $$cookieWriter * @requires $document * * @description * This is a private service for writing cookies * * @param {string} name Cookie name * @param {string=} value Cookie value (if undefined, cookie will be deleted) * @param {Object=} options Object with options that need to be stored for the cookie. */ function $$CookieWriter($document, $log, $browser) { var cookiePath = $browser.baseHref(); var rawDocument = $document[0]; function buildCookieString(name, value, options) { var path, expires; options = options || {}; expires = options.expires; path = angular.isDefined(options.path) ? options.path : cookiePath; if (angular.isUndefined(value)) { expires = 'Thu, 01 Jan 1970 00:00:00 GMT'; value = ''; } if (angular.isString(expires)) { expires = new Date(expires); } var str = encodeURIComponent(name) + '=' + encodeURIComponent(value); str += path ? ';path=' + path : ''; str += options.domain ? ';domain=' + options.domain : ''; str += expires ? ';expires=' + expires.toUTCString() : ''; str += options.secure ? ';secure' : ''; // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum: // - 300 cookies // - 20 cookies per unique domain // - 4096 bytes per cookie var cookieLength = str.length + 1; if (cookieLength > 4096) { $log.warn("Cookie '" + name + "' possibly not set or overflowed because it was too large (" + cookieLength + " > 4096 bytes)!"); } return str; } return function(name, value, options) { rawDocument.cookie = buildCookieString(name, value, options); }; } $$CookieWriter.$inject = ['$document', '$log', '$browser']; angular.module('ngCookies').provider('$$cookieWriter', function $$CookieWriterProvider() { this.$get = $$CookieWriter; }); })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-csp.css ================================================ /* Include this file in your html if you are using the CSP mode. */ @charset "UTF-8"; [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak, .ng-hide:not(.ng-hide-animate) { display: none !important; } ng\:form { display: block; } .ng-animate-shim { visibility:hidden; } .ng-anchor { position:absolute; } ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-loader.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function() {'use strict'; function isFunction(value) {return typeof value === 'function';}; /** * @description * * This object provides a utility for producing rich Error messages within * Angular. It can be called as follows: * * var exampleMinErr = minErr('example'); * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); * * The above creates an instance of minErr in the example namespace. The * resulting error will have a namespaced error code of example.one. The * resulting error will replace {0} with the value of foo, and {1} with the * value of bar. The object is not restricted in the number of arguments it can * take. * * If fewer arguments are specified than necessary for interpolation, the extra * interpolation markers will be preserved in the final string. * * Since data will be parsed statically during a build step, some restrictions * are applied with respect to how minErr instances are created and called. * Instances should have names of the form namespaceMinErr for a minErr created * using minErr('namespace') . Error codes, namespaces and template strings * should all be static strings, not variables or general expressions. * * @param {string} module The namespace to use for the new minErr instance. * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning * error from returned function, for cases when a particular type of error is useful. * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance */ function minErr(module, ErrorConstructor) { ErrorConstructor = ErrorConstructor || Error; return function() { var SKIP_INDEXES = 2; var templateArgs = arguments, code = templateArgs[0], message = '[' + (module ? module + ':' : '') + code + '] ', template = templateArgs[1], paramPrefix, i; message += template.replace(/\{\d+\}/g, function(match) { var index = +match.slice(1, -1), shiftedIndex = index + SKIP_INDEXES; if (shiftedIndex < templateArgs.length) { return toDebugString(templateArgs[shiftedIndex]); } return match; }); message += '\nhttp://errors.angularjs.org/1.4.8/' + (module ? module + '/' : '') + code; for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' + encodeURIComponent(toDebugString(templateArgs[i])); } return new ErrorConstructor(message); }; } /** * @ngdoc type * @name angular.Module * @module ng * @description * * Interface for configuring angular {@link angular.module modules}. */ function setupModuleLoader(window) { var $injectorMinErr = minErr('$injector'); var ngMinErr = minErr('ng'); function ensure(obj, name, factory) { return obj[name] || (obj[name] = factory()); } var angular = ensure(window, 'angular', Object); // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap angular.$$minErr = angular.$$minErr || minErr; return ensure(angular, 'module', function() { /** @type {Object.} */ var modules = {}; /** * @ngdoc function * @name angular.module * @module ng * @description * * The `angular.module` is a global place for creating, registering and retrieving Angular * modules. * All modules (angular core or 3rd party) that should be available to an application must be * registered using this mechanism. * * Passing one argument retrieves an existing {@link angular.Module}, * whereas passing more than one argument creates a new {@link angular.Module} * * * # Module * * A module is a collection of services, directives, controllers, filters, and configuration information. * `angular.module` is used to configure the {@link auto.$injector $injector}. * * ```js * // Create a new module * var myModule = angular.module('myModule', []); * * // register a new service * myModule.value('appName', 'MyCoolApp'); * * // configure existing services inside initialization blocks. * myModule.config(['$locationProvider', function($locationProvider) { * // Configure existing providers * $locationProvider.hashPrefix('!'); * }]); * ``` * * Then you can create an injector and load your modules like this: * * ```js * var injector = angular.injector(['ng', 'myModule']) * ``` * * However it's more likely that you'll just use * {@link ng.directive:ngApp ngApp} or * {@link angular.bootstrap} to simplify this process for you. * * @param {!string} name The name of the module to create or retrieve. * @param {!Array.=} requires If specified then new module is being created. If * unspecified then the module is being retrieved for further configuration. * @param {Function=} configFn Optional configuration function for the module. Same as * {@link angular.Module#config Module#config()}. * @returns {module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { var assertNotHasOwnProperty = function(name, context) { if (name === 'hasOwnProperty') { throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); } }; assertNotHasOwnProperty(name, 'module'); if (requires && modules.hasOwnProperty(name)) { modules[name] = null; } return ensure(modules, name, function() { if (!requires) { throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + "the module name or forgot to load it. If registering a module ensure that you " + "specify the dependencies as the second argument.", name); } /** @type {!Array.>} */ var invokeQueue = []; /** @type {!Array.} */ var configBlocks = []; /** @type {!Array.} */ var runBlocks = []; var config = invokeLater('$injector', 'invoke', 'push', configBlocks); /** @type {angular.Module} */ var moduleInstance = { // Private state _invokeQueue: invokeQueue, _configBlocks: configBlocks, _runBlocks: runBlocks, /** * @ngdoc property * @name angular.Module#requires * @module ng * * @description * Holds the list of modules which the injector will load before the current module is * loaded. */ requires: requires, /** * @ngdoc property * @name angular.Module#name * @module ng * * @description * Name of the module. */ name: name, /** * @ngdoc method * @name angular.Module#provider * @module ng * @param {string} name service name * @param {Function} providerType Construction function for creating new instance of the * service. * @description * See {@link auto.$provide#provider $provide.provider()}. */ provider: invokeLaterAndSetModuleName('$provide', 'provider'), /** * @ngdoc method * @name angular.Module#factory * @module ng * @param {string} name service name * @param {Function} providerFunction Function for creating new instance of the service. * @description * See {@link auto.$provide#factory $provide.factory()}. */ factory: invokeLaterAndSetModuleName('$provide', 'factory'), /** * @ngdoc method * @name angular.Module#service * @module ng * @param {string} name service name * @param {Function} constructor A constructor function that will be instantiated. * @description * See {@link auto.$provide#service $provide.service()}. */ service: invokeLaterAndSetModuleName('$provide', 'service'), /** * @ngdoc method * @name angular.Module#value * @module ng * @param {string} name service name * @param {*} object Service instance object. * @description * See {@link auto.$provide#value $provide.value()}. */ value: invokeLater('$provide', 'value'), /** * @ngdoc method * @name angular.Module#constant * @module ng * @param {string} name constant name * @param {*} object Constant value. * @description * Because the constants are fixed, they get applied before other provide methods. * See {@link auto.$provide#constant $provide.constant()}. */ constant: invokeLater('$provide', 'constant', 'unshift'), /** * @ngdoc method * @name angular.Module#decorator * @module ng * @param {string} The name of the service to decorate. * @param {Function} This function will be invoked when the service needs to be * instantiated and should return the decorated service instance. * @description * See {@link auto.$provide#decorator $provide.decorator()}. */ decorator: invokeLaterAndSetModuleName('$provide', 'decorator'), /** * @ngdoc method * @name angular.Module#animation * @module ng * @param {string} name animation name * @param {Function} animationFactory Factory function for creating new instance of an * animation. * @description * * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. * * * Defines an animation hook that can be later used with * {@link $animate $animate} service and directives that use this service. * * ```js * module.animation('.animation-name', function($inject1, $inject2) { * return { * eventName : function(element, done) { * //code to run the animation * //once complete, then run done() * return function cancellationFunction(element) { * //code to cancel the animation * } * } * } * }) * ``` * * See {@link ng.$animateProvider#register $animateProvider.register()} and * {@link ngAnimate ngAnimate module} for more information. */ animation: invokeLaterAndSetModuleName('$animateProvider', 'register'), /** * @ngdoc method * @name angular.Module#filter * @module ng * @param {string} name Filter name - this must be a valid angular expression identifier * @param {Function} filterFactory Factory function for creating new instance of filter. * @description * See {@link ng.$filterProvider#register $filterProvider.register()}. * *
* **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). *
*/ filter: invokeLaterAndSetModuleName('$filterProvider', 'register'), /** * @ngdoc method * @name angular.Module#controller * @module ng * @param {string|Object} name Controller name, or an object map of controllers where the * keys are the names and the values are the constructors. * @param {Function} constructor Controller constructor function. * @description * See {@link ng.$controllerProvider#register $controllerProvider.register()}. */ controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'), /** * @ngdoc method * @name angular.Module#directive * @module ng * @param {string|Object} name Directive name, or an object map of directives where the * keys are the names and the values are the factories. * @param {Function} directiveFactory Factory function for creating new instance of * directives. * @description * See {@link ng.$compileProvider#directive $compileProvider.directive()}. */ directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'), /** * @ngdoc method * @name angular.Module#config * @module ng * @param {Function} configFn Execute this function on module load. Useful for service * configuration. * @description * Use this method to register work which needs to be performed on module loading. * For more about how to configure services, see * {@link providers#provider-recipe Provider Recipe}. */ config: config, /** * @ngdoc method * @name angular.Module#run * @module ng * @param {Function} initializationFn Execute this function after injector creation. * Useful for application initialization. * @description * Use this method to register work which should be performed when the injector is done * loading all modules. */ run: function(block) { runBlocks.push(block); return this; } }; if (configFn) { config(configFn); } return moduleInstance; /** * @param {string} provider * @param {string} method * @param {String=} insertMethod * @returns {angular.Module} */ function invokeLater(provider, method, insertMethod, queue) { if (!queue) queue = invokeQueue; return function() { queue[insertMethod || 'push']([provider, method, arguments]); return moduleInstance; }; } /** * @param {string} provider * @param {string} method * @returns {angular.Module} */ function invokeLaterAndSetModuleName(provider, method) { return function(recipeName, factoryFunction) { if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name; invokeQueue.push([provider, method, arguments]); return moduleInstance; }; } }); }; }); } setupModuleLoader(window); })(window); /** * Closure compiler type information * * @typedef { { * requires: !Array., * invokeQueue: !Array.>, * * service: function(string, Function):angular.Module, * factory: function(string, Function):angular.Module, * value: function(string, *):angular.Module, * * filter: function(string, Function):angular.Module, * * init: function(Function):angular.Module * } } */ angular.Module; ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-message-format.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; // NOTE: ADVANCED_OPTIMIZATIONS mode. // // This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using // constructs incompatible with that mode. var $interpolateMinErr = window['angular']['$interpolateMinErr']; var noop = window['angular']['noop'], isFunction = window['angular']['isFunction'], toJson = window['angular']['toJson']; function stringify(value) { if (value == null /* null/undefined */) { return ''; } switch (typeof value) { case 'string': return value; case 'number': return '' + value; default: return toJson(value); } } // Convert an index into the string into line/column for use in error messages // As such, this doesn't have to be efficient. function indexToLineAndColumn(text, index) { var lines = text.split(/\n/g); for (var i=0; i < lines.length; i++) { var line=lines[i]; if (index >= line.length) { index -= line.length; } else { return { line: i + 1, column: index + 1 }; } } } var PARSE_CACHE_FOR_TEXT_LITERALS = Object.create(null); function parseTextLiteral(text) { var cachedFn = PARSE_CACHE_FOR_TEXT_LITERALS[text]; if (cachedFn != null) { return cachedFn; } function parsedFn(context) { return text; } parsedFn['$$watchDelegate'] = function watchDelegate(scope, listener, objectEquality) { var unwatch = scope['$watch'](noop, function textLiteralWatcher() { if (isFunction(listener)) { listener.call(null, text, text, scope); } unwatch(); }, objectEquality); return unwatch; }; PARSE_CACHE_FOR_TEXT_LITERALS[text] = parsedFn; parsedFn['exp'] = text; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js parsedFn['expressions'] = []; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding. return parsedFn; } function subtractOffset(expressionFn, offset) { if (offset === 0) { return expressionFn; } function minusOffset(value) { return (value == void 0) ? value : value - offset; } function parsedFn(context) { return minusOffset(expressionFn(context)); } var unwatch; parsedFn['$$watchDelegate'] = function watchDelegate(scope, listener, objectEquality) { unwatch = scope['$watch'](expressionFn, function pluralExpressionWatchListener(newValue, oldValue) { if (isFunction(listener)) { listener.call(null, minusOffset(newValue), minusOffset(oldValue), scope); } }, objectEquality); return unwatch; }; return parsedFn; } // NOTE: ADVANCED_OPTIMIZATIONS mode. // // This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using // constructs incompatible with that mode. /* global $interpolateMinErr: false */ /* global isFunction: false */ /* global noop: false */ /** * @constructor * @private */ function MessageSelectorBase(expressionFn, choices) { var self = this; this.expressionFn = expressionFn; this.choices = choices; if (choices["other"] === void 0) { throw $interpolateMinErr('reqother', '“other” is a required option.'); } this.parsedFn = function(context) { return self.getResult(context); }; this.parsedFn['$$watchDelegate'] = function $$watchDelegate(scope, listener, objectEquality) { return self.watchDelegate(scope, listener, objectEquality); }; this.parsedFn['exp'] = expressionFn['exp']; this.parsedFn['expressions'] = expressionFn['expressions']; } MessageSelectorBase.prototype.getMessageFn = function getMessageFn(value) { return this.choices[this.categorizeValue(value)]; }; MessageSelectorBase.prototype.getResult = function getResult(context) { return this.getMessageFn(this.expressionFn(context))(context); }; MessageSelectorBase.prototype.watchDelegate = function watchDelegate(scope, listener, objectEquality) { var watchers = new MessageSelectorWatchers(this, scope, listener, objectEquality); return function() { watchers.cancelWatch(); }; }; /** * @constructor * @private */ function MessageSelectorWatchers(msgSelector, scope, listener, objectEquality) { var self = this; this.scope = scope; this.msgSelector = msgSelector; this.listener = listener; this.objectEquality = objectEquality; this.lastMessage = void 0; this.messageFnWatcher = noop; var expressionFnListener = function(newValue, oldValue) { return self.expressionFnListener(newValue, oldValue); }; this.expressionFnWatcher = scope['$watch'](msgSelector.expressionFn, expressionFnListener, objectEquality); } MessageSelectorWatchers.prototype.expressionFnListener = function expressionFnListener(newValue, oldValue) { var self = this; this.messageFnWatcher(); var messageFnListener = function(newMessage, oldMessage) { return self.messageFnListener(newMessage, oldMessage); }; var messageFn = this.msgSelector.getMessageFn(newValue); this.messageFnWatcher = this.scope['$watch'](messageFn, messageFnListener, this.objectEquality); }; MessageSelectorWatchers.prototype.messageFnListener = function messageFnListener(newMessage, oldMessage) { if (isFunction(this.listener)) { this.listener.call(null, newMessage, newMessage === oldMessage ? newMessage : this.lastMessage, this.scope); } this.lastMessage = newMessage; }; MessageSelectorWatchers.prototype.cancelWatch = function cancelWatch() { this.expressionFnWatcher(); this.messageFnWatcher(); }; /** * @constructor * @extends MessageSelectorBase * @private */ function SelectMessage(expressionFn, choices) { MessageSelectorBase.call(this, expressionFn, choices); } function SelectMessageProto() {} SelectMessageProto.prototype = MessageSelectorBase.prototype; SelectMessage.prototype = new SelectMessageProto(); SelectMessage.prototype.categorizeValue = function categorizeSelectValue(value) { return (this.choices[value] !== void 0) ? value : "other"; }; /** * @constructor * @extends MessageSelectorBase * @private */ function PluralMessage(expressionFn, choices, offset, pluralCat) { MessageSelectorBase.call(this, expressionFn, choices); this.offset = offset; this.pluralCat = pluralCat; } function PluralMessageProto() {} PluralMessageProto.prototype = MessageSelectorBase.prototype; PluralMessage.prototype = new PluralMessageProto(); PluralMessage.prototype.categorizeValue = function categorizePluralValue(value) { if (isNaN(value)) { return "other"; } else if (this.choices[value] !== void 0) { return value; } else { var category = this.pluralCat(value - this.offset); return (this.choices[category] !== void 0) ? category : "other"; } }; // NOTE: ADVANCED_OPTIMIZATIONS mode. // // This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using // constructs incompatible with that mode. /* global $interpolateMinErr: false */ /* global isFunction: false */ /* global parseTextLiteral: false */ /** * @constructor * @private */ function InterpolationParts(trustedContext, allOrNothing) { this.trustedContext = trustedContext; this.allOrNothing = allOrNothing; this.textParts = []; this.expressionFns = []; this.expressionIndices = []; this.partialText = ''; this.concatParts = null; } InterpolationParts.prototype.flushPartialText = function flushPartialText() { if (this.partialText) { if (this.concatParts == null) { this.textParts.push(this.partialText); } else { this.textParts.push(this.concatParts.join('')); this.concatParts = null; } this.partialText = ''; } }; InterpolationParts.prototype.addText = function addText(text) { if (text.length) { if (!this.partialText) { this.partialText = text; } else if (this.concatParts) { this.concatParts.push(text); } else { this.concatParts = [this.partialText, text]; } } }; InterpolationParts.prototype.addExpressionFn = function addExpressionFn(expressionFn) { this.flushPartialText(); this.expressionIndices.push(this.textParts.length); this.expressionFns.push(expressionFn); this.textParts.push(''); }; InterpolationParts.prototype.getExpressionValues = function getExpressionValues(context) { var expressionValues = new Array(this.expressionFns.length); for (var i = 0; i < this.expressionFns.length; i++) { expressionValues[i] = this.expressionFns[i](context); } return expressionValues; }; InterpolationParts.prototype.getResult = function getResult(expressionValues) { for (var i = 0; i < this.expressionIndices.length; i++) { var expressionValue = expressionValues[i]; if (this.allOrNothing && expressionValue === void 0) return; this.textParts[this.expressionIndices[i]] = expressionValue; } return this.textParts.join(''); }; InterpolationParts.prototype.toParsedFn = function toParsedFn(mustHaveExpression, originalText) { var self = this; this.flushPartialText(); if (mustHaveExpression && this.expressionFns.length === 0) { return void 0; } if (this.textParts.length === 0) { return parseTextLiteral(''); } if (this.trustedContext && this.textParts.length > 1) { $interpolateMinErr['throwNoconcat'](originalText); } if (this.expressionFns.length === 0) { if (this.textParts.length != 1) { this.errorInParseLogic(); } return parseTextLiteral(this.textParts[0]); } var parsedFn = function(context) { return self.getResult(self.getExpressionValues(context)); }; parsedFn['$$watchDelegate'] = function $$watchDelegate(scope, listener, objectEquality) { return self.watchDelegate(scope, listener, objectEquality); }; parsedFn['exp'] = originalText; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js parsedFn['expressions'] = new Array(this.expressionFns.length); // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding. for (var i = 0; i < this.expressionFns.length; i++) { parsedFn['expressions'][i] = this.expressionFns[i]['exp']; } return parsedFn; }; InterpolationParts.prototype.watchDelegate = function watchDelegate(scope, listener, objectEquality) { var watcher = new InterpolationPartsWatcher(this, scope, listener, objectEquality); return function() { watcher.cancelWatch(); }; }; function InterpolationPartsWatcher(interpolationParts, scope, listener, objectEquality) { this.interpolationParts = interpolationParts; this.scope = scope; this.previousResult = (void 0); this.listener = listener; var self = this; this.expressionFnsWatcher = scope['$watchGroup'](interpolationParts.expressionFns, function(newExpressionValues, oldExpressionValues) { self.watchListener(newExpressionValues, oldExpressionValues); }); } InterpolationPartsWatcher.prototype.watchListener = function watchListener(newExpressionValues, oldExpressionValues) { var result = this.interpolationParts.getResult(newExpressionValues); if (isFunction(this.listener)) { this.listener.call(null, result, newExpressionValues === oldExpressionValues ? result : this.previousResult, this.scope); } this.previousResult = result; }; InterpolationPartsWatcher.prototype.cancelWatch = function cancelWatch() { this.expressionFnsWatcher(); }; // NOTE: ADVANCED_OPTIMIZATIONS mode. // // This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using // constructs incompatible with that mode. /* global $interpolateMinErr: false */ /* global indexToLineAndColumn: false */ /* global InterpolationParts: false */ /* global PluralMessage: false */ /* global SelectMessage: false */ /* global subtractOffset: false */ // The params src and dst are exactly one of two types: NestedParserState or MessageFormatParser. // This function is fully optimized by V8. (inspect via IRHydra or --trace-deopt.) // The idea behind writing it this way is to avoid repeating oneself. This is the ONE place where // the parser state that is saved/restored when parsing nested mustaches is specified. function copyNestedParserState(src, dst) { dst.expressionFn = src.expressionFn; dst.expressionMinusOffsetFn = src.expressionMinusOffsetFn; dst.pluralOffset = src.pluralOffset; dst.choices = src.choices; dst.choiceKey = src.choiceKey; dst.interpolationParts = src.interpolationParts; dst.ruleChoiceKeyword = src.ruleChoiceKeyword; dst.msgStartIndex = src.msgStartIndex; dst.expressionStartIndex = src.expressionStartIndex; } function NestedParserState(parser) { copyNestedParserState(parser, this); } /** * @constructor * @private */ function MessageFormatParser(text, startIndex, $parse, pluralCat, stringifier, mustHaveExpression, trustedContext, allOrNothing) { this.text = text; this.index = startIndex || 0; this.$parse = $parse; this.pluralCat = pluralCat; this.stringifier = stringifier; this.mustHaveExpression = !!mustHaveExpression; this.trustedContext = trustedContext; this.allOrNothing = !!allOrNothing; this.expressionFn = null; this.expressionMinusOffsetFn = null; this.pluralOffset = null; this.choices = null; this.choiceKey = null; this.interpolationParts = null; this.msgStartIndex = null; this.nestedStateStack = []; this.parsedFn = null; this.rule = null; this.ruleStack = null; this.ruleChoiceKeyword = null; this.interpNestLevel = null; this.expressionStartIndex = null; this.stringStartIndex = null; this.stringQuote = null; this.stringInterestsRe = null; this.angularOperatorStack = null; this.textPart = null; } // preserve v8 optimization. var EMPTY_STATE = new NestedParserState(new MessageFormatParser( /* text= */ '', /* startIndex= */ 0, /* $parse= */ null, /* pluralCat= */ null, /* stringifier= */ null, /* mustHaveExpression= */ false, /* trustedContext= */ null, /* allOrNothing */ false)); MessageFormatParser.prototype.pushState = function pushState() { this.nestedStateStack.push(new NestedParserState(this)); copyNestedParserState(EMPTY_STATE, this); }; MessageFormatParser.prototype.popState = function popState() { if (this.nestedStateStack.length === 0) { this.errorInParseLogic(); } var previousState = this.nestedStateStack.pop(); copyNestedParserState(previousState, this); }; // Oh my JavaScript! Who knew you couldn't match a regex at a specific // location in a string but will always search forward?! // Apparently you'll be growing this ability via the sticky flag (y) in // ES6. I'll just to work around you for now. MessageFormatParser.prototype.matchRe = function matchRe(re, search) { re.lastIndex = this.index; var match = re.exec(this.text); if (match != null && (search === true || (match.index == this.index))) { this.index = re.lastIndex; return match; } return null; }; MessageFormatParser.prototype.searchRe = function searchRe(re) { return this.matchRe(re, true); }; MessageFormatParser.prototype.consumeRe = function consumeRe(re) { // Without the sticky flag, we can't use the .test() method to consume a // match at the current index. Instead, we'll use the slower .exec() method // and verify match.index. return !!this.matchRe(re); }; // Run through our grammar avoiding deeply nested function call chains. MessageFormatParser.prototype.run = function run(initialRule) { this.ruleStack = [initialRule]; do { this.rule = this.ruleStack.pop(); while (this.rule) { this.rule(); } this.assertRuleOrNull(this.rule); } while (this.ruleStack.length > 0); }; MessageFormatParser.prototype.errorInParseLogic = function errorInParseLogic() { throw $interpolateMinErr('logicbug', 'The messageformat parser has encountered an internal error. Please file a github issue against the AngularJS project and provide this message text that triggers the bug. Text: “{0}”', this.text); }; MessageFormatParser.prototype.assertRuleOrNull = function assertRuleOrNull(rule) { if (rule === void 0) { this.errorInParseLogic(); } }; var NEXT_WORD_RE = /\s*(\w+)\s*/g; MessageFormatParser.prototype.errorExpecting = function errorExpecting() { // What was wrong with the syntax? Unsupported type, missing comma, or something else? var match = this.matchRe(NEXT_WORD_RE), position; if (match == null) { position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('reqarg', 'Expected one of “plural” or “select” at line {0}, column {1} of text “{2}”', position.line, position.column, this.text); } var word = match[1]; if (word == "select" || word == "plural") { position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('reqcomma', 'Expected a comma after the keyword “{0}” at line {1}, column {2} of text “{3}”', word, position.line, position.column, this.text); } else { position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('unknarg', 'Unsupported keyword “{0}” at line {0}, column {1}. Only “plural” and “select” are currently supported. Text: “{3}”', word, position.line, position.column, this.text); } }; var STRING_START_RE = /['"]/g; MessageFormatParser.prototype.ruleString = function ruleString() { var match = this.matchRe(STRING_START_RE); if (match == null) { var position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('wantstring', 'Expected the beginning of a string at line {0}, column {1} in text “{2}”', position.line, position.column, this.text); } this.startStringAtMatch(match); }; MessageFormatParser.prototype.startStringAtMatch = function startStringAtMatch(match) { this.stringStartIndex = match.index; this.stringQuote = match[0]; this.stringInterestsRe = this.stringQuote == "'" ? SQUOTED_STRING_INTEREST_RE : DQUOTED_STRING_INTEREST_RE; this.rule = this.ruleInsideString; }; var SQUOTED_STRING_INTEREST_RE = /\\(?:\\|'|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}|[0-7]{3}|\r\n|\n|[\s\S])|'/g; var DQUOTED_STRING_INTEREST_RE = /\\(?:\\|"|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}|[0-7]{3}|\r\n|\n|[\s\S])|"/g; MessageFormatParser.prototype.ruleInsideString = function ruleInsideString() { var match = this.searchRe(this.stringInterestsRe); if (match == null) { var position = indexToLineAndColumn(this.text, this.stringStartIndex); throw $interpolateMinErr('untermstr', 'The string beginning at line {0}, column {1} is unterminated in text “{2}”', position.line, position.column, this.text); } var chars = match[0]; if (match == this.stringQuote) { this.rule = null; } }; var PLURAL_OR_SELECT_ARG_TYPE_RE = /\s*(plural|select)\s*,\s*/g; MessageFormatParser.prototype.rulePluralOrSelect = function rulePluralOrSelect() { var match = this.searchRe(PLURAL_OR_SELECT_ARG_TYPE_RE); if (match == null) { this.errorExpecting(); } var argType = match[1]; switch (argType) { case "plural": this.rule = this.rulePluralStyle; break; case "select": this.rule = this.ruleSelectStyle; break; default: this.errorInParseLogic(); } }; MessageFormatParser.prototype.rulePluralStyle = function rulePluralStyle() { this.choices = Object.create(null); this.ruleChoiceKeyword = this.rulePluralValueOrKeyword; this.rule = this.rulePluralOffset; }; MessageFormatParser.prototype.ruleSelectStyle = function ruleSelectStyle() { this.choices = Object.create(null); this.ruleChoiceKeyword = this.ruleSelectKeyword; this.rule = this.ruleSelectKeyword; }; var NUMBER_RE = /[0]|(?:[1-9][0-9]*)/g; var PLURAL_OFFSET_RE = new RegExp("\\s*offset\\s*:\\s*(" + NUMBER_RE.source + ")", "g"); MessageFormatParser.prototype.rulePluralOffset = function rulePluralOffset() { var match = this.matchRe(PLURAL_OFFSET_RE); this.pluralOffset = (match == null) ? 0 : parseInt(match[1], 10); this.expressionMinusOffsetFn = subtractOffset(this.expressionFn, this.pluralOffset); this.rule = this.rulePluralValueOrKeyword; }; MessageFormatParser.prototype.assertChoiceKeyIsNew = function assertChoiceKeyIsNew(choiceKey, index) { if (this.choices[choiceKey] !== void 0) { var position = indexToLineAndColumn(this.text, index); throw $interpolateMinErr('dupvalue', 'The choice “{0}” is specified more than once. Duplicate key is at line {1}, column {2} in text “{3}”', choiceKey, position.line, position.column, this.text); } }; var SELECT_KEYWORD = /\s*(\w+)/g; MessageFormatParser.prototype.ruleSelectKeyword = function ruleSelectKeyword() { var match = this.matchRe(SELECT_KEYWORD); if (match == null) { this.parsedFn = new SelectMessage(this.expressionFn, this.choices).parsedFn; this.rule = null; return; } this.choiceKey = match[1]; this.assertChoiceKeyIsNew(this.choiceKey, match.index); this.rule = this.ruleMessageText; }; var EXPLICIT_VALUE_OR_KEYWORD_RE = new RegExp("\\s*(?:(?:=(" + NUMBER_RE.source + "))|(\\w+))", "g"); MessageFormatParser.prototype.rulePluralValueOrKeyword = function rulePluralValueOrKeyword() { var match = this.matchRe(EXPLICIT_VALUE_OR_KEYWORD_RE); if (match == null) { this.parsedFn = new PluralMessage(this.expressionFn, this.choices, this.pluralOffset, this.pluralCat).parsedFn; this.rule = null; return; } if (match[1] != null) { this.choiceKey = parseInt(match[1], 10); } else { this.choiceKey = match[2]; } this.assertChoiceKeyIsNew(this.choiceKey, match.index); this.rule = this.ruleMessageText; }; var BRACE_OPEN_RE = /\s*{/g; var BRACE_CLOSE_RE = /}/g; MessageFormatParser.prototype.ruleMessageText = function ruleMessageText() { if (!this.consumeRe(BRACE_OPEN_RE)) { var position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('reqopenbrace', 'The plural choice “{0}” must be followed by a message in braces at line {1}, column {2} in text “{3}”', this.choiceKey, position.line, position.column, this.text); } this.msgStartIndex = this.index; this.interpolationParts = new InterpolationParts(this.trustedContext, this.allOrNothing); this.rule = this.ruleInInterpolationOrMessageText; }; // Note: Since "\" is used as an escape character, don't allow it to be part of the // startSymbol/endSymbol when I add the feature to allow them to be redefined. var INTERP_OR_END_MESSAGE_RE = /\\.|{{|}/g; var INTERP_OR_PLURALVALUE_OR_END_MESSAGE_RE = /\\.|{{|#|}/g; var ESCAPE_OR_MUSTACHE_BEGIN_RE = /\\.|{{/g; MessageFormatParser.prototype.advanceInInterpolationOrMessageText = function advanceInInterpolationOrMessageText() { var currentIndex = this.index, match, re; if (this.ruleChoiceKeyword == null) { // interpolation match = this.searchRe(ESCAPE_OR_MUSTACHE_BEGIN_RE); if (match == null) { // End of interpolation text. Nothing more to process. this.textPart = this.text.substring(currentIndex); this.index = this.text.length; return null; } } else { match = this.searchRe(this.ruleChoiceKeyword == this.rulePluralValueOrKeyword ? INTERP_OR_PLURALVALUE_OR_END_MESSAGE_RE : INTERP_OR_END_MESSAGE_RE); if (match == null) { var position = indexToLineAndColumn(this.text, this.msgStartIndex); throw $interpolateMinErr('reqendbrace', 'The plural/select choice “{0}” message starting at line {1}, column {2} does not have an ending closing brace. Text “{3}”', this.choiceKey, position.line, position.column, this.text); } } // match is non-null. var token = match[0]; this.textPart = this.text.substring(currentIndex, match.index); return token; }; MessageFormatParser.prototype.ruleInInterpolationOrMessageText = function ruleInInterpolationOrMessageText() { var currentIndex = this.index; var token = this.advanceInInterpolationOrMessageText(); if (token == null) { // End of interpolation text. Nothing more to process. this.index = this.text.length; this.interpolationParts.addText(this.text.substring(currentIndex)); this.rule = null; return; } if (token[0] == "\\") { // unescape next character and continue this.interpolationParts.addText(this.textPart + token[1]); return; } this.interpolationParts.addText(this.textPart); if (token == "{{") { this.pushState(); this.ruleStack.push(this.ruleEndMustacheInInterpolationOrMessage); this.rule = this.ruleEnteredMustache; } else if (token == "}") { this.choices[this.choiceKey] = this.interpolationParts.toParsedFn(/*mustHaveExpression=*/false, this.text); this.rule = this.ruleChoiceKeyword; } else if (token == "#") { this.interpolationParts.addExpressionFn(this.expressionMinusOffsetFn); } else { this.errorInParseLogic(); } }; MessageFormatParser.prototype.ruleInterpolate = function ruleInterpolate() { this.interpolationParts = new InterpolationParts(this.trustedContext, this.allOrNothing); this.rule = this.ruleInInterpolation; }; MessageFormatParser.prototype.ruleInInterpolation = function ruleInInterpolation() { var currentIndex = this.index; var match = this.searchRe(ESCAPE_OR_MUSTACHE_BEGIN_RE); if (match == null) { // End of interpolation text. Nothing more to process. this.index = this.text.length; this.interpolationParts.addText(this.text.substring(currentIndex)); this.parsedFn = this.interpolationParts.toParsedFn(this.mustHaveExpression, this.text); this.rule = null; return; } var token = match[0]; if (token[0] == "\\") { // unescape next character and continue this.interpolationParts.addText(this.text.substring(currentIndex, match.index) + token[1]); return; } this.interpolationParts.addText(this.text.substring(currentIndex, match.index)); this.pushState(); this.ruleStack.push(this.ruleInterpolationEndMustache); this.rule = this.ruleEnteredMustache; }; MessageFormatParser.prototype.ruleInterpolationEndMustache = function ruleInterpolationEndMustache() { var expressionFn = this.parsedFn; this.popState(); this.interpolationParts.addExpressionFn(expressionFn); this.rule = this.ruleInInterpolation; }; MessageFormatParser.prototype.ruleEnteredMustache = function ruleEnteredMustache() { this.parsedFn = null; this.ruleStack.push(this.ruleEndMustache); this.rule = this.ruleAngularExpression; }; MessageFormatParser.prototype.ruleEndMustacheInInterpolationOrMessage = function ruleEndMustacheInInterpolationOrMessage() { var expressionFn = this.parsedFn; this.popState(); this.interpolationParts.addExpressionFn(expressionFn); this.rule = this.ruleInInterpolationOrMessageText; }; var INTERP_END_RE = /\s*}}/g; MessageFormatParser.prototype.ruleEndMustache = function ruleEndMustache() { var match = this.matchRe(INTERP_END_RE); if (match == null) { var position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('reqendinterp', 'Expecting end of interpolation symbol, “{0}”, at line {1}, column {2} in text “{3}”', '}}', position.line, position.column, this.text); } if (this.parsedFn == null) { // If we parsed a MessageFormat extension, (e.g. select/plural today, maybe more some other // day), then the result *has* to be a string and those rules would have already set // this.parsedFn. If there was no MessageFormat extension, then there is no requirement to // stringify the result and parsedFn isn't set. We set it here. While we could have set it // unconditionally when exiting the Angular expression, I intend for us to not just replace // $interpolate, but also to replace $parse in a future version (so ng-bind can work), and in // such a case we do not want to unnecessarily stringify something if it's not going to be used // in a string context. this.parsedFn = this.$parse(this.expressionFn, this.stringifier); this.parsedFn['exp'] = this.expressionFn['exp']; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js this.parsedFn['expressions'] = this.expressionFn['expressions']; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding. } this.rule = null; }; MessageFormatParser.prototype.ruleAngularExpression = function ruleAngularExpression() { this.angularOperatorStack = []; this.expressionStartIndex = this.index; this.rule = this.ruleInAngularExpression; }; function getEndOperator(opBegin) { switch (opBegin) { case "{": return "}"; case "[": return "]"; case "(": return ")"; default: return null; } } function getBeginOperator(opEnd) { switch (opEnd) { case "}": return "{"; case "]": return "["; case ")": return "("; default: return null; } } // TODO(chirayu): The interpolation endSymbol must also be accounted for. It // just so happens that "}" is an operator so it's in the list below. But we // should support any other type of start/end interpolation symbol. var INTERESTING_OPERATORS_RE = /[[\]{}()'",]/g; MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularExpression() { var startIndex = this.index; var match = this.searchRe(INTERESTING_OPERATORS_RE); var position; if (match == null) { if (this.angularOperatorStack.length === 0) { // This is the end of the Angular expression so this is actually a // success. Note that when inside an interpolation, this means we even // consumed the closing interpolation symbols if they were curlies. This // is NOT an error at this point but will become an error further up the // stack when the part that saw the opening curlies is unable to find the // closing ones. this.index = this.text.length; this.expressionFn = this.$parse(this.text.substring(this.expressionStartIndex, this.index)); // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js this.expressionFn['exp'] = this.text.substring(this.expressionStartIndex, this.index); this.expressionFn['expressions'] = this.expressionFn['expressions']; this.rule = null; return; } var innermostOperator = this.angularOperatorStack[0]; throw $interpolateMinErr('badexpr', 'Unexpected end of Angular expression. Expecting operator “{0}” at the end of the text “{1}”', this.getEndOperator(innermostOperator), this.text); } var operator = match[0]; if (operator == "'" || operator == '"') { this.ruleStack.push(this.ruleInAngularExpression); this.startStringAtMatch(match); return; } if (operator == ",") { if (this.trustedContext) { position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('unsafe', 'Use of select/plural MessageFormat syntax is currently disallowed in a secure context ({0}). At line {1}, column {2} of text “{3}”', this.trustedContext, position.line, position.column, this.text); } // only the top level comma has relevance. if (this.angularOperatorStack.length === 0) { // todo: does this need to be trimmed? this.expressionFn = this.$parse(this.text.substring(this.expressionStartIndex, match.index)); // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js this.expressionFn['exp'] = this.text.substring(this.expressionStartIndex, match.index); this.expressionFn['expressions'] = this.expressionFn['expressions']; this.rule = null; this.rule = this.rulePluralOrSelect; } return; } if (getEndOperator(operator) != null) { this.angularOperatorStack.unshift(operator); return; } var beginOperator = getBeginOperator(operator); if (beginOperator == null) { this.errorInParseLogic(); } if (this.angularOperatorStack.length > 0) { if (beginOperator == this.angularOperatorStack[0]) { this.angularOperatorStack.shift(); return; } position = indexToLineAndColumn(this.text, this.index); throw $interpolateMinErr('badexpr', 'Unexpected operator “{0}” at line {1}, column {2} in text. Was expecting “{3}”. Text: “{4}”', operator, position.line, position.column, getEndOperator(this.angularOperatorStack[0]), this.text); } // We are trying to pop off the operator stack but there really isn't anything to pop off. this.index = match.index; this.expressionFn = this.$parse(this.text.substring(this.expressionStartIndex, this.index)); // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js this.expressionFn['exp'] = this.text.substring(this.expressionStartIndex, this.index); this.expressionFn['expressions'] = this.expressionFn['expressions']; this.rule = null; }; // NOTE: ADVANCED_OPTIMIZATIONS mode. // // This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using // constructs incompatible with that mode. /* global $interpolateMinErr: false */ /* global MessageFormatParser: false */ /* global stringify: false */ /** * @ngdoc service * @name $$messageFormat * * @description * Angular internal service to recognize MessageFormat extensions in interpolation expressions. * For more information, see: * https://docs.google.com/a/google.com/document/d/1pbtW2yvtmFBikfRrJd8VAsabiFkKezmYZ_PbgdjQOVU/edit * * ## Example * * * *
*
* {{recipients.length, plural, offset:1 * =0 {{{sender.name}} gave no gifts (\#=#)} * =1 {{{sender.name}} gave one gift to {{recipients[0].name}} (\#=#)} * one {{{sender.name}} gave {{recipients[0].name}} and one other person a gift (\#=#)} * other {{{sender.name}} gave {{recipients[0].name}} and # other people a gift (\#=#)} * }} *
*
* * * function Person(name, gender) { * this.name = name; * this.gender = gender; * } * * var alice = new Person("Alice", "female"), * bob = new Person("Bob", "male"), * charlie = new Person("Charlie", "male"), * harry = new Person("Harry Potter", "male"); * * angular.module('msgFmtExample', ['ngMessageFormat']) * .controller('AppController', ['$scope', function($scope) { * $scope.recipients = [alice, bob, charlie]; * $scope.sender = harry; * $scope.decreaseRecipients = function() { * --$scope.recipients.length; * }; * }]); * * * * describe('MessageFormat plural', function() { * it('should pluralize initial values', function() { * var messageElem = element(by.binding('recipients.length')), decreaseRecipientsBtn = element(by.id('decreaseRecipients')); * expect(messageElem.getText()).toEqual('Harry Potter gave Alice and 2 other people a gift (#=2)'); * decreaseRecipientsBtn.click(); * expect(messageElem.getText()).toEqual('Harry Potter gave Alice and one other person a gift (#=1)'); * decreaseRecipientsBtn.click(); * expect(messageElem.getText()).toEqual('Harry Potter gave one gift to Alice (#=0)'); * decreaseRecipientsBtn.click(); * expect(messageElem.getText()).toEqual('Harry Potter gave no gifts (#=-1)'); * }); * }); * *
*/ var $$MessageFormatFactory = ['$parse', '$locale', '$sce', '$exceptionHandler', function $$messageFormat( $parse, $locale, $sce, $exceptionHandler) { function getStringifier(trustedContext, allOrNothing, text) { return function stringifier(value) { try { value = trustedContext ? $sce['getTrusted'](trustedContext, value) : $sce['valueOf'](value); return allOrNothing && (value === void 0) ? value : stringify(value); } catch (err) { $exceptionHandler($interpolateMinErr['interr'](text, err)); } }; } function interpolate(text, mustHaveExpression, trustedContext, allOrNothing) { var stringifier = getStringifier(trustedContext, allOrNothing, text); var parser = new MessageFormatParser(text, 0, $parse, $locale['pluralCat'], stringifier, mustHaveExpression, trustedContext, allOrNothing); parser.run(parser.ruleInterpolate); return parser.parsedFn; } return { 'interpolate': interpolate }; }]; var $$interpolateDecorator = ['$$messageFormat', '$delegate', function $$interpolateDecorator($$messageFormat, $interpolate) { if ($interpolate['startSymbol']() != "{{" || $interpolate['endSymbol']() != "}}") { throw $interpolateMinErr('nochgmustache', 'angular-message-format.js currently does not allow you to use custom start and end symbols for interpolation.'); } var interpolate = $$messageFormat['interpolate']; interpolate['startSymbol'] = $interpolate['startSymbol']; interpolate['endSymbol'] = $interpolate['endSymbol']; return interpolate; }]; /** * @ngdoc module * @name ngMessageFormat * @packageName angular-message-format * @description */ var module = window['angular']['module']('ngMessageFormat', ['ng']); module['factory']('$$messageFormat', $$MessageFormatFactory); module['config'](['$provide', function($provide) { $provide['decorator']('$interpolate', $$interpolateDecorator); }]); })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-messages.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /* jshint ignore:start */ // this code is in the core, but not in angular-messages.js var isArray = angular.isArray; var forEach = angular.forEach; var isString = angular.isString; var jqLite = angular.element; /* jshint ignore:end */ /** * @ngdoc module * @name ngMessages * @description * * The `ngMessages` module provides enhanced support for displaying messages within templates * (typically within forms or when rendering message objects that return key/value data). * Instead of relying on JavaScript code and/or complex ng-if statements within your form template to * show and hide error messages specific to the state of an input field, the `ngMessages` and * `ngMessage` directives are designed to handle the complexity, inheritance and priority * sequencing based on the order of how the messages are defined in the template. * * Currently, the ngMessages module only contains the code for the `ngMessages`, `ngMessagesInclude` * `ngMessage` and `ngMessageExp` directives. * * # Usage * The `ngMessages` directive listens on a key/value collection which is set on the ngMessages attribute. * Since the {@link ngModel ngModel} directive exposes an `$error` object, this error object can be * used with `ngMessages` to display control error messages in an easier way than with just regular angular * template directives. * * ```html *
* *
*
You did not enter a field
*
* Your email must be between 5 and 100 characters long *
*
*
* ``` * * Now whatever key/value entries are present within the provided object (in this case `$error`) then * the ngMessages directive will render the inner first ngMessage directive (depending if the key values * match the attribute value present on each ngMessage directive). In other words, if your errors * object contains the following data: * * ```javascript * * myField.$error = { minlength : true, required : true }; * ``` * * Then the `required` message will be displayed first. When required is false then the `minlength` message * will be displayed right after (since these messages are ordered this way in the template HTML code). * The prioritization of each message is determined by what order they're present in the DOM. * Therefore, instead of having custom JavaScript code determine the priority of what errors are * present before others, the presentation of the errors are handled within the template. * * By default, ngMessages will only display one error at a time. However, if you wish to display all * messages then the `ng-messages-multiple` attribute flag can be used on the element containing the * ngMessages directive to make this happen. * * ```html * *
...
* * * ... * ``` * * ## Reusing and Overriding Messages * In addition to prioritization, ngMessages also allows for including messages from a remote or an inline * template. This allows for generic collection of messages to be reused across multiple parts of an * application. * * ```html * * *
*
*
* ``` * * However, including generic messages may not be useful enough to match all input fields, therefore, * `ngMessages` provides the ability to override messages defined in the remote template by redefining * them within the directive container. * * ```html * * * *
* * *
* *
You did not enter your email address
* * *
Your email address is invalid
* * *
*
*
* ``` * * In the example HTML code above the message that is set on required will override the corresponding * required message defined within the remote template. Therefore, with particular input fields (such * email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied * while more generic messages can be used to handle other, more general input errors. * * ## Dynamic Messaging * ngMessages also supports using expressions to dynamically change key values. Using arrays and * repeaters to list messages is also supported. This means that the code below will be able to * fully adapt itself and display the appropriate message when any of the expression data changes: * * ```html *
* *
*
You did not enter your email address
*
* *
{{ errorMessage.text }}
*
*
*
* ``` * * The `errorMessage.type` expression can be a string value or it can be an array so * that multiple errors can be associated with a single error message: * * ```html * *
*
You did not enter your email address
*
* Your email must be between 5 and 100 characters long *
*
* ``` * * Feel free to use other structural directives such as ng-if and ng-switch to further control * what messages are active and when. Be careful, if you place ng-message on the same element * as these structural directives, Angular may not be able to determine if a message is active * or not. Therefore it is best to place the ng-message on a child element of the structural * directive. * * ```html *
*
*
Please enter something
*
*
* ``` * * ## Animations * If the `ngAnimate` module is active within the application then the `ngMessages`, `ngMessage` and * `ngMessageExp` directives will trigger animations whenever any messages are added and removed from * the DOM by the `ngMessages` directive. * * Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS * class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no * messages present. Therefore, CSS transitions and keyframes as well as JavaScript animations can * hook into the animations whenever these classes are added/removed. * * Let's say that our HTML code for our messages container looks like so: * * ```html * * ``` * * Then the CSS animation code for the message container looks like so: * * ```css * .my-messages { * transition:1s linear all; * } * .my-messages.ng-active { * // messages are visible * } * .my-messages.ng-inactive { * // messages are hidden * } * ``` * * Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter * and leave animation is triggered for each particular element bound to the `ngMessage` directive. * * Therefore, the CSS code for the inner messages looks like so: * * ```css * .some-message { * transition:1s linear all; * } * * .some-message.ng-enter {} * .some-message.ng-enter.ng-enter-active {} * * .some-message.ng-leave {} * .some-message.ng-leave.ng-leave-active {} * ``` * * {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate. */ angular.module('ngMessages', []) /** * @ngdoc directive * @module ngMessages * @name ngMessages * @restrict AE * * @description * `ngMessages` is a directive that is designed to show and hide messages based on the state * of a key/value object that it listens on. The directive itself complements error message * reporting with the `ngModel` $error object (which stores a key/value state of validation errors). * * `ngMessages` manages the state of internal messages within its container element. The internal * messages use the `ngMessage` directive and will be inserted/removed from the page depending * on if they're present within the key/value object. By default, only one message will be displayed * at a time and this depends on the prioritization of the messages within the template. (This can * be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.) * * A remote template can also be used to promote message reusability and messages can also be * overridden. * * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`. * * @usage * ```html * * * ... * ... * ... * * * * * ... * ... * ... * * ``` * * @param {string} ngMessages an angular expression evaluating to a key/value object * (this is typically the $error object on an ngModel instance). * @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true * * @example * * *
* *
myForm.myName.$error = {{ myForm.myName.$error | json }}
* *
*
You did not enter a field
*
Your field is too short
*
Your field is too long
*
*
*
* * angular.module('ngMessagesExample', ['ngMessages']); * *
*/ .directive('ngMessages', ['$animate', function($animate) { var ACTIVE_CLASS = 'ng-active'; var INACTIVE_CLASS = 'ng-inactive'; return { require: 'ngMessages', restrict: 'AE', controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) { var ctrl = this; var latestKey = 0; var nextAttachId = 0; this.getAttachId = function getAttachId() { return nextAttachId++; }; var messages = this.messages = {}; var renderLater, cachedCollection; this.render = function(collection) { collection = collection || {}; renderLater = false; cachedCollection = collection; // this is true if the attribute is empty or if the attribute value is truthy var multiple = isAttrTruthy($scope, $attrs.ngMessagesMultiple) || isAttrTruthy($scope, $attrs.multiple); var unmatchedMessages = []; var matchedKeys = {}; var messageItem = ctrl.head; var messageFound = false; var totalMessages = 0; // we use != instead of !== to allow for both undefined and null values while (messageItem != null) { totalMessages++; var messageCtrl = messageItem.message; var messageUsed = false; if (!messageFound) { forEach(collection, function(value, key) { if (!messageUsed && truthy(value) && messageCtrl.test(key)) { // this is to prevent the same error name from showing up twice if (matchedKeys[key]) return; matchedKeys[key] = true; messageUsed = true; messageCtrl.attach(); } }); } if (messageUsed) { // unless we want to display multiple messages then we should // set a flag here to avoid displaying the next message in the list messageFound = !multiple; } else { unmatchedMessages.push(messageCtrl); } messageItem = messageItem.next; } forEach(unmatchedMessages, function(messageCtrl) { messageCtrl.detach(); }); unmatchedMessages.length !== totalMessages ? $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS) : $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS); }; $scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render); this.reRender = function() { if (!renderLater) { renderLater = true; $scope.$evalAsync(function() { if (renderLater) { cachedCollection && ctrl.render(cachedCollection); } }); } }; this.register = function(comment, messageCtrl) { var nextKey = latestKey.toString(); messages[nextKey] = { message: messageCtrl }; insertMessageNode($element[0], comment, nextKey); comment.$$ngMessageNode = nextKey; latestKey++; ctrl.reRender(); }; this.deregister = function(comment) { var key = comment.$$ngMessageNode; delete comment.$$ngMessageNode; removeMessageNode($element[0], comment, key); delete messages[key]; ctrl.reRender(); }; function findPreviousMessage(parent, comment) { var prevNode = comment; var parentLookup = []; while (prevNode && prevNode !== parent) { var prevKey = prevNode.$$ngMessageNode; if (prevKey && prevKey.length) { return messages[prevKey]; } // dive deeper into the DOM and examine its children for any ngMessage // comments that may be in an element that appears deeper in the list if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) == -1) { parentLookup.push(prevNode); prevNode = prevNode.childNodes[prevNode.childNodes.length - 1]; } else { prevNode = prevNode.previousSibling || prevNode.parentNode; } } } function insertMessageNode(parent, comment, key) { var messageNode = messages[key]; if (!ctrl.head) { ctrl.head = messageNode; } else { var match = findPreviousMessage(parent, comment); if (match) { messageNode.next = match.next; match.next = messageNode; } else { messageNode.next = ctrl.head; ctrl.head = messageNode; } } } function removeMessageNode(parent, comment, key) { var messageNode = messages[key]; var match = findPreviousMessage(parent, comment); if (match) { match.next = messageNode.next; } else { ctrl.head = messageNode.next; } } }] }; function isAttrTruthy(scope, attr) { return (isString(attr) && attr.length === 0) || //empty attribute truthy(scope.$eval(attr)); } function truthy(val) { return isString(val) ? val.length : !!val; } }]) /** * @ngdoc directive * @name ngMessagesInclude * @restrict AE * @scope * * @description * `ngMessagesInclude` is a directive with the purpose to import existing ngMessage template * code from a remote template and place the downloaded template code into the exact spot * that the ngMessagesInclude directive is placed within the ngMessages container. This allows * for a series of pre-defined messages to be reused and also allows for the developer to * determine what messages are overridden due to the placement of the ngMessagesInclude directive. * * @usage * ```html * * * ... * * * * * ... * * ``` * * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`. * * @param {string} ngMessagesInclude|src a string value corresponding to the remote template. */ .directive('ngMessagesInclude', ['$templateRequest', '$document', '$compile', function($templateRequest, $document, $compile) { return { restrict: 'AE', require: '^^ngMessages', // we only require this for validation sake link: function($scope, element, attrs) { var src = attrs.ngMessagesInclude || attrs.src; $templateRequest(src).then(function(html) { $compile(html)($scope, function(contents) { element.after(contents); // the anchor is placed for debugging purposes var anchor = jqLite($document[0].createComment(' ngMessagesInclude: ' + src + ' ')); element.after(anchor); // we don't want to pollute the DOM anymore by keeping an empty directive element element.remove(); }); }); } }; }]) /** * @ngdoc directive * @name ngMessage * @restrict AE * @scope * * @description * `ngMessage` is a directive with the purpose to show and hide a particular message. * For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element * must be situated since it determines which messages are visible based on the state * of the provided key/value map that `ngMessages` listens on. * * More information about using `ngMessage` can be found in the * {@link module:ngMessages `ngMessages` module documentation}. * * @usage * ```html * * * ... * ... * * * * * ... * ... * * ``` * * @param {expression} ngMessage|when a string value corresponding to the message key. */ .directive('ngMessage', ngMessageDirectiveFactory('AE')) /** * @ngdoc directive * @name ngMessageExp * @restrict AE * @scope * * @description * `ngMessageExp` is a directive with the purpose to show and hide a particular message. * For `ngMessageExp` to operate, a parent `ngMessages` directive on a parent DOM element * must be situated since it determines which messages are visible based on the state * of the provided key/value map that `ngMessages` listens on. * * @usage * ```html * * * ... * * * * * ... * * ``` * * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`. * * @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key. */ .directive('ngMessageExp', ngMessageDirectiveFactory('A')); function ngMessageDirectiveFactory(restrict) { return ['$animate', function($animate) { return { restrict: 'AE', transclude: 'element', terminal: true, require: '^^ngMessages', link: function(scope, element, attrs, ngMessagesCtrl, $transclude) { var commentNode = element[0]; var records; var staticExp = attrs.ngMessage || attrs.when; var dynamicExp = attrs.ngMessageExp || attrs.whenExp; var assignRecords = function(items) { records = items ? (isArray(items) ? items : items.split(/[\s,]+/)) : null; ngMessagesCtrl.reRender(); }; if (dynamicExp) { assignRecords(scope.$eval(dynamicExp)); scope.$watchCollection(dynamicExp, assignRecords); } else { assignRecords(staticExp); } var currentElement, messageCtrl; ngMessagesCtrl.register(commentNode, messageCtrl = { test: function(name) { return contains(records, name); }, attach: function() { if (!currentElement) { $transclude(scope, function(elm) { $animate.enter(elm, null, element); currentElement = elm; // Each time we attach this node to a message we get a new id that we can match // when we are destroying the node later. var $$attachId = currentElement.$$attachId = ngMessagesCtrl.getAttachId(); // in the event that the parent element is destroyed // by any other structural directive then it's time // to deregister the message from the controller currentElement.on('$destroy', function() { if (currentElement && currentElement.$$attachId === $$attachId) { ngMessagesCtrl.deregister(commentNode); messageCtrl.detach(); } }); }); } }, detach: function() { if (currentElement) { var elm = currentElement; currentElement = null; $animate.leave(elm); } } }); } }; }]; function contains(collection, key) { if (collection) { return isArray(collection) ? collection.indexOf(key) >= 0 : collection.hasOwnProperty(key); } } } })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-mocks.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) { 'use strict'; /** * @ngdoc object * @name angular.mock * @description * * Namespace from 'angular-mocks.js' which contains testing related code. */ angular.mock = {}; /** * ! This is a private undocumented service ! * * @name $browser * * @description * This service is a mock implementation of {@link ng.$browser}. It provides fake * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr, * cookies, etc... * * The api of this service is the same as that of the real {@link ng.$browser $browser}, except * that there are several helper methods available which can be used in tests. */ angular.mock.$BrowserProvider = function() { this.$get = function() { return new angular.mock.$Browser(); }; }; angular.mock.$Browser = function() { var self = this; this.isMock = true; self.$$url = "http://server/"; self.$$lastUrl = self.$$url; // used by url polling fn self.pollFns = []; // TODO(vojta): remove this temporary api self.$$completeOutstandingRequest = angular.noop; self.$$incOutstandingRequestCount = angular.noop; // register url polling fn self.onUrlChange = function(listener) { self.pollFns.push( function() { if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) { self.$$lastUrl = self.$$url; self.$$lastState = self.$$state; listener(self.$$url, self.$$state); } } ); return listener; }; self.$$applicationDestroyed = angular.noop; self.$$checkUrlChange = angular.noop; self.deferredFns = []; self.deferredNextId = 0; self.defer = function(fn, delay) { delay = delay || 0; self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId}); self.deferredFns.sort(function(a, b) { return a.time - b.time;}); return self.deferredNextId++; }; /** * @name $browser#defer.now * * @description * Current milliseconds mock time. */ self.defer.now = 0; self.defer.cancel = function(deferId) { var fnIndex; angular.forEach(self.deferredFns, function(fn, index) { if (fn.id === deferId) fnIndex = index; }); if (angular.isDefined(fnIndex)) { self.deferredFns.splice(fnIndex, 1); return true; } return false; }; /** * @name $browser#defer.flush * * @description * Flushes all pending requests and executes the defer callbacks. * * @param {number=} number of milliseconds to flush. See {@link #defer.now} */ self.defer.flush = function(delay) { if (angular.isDefined(delay)) { self.defer.now += delay; } else { if (self.deferredFns.length) { self.defer.now = self.deferredFns[self.deferredFns.length - 1].time; } else { throw new Error('No deferred tasks to be flushed'); } } while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) { self.deferredFns.shift().fn(); } }; self.$$baseHref = '/'; self.baseHref = function() { return this.$$baseHref; }; }; angular.mock.$Browser.prototype = { /** * @name $browser#poll * * @description * run all fns in pollFns */ poll: function poll() { angular.forEach(this.pollFns, function(pollFn) { pollFn(); }); }, url: function(url, replace, state) { if (angular.isUndefined(state)) { state = null; } if (url) { this.$$url = url; // Native pushState serializes & copies the object; simulate it. this.$$state = angular.copy(state); return this; } return this.$$url; }, state: function() { return this.$$state; }, notifyWhenNoOutstandingRequests: function(fn) { fn(); } }; /** * @ngdoc provider * @name $exceptionHandlerProvider * * @description * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors * passed to the `$exceptionHandler`. */ /** * @ngdoc service * @name $exceptionHandler * * @description * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration * information. * * * ```js * describe('$exceptionHandlerProvider', function() { * * it('should capture log messages and exceptions', function() { * * module(function($exceptionHandlerProvider) { * $exceptionHandlerProvider.mode('log'); * }); * * inject(function($log, $exceptionHandler, $timeout) { * $timeout(function() { $log.log(1); }); * $timeout(function() { $log.log(2); throw 'banana peel'; }); * $timeout(function() { $log.log(3); }); * expect($exceptionHandler.errors).toEqual([]); * expect($log.assertEmpty()); * $timeout.flush(); * expect($exceptionHandler.errors).toEqual(['banana peel']); * expect($log.log.logs).toEqual([[1], [2], [3]]); * }); * }); * }); * ``` */ angular.mock.$ExceptionHandlerProvider = function() { var handler; /** * @ngdoc method * @name $exceptionHandlerProvider#mode * * @description * Sets the logging mode. * * @param {string} mode Mode of operation, defaults to `rethrow`. * * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` * mode stores an array of errors in `$exceptionHandler.errors`, to allow later * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and * {@link ngMock.$log#reset reset()} * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there * is a bug in the application or test, so this mock will make these tests fail. * For any implementations that expect exceptions to be thrown, the `rethrow` mode * will also maintain a log of thrown errors. */ this.mode = function(mode) { switch (mode) { case 'log': case 'rethrow': var errors = []; handler = function(e) { if (arguments.length == 1) { errors.push(e); } else { errors.push([].slice.call(arguments, 0)); } if (mode === "rethrow") { throw e; } }; handler.errors = errors; break; default: throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!"); } }; this.$get = function() { return handler; }; this.mode('rethrow'); }; /** * @ngdoc service * @name $log * * @description * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays * (one array per logging level). These arrays are exposed as `logs` property of each of the * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`. * */ angular.mock.$LogProvider = function() { var debug = true; function concat(array1, array2, index) { return array1.concat(Array.prototype.slice.call(array2, index)); } this.debugEnabled = function(flag) { if (angular.isDefined(flag)) { debug = flag; return this; } else { return debug; } }; this.$get = function() { var $log = { log: function() { $log.log.logs.push(concat([], arguments, 0)); }, warn: function() { $log.warn.logs.push(concat([], arguments, 0)); }, info: function() { $log.info.logs.push(concat([], arguments, 0)); }, error: function() { $log.error.logs.push(concat([], arguments, 0)); }, debug: function() { if (debug) { $log.debug.logs.push(concat([], arguments, 0)); } } }; /** * @ngdoc method * @name $log#reset * * @description * Reset all of the logging arrays to empty. */ $log.reset = function() { /** * @ngdoc property * @name $log#log.logs * * @description * Array of messages logged using {@link ng.$log#log `log()`}. * * @example * ```js * $log.log('Some Log'); * var first = $log.log.logs.unshift(); * ``` */ $log.log.logs = []; /** * @ngdoc property * @name $log#info.logs * * @description * Array of messages logged using {@link ng.$log#info `info()`}. * * @example * ```js * $log.info('Some Info'); * var first = $log.info.logs.unshift(); * ``` */ $log.info.logs = []; /** * @ngdoc property * @name $log#warn.logs * * @description * Array of messages logged using {@link ng.$log#warn `warn()`}. * * @example * ```js * $log.warn('Some Warning'); * var first = $log.warn.logs.unshift(); * ``` */ $log.warn.logs = []; /** * @ngdoc property * @name $log#error.logs * * @description * Array of messages logged using {@link ng.$log#error `error()`}. * * @example * ```js * $log.error('Some Error'); * var first = $log.error.logs.unshift(); * ``` */ $log.error.logs = []; /** * @ngdoc property * @name $log#debug.logs * * @description * Array of messages logged using {@link ng.$log#debug `debug()`}. * * @example * ```js * $log.debug('Some Error'); * var first = $log.debug.logs.unshift(); * ``` */ $log.debug.logs = []; }; /** * @ngdoc method * @name $log#assertEmpty * * @description * Assert that all of the logging methods have no logged messages. If any messages are present, * an exception is thrown. */ $log.assertEmpty = function() { var errors = []; angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) { angular.forEach($log[logLevel].logs, function(log) { angular.forEach(log, function(logItem) { errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || '')); }); }); }); if (errors.length) { errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " + "an expected log message was not checked and removed:"); errors.push(''); throw new Error(errors.join('\n---------\n')); } }; $log.reset(); return $log; }; }; /** * @ngdoc service * @name $interval * * @description * Mock implementation of the $interval service. * * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to * move forward by `millis` milliseconds and trigger any functions scheduled to run in that * time. * * @param {function()} fn A function that should be called repeatedly. * @param {number} delay Number of milliseconds between each function call. * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat * indefinitely. * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. * @param {...*=} Pass additional parameters to the executed function. * @returns {promise} A promise which will be notified on each iteration. */ angular.mock.$IntervalProvider = function() { this.$get = ['$browser', '$rootScope', '$q', '$$q', function($browser, $rootScope, $q, $$q) { var repeatFns = [], nextRepeatId = 0, now = 0; var $interval = function(fn, delay, count, invokeApply) { var hasParams = arguments.length > 4, args = hasParams ? Array.prototype.slice.call(arguments, 4) : [], iteration = 0, skipApply = (angular.isDefined(invokeApply) && !invokeApply), deferred = (skipApply ? $$q : $q).defer(), promise = deferred.promise; count = (angular.isDefined(count)) ? count : 0; promise.then(null, null, (!hasParams) ? fn : function() { fn.apply(null, args); }); promise.$$intervalId = nextRepeatId; function tick() { deferred.notify(iteration++); if (count > 0 && iteration >= count) { var fnIndex; deferred.resolve(iteration); angular.forEach(repeatFns, function(fn, index) { if (fn.id === promise.$$intervalId) fnIndex = index; }); if (angular.isDefined(fnIndex)) { repeatFns.splice(fnIndex, 1); } } if (skipApply) { $browser.defer.flush(); } else { $rootScope.$apply(); } } repeatFns.push({ nextTime:(now + delay), delay: delay, fn: tick, id: nextRepeatId, deferred: deferred }); repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;}); nextRepeatId++; return promise; }; /** * @ngdoc method * @name $interval#cancel * * @description * Cancels a task associated with the `promise`. * * @param {promise} promise A promise from calling the `$interval` function. * @returns {boolean} Returns `true` if the task was successfully cancelled. */ $interval.cancel = function(promise) { if (!promise) return false; var fnIndex; angular.forEach(repeatFns, function(fn, index) { if (fn.id === promise.$$intervalId) fnIndex = index; }); if (angular.isDefined(fnIndex)) { repeatFns[fnIndex].deferred.reject('canceled'); repeatFns.splice(fnIndex, 1); return true; } return false; }; /** * @ngdoc method * @name $interval#flush * @description * * Runs interval tasks scheduled to be run in the next `millis` milliseconds. * * @param {number=} millis maximum timeout amount to flush up until. * * @return {number} The amount of time moved forward. */ $interval.flush = function(millis) { now += millis; while (repeatFns.length && repeatFns[0].nextTime <= now) { var task = repeatFns[0]; task.fn(); task.nextTime += task.delay; repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;}); } return millis; }; return $interval; }]; }; /* jshint -W101 */ /* The R_ISO8061_STR regex is never going to fit into the 100 char limit! * This directive should go inside the anonymous function but a bug in JSHint means that it would * not be enacted early enough to prevent the warning. */ var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/; function jsonStringToDate(string) { var match; if (match = string.match(R_ISO8061_STR)) { var date = new Date(0), tzHour = 0, tzMin = 0; if (match[9]) { tzHour = toInt(match[9] + match[10]); tzMin = toInt(match[9] + match[11]); } date.setUTCFullYear(toInt(match[1]), toInt(match[2]) - 1, toInt(match[3])); date.setUTCHours(toInt(match[4] || 0) - tzHour, toInt(match[5] || 0) - tzMin, toInt(match[6] || 0), toInt(match[7] || 0)); return date; } return string; } function toInt(str) { return parseInt(str, 10); } function padNumber(num, digits, trim) { var neg = ''; if (num < 0) { neg = '-'; num = -num; } num = '' + num; while (num.length < digits) num = '0' + num; if (trim) { num = num.substr(num.length - digits); } return neg + num; } /** * @ngdoc type * @name angular.mock.TzDate * @description * * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`. * * Mock of the Date type which has its timezone specified via constructor arg. * * The main purpose is to create Date-like instances with timezone fixed to the specified timezone * offset, so that we can test code that depends on local timezone settings without dependency on * the time zone settings of the machine where the code is running. * * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored) * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* * * @example * !!!! WARNING !!!!! * This is not a complete Date object so only methods that were implemented can be called safely. * To make matters worse, TzDate instances inherit stuff from Date via a prototype. * * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is * incomplete we might be missing some non-standard methods. This can result in errors like: * "Date.prototype.foo called on incompatible Object". * * ```js * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z'); * newYearInBratislava.getTimezoneOffset() => -60; * newYearInBratislava.getFullYear() => 2010; * newYearInBratislava.getMonth() => 0; * newYearInBratislava.getDate() => 1; * newYearInBratislava.getHours() => 0; * newYearInBratislava.getMinutes() => 0; * newYearInBratislava.getSeconds() => 0; * ``` * */ angular.mock.TzDate = function(offset, timestamp) { var self = new Date(0); if (angular.isString(timestamp)) { var tsStr = timestamp; self.origDate = jsonStringToDate(timestamp); timestamp = self.origDate.getTime(); if (isNaN(timestamp)) { throw { name: "Illegal Argument", message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string" }; } } else { self.origDate = new Date(timestamp); } var localOffset = new Date(timestamp).getTimezoneOffset(); self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60; self.date = new Date(timestamp + self.offsetDiff); self.getTime = function() { return self.date.getTime() - self.offsetDiff; }; self.toLocaleDateString = function() { return self.date.toLocaleDateString(); }; self.getFullYear = function() { return self.date.getFullYear(); }; self.getMonth = function() { return self.date.getMonth(); }; self.getDate = function() { return self.date.getDate(); }; self.getHours = function() { return self.date.getHours(); }; self.getMinutes = function() { return self.date.getMinutes(); }; self.getSeconds = function() { return self.date.getSeconds(); }; self.getMilliseconds = function() { return self.date.getMilliseconds(); }; self.getTimezoneOffset = function() { return offset * 60; }; self.getUTCFullYear = function() { return self.origDate.getUTCFullYear(); }; self.getUTCMonth = function() { return self.origDate.getUTCMonth(); }; self.getUTCDate = function() { return self.origDate.getUTCDate(); }; self.getUTCHours = function() { return self.origDate.getUTCHours(); }; self.getUTCMinutes = function() { return self.origDate.getUTCMinutes(); }; self.getUTCSeconds = function() { return self.origDate.getUTCSeconds(); }; self.getUTCMilliseconds = function() { return self.origDate.getUTCMilliseconds(); }; self.getDay = function() { return self.date.getDay(); }; // provide this method only on browsers that already have it if (self.toISOString) { self.toISOString = function() { return padNumber(self.origDate.getUTCFullYear(), 4) + '-' + padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' + padNumber(self.origDate.getUTCDate(), 2) + 'T' + padNumber(self.origDate.getUTCHours(), 2) + ':' + padNumber(self.origDate.getUTCMinutes(), 2) + ':' + padNumber(self.origDate.getUTCSeconds(), 2) + '.' + padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'; }; } //hide all methods not implemented in this mock that the Date prototype exposes var unimplementedMethods = ['getUTCDay', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString', 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf']; angular.forEach(unimplementedMethods, function(methodName) { self[methodName] = function() { throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock"); }; }); return self; }; //make "tzDateInstance instanceof Date" return true angular.mock.TzDate.prototype = Date.prototype; /* jshint +W101 */ angular.mock.animate = angular.module('ngAnimateMock', ['ng']) .config(['$provide', function($provide) { $provide.factory('$$forceReflow', function() { function reflowFn() { reflowFn.totalReflows++; } reflowFn.totalReflows = 0; return reflowFn; }); $provide.factory('$$animateAsyncRun', function() { var queue = []; var queueFn = function() { return function(fn) { queue.push(fn); }; }; queueFn.flush = function() { if (queue.length === 0) return false; for (var i = 0; i < queue.length; i++) { queue[i](); } queue = []; return true; }; return queueFn; }); $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF', '$$forceReflow', '$$animateAsyncRun', '$rootScope', function($delegate, $timeout, $browser, $$rAF, $$forceReflow, $$animateAsyncRun, $rootScope) { var animate = { queue: [], cancel: $delegate.cancel, on: $delegate.on, off: $delegate.off, pin: $delegate.pin, get reflows() { return $$forceReflow.totalReflows; }, enabled: $delegate.enabled, flush: function() { $rootScope.$digest(); var doNextRun, somethingFlushed = false; do { doNextRun = false; if ($$rAF.queue.length) { $$rAF.flush(); doNextRun = somethingFlushed = true; } if ($$animateAsyncRun.flush()) { doNextRun = somethingFlushed = true; } } while (doNextRun); if (!somethingFlushed) { throw new Error('No pending animations ready to be closed or flushed'); } $rootScope.$digest(); } }; angular.forEach( ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) { animate[method] = function() { animate.queue.push({ event: method, element: arguments[0], options: arguments[arguments.length - 1], args: arguments }); return $delegate[method].apply($delegate, arguments); }; }); return animate; }]); }]); /** * @ngdoc function * @name angular.mock.dump * @description * * *NOTE*: this is not an injectable instance, just a globally available function. * * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for * debugging. * * This method is also available on window, where it can be used to display objects on debug * console. * * @param {*} object - any object to turn into string. * @return {string} a serialized string of the argument */ angular.mock.dump = function(object) { return serialize(object); function serialize(object) { var out; if (angular.isElement(object)) { object = angular.element(object); out = angular.element('
'); angular.forEach(object, function(element) { out.append(angular.element(element).clone()); }); out = out.html(); } else if (angular.isArray(object)) { out = []; angular.forEach(object, function(o) { out.push(serialize(o)); }); out = '[ ' + out.join(', ') + ' ]'; } else if (angular.isObject(object)) { if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) { out = serializeScope(object); } else if (object instanceof Error) { out = object.stack || ('' + object.name + ': ' + object.message); } else { // TODO(i): this prevents methods being logged, // we should have a better way to serialize objects out = angular.toJson(object, true); } } else { out = String(object); } return out; } function serializeScope(scope, offset) { offset = offset || ' '; var log = [offset + 'Scope(' + scope.$id + '): {']; for (var key in scope) { if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) { log.push(' ' + key + ': ' + angular.toJson(scope[key])); } } var child = scope.$$childHead; while (child) { log.push(serializeScope(child, offset + ' ')); child = child.$$nextSibling; } log.push('}'); return log.join('\n' + offset); } }; /** * @ngdoc service * @name $httpBackend * @description * Fake HTTP backend implementation suitable for unit testing applications that use the * {@link ng.$http $http service}. * * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}. * * During unit testing, we want our unit tests to run quickly and have no external dependencies so * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is * to verify whether a certain request has been sent or not, or alternatively just let the * application make requests, respond with pre-trained responses and assert that the end result is * what we expect it to be. * * This mock implementation can be used to respond with static or dynamic responses via the * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc). * * When an Angular application needs some data from a server, it calls the $http service, which * sends the request to a real server using $httpBackend service. With dependency injection, it is * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify * the requests and respond with some testing data without sending a request to a real server. * * There are two ways to specify what test data should be returned as http responses by the mock * backend when the code under test makes http requests: * * - `$httpBackend.expect` - specifies a request expectation * - `$httpBackend.when` - specifies a backend definition * * * # Request Expectations vs Backend Definitions * * Request expectations provide a way to make assertions about requests made by the application and * to define responses for those requests. The test will fail if the expected requests are not made * or they are made in the wrong order. * * Backend definitions allow you to define a fake backend for your application which doesn't assert * if a particular request was made or not, it just returns a trained response if a request is made. * The test will pass whether or not the request gets made during testing. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Request expectationsBackend definitions
Syntax.expect(...).respond(...).when(...).respond(...)
Typical usagestrict unit testsloose (black-box) unit testing
Fulfills multiple requestsNOYES
Order of requests mattersYESNO
Request requiredYESNO
Response requiredoptional (see below)YES
* * In cases where both backend definitions and request expectations are specified during unit * testing, the request expectations are evaluated first. * * If a request expectation has no response specified, the algorithm will search your backend * definitions for an appropriate response. * * If a request didn't match any expectation or if the expectation doesn't have the response * defined, the backend definitions are evaluated in sequential order to see if any of them match * the request. The response from the first matched definition is returned. * * * # Flushing HTTP requests * * The $httpBackend used in production always responds to requests asynchronously. If we preserved * this behavior in unit testing, we'd have to create async unit tests, which are hard to write, * to follow and to maintain. But neither can the testing mock respond synchronously; that would * change the execution of the code under test. For this reason, the mock $httpBackend has a * `flush()` method, which allows the test to explicitly flush pending requests. This preserves * the async api of the backend, while allowing the test to execute synchronously. * * * # Unit testing with mock $httpBackend * The following code shows how to setup and use the mock backend when unit testing a controller. * First we create the controller under test: * ```js // The module code angular .module('MyApp', []) .controller('MyController', MyController); // The controller code function MyController($scope, $http) { var authToken; $http.get('/auth.py').success(function(data, status, headers) { authToken = headers('A-Token'); $scope.user = data; }); $scope.saveMessage = function(message) { var headers = { 'Authorization': authToken }; $scope.status = 'Saving...'; $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) { $scope.status = ''; }).error(function() { $scope.status = 'Failed...'; }); }; } ``` * * Now we setup the mock backend and create the test specs: * ```js // testing controller describe('MyController', function() { var $httpBackend, $rootScope, createController, authRequestHandler; // Set up the module beforeEach(module('MyApp')); beforeEach(inject(function($injector) { // Set up the mock http service responses $httpBackend = $injector.get('$httpBackend'); // backend definition common for all tests authRequestHandler = $httpBackend.when('GET', '/auth.py') .respond({userId: 'userX'}, {'A-Token': 'xxx'}); // Get hold of a scope (i.e. the root scope) $rootScope = $injector.get('$rootScope'); // The $controller service is used to create instances of controllers var $controller = $injector.get('$controller'); createController = function() { return $controller('MyController', {'$scope' : $rootScope }); }; })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); it('should fetch authentication token', function() { $httpBackend.expectGET('/auth.py'); var controller = createController(); $httpBackend.flush(); }); it('should fail authentication', function() { // Notice how you can change the response even after it was set authRequestHandler.respond(401, ''); $httpBackend.expectGET('/auth.py'); var controller = createController(); $httpBackend.flush(); expect($rootScope.status).toBe('Failed...'); }); it('should send msg to server', function() { var controller = createController(); $httpBackend.flush(); // now you don’t care about the authentication, but // the controller will still send the request and // $httpBackend will respond without you having to // specify the expectation and response for this request $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, ''); $rootScope.saveMessage('message content'); expect($rootScope.status).toBe('Saving...'); $httpBackend.flush(); expect($rootScope.status).toBe(''); }); it('should send auth header', function() { var controller = createController(); $httpBackend.flush(); $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) { // check if the header was sent, if it wasn't the expectation won't // match the request and the test will fail return headers['Authorization'] == 'xxx'; }).respond(201, ''); $rootScope.saveMessage('whatever'); $httpBackend.flush(); }); }); ``` */ angular.mock.$HttpBackendProvider = function() { this.$get = ['$rootScope', '$timeout', createHttpBackendMock]; }; /** * General factory function for $httpBackend mock. * Returns instance for unit testing (when no arguments specified): * - passing through is disabled * - auto flushing is disabled * * Returns instance for e2e testing (when `$delegate` and `$browser` specified): * - passing through (delegating request to real backend) is enabled * - auto flushing is enabled * * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified) * @param {Object=} $browser Auto-flushing enabled if specified * @return {Object} Instance of $httpBackend mock */ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { var definitions = [], expectations = [], responses = [], responsesPush = angular.bind(responses, responses.push), copy = angular.copy; function createResponse(status, data, headers, statusText) { if (angular.isFunction(status)) return status; return function() { return angular.isNumber(status) ? [status, data, headers, statusText] : [200, status, data, headers]; }; } // TODO(vojta): change params to: method, url, data, headers, callback function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) { var xhr = new MockXhr(), expectation = expectations[0], wasExpected = false; function prettyPrint(data) { return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp) ? data : angular.toJson(data); } function wrapResponse(wrapped) { if (!$browser && timeout) { timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout); } return handleResponse; function handleResponse() { var response = wrapped.response(method, url, data, headers); xhr.$$respHeaders = response[2]; callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(), copy(response[3] || '')); } function handleTimeout() { for (var i = 0, ii = responses.length; i < ii; i++) { if (responses[i] === handleResponse) { responses.splice(i, 1); callback(-1, undefined, ''); break; } } } } if (expectation && expectation.match(method, url)) { if (!expectation.matchData(data)) { throw new Error('Expected ' + expectation + ' with different data\n' + 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data); } if (!expectation.matchHeaders(headers)) { throw new Error('Expected ' + expectation + ' with different headers\n' + 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' + prettyPrint(headers)); } expectations.shift(); if (expectation.response) { responses.push(wrapResponse(expectation)); return; } wasExpected = true; } var i = -1, definition; while ((definition = definitions[++i])) { if (definition.match(method, url, data, headers || {})) { if (definition.response) { // if $browser specified, we do auto flush all requests ($browser ? $browser.defer : responsesPush)(wrapResponse(definition)); } else if (definition.passThrough) { $delegate(method, url, data, callback, headers, timeout, withCredentials); } else throw new Error('No response defined !'); return; } } throw wasExpected ? new Error('No response defined !') : new Error('Unexpected request: ' + method + ' ' + url + '\n' + (expectation ? 'Expected ' + expectation : 'No more request expected')); } /** * @ngdoc method * @name $httpBackend#when * @description * Creates a new backend definition. * * @param {string} method HTTP method. * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives * data string and returns true if the data is as expected. * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header * object and returns true if the headers match the current definition. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. * * - respond – * `{function([status,] data[, headers, statusText]) * | function(function(method, url, data, headers)}` * – The respond method takes a set of static data to be returned or a function that can * return an array containing response status (number), response data (string), response * headers (Object), and the text for the status (string). The respond method returns the * `requestHandler` object for possible overrides. */ $httpBackend.when = function(method, url, data, headers) { var definition = new MockHttpExpectation(method, url, data, headers), chain = { respond: function(status, data, headers, statusText) { definition.passThrough = undefined; definition.response = createResponse(status, data, headers, statusText); return chain; } }; if ($browser) { chain.passThrough = function() { definition.response = undefined; definition.passThrough = true; return chain; }; } definitions.push(definition); return chain; }; /** * @ngdoc method * @name $httpBackend#whenGET * @description * Creates a new backend definition for GET requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenHEAD * @description * Creates a new backend definition for HEAD requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenDELETE * @description * Creates a new backend definition for DELETE requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenPOST * @description * Creates a new backend definition for POST requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives * data string and returns true if the data is as expected. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenPUT * @description * Creates a new backend definition for PUT requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives * data string and returns true if the data is as expected. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenJSONP * @description * Creates a new backend definition for JSONP requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ createShortMethods('when'); /** * @ngdoc method * @name $httpBackend#expect * @description * Creates a new request expectation. * * @param {string} method HTTP method. * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that * receives data string and returns true if the data is as expected, or Object if request body * is in JSON format. * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header * object and returns true if the headers match the current expectation. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. * * - respond – * `{function([status,] data[, headers, statusText]) * | function(function(method, url, data, headers)}` * – The respond method takes a set of static data to be returned or a function that can * return an array containing response status (number), response data (string), response * headers (Object), and the text for the status (string). The respond method returns the * `requestHandler` object for possible overrides. */ $httpBackend.expect = function(method, url, data, headers) { var expectation = new MockHttpExpectation(method, url, data, headers), chain = { respond: function(status, data, headers, statusText) { expectation.response = createResponse(status, data, headers, statusText); return chain; } }; expectations.push(expectation); return chain; }; /** * @ngdoc method * @name $httpBackend#expectGET * @description * Creates a new request expectation for GET requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {Object=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. See #expect for more info. */ /** * @ngdoc method * @name $httpBackend#expectHEAD * @description * Creates a new request expectation for HEAD requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {Object=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#expectDELETE * @description * Creates a new request expectation for DELETE requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {Object=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#expectPOST * @description * Creates a new request expectation for POST requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that * receives data string and returns true if the data is as expected, or Object if request body * is in JSON format. * @param {Object=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#expectPUT * @description * Creates a new request expectation for PUT requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that * receives data string and returns true if the data is as expected, or Object if request body * is in JSON format. * @param {Object=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#expectPATCH * @description * Creates a new request expectation for PATCH requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that * receives data string and returns true if the data is as expected, or Object if request body * is in JSON format. * @param {Object=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#expectJSONP * @description * Creates a new request expectation for JSONP requests. For more info see `expect()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives an url * and returns true if the url matches the current definition. * @returns {requestHandler} Returns an object with `respond` method that controls how a matched * request is handled. You can save this object for later use and invoke `respond` again in * order to change how a matched request is handled. */ createShortMethods('expect'); /** * @ngdoc method * @name $httpBackend#flush * @description * Flushes all pending requests using the trained responses. * * @param {number=} count Number of responses to flush (in the order they arrived). If undefined, * all pending requests will be flushed. If there are no pending requests when the flush method * is called an exception is thrown (as this typically a sign of programming error). */ $httpBackend.flush = function(count, digest) { if (digest !== false) $rootScope.$digest(); if (!responses.length) throw new Error('No pending request to flush !'); if (angular.isDefined(count) && count !== null) { while (count--) { if (!responses.length) throw new Error('No more pending request to flush !'); responses.shift()(); } } else { while (responses.length) { responses.shift()(); } } $httpBackend.verifyNoOutstandingExpectation(digest); }; /** * @ngdoc method * @name $httpBackend#verifyNoOutstandingExpectation * @description * Verifies that all of the requests defined via the `expect` api were made. If any of the * requests were not made, verifyNoOutstandingExpectation throws an exception. * * Typically, you would call this method following each test case that asserts requests using an * "afterEach" clause. * * ```js * afterEach($httpBackend.verifyNoOutstandingExpectation); * ``` */ $httpBackend.verifyNoOutstandingExpectation = function(digest) { if (digest !== false) $rootScope.$digest(); if (expectations.length) { throw new Error('Unsatisfied requests: ' + expectations.join(', ')); } }; /** * @ngdoc method * @name $httpBackend#verifyNoOutstandingRequest * @description * Verifies that there are no outstanding requests that need to be flushed. * * Typically, you would call this method following each test case that asserts requests using an * "afterEach" clause. * * ```js * afterEach($httpBackend.verifyNoOutstandingRequest); * ``` */ $httpBackend.verifyNoOutstandingRequest = function() { if (responses.length) { throw new Error('Unflushed requests: ' + responses.length); } }; /** * @ngdoc method * @name $httpBackend#resetExpectations * @description * Resets all request expectations, but preserves all backend definitions. Typically, you would * call resetExpectations during a multiple-phase test when you want to reuse the same instance of * $httpBackend mock. */ $httpBackend.resetExpectations = function() { expectations.length = 0; responses.length = 0; }; return $httpBackend; function createShortMethods(prefix) { angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) { $httpBackend[prefix + method] = function(url, headers) { return $httpBackend[prefix](method, url, undefined, headers); }; }); angular.forEach(['PUT', 'POST', 'PATCH'], function(method) { $httpBackend[prefix + method] = function(url, data, headers) { return $httpBackend[prefix](method, url, data, headers); }; }); } } function MockHttpExpectation(method, url, data, headers) { this.data = data; this.headers = headers; this.match = function(m, u, d, h) { if (method != m) return false; if (!this.matchUrl(u)) return false; if (angular.isDefined(d) && !this.matchData(d)) return false; if (angular.isDefined(h) && !this.matchHeaders(h)) return false; return true; }; this.matchUrl = function(u) { if (!url) return true; if (angular.isFunction(url.test)) return url.test(u); if (angular.isFunction(url)) return url(u); return url == u; }; this.matchHeaders = function(h) { if (angular.isUndefined(headers)) return true; if (angular.isFunction(headers)) return headers(h); return angular.equals(headers, h); }; this.matchData = function(d) { if (angular.isUndefined(data)) return true; if (data && angular.isFunction(data.test)) return data.test(d); if (data && angular.isFunction(data)) return data(d); if (data && !angular.isString(data)) { return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d)); } return data == d; }; this.toString = function() { return method + ' ' + url; }; } function createMockXhr() { return new MockXhr(); } function MockXhr() { // hack for testing $http, $httpBackend MockXhr.$$lastInstance = this; this.open = function(method, url, async) { this.$$method = method; this.$$url = url; this.$$async = async; this.$$reqHeaders = {}; this.$$respHeaders = {}; }; this.send = function(data) { this.$$data = data; }; this.setRequestHeader = function(key, value) { this.$$reqHeaders[key] = value; }; this.getResponseHeader = function(name) { // the lookup must be case insensitive, // that's why we try two quick lookups first and full scan last var header = this.$$respHeaders[name]; if (header) return header; name = angular.lowercase(name); header = this.$$respHeaders[name]; if (header) return header; header = undefined; angular.forEach(this.$$respHeaders, function(headerVal, headerName) { if (!header && angular.lowercase(headerName) == name) header = headerVal; }); return header; }; this.getAllResponseHeaders = function() { var lines = []; angular.forEach(this.$$respHeaders, function(value, key) { lines.push(key + ': ' + value); }); return lines.join('\n'); }; this.abort = angular.noop; } /** * @ngdoc service * @name $timeout * @description * * This service is just a simple decorator for {@link ng.$timeout $timeout} service * that adds a "flush" and "verifyNoPendingTasks" methods. */ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) { /** * @ngdoc method * @name $timeout#flush * @description * * Flushes the queue of pending tasks. * * @param {number=} delay maximum timeout amount to flush up until */ $delegate.flush = function(delay) { $browser.defer.flush(delay); }; /** * @ngdoc method * @name $timeout#verifyNoPendingTasks * @description * * Verifies that there are no pending tasks that need to be flushed. */ $delegate.verifyNoPendingTasks = function() { if ($browser.deferredFns.length) { throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' + formatPendingTasksAsString($browser.deferredFns)); } }; function formatPendingTasksAsString(tasks) { var result = []; angular.forEach(tasks, function(task) { result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}'); }); return result.join(', '); } return $delegate; }]; angular.mock.$RAFDecorator = ['$delegate', function($delegate) { var rafFn = function(fn) { var index = rafFn.queue.length; rafFn.queue.push(fn); return function() { rafFn.queue.splice(index, 1); }; }; rafFn.queue = []; rafFn.supported = $delegate.supported; rafFn.flush = function() { if (rafFn.queue.length === 0) { throw new Error('No rAF callbacks present'); } var length = rafFn.queue.length; for (var i = 0; i < length; i++) { rafFn.queue[i](); } rafFn.queue = rafFn.queue.slice(i); }; return rafFn; }]; /** * */ angular.mock.$RootElementProvider = function() { this.$get = function() { return angular.element('
'); }; }; /** * @ngdoc service * @name $controller * @description * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}. * * * ## Example * * ```js * * // Directive definition ... * * myMod.directive('myDirective', { * controller: 'MyDirectiveController', * bindToController: { * name: '@' * } * }); * * * // Controller definition ... * * myMod.controller('MyDirectiveController', ['log', function($log) { * $log.info(this.name); * })]; * * * // In a test ... * * describe('myDirectiveController', function() { * it('should write the bound name to the log', inject(function($controller, $log) { * var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' }); * expect(ctrl.name).toEqual('Clark Kent'); * expect($log.info.logs).toEqual(['Clark Kent']); * }); * }); * * ``` * * @param {Function|string} constructor If called with a function then it's considered to be the * controller constructor function. Otherwise it's considered to be a string which is used * to retrieve the controller constructor using the following steps: * * * check if a controller with given name is registered via `$controllerProvider` * * check if evaluating the string on the current scope returns a constructor * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global * `window` object (not recommended) * * The string can use the `controller as property` syntax, where the controller instance is published * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this * to work correctly. * * @param {Object} locals Injection locals for Controller. * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used * to simulate the `bindToController` feature and simplify certain kinds of tests. * @return {Object} Instance of given controller. */ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) { return function(expression, locals, later, ident) { if (later && typeof later === 'object') { var create = $delegate(expression, locals, true, ident); angular.extend(create.instance, later); return create(); } return $delegate(expression, locals, later, ident); }; }]; /** * @ngdoc module * @name ngMock * @packageName angular-mocks * @description * * # ngMock * * The `ngMock` module provides support to inject and mock Angular services into unit tests. * In addition, ngMock also extends various core ng services such that they can be * inspected and controlled in a synchronous manner within test code. * * *
* */ angular.module('ngMock', ['ng']).provider({ $browser: angular.mock.$BrowserProvider, $exceptionHandler: angular.mock.$ExceptionHandlerProvider, $log: angular.mock.$LogProvider, $interval: angular.mock.$IntervalProvider, $httpBackend: angular.mock.$HttpBackendProvider, $rootElement: angular.mock.$RootElementProvider }).config(['$provide', function($provide) { $provide.decorator('$timeout', angular.mock.$TimeoutDecorator); $provide.decorator('$$rAF', angular.mock.$RAFDecorator); $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator); $provide.decorator('$controller', angular.mock.$ControllerDecorator); }]); /** * @ngdoc module * @name ngMockE2E * @module ngMockE2E * @packageName angular-mocks * @description * * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing. * Currently there is only one mock present in this module - * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock. */ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator); }]); /** * @ngdoc service * @name $httpBackend * @module ngMockE2E * @description * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of * applications that use the {@link ng.$http $http service}. * * *Note*: For fake http backend implementation suitable for unit testing please see * {@link ngMock.$httpBackend unit-testing $httpBackend mock}. * * This implementation can be used to respond with static or dynamic responses via the `when` api * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch * templates from a webserver). * * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application * is being developed with the real backend api replaced with a mock, it is often desirable for * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch * templates or static files from the webserver). To configure the backend with this behavior * use the `passThrough` request handler of `when` instead of `respond`. * * Additionally, we don't want to manually have to flush mocked out requests like we do during unit * testing. For this reason the e2e $httpBackend flushes mocked out requests * automatically, closely simulating the behavior of the XMLHttpRequest object. * * To setup the application to run with this http backend, you have to create a module that depends * on the `ngMockE2E` and your application modules and defines the fake backend: * * ```js * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']); * myAppDev.run(function($httpBackend) { * phones = [{name: 'phone1'}, {name: 'phone2'}]; * * // returns the current list of phones * $httpBackend.whenGET('/phones').respond(phones); * * // adds a new phone to the phones array * $httpBackend.whenPOST('/phones').respond(function(method, url, data) { * var phone = angular.fromJson(data); * phones.push(phone); * return [200, phone, {}]; * }); * $httpBackend.whenGET(/^\/templates\//).passThrough(); * //... * }); * ``` * * Afterwards, bootstrap your app with this new module. */ /** * @ngdoc method * @name $httpBackend#when * @module ngMockE2E * @description * Creates a new backend definition. * * @param {string} method HTTP method. * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp)=} data HTTP request body. * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header * object and returns true if the headers match the current definition. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. * * - respond – * `{function([status,] data[, headers, statusText]) * | function(function(method, url, data, headers)}` * – The respond method takes a set of static data to be returned or a function that can return * an array containing response status (number), response data (string), response headers * (Object), and the text for the status (string). * - passThrough – `{function()}` – Any request matching a backend definition with * `passThrough` handler will be passed through to the real backend (an XHR request will be made * to the server.) * - Both methods return the `requestHandler` object for possible overrides. */ /** * @ngdoc method * @name $httpBackend#whenGET * @module ngMockE2E * @description * Creates a new backend definition for GET requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenHEAD * @module ngMockE2E * @description * Creates a new backend definition for HEAD requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenDELETE * @module ngMockE2E * @description * Creates a new backend definition for DELETE requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenPOST * @module ngMockE2E * @description * Creates a new backend definition for POST requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp)=} data HTTP request body. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenPUT * @module ngMockE2E * @description * Creates a new backend definition for PUT requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp)=} data HTTP request body. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenPATCH * @module ngMockE2E * @description * Creates a new backend definition for PATCH requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @param {(string|RegExp)=} data HTTP request body. * @param {(Object|function(Object))=} headers HTTP headers. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ /** * @ngdoc method * @name $httpBackend#whenJSONP * @module ngMockE2E * @description * Creates a new backend definition for JSONP requests. For more info see `when()`. * * @param {string|RegExp|function(string)} url HTTP url or function that receives a url * and returns true if the url matches the current definition. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that * control how a matched request is handled. You can save this object for later use and invoke * `respond` or `passThrough` again in order to change how a matched request is handled. */ angular.mock.e2e = {}; angular.mock.e2e.$httpBackendDecorator = ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock]; /** * @ngdoc type * @name $rootScope.Scope * @module ngMock * @description * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when * `ngMock` module is loaded. * * In addition to all the regular `Scope` methods, the following helper methods are available: */ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) { var $rootScopePrototype = Object.getPrototypeOf($delegate); $rootScopePrototype.$countChildScopes = countChildScopes; $rootScopePrototype.$countWatchers = countWatchers; return $delegate; // ------------------------------------------------------------------------------------------ // /** * @ngdoc method * @name $rootScope.Scope#$countChildScopes * @module ngMock * @description * Counts all the direct and indirect child scopes of the current scope. * * The current scope is excluded from the count. The count includes all isolate child scopes. * * @returns {number} Total number of child scopes. */ function countChildScopes() { // jshint validthis: true var count = 0; // exclude the current scope var pendingChildHeads = [this.$$childHead]; var currentScope; while (pendingChildHeads.length) { currentScope = pendingChildHeads.shift(); while (currentScope) { count += 1; pendingChildHeads.push(currentScope.$$childHead); currentScope = currentScope.$$nextSibling; } } return count; } /** * @ngdoc method * @name $rootScope.Scope#$countWatchers * @module ngMock * @description * Counts all the watchers of direct and indirect child scopes of the current scope. * * The watchers of the current scope are included in the count and so are all the watchers of * isolate child scopes. * * @returns {number} Total number of watchers. */ function countWatchers() { // jshint validthis: true var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope var pendingChildHeads = [this.$$childHead]; var currentScope; while (pendingChildHeads.length) { currentScope = pendingChildHeads.shift(); while (currentScope) { count += currentScope.$$watchers ? currentScope.$$watchers.length : 0; pendingChildHeads.push(currentScope.$$childHead); currentScope = currentScope.$$nextSibling; } } return count; } }]; if (window.jasmine || window.mocha) { var currentSpec = null, annotatedFunctions = [], isSpecRunning = function() { return !!currentSpec; }; angular.mock.$$annotate = angular.injector.$$annotate; angular.injector.$$annotate = function(fn) { if (typeof fn === 'function' && !fn.$inject) { annotatedFunctions.push(fn); } return angular.mock.$$annotate.apply(this, arguments); }; (window.beforeEach || window.setup)(function() { annotatedFunctions = []; currentSpec = this; }); (window.afterEach || window.teardown)(function() { var injector = currentSpec.$injector; annotatedFunctions.forEach(function(fn) { delete fn.$inject; }); angular.forEach(currentSpec.$modules, function(module) { if (module && module.$$hashKey) { module.$$hashKey = undefined; } }); currentSpec.$injector = null; currentSpec.$modules = null; currentSpec = null; if (injector) { injector.get('$rootElement').off(); } // clean up jquery's fragment cache angular.forEach(angular.element.fragments, function(val, key) { delete angular.element.fragments[key]; }); MockXhr.$$lastInstance = null; angular.forEach(angular.callbacks, function(val, key) { delete angular.callbacks[key]; }); angular.callbacks.counter = 0; }); /** * @ngdoc function * @name angular.mock.module * @description * * *NOTE*: This function is also published on window for easy access.
* *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha * * This function registers a module configuration code. It collects the configuration information * which will be used when the injector is created by {@link angular.mock.inject inject}. * * See {@link angular.mock.inject inject} for usage example * * @param {...(string|Function|Object)} fns any number of modules which are represented as string * aliases or as anonymous module initialization functions. The modules are used to * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an * object literal is passed each key-value pair will be registered on the module via * {@link auto.$provide $provide}.value, the key being the string name (or token) to associate * with the value on the injector. */ window.module = angular.mock.module = function() { var moduleFns = Array.prototype.slice.call(arguments, 0); return isSpecRunning() ? workFn() : workFn; ///////////////////// function workFn() { if (currentSpec.$injector) { throw new Error('Injector already created, can not register a module!'); } else { var modules = currentSpec.$modules || (currentSpec.$modules = []); angular.forEach(moduleFns, function(module) { if (angular.isObject(module) && !angular.isArray(module)) { modules.push(function($provide) { angular.forEach(module, function(value, key) { $provide.value(key, value); }); }); } else { modules.push(module); } }); } } }; /** * @ngdoc function * @name angular.mock.inject * @description * * *NOTE*: This function is also published on window for easy access.
* *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha * * The inject function wraps a function into an injectable function. The inject() creates new * instance of {@link auto.$injector $injector} per test, which is then used for * resolving references. * * * ## Resolving References (Underscore Wrapping) * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable * that is declared in the scope of the `describe()` block. Since we would, most likely, want * the variable to have the same name of the reference we have a problem, since the parameter * to the `inject()` function would hide the outer variable. * * To help with this, the injected parameters can, optionally, be enclosed with underscores. * These are ignored by the injector when the reference name is resolved. * * For example, the parameter `_myService_` would be resolved as the reference `myService`. * Since it is available in the function body as _myService_, we can then assign it to a variable * defined in an outer scope. * * ``` * // Defined out reference variable outside * var myService; * * // Wrap the parameter in underscores * beforeEach( inject( function(_myService_){ * myService = _myService_; * })); * * // Use myService in a series of tests. * it('makes use of myService', function() { * myService.doStuff(); * }); * * ``` * * See also {@link angular.mock.module angular.mock.module} * * ## Example * Example of what a typical jasmine tests looks like with the inject method. * ```js * * angular.module('myApplicationModule', []) * .value('mode', 'app') * .value('version', 'v1.0.1'); * * * describe('MyApp', function() { * * // You need to load modules that you want to test, * // it loads only the "ng" module by default. * beforeEach(module('myApplicationModule')); * * * // inject() is used to inject arguments of all given functions * it('should provide a version', inject(function(mode, version) { * expect(version).toEqual('v1.0.1'); * expect(mode).toEqual('app'); * })); * * * // The inject and module method can also be used inside of the it or beforeEach * it('should override a version and test the new version is injected', function() { * // module() takes functions or strings (module aliases) * module(function($provide) { * $provide.value('version', 'overridden'); // override version here * }); * * inject(function(version) { * expect(version).toEqual('overridden'); * }); * }); * }); * * ``` * * @param {...Function} fns any number of functions which will be injected using the injector. */ var ErrorAddingDeclarationLocationStack = function(e, errorForStack) { this.message = e.message; this.name = e.name; if (e.line) this.line = e.line; if (e.sourceId) this.sourceId = e.sourceId; if (e.stack && errorForStack) this.stack = e.stack + '\n' + errorForStack.stack; if (e.stackArray) this.stackArray = e.stackArray; }; ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString; window.inject = angular.mock.inject = function() { var blockFns = Array.prototype.slice.call(arguments, 0); var errorForStack = new Error('Declaration Location'); return isSpecRunning() ? workFn.call(currentSpec) : workFn; ///////////////////// function workFn() { var modules = currentSpec.$modules || []; var strictDi = !!currentSpec.$injectorStrict; modules.unshift('ngMock'); modules.unshift('ng'); var injector = currentSpec.$injector; if (!injector) { if (strictDi) { // If strictDi is enabled, annotate the providerInjector blocks angular.forEach(modules, function(moduleFn) { if (typeof moduleFn === "function") { angular.injector.$$annotate(moduleFn); } }); } injector = currentSpec.$injector = angular.injector(modules, strictDi); currentSpec.$injectorStrict = strictDi; } for (var i = 0, ii = blockFns.length; i < ii; i++) { if (currentSpec.$injectorStrict) { // If the injector is strict / strictDi, and the spec wants to inject using automatic // annotation, then annotate the function here. injector.annotate(blockFns[i]); } try { /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */ injector.invoke(blockFns[i] || angular.noop, this); /* jshint +W040 */ } catch (e) { if (e.stack && errorForStack) { throw new ErrorAddingDeclarationLocationStack(e, errorForStack); } throw e; } finally { errorForStack = null; } } } }; angular.mock.inject.strictDi = function(value) { value = arguments.length ? !!value : true; return isSpecRunning() ? workFn() : workFn; function workFn() { if (value !== currentSpec.$injectorStrict) { if (currentSpec.$injector) { throw new Error('Injector already created, can not modify strict annotations'); } else { currentSpec.$injectorStrict = value; } } } }; } })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-resource.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; var $resourceMinErr = angular.$$minErr('$resource'); // Helper functions and regex to lookup a dotted path on an object // stopping at undefined/null. The path must be composed of ASCII // identifiers (just like $parse) var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/; function isValidDottedPath(path) { return (path != null && path !== '' && path !== 'hasOwnProperty' && MEMBER_NAME_REGEX.test('.' + path)); } function lookupDottedPath(obj, path) { if (!isValidDottedPath(path)) { throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path); } var keys = path.split('.'); for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) { var key = keys[i]; obj = (obj !== null) ? obj[key] : undefined; } return obj; } /** * Create a shallow copy of an object and clear other fields from the destination */ function shallowClearAndCopy(src, dst) { dst = dst || {}; angular.forEach(dst, function(value, key) { delete dst[key]; }); for (var key in src) { if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { dst[key] = src[key]; } } return dst; } /** * @ngdoc module * @name ngResource * @description * * # ngResource * * The `ngResource` module provides interaction support with RESTful services * via the $resource service. * * *
* * See {@link ngResource.$resource `$resource`} for usage. */ /** * @ngdoc service * @name $resource * @requires $http * * @description * A factory which creates a resource object that lets you interact with * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources. * * The returned resource object has action methods which provide high-level behaviors without * the need to interact with the low level {@link ng.$http $http} service. * * Requires the {@link ngResource `ngResource`} module to be installed. * * By default, trailing slashes will be stripped from the calculated URLs, * which can pose problems with server backends that do not expect that * behavior. This can be disabled by configuring the `$resourceProvider` like * this: * * ```js app.config(['$resourceProvider', function($resourceProvider) { // Don't strip trailing slashes from calculated URLs $resourceProvider.defaults.stripTrailingSlashes = false; }]); * ``` * * @param {string} url A parameterized URL template with parameters prefixed by `:` as in * `/user/:username`. If you are using a URL with a port number (e.g. * `http://example.com:8080/api`), it will be respected. * * If you are using a url with a suffix, just add the suffix, like this: * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')` * or even `$resource('http://example.com/resource/:resource_id.:format')` * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you * can escape it with `/\.`. * * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in * `actions` methods. If any of the parameter value is a function, it will be executed every time * when a param value needs to be obtained for a request (unless the param was overridden). * * Each key value in the parameter object is first bound to url template if present and then any * excess keys are appended to the url search query after the `?`. * * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in * URL `/path/greet?salutation=Hello`. * * If the parameter value is prefixed with `@` then the value for that parameter will be extracted * from the corresponding property on the `data` object (provided when calling an action method). For * example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam` * will be `data.someProp`. * * @param {Object.=} actions Hash with declaration of custom actions that should extend * the default set of resource actions. The declaration should be created in the format of {@link * ng.$http#usage $http.config}: * * {action1: {method:?, params:?, isArray:?, headers:?, ...}, * action2: {method:?, params:?, isArray:?, headers:?, ...}, * ...} * * Where: * * - **`action`** – {string} – The name of action. This name becomes the name of the method on * your resource object. * - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`, * `DELETE`, `JSONP`, etc). * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of * the parameter value is a function, it will be executed every time when a param value needs to * be obtained for a request (unless the param was overridden). * - **`url`** – {string} – action specific `url` override. The url templating is supported just * like for the resource-level urls. * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, * see `returns` section. * - **`transformRequest`** – * `{function(data, headersGetter)|Array.}` – * transform function or an array of such functions. The transform function takes the http * request body and headers and returns its transformed (typically serialized) version. * By default, transformRequest will contain one function that checks if the request data is * an object and serializes to using `angular.toJson`. To prevent this behavior, set * `transformRequest` to an empty array: `transformRequest: []` * - **`transformResponse`** – * `{function(data, headersGetter)|Array.}` – * transform function or an array of such functions. The transform function takes the http * response body and headers and returns its transformed (typically deserialized) version. * By default, transformResponse will contain one function that checks if the response looks like * a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set * `transformResponse` to an empty array: `transformResponse: []` * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the * GET request, otherwise if a cache instance built with * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for * caching. * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that * should abort the request when resolved. * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the * XHR object. See * [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5) * for more information. * - **`responseType`** - `{string}` - see * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods - * `response` and `responseError`. Both `response` and `responseError` interceptors get called * with `http response` object. See {@link ng.$http $http interceptors}. * * @param {Object} options Hash with custom settings that should extend the * default `$resourceProvider` behavior. The only supported option is * * Where: * * - **`stripTrailingSlashes`** – {boolean} – If true then the trailing * slashes from any calculated URL will be stripped. (Defaults to true.) * * @returns {Object} A resource "class" object with methods for the default set of resource actions * optionally extended with custom `actions`. The default set contains these actions: * ```js * { 'get': {method:'GET'}, * 'save': {method:'POST'}, * 'query': {method:'GET', isArray:true}, * 'remove': {method:'DELETE'}, * 'delete': {method:'DELETE'} }; * ``` * * Calling these methods invoke an {@link ng.$http} with the specified http method, * destination and parameters. When the data is returned from the server then the object is an * instance of the resource class. The actions `save`, `remove` and `delete` are available on it * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create, * read, update, delete) on server-side data like this: * ```js * var User = $resource('/user/:userId', {userId:'@id'}); * var user = User.get({userId:123}, function() { * user.abc = true; * user.$save(); * }); * ``` * * It is important to realize that invoking a $resource object method immediately returns an * empty reference (object or array depending on `isArray`). Once the data is returned from the * server the existing reference is populated with the actual data. This is a useful trick since * usually the resource is assigned to a model which is then rendered by the view. Having an empty * object results in no rendering, once the data arrives from the server then the object is * populated with the data and the view automatically re-renders itself showing the new data. This * means that in most cases one never has to write a callback function for the action methods. * * The action methods on the class object or instance object can be invoked with the following * parameters: * * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])` * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])` * - non-GET instance actions: `instance.$action([parameters], [success], [error])` * * * Success callback is called with (value, responseHeaders) arguments, where the value is * the populated resource instance or collection object. The error callback is called * with (httpResponse) argument. * * Class actions return empty instance (with additional properties below). * Instance actions return promise of the action. * * The Resource instances and collection have these additional properties: * * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this * instance or collection. * * On success, the promise is resolved with the same resource instance or collection object, * updated with data from server. This makes it easy to use in * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view * rendering until the resource(s) are loaded. * * On failure, the promise is resolved with the {@link ng.$http http response} object, without * the `resource` property. * * If an interceptor object was provided, the promise will instead be resolved with the value * returned by the interceptor. * * - `$resolved`: `true` after first server interaction is completed (either with success or * rejection), `false` before that. Knowing if the Resource has been resolved is useful in * data-binding. * * @example * * # Credit card resource * * ```js // Define CreditCard class var CreditCard = $resource('/user/:userId/card/:cardId', {userId:123, cardId:'@id'}, { charge: {method:'POST', params:{charge:true}} }); // We can retrieve a collection from the server var cards = CreditCard.query(function() { // GET: /user/123/card // server returns: [ {id:456, number:'1234', name:'Smith'} ]; var card = cards[0]; // each item is an instance of CreditCard expect(card instanceof CreditCard).toEqual(true); card.name = "J. Smith"; // non GET methods are mapped onto the instances card.$save(); // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'} // server returns: {id:456, number:'1234', name: 'J. Smith'}; // our custom method is mapped as well. card.$charge({amount:9.99}); // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'} }); // we can create an instance as well var newCard = new CreditCard({number:'0123'}); newCard.name = "Mike Smith"; newCard.$save(); // POST: /user/123/card {number:'0123', name:'Mike Smith'} // server returns: {id:789, number:'0123', name: 'Mike Smith'}; expect(newCard.id).toEqual(789); * ``` * * The object returned from this function execution is a resource "class" which has "static" method * for each action in the definition. * * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and * `headers`. * When the data is returned from the server then the object is an instance of the resource type and * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD * operations (create, read, update, delete) on server-side data. ```js var User = $resource('/user/:userId', {userId:'@id'}); User.get({userId:123}, function(user) { user.abc = true; user.$save(); }); ``` * * It's worth noting that the success callback for `get`, `query` and other methods gets passed * in the response that came from the server as well as $http header getter function, so one * could rewrite the above example and get access to http headers as: * ```js var User = $resource('/user/:userId', {userId:'@id'}); User.get({userId:123}, function(u, getResponseHeaders){ u.abc = true; u.$save(function(u, putResponseHeaders) { //u => saved user object //putResponseHeaders => $http header getter }); }); ``` * * You can also access the raw `$http` promise via the `$promise` property on the object returned * ``` var User = $resource('/user/:userId', {userId:'@id'}); User.get({userId:123}) .$promise.then(function(user) { $scope.user = user; }); ``` * # Creating a custom 'PUT' request * In this example we create a custom method on our resource to make a PUT request * ```js * var app = angular.module('app', ['ngResource', 'ngRoute']); * * // Some APIs expect a PUT request in the format URL/object/ID * // Here we are creating an 'update' method * app.factory('Notes', ['$resource', function($resource) { * return $resource('/notes/:id', null, * { * 'update': { method:'PUT' } * }); * }]); * * // In our controller we get the ID from the URL using ngRoute and $routeParams * // We pass in $routeParams and our Notes factory along with $scope * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes', function($scope, $routeParams, Notes) { * // First get a note object from the factory * var note = Notes.get({ id:$routeParams.id }); * $id = note.id; * * // Now call update passing in the ID first then the object you are updating * Notes.update({ id:$id }, note); * * // This will PUT /notes/ID with the note object in the request payload * }]); * ``` */ angular.module('ngResource', ['ng']). provider('$resource', function() { var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/; var provider = this; this.defaults = { // Strip slashes by default stripTrailingSlashes: true, // Default actions configuration actions: { 'get': {method: 'GET'}, 'save': {method: 'POST'}, 'query': {method: 'GET', isArray: true}, 'remove': {method: 'DELETE'}, 'delete': {method: 'DELETE'} } }; this.$get = ['$http', '$q', function($http, $q) { var noop = angular.noop, forEach = angular.forEach, extend = angular.extend, copy = angular.copy, isFunction = angular.isFunction; /** * We need our custom method because encodeURIComponent is too aggressive and doesn't follow * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set * (pchar) allowed in path segments: * segment = *pchar * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" * pct-encoded = "%" HEXDIG HEXDIG * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" * / "*" / "+" / "," / ";" / "=" */ function encodeUriSegment(val) { return encodeUriQuery(val, true). replace(/%26/gi, '&'). replace(/%3D/gi, '='). replace(/%2B/gi, '+'); } /** * This method is intended for encoding *key* or *value* parts of query component. We need a * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't * have to be encoded per http://tools.ietf.org/html/rfc3986: * query = *( pchar / "/" / "?" ) * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" * pct-encoded = "%" HEXDIG HEXDIG * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" * / "*" / "+" / "," / ";" / "=" */ function encodeUriQuery(val, pctEncodeSpaces) { return encodeURIComponent(val). replace(/%40/gi, '@'). replace(/%3A/gi, ':'). replace(/%24/g, '$'). replace(/%2C/gi, ','). replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); } function Route(template, defaults) { this.template = template; this.defaults = extend({}, provider.defaults, defaults); this.urlParams = {}; } Route.prototype = { setUrlParams: function(config, params, actionUrl) { var self = this, url = actionUrl || self.template, val, encodedVal, protocolAndDomain = ''; var urlParams = self.urlParams = {}; forEach(url.split(/\W/), function(param) { if (param === 'hasOwnProperty') { throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name."); } if (!(new RegExp("^\\d+$").test(param)) && param && (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) { urlParams[param] = true; } }); url = url.replace(/\\:/g, ':'); url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) { protocolAndDomain = match; return ''; }); params = params || {}; forEach(self.urlParams, function(_, urlParam) { val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam]; if (angular.isDefined(val) && val !== null) { encodedVal = encodeUriSegment(val); url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) { return encodedVal + p1; }); } else { url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match, leadingSlashes, tail) { if (tail.charAt(0) == '/') { return tail; } else { return leadingSlashes + tail; } }); } }); // strip trailing slashes and set the url (unless this behavior is specifically disabled) if (self.defaults.stripTrailingSlashes) { url = url.replace(/\/+$/, '') || '/'; } // then replace collapse `/.` if found in the last URL path segment before the query // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x` url = url.replace(/\/\.(?=\w+($|\?))/, '.'); // replace escaped `/\.` with `/.` config.url = protocolAndDomain + url.replace(/\/\\\./, '/.'); // set params - delegate param encoding to $http forEach(params, function(value, key) { if (!self.urlParams[key]) { config.params = config.params || {}; config.params[key] = value; } }); } }; function resourceFactory(url, paramDefaults, actions, options) { var route = new Route(url, options); actions = extend({}, provider.defaults.actions, actions); function extractParams(data, actionParams) { var ids = {}; actionParams = extend({}, paramDefaults, actionParams); forEach(actionParams, function(value, key) { if (isFunction(value)) { value = value(); } ids[key] = value && value.charAt && value.charAt(0) == '@' ? lookupDottedPath(data, value.substr(1)) : value; }); return ids; } function defaultResponseInterceptor(response) { return response.resource; } function Resource(value) { shallowClearAndCopy(value || {}, this); } Resource.prototype.toJSON = function() { var data = extend({}, this); delete data.$promise; delete data.$resolved; return data; }; forEach(actions, function(action, name) { var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method); Resource[name] = function(a1, a2, a3, a4) { var params = {}, data, success, error; /* jshint -W086 */ /* (purposefully fall through case statements) */ switch (arguments.length) { case 4: error = a4; success = a3; //fallthrough case 3: case 2: if (isFunction(a2)) { if (isFunction(a1)) { success = a1; error = a2; break; } success = a2; error = a3; //fallthrough } else { params = a1; data = a2; success = a3; break; } case 1: if (isFunction(a1)) success = a1; else if (hasBody) data = a1; else params = a1; break; case 0: break; default: throw $resourceMinErr('badargs', "Expected up to 4 arguments [params, data, success, error], got {0} arguments", arguments.length); } /* jshint +W086 */ /* (purposefully fall through case statements) */ var isInstanceCall = this instanceof Resource; var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data)); var httpConfig = {}; var responseInterceptor = action.interceptor && action.interceptor.response || defaultResponseInterceptor; var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || undefined; forEach(action, function(value, key) { switch (key) { default: httpConfig[key] = copy(value); break; case 'params': case 'isArray': case 'interceptor': break; case 'timeout': httpConfig[key] = value; break; } }); if (hasBody) httpConfig.data = data; route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), action.url); var promise = $http(httpConfig).then(function(response) { var data = response.data, promise = value.$promise; if (data) { // Need to convert action.isArray to boolean in case it is undefined // jshint -W018 if (angular.isArray(data) !== (!!action.isArray)) { throw $resourceMinErr('badcfg', 'Error in resource configuration for action `{0}`. Expected response to ' + 'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object', angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url); } // jshint +W018 if (action.isArray) { value.length = 0; forEach(data, function(item) { if (typeof item === "object") { value.push(new Resource(item)); } else { // Valid JSON values may be string literals, and these should not be converted // into objects. These items will not have access to the Resource prototype // methods, but unfortunately there value.push(item); } }); } else { shallowClearAndCopy(data, value); value.$promise = promise; } } value.$resolved = true; response.resource = value; return response; }, function(response) { value.$resolved = true; (error || noop)(response); return $q.reject(response); }); promise = promise.then( function(response) { var value = responseInterceptor(response); (success || noop)(value, response.headers); return value; }, responseErrorInterceptor); if (!isInstanceCall) { // we are creating instance / collection // - set the initial promise // - return the instance / collection value.$promise = promise; value.$resolved = false; return value; } // instance call return promise; }; Resource.prototype['$' + name] = function(params, success, error) { if (isFunction(params)) { error = success; success = params; params = {}; } var result = Resource[name].call(this, params, this, success, error); return result.$promise || result; }; }); Resource.bind = function(additionalParamDefaults) { return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions); }; return Resource; } return resourceFactory; }]; }); })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-route.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /** * @ngdoc module * @name ngRoute * @description * * # ngRoute * * The `ngRoute` module provides routing and deeplinking services and directives for angular apps. * * ## Example * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. * * *
*/ /* global -ngRouteModule */ var ngRouteModule = angular.module('ngRoute', ['ng']). provider('$route', $RouteProvider), $routeMinErr = angular.$$minErr('ngRoute'); /** * @ngdoc provider * @name $routeProvider * * @description * * Used for configuring routes. * * ## Example * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. * * ## Dependencies * Requires the {@link ngRoute `ngRoute`} module to be installed. */ function $RouteProvider() { function inherit(parent, extra) { return angular.extend(Object.create(parent), extra); } var routes = {}; /** * @ngdoc method * @name $routeProvider#when * * @param {string} path Route path (matched against `$location.path`). If `$location.path` * contains redundant trailing slash or is missing one, the route will still match and the * `$location.path` will be updated to add or drop the trailing slash to exactly match the * route definition. * * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up * to the next slash are matched and stored in `$routeParams` under the given `name` * when the route matches. * * `path` can contain named groups starting with a colon and ending with a star: * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name` * when the route matches. * * `path` can contain optional named groups with a question mark: e.g.`:name?`. * * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match * `/color/brown/largecode/code/with/slashes/edit` and extract: * * * `color: brown` * * `largecode: code/with/slashes`. * * * @param {Object} route Mapping information to be assigned to `$route.current` on route * match. * * Object properties: * * - `controller` – `{(string|function()=}` – Controller fn that should be associated with * newly created scope or the name of a {@link angular.Module#controller registered * controller} if passed as a string. * - `controllerAs` – `{string=}` – An identifier name for a reference to the controller. * If present, the controller will be published to scope under the `controllerAs` name. * - `template` – `{string=|function()=}` – html template as a string or a function that * returns an html template as a string which should be used by {@link * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives. * This property takes precedence over `templateUrl`. * * If `template` is a function, it will be called with the following parameters: * * - `{Array.}` - route parameters extracted from the current * `$location.path()` by applying the current route * * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html * template that should be used by {@link ngRoute.directive:ngView ngView}. * * If `templateUrl` is a function, it will be called with the following parameters: * * - `{Array.}` - route parameters extracted from the current * `$location.path()` by applying the current route * * - `resolve` - `{Object.=}` - An optional map of dependencies which should * be injected into the controller. If any of these dependencies are promises, the router * will wait for them all to be resolved or one to be rejected before the controller is * instantiated. * If all the promises are resolved successfully, the values of the resolved promises are * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is * fired. If any of the promises are rejected the * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object * is: * * - `key` – `{string}`: a name of a dependency to be injected into the controller. * - `factory` - `{string|function}`: If `string` then it is an alias for a service. * Otherwise if function, then it is {@link auto.$injector#invoke injected} * and the return value is treated as the dependency. If the result is a promise, it is * resolved before its value is injected into the controller. Be aware that * `ngRoute.$routeParams` will still refer to the previous route within these resolve * functions. Use `$route.current.params` to access the new route parameters, instead. * * - `redirectTo` – {(string|function())=} – value to update * {@link ng.$location $location} path with and trigger route redirection. * * If `redirectTo` is a function, it will be called with the following parameters: * * - `{Object.}` - route parameters extracted from the current * `$location.path()` by applying the current route templateUrl. * - `{string}` - current `$location.path()` * - `{Object}` - current `$location.search()` * * The custom `redirectTo` function is expected to return a string which will be used * to update `$location.path()` and `$location.search()`. * * - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()` * or `$location.hash()` changes. * * If the option is set to `false` and url in the browser changes, then * `$routeUpdate` event is broadcasted on the root scope. * * - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive * * If the option is set to `true`, then the particular route can be matched without being * case sensitive * * @returns {Object} self * * @description * Adds a new route definition to the `$route` service. */ this.when = function(path, route) { //copy original route object to preserve params inherited from proto chain var routeCopy = angular.copy(route); if (angular.isUndefined(routeCopy.reloadOnSearch)) { routeCopy.reloadOnSearch = true; } if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) { routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch; } routes[path] = angular.extend( routeCopy, path && pathRegExp(path, routeCopy) ); // create redirection for trailing slashes if (path) { var redirectPath = (path[path.length - 1] == '/') ? path.substr(0, path.length - 1) : path + '/'; routes[redirectPath] = angular.extend( {redirectTo: path}, pathRegExp(redirectPath, routeCopy) ); } return this; }; /** * @ngdoc property * @name $routeProvider#caseInsensitiveMatch * @description * * A boolean property indicating if routes defined * using this provider should be matched using a case insensitive * algorithm. Defaults to `false`. */ this.caseInsensitiveMatch = false; /** * @param path {string} path * @param opts {Object} options * @return {?Object} * * @description * Normalizes the given path, returning a regular expression * and the original path. * * Inspired by pathRexp in visionmedia/express/lib/utils.js. */ function pathRegExp(path, opts) { var insensitive = opts.caseInsensitiveMatch, ret = { originalPath: path, regexp: path }, keys = ret.keys = []; path = path .replace(/([().])/g, '\\$1') .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) { var optional = option === '?' ? option : null; var star = option === '*' ? option : null; keys.push({ name: key, optional: !!optional }); slash = slash || ''; return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (star && '(.+?)' || '([^/]+)') + (optional || '') + ')' + (optional || ''); }) .replace(/([\/$\*])/g, '\\$1'); ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : ''); return ret; } /** * @ngdoc method * @name $routeProvider#otherwise * * @description * Sets route definition that will be used on route change when no other route definition * is matched. * * @param {Object|string} params Mapping information to be assigned to `$route.current`. * If called with a string, the value maps to `redirectTo`. * @returns {Object} self */ this.otherwise = function(params) { if (typeof params === 'string') { params = {redirectTo: params}; } this.when(null, params); return this; }; this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$templateRequest', '$sce', function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) { /** * @ngdoc service * @name $route * @requires $location * @requires $routeParams * * @property {Object} current Reference to the current route definition. * The route definition contains: * * - `controller`: The controller constructor as define in route definition. * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for * controller instantiation. The `locals` contain * the resolved values of the `resolve` map. Additionally the `locals` also contain: * * - `$scope` - The current route scope. * - `$template` - The current route template HTML. * * @property {Object} routes Object with all route configuration Objects as its properties. * * @description * `$route` is used for deep-linking URLs to controllers and views (HTML partials). * It watches `$location.url()` and tries to map the path to an existing route definition. * * Requires the {@link ngRoute `ngRoute`} module to be installed. * * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. * * The `$route` service is typically used in conjunction with the * {@link ngRoute.directive:ngView `ngView`} directive and the * {@link ngRoute.$routeParams `$routeParams`} service. * * @example * This example shows how changing the URL hash causes the `$route` to match a route against the * URL, and the `ngView` pulls in the partial. * * * *
* Choose: * Moby | * Moby: Ch1 | * Gatsby | * Gatsby: Ch4 | * Scarlet Letter
* *
* *
* *
$location.path() = {{$location.path()}}
*
$route.current.templateUrl = {{$route.current.templateUrl}}
*
$route.current.params = {{$route.current.params}}
*
$route.current.scope.name = {{$route.current.scope.name}}
*
$routeParams = {{$routeParams}}
*
*
* * * controller: {{name}}
* Book Id: {{params.bookId}}
*
* * * controller: {{name}}
* Book Id: {{params.bookId}}
* Chapter Id: {{params.chapterId}} *
* * * angular.module('ngRouteExample', ['ngRoute']) * * .controller('MainController', function($scope, $route, $routeParams, $location) { * $scope.$route = $route; * $scope.$location = $location; * $scope.$routeParams = $routeParams; * }) * * .controller('BookController', function($scope, $routeParams) { * $scope.name = "BookController"; * $scope.params = $routeParams; * }) * * .controller('ChapterController', function($scope, $routeParams) { * $scope.name = "ChapterController"; * $scope.params = $routeParams; * }) * * .config(function($routeProvider, $locationProvider) { * $routeProvider * .when('/Book/:bookId', { * templateUrl: 'book.html', * controller: 'BookController', * resolve: { * // I will cause a 1 second delay * delay: function($q, $timeout) { * var delay = $q.defer(); * $timeout(delay.resolve, 1000); * return delay.promise; * } * } * }) * .when('/Book/:bookId/ch/:chapterId', { * templateUrl: 'chapter.html', * controller: 'ChapterController' * }); * * // configure html5 to get links working on jsfiddle * $locationProvider.html5Mode(true); * }); * * * * * it('should load and compile correct template', function() { * element(by.linkText('Moby: Ch1')).click(); * var content = element(by.css('[ng-view]')).getText(); * expect(content).toMatch(/controller\: ChapterController/); * expect(content).toMatch(/Book Id\: Moby/); * expect(content).toMatch(/Chapter Id\: 1/); * * element(by.partialLinkText('Scarlet')).click(); * * content = element(by.css('[ng-view]')).getText(); * expect(content).toMatch(/controller\: BookController/); * expect(content).toMatch(/Book Id\: Scarlet/); * }); * *
*/ /** * @ngdoc event * @name $route#$routeChangeStart * @eventType broadcast on root scope * @description * Broadcasted before a route change. At this point the route services starts * resolving all of the dependencies needed for the route change to occur. * Typically this involves fetching the view template as well as any dependencies * defined in `resolve` route property. Once all of the dependencies are resolved * `$routeChangeSuccess` is fired. * * The route change (and the `$location` change that triggered it) can be prevented * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} * for more details about event object. * * @param {Object} angularEvent Synthetic event object. * @param {Route} next Future route information. * @param {Route} current Current route information. */ /** * @ngdoc event * @name $route#$routeChangeSuccess * @eventType broadcast on root scope * @description * Broadcasted after a route change has happened successfully. * The `resolve` dependencies are now available in the `current.locals` property. * * {@link ngRoute.directive:ngView ngView} listens for the directive * to instantiate the controller and render the view. * * @param {Object} angularEvent Synthetic event object. * @param {Route} current Current route information. * @param {Route|Undefined} previous Previous route information, or undefined if current is * first route entered. */ /** * @ngdoc event * @name $route#$routeChangeError * @eventType broadcast on root scope * @description * Broadcasted if any of the resolve promises are rejected. * * @param {Object} angularEvent Synthetic event object * @param {Route} current Current route information. * @param {Route} previous Previous route information. * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise. */ /** * @ngdoc event * @name $route#$routeUpdate * @eventType broadcast on root scope * @description * The `reloadOnSearch` property has been set to false, and we are reusing the same * instance of the Controller. * * @param {Object} angularEvent Synthetic event object * @param {Route} current Current/previous route information. */ var forceReload = false, preparedRoute, preparedRouteIsUpdateOnly, $route = { routes: routes, /** * @ngdoc method * @name $route#reload * * @description * Causes `$route` service to reload the current route even if * {@link ng.$location $location} hasn't changed. * * As a result of that, {@link ngRoute.directive:ngView ngView} * creates new scope and reinstantiates the controller. */ reload: function() { forceReload = true; $rootScope.$evalAsync(function() { // Don't support cancellation of a reload for now... prepareRoute(); commitRoute(); }); }, /** * @ngdoc method * @name $route#updateParams * * @description * Causes `$route` service to update the current URL, replacing * current route parameters with those specified in `newParams`. * Provided property names that match the route's path segment * definitions will be interpolated into the location's path, while * remaining properties will be treated as query params. * * @param {!Object} newParams mapping of URL parameter names to values */ updateParams: function(newParams) { if (this.current && this.current.$$route) { newParams = angular.extend({}, this.current.params, newParams); $location.path(interpolate(this.current.$$route.originalPath, newParams)); // interpolate modifies newParams, only query params are left $location.search(newParams); } else { throw $routeMinErr('norout', 'Tried updating route when with no current route'); } } }; $rootScope.$on('$locationChangeStart', prepareRoute); $rootScope.$on('$locationChangeSuccess', commitRoute); return $route; ///////////////////////////////////////////////////// /** * @param on {string} current url * @param route {Object} route regexp to match the url against * @return {?Object} * * @description * Check if the route matches the current url. * * Inspired by match in * visionmedia/express/lib/router/router.js. */ function switchRouteMatcher(on, route) { var keys = route.keys, params = {}; if (!route.regexp) return null; var m = route.regexp.exec(on); if (!m) return null; for (var i = 1, len = m.length; i < len; ++i) { var key = keys[i - 1]; var val = m[i]; if (key && val) { params[key.name] = val; } } return params; } function prepareRoute($locationEvent) { var lastRoute = $route.current; preparedRoute = parseRoute(); preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route && angular.equals(preparedRoute.pathParams, lastRoute.pathParams) && !preparedRoute.reloadOnSearch && !forceReload; if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) { if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) { if ($locationEvent) { $locationEvent.preventDefault(); } } } } function commitRoute() { var lastRoute = $route.current; var nextRoute = preparedRoute; if (preparedRouteIsUpdateOnly) { lastRoute.params = nextRoute.params; angular.copy(lastRoute.params, $routeParams); $rootScope.$broadcast('$routeUpdate', lastRoute); } else if (nextRoute || lastRoute) { forceReload = false; $route.current = nextRoute; if (nextRoute) { if (nextRoute.redirectTo) { if (angular.isString(nextRoute.redirectTo)) { $location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params) .replace(); } else { $location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search())) .replace(); } } } $q.when(nextRoute). then(function() { if (nextRoute) { var locals = angular.extend({}, nextRoute.resolve), template, templateUrl; angular.forEach(locals, function(value, key) { locals[key] = angular.isString(value) ? $injector.get(value) : $injector.invoke(value, null, null, key); }); if (angular.isDefined(template = nextRoute.template)) { if (angular.isFunction(template)) { template = template(nextRoute.params); } } else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) { if (angular.isFunction(templateUrl)) { templateUrl = templateUrl(nextRoute.params); } if (angular.isDefined(templateUrl)) { nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl); template = $templateRequest(templateUrl); } } if (angular.isDefined(template)) { locals['$template'] = template; } return $q.all(locals); } }). then(function(locals) { // after route change if (nextRoute == $route.current) { if (nextRoute) { nextRoute.locals = locals; angular.copy(nextRoute.params, $routeParams); } $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute); } }, function(error) { if (nextRoute == $route.current) { $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error); } }); } } /** * @returns {Object} the current active route, by matching it against the URL */ function parseRoute() { // Match a route var params, match; angular.forEach(routes, function(route, path) { if (!match && (params = switchRouteMatcher($location.path(), route))) { match = inherit(route, { params: angular.extend({}, $location.search(), params), pathParams: params}); match.$$route = route; } }); // No route matched; fallback to "otherwise" route return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); } /** * @returns {string} interpolation of the redirect path with the parameters */ function interpolate(string, params) { var result = []; angular.forEach((string || '').split(':'), function(segment, i) { if (i === 0) { result.push(segment); } else { var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/); var key = segmentMatch[1]; result.push(params[key]); result.push(segmentMatch[2] || ''); delete params[key]; } }); return result.join(''); } }]; } ngRouteModule.provider('$routeParams', $RouteParamsProvider); /** * @ngdoc service * @name $routeParams * @requires $route * * @description * The `$routeParams` service allows you to retrieve the current set of route parameters. * * Requires the {@link ngRoute `ngRoute`} module to be installed. * * The route parameters are a combination of {@link ng.$location `$location`}'s * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. * * In case of parameter name collision, `path` params take precedence over `search` params. * * The service guarantees that the identity of the `$routeParams` object will remain unchanged * (but its properties will likely change) even when a route change occurs. * * Note that the `$routeParams` are only updated *after* a route change completes successfully. * This means that you cannot rely on `$routeParams` being correct in route resolve functions. * Instead you can use `$route.current.params` to access the new route's parameters. * * @example * ```js * // Given: * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby * // Route: /Chapter/:chapterId/Section/:sectionId * // * // Then * $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'} * ``` */ function $RouteParamsProvider() { this.$get = function() { return {}; }; } ngRouteModule.directive('ngView', ngViewFactory); ngRouteModule.directive('ngView', ngViewFillContentFactory); /** * @ngdoc directive * @name ngView * @restrict ECA * * @description * # Overview * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by * including the rendered template of the current route into the main layout (`index.html`) file. * Every time the current route changes, the included view changes with it according to the * configuration of the `$route` service. * * Requires the {@link ngRoute `ngRoute`} module to be installed. * * @animations * enter - animation is used to bring new content into the browser. * leave - animation is used to animate existing content away. * * The enter and leave animation occur concurrently. * * @scope * @priority 400 * @param {string=} onload Expression to evaluate whenever the view updates. * * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll * $anchorScroll} to scroll the viewport after the view is updated. * * - If the attribute is not set, disable scrolling. * - If the attribute is set without value, enable scrolling. * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated * as an expression yields a truthy value. * @example
Choose: Moby | Moby: Ch1 | Gatsby | Gatsby: Ch4 | Scarlet Letter

$location.path() = {{main.$location.path()}}
$route.current.templateUrl = {{main.$route.current.templateUrl}}
$route.current.params = {{main.$route.current.params}}
$routeParams = {{main.$routeParams}}
controller: {{book.name}}
Book Id: {{book.params.bookId}}
controller: {{chapter.name}}
Book Id: {{chapter.params.bookId}}
Chapter Id: {{chapter.params.chapterId}}
.view-animate-container { position:relative; height:100px!important; background:white; border:1px solid black; height:40px; overflow:hidden; } .view-animate { padding:10px; } .view-animate.ng-enter, .view-animate.ng-leave { transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; display:block; width:100%; border-left:1px solid black; position:absolute; top:0; left:0; right:0; bottom:0; padding:10px; } .view-animate.ng-enter { left:100%; } .view-animate.ng-enter.ng-enter-active { left:0; } .view-animate.ng-leave.ng-leave-active { left:-100%; } angular.module('ngViewExample', ['ngRoute', 'ngAnimate']) .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { $routeProvider .when('/Book/:bookId', { templateUrl: 'book.html', controller: 'BookCtrl', controllerAs: 'book' }) .when('/Book/:bookId/ch/:chapterId', { templateUrl: 'chapter.html', controller: 'ChapterCtrl', controllerAs: 'chapter' }); $locationProvider.html5Mode(true); }]) .controller('MainCtrl', ['$route', '$routeParams', '$location', function($route, $routeParams, $location) { this.$route = $route; this.$location = $location; this.$routeParams = $routeParams; }]) .controller('BookCtrl', ['$routeParams', function($routeParams) { this.name = "BookCtrl"; this.params = $routeParams; }]) .controller('ChapterCtrl', ['$routeParams', function($routeParams) { this.name = "ChapterCtrl"; this.params = $routeParams; }]); it('should load and compile correct template', function() { element(by.linkText('Moby: Ch1')).click(); var content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller\: ChapterCtrl/); expect(content).toMatch(/Book Id\: Moby/); expect(content).toMatch(/Chapter Id\: 1/); element(by.partialLinkText('Scarlet')).click(); content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller\: BookCtrl/); expect(content).toMatch(/Book Id\: Scarlet/); });
*/ /** * @ngdoc event * @name ngView#$viewContentLoaded * @eventType emit on the current ngView scope * @description * Emitted every time the ngView content is reloaded. */ ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate']; function ngViewFactory($route, $anchorScroll, $animate) { return { restrict: 'ECA', terminal: true, priority: 400, transclude: 'element', link: function(scope, $element, attr, ctrl, $transclude) { var currentScope, currentElement, previousLeaveAnimation, autoScrollExp = attr.autoscroll, onloadExp = attr.onload || ''; scope.$on('$routeChangeSuccess', update); update(); function cleanupLastView() { if (previousLeaveAnimation) { $animate.cancel(previousLeaveAnimation); previousLeaveAnimation = null; } if (currentScope) { currentScope.$destroy(); currentScope = null; } if (currentElement) { previousLeaveAnimation = $animate.leave(currentElement); previousLeaveAnimation.then(function() { previousLeaveAnimation = null; }); currentElement = null; } } function update() { var locals = $route.current && $route.current.locals, template = locals && locals.$template; if (angular.isDefined(template)) { var newScope = scope.$new(); var current = $route.current; // Note: This will also link all children of ng-view that were contained in the original // html. If that content contains controllers, ... they could pollute/change the scope. // However, using ng-view on an element with additional content does not make sense... // Note: We can't remove them in the cloneAttchFn of $transclude as that // function is called before linking the content, which would apply child // directives to non existing elements. var clone = $transclude(newScope, function(clone) { $animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter() { if (angular.isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { $anchorScroll(); } }); cleanupLastView(); }); currentElement = clone; currentScope = current.scope = newScope; currentScope.$emit('$viewContentLoaded'); currentScope.$eval(onloadExp); } else { cleanupLastView(); } } } }; } // This directive is called during the $transclude call of the first `ngView` directive. // It will replace and compile the content of the element with the loaded template. // We need this directive so that the element content is already filled when // the link function of another directive on the same element as ngView // is called. ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route']; function ngViewFillContentFactory($compile, $controller, $route) { return { restrict: 'ECA', priority: -400, link: function(scope, $element) { var current = $route.current, locals = current.locals; $element.html(locals.$template); var link = $compile($element.contents()); if (current.controller) { locals.$scope = scope; var controller = $controller(current.controller, locals); if (current.controllerAs) { scope[current.controllerAs] = controller; } $element.data('$ngControllerController', controller); $element.children().data('$ngControllerController', controller); } link(scope); } }; } })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-sanitize.js ================================================ /** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Any commits to this file should be reviewed with security in mind. * * Changes to this file can potentially create security vulnerabilities. * * An approval from 2 Core members with history of modifying * * this file is required. * * * * Does the change somehow allow for arbitrary javascript to be executed? * * Or allows for someone to change the prototype of built-in objects? * * Or gives undesired access to variables likes document or window? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var $sanitizeMinErr = angular.$$minErr('$sanitize'); /** * @ngdoc module * @name ngSanitize * @description * * # ngSanitize * * The `ngSanitize` module provides functionality to sanitize HTML. * * *
* * See {@link ngSanitize.$sanitize `$sanitize`} for usage. */ /* * HTML Parser By Misko Hevery (misko@hevery.com) * based on: HTML Parser By John Resig (ejohn.org) * Original code by Erik Arvidsson, Mozilla Public License * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js * * // Use like so: * htmlParser(htmlString, { * start: function(tag, attrs, unary) {}, * end: function(tag) {}, * chars: function(text) {}, * comment: function(text) {} * }); * */ /** * @ngdoc service * @name $sanitize * @kind function * * @description * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are * then serialized back to properly escaped html string. This means that no unsafe input can make * it into the returned string, however, since our parser is more strict than a typical browser * parser, it's possible that some obscure input, which would be recognized as valid HTML by a * browser, won't make it through the sanitizer. The input may also contain SVG markup. * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. * * @param {string} html HTML input. * @returns {string} Sanitized HTML. * * @example
Snippet:
Directive How Source Rendered
ng-bind-html Automatically uses $sanitize
<div ng-bind-html="snippet">
</div>
ng-bind-html Bypass $sanitize by explicitly trusting the dangerous value
<div ng-bind-html="deliberatelyTrustDangerousSnippet()">
</div>
ng-bind Automatically escapes
<div ng-bind="snippet">
</div>
it('should sanitize the html snippet by default', function() { expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). toBe('

an html\nclick here\nsnippet

'); }); it('should inline raw snippet if bound to a trusted value', function() { expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). toBe("

an html\n" + "click here\n" + "snippet

"); }); it('should escape snippet without any filter', function() { expect(element(by.css('#bind-default div')).getInnerHtml()). toBe("<p style=\"color:blue\">an html\n" + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + "snippet</p>"); }); it('should update', function() { element(by.model('snippet')).clear(); element(by.model('snippet')).sendKeys('new text'); expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). toBe('new text'); expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( 'new text'); expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( "new <b onclick=\"alert(1)\">text</b>"); });
*/ function $SanitizeProvider() { this.$get = ['$$sanitizeUri', function($$sanitizeUri) { return function(html) { var buf = []; htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { return !/^unsafe/.test($$sanitizeUri(uri, isImage)); })); return buf.join(''); }; }]; } function sanitizeText(chars) { var buf = []; var writer = htmlSanitizeWriter(buf, angular.noop); writer.chars(chars); return buf.join(''); } // Regular Expressions for parsing tags and attributes var START_TAG_REGEXP = /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/, END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/, ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, BEGIN_TAG_REGEXP = /^/g, DOCTYPE_REGEXP = /]*?)>/i, CDATA_REGEXP = //g, SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, // Match everything outside of normal chars and " (quote character) NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Good source of info about elements and attributes // http://dev.w3.org/html5/spec/Overview.html#semantics // http://simon.html5.org/html-elements // Safe Void Elements - HTML5 // http://dev.w3.org/html5/spec/Overview.html#void-elements var voidElements = makeMap("area,br,col,hr,img,wbr"); // Elements that you can, intentionally, leave open (and which close themselves) // http://dev.w3.org/html5/spec/Overview.html#optional-tags var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), optionalEndTagInlineElements = makeMap("rp,rt"), optionalEndTagElements = angular.extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements); // Safe Block Elements - HTML5 var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); // Inline Elements - HTML5 var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); // SVG Elements // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. // They can potentially allow for arbitrary javascript to be executed. See #11290 var svgElements = makeMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," + "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," + "radialGradient,rect,stop,svg,switch,text,title,tspan,use"); // Special Elements (can contain anything) var specialElements = makeMap("script,style"); var validElements = angular.extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements, svgElements); //Attributes that have href and hence need to be sanitized var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href"); var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' + 'valign,value,vspace,width'); // SVG attributes (without "id" and "name" attributes) // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' + 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' + 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' + 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' + 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' + 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' + 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' + 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' + 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' + 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' + 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true); var validAttrs = angular.extend({}, uriAttrs, svgAttrs, htmlAttrs); function makeMap(str, lowercaseKeys) { var obj = {}, items = str.split(','), i; for (i = 0; i < items.length; i++) { obj[lowercaseKeys ? angular.lowercase(items[i]) : items[i]] = true; } return obj; } /** * @example * htmlParser(htmlString, { * start: function(tag, attrs, unary) {}, * end: function(tag) {}, * chars: function(text) {}, * comment: function(text) {} * }); * * @param {string} html string * @param {object} handler */ function htmlParser(html, handler) { if (typeof html !== 'string') { if (html === null || typeof html === 'undefined') { html = ''; } else { html = '' + html; } } var index, chars, match, stack = [], last = html, text; stack.last = function() { return stack[stack.length - 1]; }; while (html) { text = ''; chars = true; // Make sure we're not in a script or style element if (!stack.last() || !specialElements[stack.last()]) { // Comment if (html.indexOf("", index) === index) { if (handler.comment) handler.comment(html.substring(4, index)); html = html.substring(index + 3); chars = false; } // DOCTYPE } else if (DOCTYPE_REGEXP.test(html)) { match = html.match(DOCTYPE_REGEXP); if (match) { html = html.replace(match[0], ''); chars = false; } // end tag } else if (BEGING_END_TAGE_REGEXP.test(html)) { match = html.match(END_TAG_REGEXP); if (match) { html = html.substring(match[0].length); match[0].replace(END_TAG_REGEXP, parseEndTag); chars = false; } // start tag } else if (BEGIN_TAG_REGEXP.test(html)) { match = html.match(START_TAG_REGEXP); if (match) { // We only have a valid start-tag if there is a '>'. if (match[4]) { html = html.substring(match[0].length); match[0].replace(START_TAG_REGEXP, parseStartTag); } chars = false; } else { // no ending tag found --- this piece should be encoded as an entity. text += '<'; html = html.substring(1); } } if (chars) { index = html.indexOf("<"); text += index < 0 ? html : html.substring(0, index); html = index < 0 ? "" : html.substring(index); if (handler.chars) handler.chars(decodeEntities(text)); } } else { // IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w]. html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), function(all, text) { text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); if (handler.chars) handler.chars(decodeEntities(text)); return ""; }); parseEndTag("", stack.last()); } if (html == last) { throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + "of html: {0}", html); } last = html; } // Clean up any remaining tags parseEndTag(); function parseStartTag(tag, tagName, rest, unary) { tagName = angular.lowercase(tagName); if (blockElements[tagName]) { while (stack.last() && inlineElements[stack.last()]) { parseEndTag("", stack.last()); } } if (optionalEndTagElements[tagName] && stack.last() == tagName) { parseEndTag("", tagName); } unary = voidElements[tagName] || !!unary; if (!unary) { stack.push(tagName); } var attrs = {}; rest.replace(ATTR_REGEXP, function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { var value = doubleQuotedValue || singleQuotedValue || unquotedValue || ''; attrs[name] = decodeEntities(value); }); if (handler.start) handler.start(tagName, attrs, unary); } function parseEndTag(tag, tagName) { var pos = 0, i; tagName = angular.lowercase(tagName); if (tagName) { // Find the closest opened tag of the same type for (pos = stack.length - 1; pos >= 0; pos--) { if (stack[pos] == tagName) break; } } if (pos >= 0) { // Close all the open elements, up the stack for (i = stack.length - 1; i >= pos; i--) if (handler.end) handler.end(stack[i]); // Remove the open elements from the stack stack.length = pos; } } } var hiddenPre=document.createElement("pre"); /** * decodes all entities into regular string * @param value * @returns {string} A string with decoded entities. */ function decodeEntities(value) { if (!value) { return ''; } hiddenPre.innerHTML = value.replace(//g, '>'); } /** * create an HTML/XML writer which writes to buffer * @param {Array} buf use buf.jain('') to get out sanitized html string * @returns {object} in the form of { * start: function(tag, attrs, unary) {}, * end: function(tag) {}, * chars: function(text) {}, * comment: function(text) {} * } */ function htmlSanitizeWriter(buf, uriValidator) { var ignore = false; var out = angular.bind(buf, buf.push); return { start: function(tag, attrs, unary) { tag = angular.lowercase(tag); if (!ignore && specialElements[tag]) { ignore = tag; } if (!ignore && validElements[tag] === true) { out('<'); out(tag); angular.forEach(attrs, function(value, key) { var lkey=angular.lowercase(key); var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); if (validAttrs[lkey] === true && (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { out(' '); out(key); out('="'); out(encodeEntities(value)); out('"'); } }); out(unary ? '/>' : '>'); } }, end: function(tag) { tag = angular.lowercase(tag); if (!ignore && validElements[tag] === true) { out(''); } if (tag == ignore) { ignore = false; } }, chars: function(chars) { if (!ignore) { out(encodeEntities(chars)); } } }; } // define ngSanitize module and register $sanitize service angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); /* global sanitizeText: false */ /** * @ngdoc filter * @name linky * @kind function * * @description * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and * plain email address links. * * Requires the {@link ngSanitize `ngSanitize`} module to be installed. * * @param {string} text Input text. * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. * @returns {string} Html-linkified text. * * @usage * * @example
Snippet:
Filter Source Rendered
linky filter
<div ng-bind-html="snippet | linky">
</div>
linky target
<div ng-bind-html="snippetWithTarget | linky:'_blank'">
</div>
no filter
<div ng-bind="snippet">
</div>
it('should linkify the snippet with urls', function() { expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); }); it('should not linkify snippet without the linky filter', function() { expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); }); it('should update', function() { element(by.model('snippet')).clear(); element(by.model('snippet')).sendKeys('new http://link.'); expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). toBe('new http://link.'); expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) .toBe('new http://link.'); }); it('should work with the target property', function() { expect(element(by.id('linky-target')). element(by.binding("snippetWithTarget | linky:'_blank'")).getText()). toBe('http://angularjs.org/'); expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); }); */ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, MAILTO_REGEXP = /^mailto:/i; return function(text, target) { if (!text) return text; var match; var raw = text; var html = []; var url; var i; while ((match = raw.match(LINKY_URL_REGEXP))) { // We can not end in these as they are sometimes found at the end of the sentence url = match[0]; // if we did not match ftp/http/www/mailto then assume mailto if (!match[2] && !match[4]) { url = (match[3] ? 'http://' : 'mailto:') + url; } i = match.index; addText(raw.substr(0, i)); addLink(url, match[0].replace(MAILTO_REGEXP, '')); raw = raw.substring(i + match[0].length); } addText(raw); return $sanitize(html.join('')); function addText(text) { if (!text) { return; } html.push(sanitizeText(text)); } function addLink(url, text) { html.push(''); addText(text); html.push(''); } }; }]); })(window, window.angular); ================================================ FILE: Samples/Difficult/Reinforced.Typings.Samples.Difficult.CodeGenerators/Scripts/angular-scenario.js ================================================ /*! * jQuery JavaScript Library v2.1.1 * http://jquery.com/ * * Includes Sizzle.js * http://sizzlejs.com/ * * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-05-01T17:11Z */ (function( global, factory ) {'use strict'; if ( typeof module === "object" && typeof module.exports === "object" ) { // For CommonJS and CommonJS-like environments where a proper window is present, // execute the factory and get jQuery // For environments that do not inherently posses a window with a document // (such as Node.js), expose a jQuery-making factory as module.exports // This accentuates the need for the creation of a real window // e.g. var jQuery = require("jquery")(window); // See ticket #14549 for more info module.exports = global.document ? factory( global, true ) : function( w ) { if ( !w.document ) { throw new Error( "jQuery requires a window with a document" ); } return factory( w ); }; } else { factory( global ); } // Pass this if window is not defined yet }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { // Can't do this because several apps including ASP.NET trace // the stack via arguments.caller.callee and Firefox dies if // you try to trace through "use strict" call chains. (#13335) // Support: Firefox 18+ // var arr = []; var slice = arr.slice; var concat = arr.concat; var push = arr.push; var indexOf = arr.indexOf; var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var support = {}; var // Use the correct document accordingly with window argument (sandbox) document = window.document, version = "2.1.1", // Define a local copy of jQuery jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); }, // Support: Android<4.1 // Make sure we trim BOM and NBSP rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, // Matches dashed string for camelizing rmsPrefix = /^-ms-/, rdashAlpha = /-([\da-z])/gi, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return letter.toUpperCase(); }; jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: version, constructor: jQuery, // Start with an empty selector selector: "", // The default length of a jQuery object is 0 length: 0, toArray: function() { return slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num != null ? // Return just the one element from the set ( num < 0 ? this[ num + this.length ] : this[ num ] ) : // Return all the elements in a clean array slice.call( this ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, slice: function() { return this.pushStack( slice.apply( this, arguments ) ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: arr.sort, splice: arr.splice }; jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; // skip the boolean and the target target = arguments[ i ] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ // Unique for each copy of jQuery on the page expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), // Assume jQuery is ready without the ready module isReady: true, error: function( msg ) { throw new Error( msg ); }, noop: function() {}, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray, isWindow: function( obj ) { return obj != null && obj === obj.window; }, isNumeric: function( obj ) { // parseFloat NaNs numeric-cast false positives (null|true|false|"") // ...but misinterprets leading-number strings, particularly hex literals ("0x...") // subtraction forces infinities to NaN return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; }, isPlainObject: function( obj ) { // Not plain objects: // - Any object or value whose internal [[Class]] property is not "[object Object]" // - DOM nodes // - window if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } if ( obj.constructor && !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { return false; } // If the function hasn't returned already, we're confident that // |obj| is a plain object, created by {} or constructed with new Object return true; }, isEmptyObject: function( obj ) { var name; for ( name in obj ) { return false; } return true; }, type: function( obj ) { if ( obj == null ) { return obj + ""; } // Support: Android < 4.0, iOS < 6 (functionish RegExp) return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ] || "object" : typeof obj; }, // Evaluates a script in a global context globalEval: function( code ) { var script, indirect = eval; code = jQuery.trim( code ); if ( code ) { // If the code includes a valid, prologue position // strict mode pragma, execute code by injecting a // script tag into the document. if ( code.indexOf("use strict") === 1 ) { script = document.createElement("script"); script.text = code; document.head.appendChild( script ).parentNode.removeChild( script ); } else { // Otherwise, avoid the DOM node creation, insertion // and removal by using an indirect global eval indirect( code ); } } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); }, // args is for internal usage only each: function( obj, callback, args ) { var value, i = 0, length = obj.length, isArray = isArraylike( obj ); if ( args ) { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } } return obj; }, // Support: Android<4.1 trim: function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArraylike( Object(arr) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { push.call( ret, arr ); } } return ret; }, inArray: function( elem, arr, i ) { return arr == null ? -1 : indexOf.call( arr, elem, i ); }, merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; for ( ; j < len; j++ ) { first[ i++ ] = second[ j ]; } first.length = i; return first; }, grep: function( elems, callback, invert ) { var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { callbackInverse = !callback( elems[ i ], i ); if ( callbackInverse !== callbackExpect ) { matches.push( elems[ i ] ); } } return matches; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, i = 0, length = elems.length, isArray = isArraylike( elems ), ret = []; // Go through the array, translating each of the items to their new values if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } // Go through every key on the object, } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } } // Flatten any nested arrays return concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { var tmp, args, proxy; if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind args = slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; }, now: Date.now, // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support }); // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); function isArraylike( obj ) { var length = obj.length, type = jQuery.type( obj ); if ( type === "function" || jQuery.isWindow( obj ) ) { return false; } if ( obj.nodeType === 1 && length ) { return true; } return type === "array" || length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj; } var Sizzle = /*! * Sizzle CSS Selector Engine v1.10.19 * http://sizzlejs.com/ * * Copyright 2013 jQuery Foundation, Inc. and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-04-18 */ (function( window ) { var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, // Local document vars setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains, // Instance-specific data expando = "sizzle" + -(new Date()), preferredDoc = window.document, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; } return 0; }, // General-purpose constants strundefined = typeof undefined, MAX_NEGATIVE = 1 << 31, // Instance methods hasOwn = ({}).hasOwnProperty, arr = [], pop = arr.pop, push_native = arr.push, push = arr.push, slice = arr.slice, // Use a stripped-down indexOf if we can't use a native one indexOf = arr.indexOf || function( elem ) { var i = 0, len = this.length; for ( ; i < len; i++ ) { if ( this[i] === elem ) { return i; } } return -1; }, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", // http://www.w3.org/TR/css3-syntax/#characters characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", // Loosely modeled on CSS identifier characters // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier identifier = characterEncoding.replace( "w", "w#" ), // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", pseudos = ":(" + characterEncoding + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) ".*" + ")\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), matchExpr = { "ID": new RegExp( "^#(" + characterEncoding + ")" ), "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), // For use in libraries implementing .is() // We use this for POS matching in `select` "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rnative = /^[^{]+\{\s*\[native \w/, // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, rescape = /'|\\/g, // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), funescape = function( _, escaped, escapedWhitespace ) { var high = "0x" + escaped - 0x10000; // NaN means non-codepoint // Support: Firefox<24 // Workaround erroneous numeric interpretation of +"0x" return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint String.fromCharCode( high + 0x10000 ) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }; // Optimize for push.apply( _, NodeList ) try { push.apply( (arr = slice.call( preferredDoc.childNodes )), preferredDoc.childNodes ); // Support: Android<4.0 // Detect silently failing push.apply arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { push_native.apply( target, slice.call(els) ); } : // Support: IE<9 // Otherwise append directly function( target, els ) { var j = target.length, i = 0; // Can't trust NodeList.length while ( (target[j++] = els[i++]) ) {} target.length = j - 1; } }; } function Sizzle( selector, context, results, seed ) { var match, elem, m, nodeType, // QSA vars i, groups, old, nid, newContext, newSelector; if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { setDocument( context ); } context = context || document; results = results || []; if ( !selector || typeof selector !== "string" ) { return results; } if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { return []; } if ( documentIsHTML && !seed ) { // Shortcuts if ( (match = rquickExpr.exec( selector )) ) { // Speed-up: Sizzle("#ID") if ( (m = match[1]) ) { if ( nodeType === 9 ) { elem = context.getElementById( m ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document (jQuery #6963) if ( elem && elem.parentNode ) { // Handle the case where IE, Opera, and Webkit return items // by name instead of ID if ( elem.id === m ) { results.push( elem ); return results; } } else { return results; } } else { // Context is not a document if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && contains( context, elem ) && elem.id === m ) { results.push( elem ); return results; } } // Speed-up: Sizzle("TAG") } else if ( match[2] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Speed-up: Sizzle(".CLASS") } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); return results; } } // QSA path if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { nid = old = expando; newContext = context; newSelector = nodeType === 9 && selector; // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { groups = tokenize( selector ); if ( (old = context.getAttribute("id")) ) { nid = old.replace( rescape, "\\$&" ); } else { context.setAttribute( "id", nid ); } nid = "[id='" + nid + "'] "; i = groups.length; while ( i-- ) { groups[i] = nid + toSelector( groups[i] ); } newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; newSelector = groups.join(","); } if ( newSelector ) { try { push.apply( results, newContext.querySelectorAll( newSelector ) ); return results; } catch(qsaError) { } finally { if ( !old ) { context.removeAttribute("id"); } } } } } // All others return select( selector.replace( rtrim, "$1" ), context, results, seed ); } /** * Create key-value caches of limited size * @returns {Function(string, Object)} Returns the Object data after storing it on itself with * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) * deleting the oldest entry */ function createCache() { var keys = []; function cache( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key + " " ] = value); } return cache; } /** * Mark a function for special use by Sizzle * @param {Function} fn The function to mark */ function markFunction( fn ) { fn[ expando ] = true; return fn; } /** * Support testing using an element * @param {Function} fn Passed the created div and expects a boolean result */ function assert( fn ) { var div = document.createElement("div"); try { return !!fn( div ); } catch (e) { return false; } finally { // Remove from its parent by default if ( div.parentNode ) { div.parentNode.removeChild( div ); } // release memory in IE div = null; } } /** * Adds the same handler for all of the specified attrs * @param {String} attrs Pipe-separated list of attributes * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { var arr = attrs.split("|"), i = attrs.length; while ( i-- ) { Expr.attrHandle[ arr[i] ] = handler; } } /** * Checks document order of two siblings * @param {Element} a * @param {Element} b * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b */ function siblingCheck( a, b ) { var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); // Use IE sourceIndex if available on both nodes if ( diff ) { return diff; } // Check if b follows a if ( cur ) { while ( (cur = cur.nextSibling) ) { if ( cur === b ) { return -1; } } } return a ? 1 : -1; } /** * Returns a function to use in pseudos for input types * @param {String} type */ function createInputPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === type; }; } /** * Returns a function to use in pseudos for buttons * @param {String} type */ function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && elem.type === type; }; } /** * Returns a function to use in pseudos for positionals * @param {Function} fn */ function createPositionalPseudo( fn ) { return markFunction(function( argument ) { argument = +argument; return markFunction(function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }); }); } /** * Checks a node for validity as a Sizzle context * @param {Element|Object=} context * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value */ function testContext( context ) { return context && typeof context.getElementsByTagName !== strundefined && context; } // Expose support vars for convenience support = Sizzle.support = {}; /** * Detects XML nodes * @param {Element|Object} elem An element or a document * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = elem && (elem.ownerDocument || elem).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; /** * Sets document-related variables once based on the current document * @param {Element|Object} [doc] An element or document object to use to set the document * @returns {Object} Returns the current document */ setDocument = Sizzle.setDocument = function( node ) { var hasCompare, doc = node ? node.ownerDocument || node : preferredDoc, parent = doc.defaultView; // If no document and documentElement is available, return if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } // Set our document document = doc; docElem = doc.documentElement; // Support tests documentIsHTML = !isXML( doc ); // Support: IE>8 // If iframe document is assigned to "document" variable and if iframe has been reloaded, // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 // IE6-8 do not support the defaultView property so parent will be undefined if ( parent && parent !== parent.top ) { // IE11 does not have attachEvent, so all must suffer if ( parent.addEventListener ) { parent.addEventListener( "unload", function() { setDocument(); }, false ); } else if ( parent.attachEvent ) { parent.attachEvent( "onunload", function() { setDocument(); }); } } /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) support.attributes = assert(function( div ) { div.className = "i"; return !div.getAttribute("className"); }); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements support.getElementsByTagName = assert(function( div ) { div.appendChild( doc.createComment("") ); return !div.getElementsByTagName("*").length; }); // Check if getElementsByClassName can be trusted support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { div.innerHTML = "
"; // Support: Safari<4 // Catch class over-caching div.firstChild.className = "i"; // Support: Opera<10 // Catch gEBCN failure to find non-leading classes return div.getElementsByClassName("i").length === 2; }); // Support: IE<10 // Check if getElementById returns elements by name // The broken getElementById methods don't pick up programatically-set names, // so use a roundabout getElementsByName test support.getById = assert(function( div ) { docElem.appendChild( div ).id = expando; return !doc.getElementsByName || !doc.getElementsByName( expando ).length; }); // ID find and filter if ( support.getById ) { Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== strundefined && documentIsHTML ) { var m = context.getElementById( id ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [ m ] : []; } }; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { return elem.getAttribute("id") === attrId; }; }; } else { // Support: IE6/7 // getElementById is not reliable as a find shortcut delete Expr.find["ID"]; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); return node && node.value === attrId; }; }; } // Tag Expr.find["TAG"] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== strundefined ) { return context.getElementsByTagName( tag ); } } : function( tag, context ) { var elem, tmp = [], i = 0, results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { while ( (elem = results[i++]) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } } return tmp; } return results; }; // Class Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { return context.getElementsByClassName( className ); } }; /* QSA/matchesSelector ---------------------------------------------------------------------- */ // QSA and matchesSelector support // matchesSelector(:active) reports false when true (IE9/Opera 11.5) rbuggyMatches = []; // qSa(:focus) reports false when true (Chrome 21) // We allow this because of a bug in IE8/9 that throws an error // whenever `document.activeElement` is accessed on an iframe // So, we allow :focus to pass through QSA all the time to avoid the IE error // See http://bugs.jquery.com/ticket/13378 rbuggyQSA = []; if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { // Build QSA regex // Regex strategy adopted from Diego Perini assert(function( div ) { // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, // since its presence should be enough // http://bugs.jquery.com/ticket/12359 div.innerHTML = ""; // Support: IE8, Opera 11-12.16 // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section if ( div.querySelectorAll("[msallowclip^='']").length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly if ( !div.querySelectorAll("[selected]").length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":checked").length ) { rbuggyQSA.push(":checked"); } }); assert(function( div ) { // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment var input = doc.createElement("input"); input.setAttribute( "type", "hidden" ); div.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute if ( div.querySelectorAll("[name=d]").length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":enabled").length ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Opera 10-11 does not throw on post-comma invalid pseudos div.querySelectorAll("*,:x"); rbuggyQSA.push(",.*:"); }); } if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector) )) ) { assert(function( div ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( div, "div" ); // This should fail with an exception // Gecko does not error, returns false instead matches.call( div, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); }); } rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); /* Contains ---------------------------------------------------------------------- */ hasCompare = rnative.test( docElem.compareDocumentPosition ); // Element contains another // Purposefully does not implement inclusive descendent // As in, an element does not contain itself contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode; return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; }; /* Sorting ---------------------------------------------------------------------- */ // Document order sorting sortOrder = hasCompare ? function( a, b ) { // Flag for duplicate removal if ( a === b ) { hasDuplicate = true; return 0; } // Sort on method existence if only one input has compareDocumentPosition var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; if ( compare ) { return compare; } // Calculate position if both inputs belong to the same document compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected 1; // Disconnected nodes if ( compare & 1 || (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { // Choose the first element that is related to our preferred document if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { return -1; } if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { return 1; } // Maintain original order return sortInput ? ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 0; } return compare & 4 ? -1 : 1; } : function( a, b ) { // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; return 0; } var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [ a ], bp = [ b ]; // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : sortInput ? ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 0; // If the nodes are siblings, we can do a quick check } else if ( aup === bup ) { return siblingCheck( a, b ); } // Otherwise we need full lists of their ancestors for comparison cur = a; while ( (cur = cur.parentNode) ) { ap.unshift( cur ); } cur = b; while ( (cur = cur.parentNode) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy while ( ap[i] === bp[i] ) { i++; } return i ? // Do a sibling check if the nodes have a common ancestor siblingCheck( ap[i], bp[i] ) : // Otherwise nodes in our document sort first ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0; }; return doc; }; Sizzle.matches = function( expr, elements ) { return Sizzle( expr, null, null, elements ); }; Sizzle.matchesSelector = function( elem, expr ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } // Make sure that attribute selectors are quoted expr = expr.replace( rattributeQuotes, "='$1']" ); if ( support.matchesSelector && documentIsHTML && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { try { var ret = matches.call( elem, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9 elem.document && elem.document.nodeType !== 11 ) { return ret; } } catch(e) {} } return Sizzle( expr, document, null, [ elem ] ).length > 0; }; Sizzle.contains = function( context, elem ) { // Set document vars if needed if ( ( context.ownerDocument || context ) !== document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : undefined; return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null; }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; /** * Document sorting and removing duplicates * @param {ArrayLike} results */ Sizzle.uniqueSort = function( results ) { var elem, duplicates = [], j = 0, i = 0; // Unless we *know* we can detect duplicates, assume their presence hasDuplicate = !support.detectDuplicates; sortInput = !support.sortStable && results.slice( 0 ); results.sort( sortOrder ); if ( hasDuplicate ) { while ( (elem = results[i++]) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } } while ( j-- ) { results.splice( duplicates[ j ], 1 ); } } // Clear input after sorting to release objects // See https://github.com/jquery/sizzle/pull/225 sortInput = null; return results; }; /** * Utility function for retrieving the text value of an array of DOM nodes * @param {Array|Element} elem */ getText = Sizzle.getText = function( elem ) { var node, ret = "", i = 0, nodeType = elem.nodeType; if ( !nodeType ) { // If no nodeType, this is expected to be an array while ( (node = elem[i++]) ) { // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } // Do not include comment or processing instruction nodes return ret; }; Expr = Sizzle.selectors = { // Can be adjusted by the user cacheLength: 50, createPseudo: markFunction, match: matchExpr, attrHandle: {}, find: {}, relative: { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }, preFilter: { "ATTR": function( match ) { match[1] = match[1].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); if ( match[2] === "~=" ) { match[3] = " " + match[3] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 4 xn-component of xn+y argument ([+-]?\d*n|) 5 sign of xn-component 6 x of xn-component 7 sign of y-component 8 y of y-component */ match[1] = match[1].toLowerCase(); if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument if ( !match[3] ) { Sizzle.error( match[0] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); // other types prohibit arguments } else if ( match[3] ) { Sizzle.error( match[0] ); } return match; }, "PSEUDO": function( match ) { var excess, unquoted = !match[6] && match[2]; if ( matchExpr["CHILD"].test( match[0] ) ) { return null; } // Accept quoted arguments as-is if ( match[3] ) { match[2] = match[4] || match[5] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && // Get excess from tokenize (recursively) (excess = tokenize( unquoted, true )) && // advance to the next closing parenthesis (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { // excess is a negative index match[0] = match[0].slice( 0, excess ); match[2] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) return match.slice( 0, 3 ); } }, filter: { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? function() { return true; } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; }, "CLASS": function( className ) { var pattern = classCache[ className + " " ]; return pattern || (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && classCache( className, function( elem ) { return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); }); }, "ATTR": function( name, operator, check ) { return function( elem ) { var result = Sizzle.attr( elem, name ); if ( result == null ) { return operator === "!="; } if ( !operator ) { return true; } result += ""; return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : operator === "*=" ? check && result.indexOf( check ) > -1 : operator === "$=" ? check && result.slice( -check.length ) === check : operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; }; }, "CHILD": function( type, what, argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; return first === 1 && last === 0 ? // Shortcut for :nth-*(n) function( elem ) { return !!elem.parentNode; } : function( elem, context, xml ) { var cache, outerCache, node, diff, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType; if ( parent ) { // :(first|last|only)-(child|of-type) if ( simple ) { while ( dir ) { node = elem; while ( (node = node[ dir ]) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { return false; } } // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } return true; } start = [ forward ? parent.firstChild : parent.lastChild ]; // non-xml :nth-child(...) stores cache data on `parent` if ( forward && useCache ) { // Seek `elem` from a previously-cached index outerCache = parent[ expando ] || (parent[ expando ] = {}); cache = outerCache[ type ] || []; nodeIndex = cache[0] === dirruns && cache[1]; diff = cache[0] === dirruns && cache[2]; node = nodeIndex && parent.childNodes[ nodeIndex ]; while ( (node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start (diff = nodeIndex = 0) || start.pop()) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { outerCache[ type ] = [ dirruns, nodeIndex, diff ]; break; } } // Use previously-cached element index if available } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { diff = cache[1]; // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) } else { // Use the same loop as above to seek `elem` from the start while ( (node = ++nodeIndex && node && node[ dir ] || (diff = nodeIndex = 0) || start.pop()) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { // Cache the index of each encountered element if ( useCache ) { (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; } if ( node === elem ) { break; } } } } // Incorporate the offset, then check against cycle size diff -= last; return diff === first || ( diff % first === 0 && diff / first >= 0 ); } }; }, "PSEUDO": function( pseudo, argument ) { // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || Sizzle.error( "unsupported pseudo: " + pseudo ); // The user may use createPseudo to indicate that // arguments are needed to create the filter function // just as Sizzle does if ( fn[ expando ] ) { return fn( argument ); } // But maintain support for old signatures if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? markFunction(function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { idx = indexOf.call( seed, matched[i] ); seed[ idx ] = !( matches[ idx ] = matched[i] ); } }) : function( elem ) { return fn( elem, 0, args ); }; } return fn; } }, pseudos: { // Potentially complex pseudos "not": markFunction(function( selector ) { // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators var input = [], results = [], matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? markFunction(function( seed, matches, context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { if ( (elem = unmatched[i]) ) { seed[i] = !(matches[i] = elem); } } }) : function( elem, context, xml ) { input[0] = elem; matcher( input, null, xml, results ); return !results.pop(); }; }), "has": markFunction(function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; }), "contains": markFunction(function( text ) { return function( elem ) { return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; }; }), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value // being equal to the identifier C, // or beginning with the identifier C immediately followed by "-". // The matching of C against the element's language value is performed case-insensitively. // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { // lang value must be a valid identifier if ( !ridentifier.test(lang || "") ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { if ( (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); return false; }; }), // Miscellaneous "target": function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, "root": function( elem ) { return elem === docElem; }, "focus": function( elem ) { return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); }, // Boolean properties "enabled": function( elem ) { return elem.disabled === false; }, "disabled": function( elem ) { return elem.disabled === true; }, "checked": function( elem ) { // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); }, "selected": function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, // Contents "empty": function( elem ) { // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) // nodeType < 6 works because attributes (2) do not appear as children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { if ( elem.nodeType < 6 ) { return false; } } return true; }, "parent": function( elem ) { return !Expr.pseudos["empty"]( elem ); }, // Element/input types "header": function( elem ) { return rheader.test( elem.nodeName ); }, "input": function( elem ) { return rinputs.test( elem.nodeName ); }, "button": function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === "button" || name === "button"; }, "text": function( elem ) { var attr; return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); }, // Position-in-collection "first": createPositionalPseudo(function() { return [ 0 ]; }), "last": createPositionalPseudo(function( matchIndexes, length ) { return [ length - 1 ]; }), "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; }), "even": createPositionalPseudo(function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "odd": createPositionalPseudo(function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; }), "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; }) } }; Expr.pseudos["nth"] = Expr.pseudos["eq"]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { Expr.pseudos[ i ] = createInputPseudo( i ); } for ( i in { submit: true, reset: true } ) { Expr.pseudos[ i ] = createButtonPseudo( i ); } // Easy API for creating new setFilters function setFilters() {} setFilters.prototype = Expr.filters = Expr.pseudos; Expr.setFilters = new setFilters(); tokenize = Sizzle.tokenize = function( selector, parseOnly ) { var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[ selector + " " ]; if ( cached ) { return parseOnly ? 0 : cached.slice( 0 ); } soFar = selector; groups = []; preFilters = Expr.preFilter; while ( soFar ) { // Comma and first run if ( !matched || (match = rcomma.exec( soFar )) ) { if ( match ) { // Don't consume trailing commas as valid soFar = soFar.slice( match[0].length ) || soFar; } groups.push( (tokens = []) ); } matched = false; // Combinators if ( (match = rcombinators.exec( soFar )) ) { matched = match.shift(); tokens.push({ value: matched, // Cast descendant combinators to space type: match[0].replace( rtrim, " " ) }); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) { matched = match.shift(); tokens.push({ value: matched, type: type, matches: match }); soFar = soFar.slice( matched.length ); } } if ( !matched ) { break; } } // Return the length of the invalid excess // if we're just parsing // Otherwise, throw an error or return tokens return parseOnly ? soFar.length : soFar ? Sizzle.error( selector ) : // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; function toSelector( tokens ) { var i = 0, len = tokens.length, selector = ""; for ( ; i < len; i++ ) { selector += tokens[i].value; } return selector; } function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, checkNonElements = base && dir === "parentNode", doneName = done++; return combinator.first ? // Check against closest ancestor/preceding element function( elem, context, xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } } } : // Check against all ancestor/preceding elements function( elem, context, xml ) { var oldCache, outerCache, newCache = [ dirruns, doneName ]; // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching if ( xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; } } } } else { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { outerCache = elem[ expando ] || (elem[ expando ] = {}); if ( (oldCache = outerCache[ dir ]) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements return (newCache[ 2 ] = oldCache[ 2 ]); } else { // Reuse newcache so results back-propagate to previous elements outerCache[ dir ] = newCache; // A match means we're done; a fail means we have to keep checking if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { return true; } } } } } }; } function elementMatcher( matchers ) { return matchers.length > 1 ? function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { if ( !matchers[i]( elem, context, xml ) ) { return false; } } return true; } : matchers[0]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { Sizzle( selector, contexts[i], results ); } return results; } function condense( unmatched, map, filter, context, xml ) { var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null; for ( ; i < len; i++ ) { if ( (elem = unmatched[i]) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { map.push( i ); } } } } return newUnmatched; } function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { if ( postFilter && !postFilter[ expando ] ) { postFilter = setMatcher( postFilter ); } if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } return markFunction(function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? condense( elems, preMap, preFilter, context, xml ) : elems, matcherOut = matcher ? // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? // ...intermediate processing is necessary [] : // ...otherwise use results directly results : matcherIn; // Find primary matches if ( matcher ) { matcher( matcherIn, matcherOut, context, xml ); } // Apply postFilter if ( postFilter ) { temp = condense( matcherOut, postMap ); postFilter( temp, [], context, xml ); // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { if ( (elem = temp[i]) ) { matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); } } } if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) ) { // Restore matcherIn since elem is not yet a final match temp.push( (matcherIn[i] = elem) ); } } postFinder( null, (matcherOut = []), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) && (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { seed[temp] = !(results[temp] = elem); } } } // Add elements to results, through postFinder if defined } else { matcherOut = condense( matcherOut === results ? matcherOut.splice( preexisting, matcherOut.length ) : matcherOut ); if ( postFinder ) { postFinder( null, results, matcherOut, xml ); } else { push.apply( results, matcherOut ); } } }); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[ tokens[0].type ], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) matchContext = addCombinator( function( elem ) { return elem === checkContext; }, implicitRelative, true ), matchAnyContext = addCombinator( function( elem ) { return indexOf.call( checkContext, elem ) > -1; }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); } ]; for ( ; i < len; i++ ) { if ( (matcher = Expr.relative[ tokens[i].type ]) ) { matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; } else { matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { if ( Expr.relative[ tokens[j].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( // If the preceding token was a descendant combinator, insert an implicit any-element `*` tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), j < len && toSelector( tokens ) ); } matchers.push( matcher ); } } return elementMatcher( matchers ); } function matcherFromGroupMatchers( elementMatchers, setMatchers ) { var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function( seed, context, xml, results, outermost ) { var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, // We must always have either seed elements or outermost context elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), // Use integer dirruns iff this is the outermost matcher dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), len = elems.length; if ( outermost ) { outermostContext = context !== document && context; } // Add elements passing elementMatchers directly to results // Keep `i` a string if there are no elements so `matchedCount` will be "00" below // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id for ( ; i !== len && (elem = elems[i]) != null; i++ ) { if ( byElement && elem ) { j = 0; while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context, xml ) ) { results.push( elem ); break; } } if ( outermost ) { dirruns = dirrunsUnique; } } // Track unmatched elements for set filters if ( bySet ) { // They will have gone through all possible matchers if ( (elem = !matcher && elem) ) { matchedCount--; } // Lengthen the array for every element, matched or not if ( seed ) { unmatched.push( elem ); } } } // Apply set filters to unmatched elements matchedCount += i; if ( bySet && i !== matchedCount ) { j = 0; while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { if ( !(unmatched[i] || setMatched[i]) ) { setMatched[i] = pop.call( results ); } } } // Discard index placeholder values to get only actual matches setMatched = condense( setMatched ); } // Add matches to results push.apply( results, setMatched ); // Seedless set matches succeeding multiple successful matchers stipulate sorting if ( outermost && !seed && setMatched.length > 0 && ( matchedCount + setMatchers.length ) > 1 ) { Sizzle.uniqueSort( results ); } } // Override manipulation of globals by nested matchers if ( outermost ) { dirruns = dirrunsUnique; outermostContext = contextBackup; } return unmatched; }; return bySet ? markFunction( superMatcher ) : superMatcher; } compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { var i, setMatchers = [], elementMatchers = [], cached = compilerCache[ selector + " " ]; if ( !cached ) { // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { cached = matcherFromTokens( match[i] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { elementMatchers.push( cached ); } } // Cache the compiled function cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); // Save selector and tokenization cached.selector = selector; } return cached; }; /** * A low-level selection function that works with Sizzle's compiled * selector functions * @param {String|Function} selector A selector or a pre-compiled * selector function built with Sizzle.compile * @param {Element} context * @param {Array} [results] * @param {Array} [seed] A set of elements to match against */ select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize( (selector = compiled.selector || selector) ); results = results || []; // Try to minimize operations if there is no seed and only one group if ( match.length === 1 ) { // Take a shortcut and set the context if the root selector is an ID tokens = match[0] = match[0].slice( 0 ); if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && support.getById && context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; if ( !context ) { return results; // Precompiled matchers will still verify ancestry, so step up a level } else if ( compiled ) { context = context.parentNode; } selector = selector.slice( tokens.shift().value.length ); } // Fetch a seed set for right-to-left matching i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; while ( i-- ) { token = tokens[i]; // Abort if we hit a combinator if ( Expr.relative[ (type = token.type) ] ) { break; } if ( (find = Expr.find[ type ]) ) { // Search, expanding context for leading sibling combinators if ( (seed = find( token.matches[0].replace( runescape, funescape ), rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context )) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); selector = seed.length && toSelector( tokens ); if ( !selector ) { push.apply( results, seed ); return results; } break; } } } } // Compile and execute a filtering function if one is not provided // Provide `match` to avoid retokenization if we modified the selector above ( compiled || compile( selector, match ) )( seed, context, !documentIsHTML, results, rsibling.test( selector ) && testContext( context.parentNode ) || context ); return results; }; // One-time assignments // Sort stability support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; // Support: Chrome<14 // Always assume duplicates if they aren't passed to the comparison function support.detectDuplicates = !!hasDuplicate; // Initialize against the default document setDocument(); // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) // Detached nodes confoundingly follow *each other* support.sortDetached = assert(function( div1 ) { // Should return 1, but returns 4 (following) return div1.compareDocumentPosition( document.createElement("div") ) & 1; }); // Support: IE<8 // Prevent attribute/property "interpolation" // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx if ( !assert(function( div ) { div.innerHTML = ""; return div.firstChild.getAttribute("href") === "#" ; }) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } }); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") if ( !support.attributes || !assert(function( div ) { div.innerHTML = ""; div.firstChild.setAttribute( "value", "" ); return div.firstChild.getAttribute( "value" ) === ""; }) ) { addHandle( "value", function( elem, name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } }); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies if ( !assert(function( div ) { return div.getAttribute("disabled") == null; }) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : (val = elem.getAttributeNode( name )) && val.specified ? val.value : null; } }); } return Sizzle; })( window ); jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.pseudos; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; var rneedsContext = jQuery.expr.match.needsContext; var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); var risSimple = /^.[^:#\[\.,]*$/; // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { /* jshint -W018 */ return !!qualifier.call( elem, i, elem ) !== not; }); } if ( qualifier.nodeType ) { return jQuery.grep( elements, function( elem ) { return ( elem === qualifier ) !== not; }); } if ( typeof qualifier === "string" ) { if ( risSimple.test( qualifier ) ) { return jQuery.filter( qualifier, elements, not ); } qualifier = jQuery.filter( qualifier, elements ); } return jQuery.grep( elements, function( elem ) { return ( indexOf.call( qualifier, elem ) >= 0 ) !== not; }); } jQuery.filter = function( expr, elems, not ) { var elem = elems[ 0 ]; if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 && elem.nodeType === 1 ? jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { return elem.nodeType === 1; })); }; jQuery.fn.extend({ find: function( selector ) { var i, len = this.length, ret = [], self = this; if ( typeof selector !== "string" ) { return this.pushStack( jQuery( selector ).filter(function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }) ); } for ( i = 0; i < len; i++ ) { jQuery.find( selector, self[ i ], ret ); } // Needed because $( selector, context ) becomes $( context ).find( selector ) ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); ret.selector = this.selector ? this.selector + " " + selector : selector; return ret; }, filter: function( selector ) { return this.pushStack( winnow(this, selector || [], false) ); }, not: function( selector ) { return this.pushStack( winnow(this, selector || [], true) ); }, is: function( selector ) { return !!winnow( this, // If this is a positional/relative selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". typeof selector === "string" && rneedsContext.test( selector ) ? jQuery( selector ) : selector || [], false ).length; } }); // Initialize a jQuery object // A central reference to the root jQuery(document) var rootjQuery, // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, init = jQuery.fn.init = function( selector, context ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { return this; } // Handle HTML strings if ( typeof selector === "string" ) { if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; // scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return typeof rootjQuery.ready !== "undefined" ? rootjQuery.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }; // Give the init function the jQuery prototype for later instantiation init.prototype = jQuery.fn; // Initialize central reference rootjQuery = jQuery( document ); var rparentsprev = /^(?:parents|prev(?:Until|All))/, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.extend({ dir: function( elem, dir, until ) { var matched = [], truncate = until !== undefined; while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) { if ( elem.nodeType === 1 ) { if ( truncate && jQuery( elem ).is( until ) ) { break; } matched.push( elem ); } } return matched; }, sibling: function( n, elem ) { var matched = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { matched.push( n ); } } return matched; } }); jQuery.fn.extend({ has: function( target ) { var targets = jQuery( target, this ), l = targets.length; return this.filter(function() { var i = 0; for ( ; i < l; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, closest: function( selectors, context ) { var cur, i = 0, l = this.length, matched = [], pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( ; i < l; i++ ) { for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { // Always skip document fragments if ( cur.nodeType < 11 && (pos ? pos.index(cur) > -1 : // Don't pass non-elements to Sizzle cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors)) ) { matched.push( cur ); break; } } } return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return indexOf.call( jQuery( elem ), this[ 0 ] ); } // Locate the position of the desired element return indexOf.call( this, // If it receives a jQuery object, the first element is used elem.jquery ? elem[ 0 ] : elem ); }, add: function( selector, context ) { return this.pushStack( jQuery.unique( jQuery.merge( this.get(), jQuery( selector, context ) ) ) ); }, addBack: function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter(selector) ); } }); function sibling( cur, dir ) { while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {} return cur; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return sibling( elem, "nextSibling" ); }, prev: function( elem ) { return sibling( elem, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return elem.contentDocument || jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var matched = jQuery.map( this, fn, until ); if ( name.slice( -5 ) !== "Until" ) { selector = until; } if ( selector && typeof selector === "string" ) { matched = jQuery.filter( selector, matched ); } if ( this.length > 1 ) { // Remove duplicates if ( !guaranteedUnique[ name ] ) { jQuery.unique( matched ); } // Reverse order for parents* and prev-derivatives if ( rparentsprev.test( name ) ) { matched.reverse(); } } return this.pushStack( matched ); }; }); var rnotwhite = (/\S+/g); // String to Object options format cache var optionsCache = {}; // Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) { var object = optionsCache[ options ] = {}; jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; }); return object; } /* * Create a callback list using the following parameters: * * options: an optional list of space-separated options that will change how * the callback list behaves or a more traditional option object * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible options: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options ); var // Last fire value (for non-forgettable lists) memory, // Flag to know if list was already fired fired, // Flag to know if list is currently firing firing, // First callback to fire (used internally by add and fireWith) firingStart, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // Actual callback list list = [], // Stack of fire calls for repeatable lists stack = !options.once && [], // Fire callbacks fire = function( data ) { memory = options.memory && data; fired = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; firing = true; for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { memory = false; // To prevent further calls using add break; } } firing = false; if ( list ) { if ( stack ) { if ( stack.length ) { fire( stack.shift() ); } } else if ( memory ) { list = []; } else { self.disable(); } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { // First, we save the current length var start = list.length; (function add( args ) { jQuery.each( args, function( _, arg ) { var type = jQuery.type( arg ); if ( type === "function" ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && type !== "string" ) { // Inspect recursively add( arg ); } }); })( arguments ); // Do we need to add the callbacks to the // current firing batch? if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away } else if ( memory ) { firingStart = start; fire( memory ); } } return this; }, // Remove a callback from the list remove: function() { if ( list ) { jQuery.each( arguments, function( _, arg ) { var index; while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { list.splice( index, 1 ); // Handle firing indexes if ( firing ) { if ( index <= firingLength ) { firingLength--; } if ( index <= firingIndex ) { firingIndex--; } } } }); } return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list empty: function() { list = []; firingLength = 0; return this; }, // Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; }, // Lock the list in its current state lock: function() { stack = undefined; if ( !memory ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { if ( list && ( !fired || stack ) ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; if ( firing ) { stack.push( args ); } else { fire( args ); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; jQuery.extend({ Deferred: function( func ) { var tuples = [ // action, add listener, listener list, final state [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], [ "notify", "progress", jQuery.Callbacks("memory") ] ], state = "pending", promise = { state: function() { return state; }, always: function() { deferred.done( arguments ).fail( arguments ); return this; }, then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred(function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer deferred[ tuple[1] ](function() { var returned = fn && fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) .progress( newDefer.notify ); } else { newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } }); }); fns = null; }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add promise[ tuple[1] ] = list.add; // Handle state if ( stateString ) { list.add(function() { // state = [ resolved | rejected ] state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ] deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); return this; }; deferred[ tuple[0] + "With" ] = list.fireWith; }); // Make the deferred a promise promise.promise( deferred ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( subordinate /* , ..., subordinateN */ ) { var i = 0, resolveValues = slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that. deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( values === progressValues ) { deferred.notifyWith( contexts, values ); } else if ( !( --remaining ) ) { deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) { if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ) .progress( updateFunc( i, progressContexts, progressValues ) ); } else { --remaining; } } } // if we're not waiting on anything, resolve the master if ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } }); // The deferred used on DOM ready var readyList; jQuery.fn.ready = function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); return this; }; jQuery.extend({ // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Abort if there are pending holds or we're already ready if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { return; } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.triggerHandler ) { jQuery( document ).triggerHandler( "ready" ); jQuery( document ).off( "ready" ); } } }); /** * The ready event handler and self cleanup method */ function completed() { document.removeEventListener( "DOMContentLoaded", completed, false ); window.removeEventListener( "load", completed, false ); jQuery.ready(); } jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); // Catch cases where $(document).ready() is called after the browser event has already occurred. // we once tried to use readyState "interactive" here, but it caused issues like the one // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout( jQuery.ready ); } else { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", completed, false ); } } return readyList.promise( obj ); }; // Kick off the DOM ready check even if the user does not jQuery.ready.promise(); // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, len = elems.length, bulk = key == null; // Sets many values if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); } // Sets one value } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } if ( bulk ) { // Bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { for ( ; i < len; i++ ) { fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); } } } return chainable ? elems : // Gets bulk ? fn.call( elems ) : len ? fn( elems[0], key ) : emptyGet; }; /** * Determines whether an object can have data */ jQuery.acceptData = function( owner ) { // Accepts only: // - Node // - Node.ELEMENT_NODE // - Node.DOCUMENT_NODE // - Object // - Any /* jshint -W018 */ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); }; function Data() { // Support: Android < 4, // Old WebKit does not have Object.preventExtensions/freeze method, // return new empty object instead with no [[set]] accessor Object.defineProperty( this.cache = {}, 0, { get: function() { return {}; } }); this.expando = jQuery.expando + Math.random(); } Data.uid = 1; Data.accepts = jQuery.acceptData; Data.prototype = { key: function( owner ) { // We can accept data for non-element nodes in modern browsers, // but we should not, see #8335. // Always return the key for a frozen object. if ( !Data.accepts( owner ) ) { return 0; } var descriptor = {}, // Check if the owner object already has a cache key unlock = owner[ this.expando ]; // If not, create one if ( !unlock ) { unlock = Data.uid++; // Secure it in a non-enumerable, non-writable property try { descriptor[ this.expando ] = { value: unlock }; Object.defineProperties( owner, descriptor ); // Support: Android < 4 // Fallback to a less secure definition } catch ( e ) { descriptor[ this.expando ] = unlock; jQuery.extend( owner, descriptor ); } } // Ensure the cache object if ( !this.cache[ unlock ] ) { this.cache[ unlock ] = {}; } return unlock; }, set: function( owner, data, value ) { var prop, // There may be an unlock assigned to this node, // if there is no entry for this "owner", create one inline // and set the unlock as though an owner entry had always existed unlock = this.key( owner ), cache = this.cache[ unlock ]; // Handle: [ owner, key, value ] args if ( typeof data === "string" ) { cache[ data ] = value; // Handle: [ owner, { properties } ] args } else { // Fresh assignments by object are shallow copied if ( jQuery.isEmptyObject( cache ) ) { jQuery.extend( this.cache[ unlock ], data ); // Otherwise, copy the properties one-by-one to the cache object } else { for ( prop in data ) { cache[ prop ] = data[ prop ]; } } } return cache; }, get: function( owner, key ) { // Either a valid cache is found, or will be created. // New caches will be created and the unlock returned, // allowing direct access to the newly created // empty data object. A valid owner object must be provided. var cache = this.cache[ this.key( owner ) ]; return key === undefined ? cache : cache[ key ]; }, access: function( owner, key, value ) { var stored; // In cases where either: // // 1. No key was specified // 2. A string key was specified, but no value provided // // Take the "read" path and allow the get method to determine // which value to return, respectively either: // // 1. The entire cache object // 2. The data stored at the key // if ( key === undefined || ((key && typeof key === "string") && value === undefined) ) { stored = this.get( owner, key ); return stored !== undefined ? stored : this.get( owner, jQuery.camelCase(key) ); } // [*]When the key is not a string, or both a key and value // are specified, set or extend (existing objects) with either: // // 1. An object of properties // 2. A key and value // this.set( owner, key, value ); // Since the "set" path can have two possible entry points // return the expected data based on which path was taken[*] return value !== undefined ? value : key; }, remove: function( owner, key ) { var i, name, camel, unlock = this.key( owner ), cache = this.cache[ unlock ]; if ( key === undefined ) { this.cache[ unlock ] = {}; } else { // Support array or space separated string of keys if ( jQuery.isArray( key ) ) { // If "name" is an array of keys... // When data is initially created, via ("key", "val") signature, // keys will be converted to camelCase. // Since there is no way to tell _how_ a key was added, remove // both plain key and camelCase key. #12786 // This will only penalize the array argument path. name = key.concat( key.map( jQuery.camelCase ) ); } else { camel = jQuery.camelCase( key ); // Try the string as a key before any manipulation if ( key in cache ) { name = [ key, camel ]; } else { // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace name = camel; name = name in cache ? [ name ] : ( name.match( rnotwhite ) || [] ); } } i = name.length; while ( i-- ) { delete cache[ name[ i ] ]; } } }, hasData: function( owner ) { return !jQuery.isEmptyObject( this.cache[ owner[ this.expando ] ] || {} ); }, discard: function( owner ) { if ( owner[ this.expando ] ) { delete this.cache[ owner[ this.expando ] ]; } } }; var data_priv = new Data(); var data_user = new Data(); /* Implementation Summary 1. Enforce API surface and semantic compatibility with 1.9.x branch 2. Improve the module's maintainability by reducing the storage paths to a single mechanism. 3. Use the same single mechanism to support "private" and "user" data. 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) 5. Avoid exposing implementation details on user objects (eg. expando properties) 6. Provide a clear path for implementation upgrade to WeakMap in 2014 */ var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /([A-Z])/g; function dataAttr( elem, key, data ) { var name; // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : // Only convert to a number if it doesn't change the string +data + "" === data ? +data : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later data_user.set( elem, key, data ); } else { data = undefined; } } return data; } jQuery.extend({ hasData: function( elem ) { return data_user.hasData( elem ) || data_priv.hasData( elem ); }, data: function( elem, name, data ) { return data_user.access( elem, name, data ); }, removeData: function( elem, name ) { data_user.remove( elem, name ); }, // TODO: Now that all calls to _data and _removeData have been replaced // with direct calls to data_priv methods, these can be deprecated. _data: function( elem, name, data ) { return data_priv.access( elem, name, data ); }, _removeData: function( elem, name ) { data_priv.remove( elem, name ); } }); jQuery.fn.extend({ data: function( key, value ) { var i, name, data, elem = this[ 0 ], attrs = elem && elem.attributes; // Gets all values if ( key === undefined ) { if ( this.length ) { data = data_user.get( elem ); if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) { i = attrs.length; while ( i-- ) { // Support: IE11+ // The attrs elements can be null (#14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.slice(5) ); dataAttr( elem, name, data[ name ] ); } } } data_priv.set( elem, "hasDataAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each(function() { data_user.set( this, key ); }); } return access( this, function( value ) { var data, camelKey = jQuery.camelCase( key ); // The calling jQuery object (element matches) is not empty // (and therefore has an element appears at this[ 0 ]) and the // `value` parameter was not undefined. An empty jQuery object // will result in `undefined` for elem = this[ 0 ] which will // throw an exception if an attempt to read a data cache is made. if ( elem && value === undefined ) { // Attempt to get data from the cache // with the key as-is data = data_user.get( elem, key ); if ( data !== undefined ) { return data; } // Attempt to get data from the cache // with the key camelized data = data_user.get( elem, camelKey ); if ( data !== undefined ) { return data; } // Attempt to "discover" the data in // HTML5 custom data-* attrs data = dataAttr( elem, camelKey, undefined ); if ( data !== undefined ) { return data; } // We tried really hard, but the data doesn't exist. return; } // Set the data... this.each(function() { // First, attempt to store a copy or reference of any // data that might've been store with a camelCased key. var data = data_user.get( this, camelKey ); // For HTML5 data-* attribute interop, we have to // store property names with dashes in a camelCase form. // This might not apply to all properties...* data_user.set( this, camelKey, value ); // *... In the case of properties that might _actually_ // have dashes, we need to also store a copy of that // unchanged property. if ( key.indexOf("-") !== -1 && data !== undefined ) { data_user.set( this, key, value ); } }); }, null, value, arguments.length > 1, null, true ); }, removeData: function( key ) { return this.each(function() { data_user.remove( this, key ); }); } }); jQuery.extend({ queue: function( elem, type, data ) { var queue; if ( elem ) { type = ( type || "fx" ) + "queue"; queue = data_priv.get( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !queue || jQuery.isArray( data ) ) { queue = data_priv.access( elem, type, jQuery.makeArray(data) ); } else { queue.push( data ); } } return queue || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks( elem, type ), next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } // clear up the last queue stop function delete hooks.stop; fn.call( elem, next, hooks ); } if ( !startLength && hooks ) { hooks.empty.fire(); } }, // not intended for public consumption - generates a queueHooks object, or returns the current one _queueHooks: function( elem, type ) { var key = type + "queueHooks"; return data_priv.get( elem, key ) || data_priv.access( elem, key, { empty: jQuery.Callbacks("once memory").add(function() { data_priv.remove( elem, [ type + "queue", key ] ); }) }); } }); jQuery.fn.extend({ queue: function( type, data ) { var setter = 2; if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } if ( arguments.length < setter ) { return jQuery.queue( this[0], type ); } return data === undefined ? this : this.each(function() { var queue = jQuery.queue( this, type, data ); // ensure a hooks for this queue jQuery._queueHooks( this, type ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, obj ) { var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } }; if ( typeof type !== "string" ) { obj = type; type = undefined; } type = type || "fx"; while ( i-- ) { tmp = data_priv.get( elements[ i ], type + "queueHooks" ); if ( tmp && tmp.empty ) { count++; tmp.empty.add( resolve ); } } resolve(); return defer.promise( obj ); } }); var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; var isHidden = function( elem, el ) { // isHidden might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); }; var rcheckableType = (/^(?:checkbox|radio)$/i); (function() { var fragment = document.createDocumentFragment(), div = fragment.appendChild( document.createElement( "div" ) ), input = document.createElement( "input" ); // #11217 - WebKit loses check when the name is after the checked attribute // Support: Windows Web Apps (WWA) // `name` and `type` need .setAttribute for WWA input.setAttribute( "type", "radio" ); input.setAttribute( "checked", "checked" ); input.setAttribute( "name", "t" ); div.appendChild( input ); // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 // old WebKit doesn't clone checked state correctly in fragments support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; // Make sure textarea (and checkbox) defaultValue is properly cloned // Support: IE9-IE11+ div.innerHTML = ""; support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; })(); var strundefined = typeof undefined; support.focusinBubbles = "onfocusin" in window; var rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; function returnTrue() { return true; } function returnFalse() { return false; } function safeActiveElement() { try { return document.activeElement; } catch ( err ) { } } /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) { var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = data_priv.get( elem ); // Don't attach events to noData or text/comment nodes (but allow plain objects) if ( !elemData ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first if ( !(events = elemData.events) ) { events = elemData.events = {}; } if ( !(eventHandle = elemData.handle) ) { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply( elem, arguments ) : undefined; }; } // Handle multiple events separated by a space types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // There *must* be a type, no attaching namespace-only handlers if ( !type ) { continue; } // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend({ type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join(".") }, handleObjIn ); // Init the event handler queue if we're the first if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } }, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = data_priv.hasData( elem ) && data_priv.get( elem ); if ( !elemData || !(events = elemData.events) ) { return; } // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector ? special.delegateType : special.bindType ) || type; handlers = events[ type ] || []; tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); // Remove matching events origCount = j = handlers.length; while ( j-- ) { handleObj = handlers[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { handlers.splice( j, 1 ); if ( handleObj.selector ) { handlers.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { delete elemData.handle; data_priv.remove( elem, "events" ); } }, trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; cur = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } ontype = type.indexOf(":") < 0 && "on" + type; // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join("."); event.namespace_re = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === (elem.ownerDocument || document) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Fire handlers on the event path i = 0; while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // jQuery handler handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && handle.apply && jQuery.acceptData( cur ) ) { event.result = handle.apply( cur, data ); if ( event.result === false ) { event.preventDefault(); } } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, dispatch: function( event ) { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event ); var i, j, ret, matched, handleObj, handlerQueue = [], args = slice.call( arguments ), handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[0] = event; event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // Determine handlers handlerQueue = jQuery.event.handlers.call( this, event, handlers ); // Run delegates first; they may want to stop propagation beneath us i = 0; while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { // Triggered event must either 1) have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) .apply( matched.elem, args ); if ( ret !== undefined ) { if ( (event.result = ret) === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; }, handlers: function( event, handlers ) { var i, matches, sel, handleObj, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; // Find delegate handlers // Black-hole SVG instance trees (#13180) // Avoid non-left-click bubbling in Firefox (#3861) if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { for ( ; cur !== this; cur = cur.parentNode || this ) { // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) if ( cur.disabled !== true || event.type !== "click" ) { matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // Don't conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; if ( matches[ sel ] === undefined ) { matches[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) >= 0 : jQuery.find( sel, this, null, [ cur ] ).length; } if ( matches[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push({ elem: cur, handlers: matches }); } } } } // Add the remaining (directly-bound) handlers if ( delegateCount < handlers.length ) { handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); } return handlerQueue; }, // Includes some event props shared by KeyEvent and MouseEvent props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split(" "), filter: function( event, original ) { // Add which for key events if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; } }, mouseHooks: { props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) { var eventDoc, doc, body, button = original.button; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; } }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // Create a writable copy of the event object and normalize some properties var i, prop, copy, type = event.type, originalEvent = event, fixHook = this.fixHooks[ type ]; if ( !fixHook ) { this.fixHooks[ type ] = fixHook = rmouseEvent.test( type ) ? this.mouseHooks : rkeyEvent.test( type ) ? this.keyHooks : {}; } copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = new jQuery.Event( originalEvent ); i = copy.length; while ( i-- ) { prop = copy[ i ]; event[ prop ] = originalEvent[ prop ]; } // Support: Cordova 2.5 (WebKit) (#13255) // All events should have a target; Cordova deviceready doesn't if ( !event.target ) { event.target = document; } // Support: Safari 6.0+, Chrome < 28 // Target should not be a text node (#504, #13143) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; }, special: { load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() { if ( this !== safeActiveElement() && this.focus ) { this.focus(); return false; } }, delegateType: "focusin" }, blur: { trigger: function() { if ( this === safeActiveElement() && this.blur ) { this.blur(); return false; } }, delegateType: "focusout" }, click: { // For checkbox, fire native event so checked state will be right trigger: function() { if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { this.click(); return false; } }, // For cross-browser consistency, don't fire native .click() on links _default: function( event ) { return jQuery.nodeName( event.target, "a" ); } }, beforeunload: { postDispatch: function( event ) { // Support: Firefox 20+ // Firefox doesn't alert if the returnValue field is not set. if ( event.result !== undefined && event.originalEvent ) { event.originalEvent.returnValue = event.result; } } } }, simulate: function( type, elem, event, bubble ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); if ( bubble ) { jQuery.event.trigger( e, null, elem ); } else { jQuery.event.dispatch.call( elem, e ); } if ( e.isDefaultPrevented() ) { event.preventDefault(); } } }; jQuery.removeEvent = function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !(this instanceof jQuery.Event) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && // Support: Android < 4.0 src.returnValue === false ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; if ( e && e.preventDefault ) { e.preventDefault(); } }, stopPropagation: function() { var e = this.originalEvent; this.isPropagationStopped = returnTrue; if ( e && e.stopPropagation ) { e.stopPropagation(); } }, stopImmediatePropagation: function() { var e = this.originalEvent; this.isImmediatePropagationStopped = returnTrue; if ( e && e.stopImmediatePropagation ) { e.stopImmediatePropagation(); } this.stopPropagation(); } }; // Create mouseenter/leave events using mouseover/out and event-time checks // Support: Chrome 15+ jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout", pointerenter: "pointerover", pointerleave: "pointerout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || (related !== target && !jQuery.contains( target, related )) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; }); // Create "bubbling" focus and blur events // Support: Firefox, Chrome, Safari if ( !support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler on the document while someone wants focusin/focusout var handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { var doc = this.ownerDocument || this, attaches = data_priv.access( doc, fix ); if ( !attaches ) { doc.addEventListener( orig, handler, true ); } data_priv.access( doc, fix, ( attaches || 0 ) + 1 ); }, teardown: function() { var doc = this.ownerDocument || this, attaches = data_priv.access( doc, fix ) - 1; if ( !attaches ) { doc.removeEventListener( orig, handler, true ); data_priv.remove( doc, fix ); } else { data_priv.access( doc, fix, attaches ); } } }; }); } jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var origFn, type; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { this.on( type, selector, data, types[ type ], one ); } return this; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return this.each( function() { jQuery.event.add( this, types, fn, data, selector ); }); }, one: function( types, selector, data, fn ) { return this.on( types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { var handleObj, type; if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each(function() { jQuery.event.remove( this, types, fn, selector ); }); }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { var elem = this[0]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } }); var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, rtagName = /<([\w:]+)/, rhtml = /<|&#?\w+;/, rnoInnerhtml = /<(?:script|style|link)/i, // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rscriptType = /^$|\/(?:java|ecma)script/i, rscriptTypeMasked = /^true\/(.*)/, rcleanScript = /^\s*\s*$/g, // We have to close these tags to support XHTML (#13200) wrapMap = { // Support: IE 9 option: [ 1, "" ], thead: [ 1, "", "
" ], col: [ 2, "", "
" ], tr: [ 2, "", "
" ], td: [ 3, "", "
" ], _default: [ 0, "", "" ] }; // Support: IE 9 wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; // Support: 1.x compatibility // Manipulating tables requires a tbody function manipulationTarget( elem, content ) { return jQuery.nodeName( elem, "table" ) && jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? elem.getElementsByTagName("tbody")[0] || elem.appendChild( elem.ownerDocument.createElement("tbody") ) : elem; } // Replace/restore the type attribute of script elements for safe DOM manipulation function disableScript( elem ) { elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type; return elem; } function restoreScript( elem ) { var match = rscriptTypeMasked.exec( elem.type ); if ( match ) { elem.type = match[ 1 ]; } else { elem.removeAttribute("type"); } return elem; } // Mark scripts as having already been evaluated function setGlobalEval( elems, refElements ) { var i = 0, l = elems.length; for ( ; i < l; i++ ) { data_priv.set( elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" ) ); } } function cloneCopyEvent( src, dest ) { var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; if ( dest.nodeType !== 1 ) { return; } // 1. Copy private data: events, handlers, etc. if ( data_priv.hasData( src ) ) { pdataOld = data_priv.access( src ); pdataCur = data_priv.set( dest, pdataOld ); events = pdataOld.events; if ( events ) { delete pdataCur.handle; pdataCur.events = {}; for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { jQuery.event.add( dest, type, events[ type ][ i ] ); } } } } // 2. Copy user data if ( data_user.hasData( src ) ) { udataOld = data_user.access( src ); udataCur = jQuery.extend( {}, udataOld ); data_user.set( dest, udataCur ); } } function getAll( context, tag ) { var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) : context.querySelectorAll ? context.querySelectorAll( tag || "*" ) : []; return tag === undefined || tag && jQuery.nodeName( context, tag ) ? jQuery.merge( [ context ], ret ) : ret; } // Support: IE >= 9 function fixInput( src, dest ) { var nodeName = dest.nodeName.toLowerCase(); // Fails to persist the checked state of a cloned checkbox or radio button. if ( nodeName === "input" && rcheckableType.test( src.type ) ) { dest.checked = src.checked; // Fails to return the selected option to the default selected state when cloning options } else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; } } jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { var i, l, srcElements, destElements, clone = elem.cloneNode( true ), inPage = jQuery.contains( elem.ownerDocument, elem ); // Support: IE >= 9 // Fix Cloning issues if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); for ( i = 0, l = srcElements.length; i < l; i++ ) { fixInput( srcElements[ i ], destElements[ i ] ); } } // Copy the events from the original to the clone if ( dataAndEvents ) { if ( deepDataAndEvents ) { srcElements = srcElements || getAll( elem ); destElements = destElements || getAll( clone ); for ( i = 0, l = srcElements.length; i < l; i++ ) { cloneCopyEvent( srcElements[ i ], destElements[ i ] ); } } else { cloneCopyEvent( elem, clone ); } } // Preserve script evaluation history destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } // Return the cloned set return clone; }, buildFragment: function( elems, context, scripts, selection ) { var elem, tmp, tag, wrap, contains, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, l = elems.length; for ( ; i < l; i++ ) { elem = elems[ i ]; if ( elem || elem === 0 ) { // Add nodes directly if ( jQuery.type( elem ) === "object" ) { // Support: QtWebKit // jQuery.merge because push.apply(_, arraylike) throws jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); // Convert non-html into a text node } else if ( !rhtml.test( elem ) ) { nodes.push( context.createTextNode( elem ) ); // Convert html into DOM nodes } else { tmp = tmp || fragment.appendChild( context.createElement("div") ); // Deserialize a standard representation tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); wrap = wrapMap[ tag ] || wrapMap._default; tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[ 2 ]; // Descend through wrappers to the right content j = wrap[ 0 ]; while ( j-- ) { tmp = tmp.lastChild; } // Support: QtWebKit // jQuery.merge because push.apply(_, arraylike) throws jQuery.merge( nodes, tmp.childNodes ); // Remember the top-level container tmp = fragment.firstChild; // Fixes #12346 // Support: Webkit, IE tmp.textContent = ""; } } } // Remove wrapper from fragment fragment.textContent = ""; i = 0; while ( (elem = nodes[ i++ ]) ) { // #4087 - If origin and destination elements are the same, and this is // that element, do not do anything if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { continue; } contains = jQuery.contains( elem.ownerDocument, elem ); // Append to fragment tmp = getAll( fragment.appendChild( elem ), "script" ); // Preserve script evaluation history if ( contains ) { setGlobalEval( tmp ); } // Capture executables if ( scripts ) { j = 0; while ( (elem = tmp[ j++ ]) ) { if ( rscriptType.test( elem.type || "" ) ) { scripts.push( elem ); } } } } return fragment; }, cleanData: function( elems ) { var data, elem, type, key, special = jQuery.event.special, i = 0; for ( ; (elem = elems[ i ]) !== undefined; i++ ) { if ( jQuery.acceptData( elem ) ) { key = elem[ data_priv.expando ]; if ( key && (data = data_priv.cache[ key ]) ) { if ( data.events ) { for ( type in data.events ) { if ( special[ type ] ) { jQuery.event.remove( elem, type ); // This is a shortcut to avoid jQuery.event.remove's overhead } else { jQuery.removeEvent( elem, type, data.handle ); } } } if ( data_priv.cache[ key ] ) { // Discard any remaining `private` data delete data_priv.cache[ key ]; } } } // Discard any remaining `user` data delete data_user.cache[ elem[ data_user.expando ] ]; } } }); jQuery.fn.extend({ text: function( value ) { return access( this, function( value ) { return value === undefined ? jQuery.text( this ) : this.empty().each(function() { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.textContent = value; } }); }, null, value, arguments.length ); }, append: function() { return this.domManip( arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.appendChild( elem ); } }); }, prepend: function() { return this.domManip( arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.insertBefore( elem, target.firstChild ); } }); }, before: function() { return this.domManip( arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } }); }, after: function() { return this.domManip( arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } }); }, remove: function( selector, keepData /* Internal Use Only */ ) { var elem, elems = selector ? jQuery.filter( selector, this ) : this, i = 0; for ( ; (elem = elems[i]) != null; i++ ) { if ( !keepData && elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem ) ); } if ( elem.parentNode ) { if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { setGlobalEval( getAll( elem, "script" ) ); } elem.parentNode.removeChild( elem ); } } return this; }, empty: function() { var elem, i = 0; for ( ; (elem = this[i]) != null; i++ ) { if ( elem.nodeType === 1 ) { // Prevent memory leaks jQuery.cleanData( getAll( elem, false ) ); // Remove any remaining nodes elem.textContent = ""; } } return this; }, clone: function( dataAndEvents, deepDataAndEvents ) { dataAndEvents = dataAndEvents == null ? false : dataAndEvents; deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; return this.map(function() { return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); }); }, html: function( value ) { return access( this, function( value ) { var elem = this[ 0 ] || {}, i = 0, l = this.length; if ( value === undefined && elem.nodeType === 1 ) { return elem.innerHTML; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1>" ); try { for ( ; i < l; i++ ) { elem = this[ i ] || {}; // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch( e ) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }, replaceWith: function() { var arg = arguments[ 0 ]; // Make the changes, replacing each context element with the new content this.domManip( arguments, function( elem ) { arg = this.parentNode; jQuery.cleanData( getAll( this ) ); if ( arg ) { arg.replaceChild( elem, this ); } }); // Force removal if there was no new content (e.g., from empty arguments) return arg && (arg.length || arg.nodeType) ? this : this.remove(); }, detach: function( selector ) { return this.remove( selector, true ); }, domManip: function( args, callback ) { // Flatten any nested arrays args = concat.apply( [], args ); var fragment, first, scripts, hasScripts, node, doc, i = 0, l = this.length, set = this, iNoClone = l - 1, value = args[ 0 ], isFunction = jQuery.isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit if ( isFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return this.each(function( index ) { var self = set.eq( index ); if ( isFunction ) { args[ 0 ] = value.call( this, index, self.html() ); } self.domManip( args, callback ); }); } if ( l ) { fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); first = fragment.firstChild; if ( fragment.childNodes.length === 1 ) { fragment = first; } if ( first ) { scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); hasScripts = scripts.length; // Use the original fragment for the last item instead of the first because it can end up // being emptied incorrectly in certain situations (#8070). for ( ; i < l; i++ ) { node = fragment; if ( i !== iNoClone ) { node = jQuery.clone( node, true, true ); // Keep references to cloned scripts for later restoration if ( hasScripts ) { // Support: QtWebKit // jQuery.merge because push.apply(_, arraylike) throws jQuery.merge( scripts, getAll( node, "script" ) ); } } callback.call( this[ i ], node, i ); } if ( hasScripts ) { doc = scripts[ scripts.length - 1 ].ownerDocument; // Reenable scripts jQuery.map( scripts, restoreScript ); // Evaluate executable scripts on first document insertion for ( i = 0; i < hasScripts; i++ ) { node = scripts[ i ]; if ( rscriptType.test( node.type || "" ) && !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { if ( node.src ) { // Optional AJAX dependency, but won't run scripts if not present if ( jQuery._evalUrl ) { jQuery._evalUrl( node.src ); } } else { jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); } } } } } } return this; } }); jQuery.each({ appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var elems, ret = [], insert = jQuery( selector ), last = insert.length - 1, i = 0; for ( ; i <= last; i++ ) { elems = i === last ? this : this.clone( true ); jQuery( insert[ i ] )[ original ]( elems ); // Support: QtWebKit // .get() because push.apply(_, arraylike) throws push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; }); var iframe, elemdisplay = {}; /** * Retrieve the actual display of a element * @param {String} name nodeName of the element * @param {Object} doc Document object */ // Called only from within defaultDisplay function actualDisplay( name, doc ) { var style, elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), // getDefaultComputedStyle might be reliably used only on attached element display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? // Use of this method is a temporary fix (more like optmization) until something better comes along, // since it was removed from specification and supported only in FF style.display : jQuery.css( elem[ 0 ], "display" ); // We don't have any data stored on the element, // so use "detach" method as fast way to get rid of the element elem.detach(); return display; } /** * Try to determine the default display value of an element * @param {String} nodeName */ function defaultDisplay( nodeName ) { var doc = document, display = elemdisplay[ nodeName ]; if ( !display ) { display = actualDisplay( nodeName, doc ); // If the simple way fails, read from inside an iframe if ( display === "none" || !display ) { // Use the already-created iframe if possible iframe = (iframe || jQuery( "