/// <inheritdoc /> public override IEnumerable <string> FormatPropertyDefinition(ConversionKernel kernel, PropertyDescriptor property) { // Return the rows for the js-doc var summary = kernel.Documentation?.GetDocumentationForProperty(property.Property); if (summary?.Summary.Length > 0) { yield return($"/** {summary.Summary} */"); } // Apply formatting for TypeScript its Array type. var type = FormatPropertyType(kernel, property); var name = property.Name; if (property.Type.IsNullable()) { name += "?"; } var statement = property.IsReadonly ? $@"readonly {name}: {type};" : $@"{name}: {type};"; yield return(statement); }
/// <inheritdoc /> public override string FormatValueForProperty(ConversionKernel kernel, PropertyDescriptor property, object value) { // What default (fallback) value is suppossed to be used? var defaultValue = GetDefaultForProperty(kernel, property); // Correct the formatting for numeric values. var numberFormat = new NumberFormatInfo { CurrencyDecimalSeparator = "." }; // Get the underlying type if the property is nullable. var type = Nullable.GetUnderlyingType(property.Type) ?? property.Type; // Date values should be parsed to a date-instance. if (type == typeof(DateTime)) { return($"!isNaN(Date.parse({kernel.ArgumentName}.{property.Name})) ? new Date({kernel.ArgumentName}.{property.Name}) : {defaultValue}"); } // Use the converter to get the formatted string value. var dataModel = kernel.Models.FirstOrDefault(x => x.FullName == type.FullName); if (!ReferenceEquals(dataModel, null)) { return($@"new {dataModel.Name}({kernel.ArgumentName}.{property.Name}) || null"); } return($"{kernel.ArgumentName}.{property.Name} || {defaultValue}"); }
/// <inheritdoc /> public override IEnumerable <ScriptConditionDescriptor> FormatStatements(ConversionKernel kernel, List <PropertyDescriptor> properties) { // Key check yield return(FormatComment(@"Check property keys", StatementType.Key)); foreach (var prop in properties) { yield return(StatementPipeline.CreateKeyCheckStatement(kernel, prop)); } // Type check yield return(new ScriptConditionDescriptor(string.Empty, StatementType.Type, false, true)); yield return(FormatComment(@"Check property type match", StatementType.Type)); foreach (var prop in properties) { yield return(StatementPipeline.CreateTypeCheckStatement(kernel, prop)); } // Instance check yield return(new ScriptConditionDescriptor(string.Empty, StatementType.Instance, false, true)); yield return(FormatComment(@"Check property class instance match", StatementType.Instance)); foreach (var prop in properties) { yield return(StatementPipeline.CreateInstanceCheckStatement(kernel, prop)); } }
public void ModelsInAssemblyTest() { using (var kernel = new ConversionKernel(_assembly)) { Assert.IsTrue(kernel.ModelCount > 0, "Expected atleast one model to be available."); Assert.IsTrue(kernel.Models.Any(x => x.Name == nameof(SchoolViewModel)), "Expected atleast one "); } }
public void FindModelWithInterfaceTest() { using (var kernel = new ConversionKernel(typeof(PersonViewModel).Assembly)) { // NameModel inherits the interface, should be true. Assert.IsTrue(kernel.Models.Any(x => x.Name == nameof(SchoolViewModel))); } }
public void CompileMinifiedTypeScriptFileTest() { var assembly = typeof(SchoolViewModel).Assembly; using (var kernel = new ConversionKernel(assembly).LoadXmlDocumentation()) { CompileTypeScript(kernel, minify: true); } }
public void CompileDefinitelyTypedFileTest() { var assembly = typeof(SchoolViewModel).Assembly; using (var kernel = new ConversionKernel(assembly).LoadXmlDocumentation()) { CompileDefinitelyTyped(kernel); } }
/// <inheritdoc /> public override string GetDefaultForProperty(ConversionKernel kernel, PropertyDescriptor property) { var type = Nullable.GetUnderlyingType(property.Type) ?? property.Type; if (type == typeof(DateTime)) { return("new Date(\"0001-01-01T00:00:00.000Z\")"); // Default date value should be 0001-01-01 } // Always return null if the given property is nullable. if (property.IsNullable) { return("null"); } // Check if a different type is supposed to be used. var csType = property.NativeType.IncludeOverride(kernel, type); // A string also inherits the IEnumerable interface, exclude. if (type.IsTypeOrInheritsOf(typeof(IEnumerable)) && type != typeof(string)) { return("[]"); } // Check the native type with certain exceptions. switch (csType) { case NativeType.Undefined: return("void 0"); case NativeType.Bool: return("false"); case NativeType.Byte: case NativeType.Decimal: case NativeType.Double: case NativeType.Float: case NativeType.Int: case NativeType.Long: case NativeType.Short: return("-1"); case NativeType.Char: case NativeType.String: return("''"); case NativeType.Enum: return("0"); default: case NativeType.Null: case NativeType.Object: return("null"); } }
public void FindModelWithAttributeTest() { using (var kernel = new ConversionKernel(_types)) { // Have the ConvertToScript attribute, should exist in queue. Assert.IsTrue(kernel.Models.Any(x => x.Name == nameof(DoNotIgnoreMe) || x.Name == nameof(IgnoreTestRoot)), $"Expected the {nameof(DoNotIgnoreMe)} and {nameof(IgnoreTestRoot)} classes to be available."); // IgnoreMe has the ignore attribute, should not exist in queue. Assert.IsTrue(kernel.Models.All(x => x.Name != nameof(IgnoreMe)), $"Expected the {nameof(IgnoreMe)} class not to be available."); } }
/// <summary> /// Compile a model for TypeScript. /// </summary> protected static void CompileTypeScript(ConversionKernel kernel, string fileName = "typescript", Func <ClassDescriptor, bool> predicate = null, bool minify = false) { var converter = kernel.CreateConverterForTypeScript(TypeScriptSpecification.TypeScript); var converted = converter.Convert(predicate); if (minify) { fileName += ".min"; } converter.WriteToFile(converted, FilePath, fileName, minify); }
public void ExcludePropertyWithAttributeTest() { using (var kernel = new ConversionKernel(_types)) { // Get the model with the properties that should use the Ignore attribute. var model = kernel.Models.SingleOrDefault(x => x.Name == nameof(DoNotIgnoreMe)); Assert.IsNotNull(model); Assert.IsTrue(model.Properties.Any(x => x.Name == nameof(DoNotIgnoreMe.ShouldExist)), $"Expected the {nameof(DoNotIgnoreMe.ShouldExist)} to be available"); Assert.IsTrue(model.Properties.All(x => x.Name != nameof(DoNotIgnoreMe.ShouldNotExist)), $"Expected the {nameof(DoNotIgnoreMe.ShouldNotExist)} to not be available"); } }
/// <inheritdoc /> public override IEnumerable <string> FormatProperty(ConversionKernel kernel, PropertyDescriptor property) { // Return the rows for the js-doc var summary = kernel.Documentation?.GetDocumentationForProperty(property.Property); if (summary?.Summary.Length > 0) { yield return($"/** {summary.Summary} */"); } // Specify the body of the property declaration. var propertySpec = FormatValueForProperty(kernel, property, property.Value); yield return($"this.{property.Name} = {propertySpec};"); }
/// <inheritdoc /> public override ScriptConditionDescriptor CreateInstanceCheckStatement(ConversionKernel kernel, PropertyDescriptor property) { var instanceCheck = $"if ({CreateDefinedStatement(kernel, property)} && !{{1}}.tryParse({kernel.ArgumentName}.{{0}})) throw new TypeError(\"{kernel.PropertyInstanceMismatch}\");"; var script = string.Empty; var scriptType = property.NativeType .IncludeOverride(kernel, property.Type) .ToJavaScriptType(); switch (scriptType) { case JavaScriptType.Undefined: case JavaScriptType.Null: case JavaScriptType.Boolean: case JavaScriptType.Number: case JavaScriptType.String: break; case JavaScriptType.Date: script = string.Format(instanceCheck, property.Name, "Date"); break; case JavaScriptType.RegExp: script = string.Format(instanceCheck, property.Name, "Regexp"); break; case JavaScriptType.Array: script = string.Format(instanceCheck, property.Name, "Array"); break; case JavaScriptType.Object: var propertyWithName = kernel.Models.FirstOrDefault(x => x.FullName == property.Type.FullName); if (!ReferenceEquals(propertyWithName, null)) { script = string.Format(instanceCheck, property.Name, propertyWithName.Name); } break; case JavaScriptType.Decimal: break; default: throw new ArgumentOutOfRangeException(); } return(new ScriptConditionDescriptor(script, StatementType.Instance)); }
public void CompileJavaScriptFileTest() { var assembly = typeof(SchoolViewModel).Assembly; using (var kernel = new ConversionKernel(assembly).LoadXmlDocumentation()) { foreach (var model in kernel.Models) { var converter = kernel.CreateConverterForJavaScript(JavaScriptVersion.V5, Wrap.SIAF); var converted = converter.Convert(x => x.Type == model.Type); var fileName = model.Name + ".model"; converter.WriteToFile(converted, FilePath, fileName); } } }
public void LoadCorrectlyTest() { var assembly = typeof(SchoolViewModel).Assembly; using (var kernel = new ConversionKernel(assembly)) { // Make sure the XML documentation is loaded var assemblyName = assembly.GetProjectName(); var xmlDocPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{assemblyName}.xml"); kernel.LoadXmlDocumentation(xmlDocPath); Assert.IsNotNull(kernel.Documentation); Assert.IsTrue(kernel.Documentation.Initialized); Assert.IsTrue(kernel.Documentation.Members.Any()); } }
/// <summary> /// Compile a model for DefinitelyTyped. /// </summary> protected static void CompileDefinitelyTyped(ConversionKernel kernel, string fileName = "reference", bool minify = false) { // Make sure the XML documentation is loaded var assemblyName = typeof(TestBase).Assembly.GetProjectName(); kernel.LoadXmlDocumentation(); var converter = kernel.CreateConverterForTypeScript(TypeScriptSpecification.Declaration); var converted = converter.Convert(); if (minify) { fileName += ".min"; } converter.WriteToFile(converted, FilePath, fileName, minify); }
public void CompileTest() { var assembly = typeof(SchoolViewModel).Assembly; using (var kernel = new ConversionKernel(assembly)) { // Make sure the XML documentation is loaded var assemblyName = assembly.GetProjectName(); var xmlDocPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{assemblyName}.xml"); kernel.LoadXmlDocumentation(xmlDocPath); // Convert the available models and look if the result is as expected. CompileJavaScript(kernel, JavaScriptVersion.V5); CompileTypeScript(kernel); CompileDefinitelyTyped(kernel); } }
/// <inheritdoc /> public override ScriptConditionDescriptor CreateTypeCheckStatement(ConversionKernel kernel, PropertyDescriptor property) { var typeCheck = $"if (typeof {kernel.ArgumentName}.{{0}} !== '{{1}}') throw new TypeError(\"{kernel.PropertyTypeMismatch}\");"; var script = string.Empty; var scriptType = property.NativeType .IncludeOverride(kernel, property.Type) .ToJavaScriptType(); switch (scriptType) { case JavaScriptType.Undefined: case JavaScriptType.Null: break; case JavaScriptType.Boolean: script = string.Format(typeCheck, property.Name, "boolean"); break; case JavaScriptType.Number: script = string.Format(typeCheck, property.Name, "number"); break; case JavaScriptType.String: script = string.Format(typeCheck, property.Name, "string"); break; case JavaScriptType.Decimal: case JavaScriptType.Date: case JavaScriptType.RegExp: case JavaScriptType.Array: case JavaScriptType.Object: script = string.Format(typeCheck, property.Name, property.Type == typeof(Guid) ? "string" : "object"); break; default: throw new ArgumentOutOfRangeException(); } return(new ScriptConditionDescriptor(script, StatementType.Type)); }
internal string FormatPropertyType(ConversionKernel kernel, PropertyDescriptor property) { var tsTypeName = GetBaseType(property.NativeType.IncludeOverride(kernel, property.Type)); var type = Nullable.GetUnderlyingType(property.Type) ?? property.Type; if (type == typeof(DateTime)) { tsTypeName = "Date"; } else { // Check if any of the available models have the same name and should be used. var dataModel = kernel.Models.FirstOrDefault(x => x.FullName == type.FullName); if (!ReferenceEquals(dataModel, null)) { tsTypeName = dataModel.Name; } } return(type.IsTypeOrInheritsOf(typeof(IEnumerable)) && type != typeof(string) ? $@"Array<{tsTypeName}>" : tsTypeName); }
public void CompileTypeScriptFileTest() { // 1: Create an instance of the ConversionKernel var assembly = typeof(SchoolViewModel).Assembly; using (var kernel = new ConversionKernel(assembly).LoadXmlDocumentation()) { // 2: Create the ModelConverter instance for the requested script-language var converter = kernel.CreateConverterForTypeScript(TypeScriptSpecification.TypeScript); // 3: Invoke the Convert method to generate the script. var converted = converter.Convert(); // Merge the generated script model(s) to one string. var contents = converter.MergeModelsToString(converted); var fileName = "typescript"; converter.WriteToFile(converted, FilePath, fileName); } }
/// <summary> /// Initialize a <see cref="ModelConverter"/> to work with ECMAScript with a specific <paramref name="version"/>. /// </summary> /// <param name="this">The <see cref="ConversionKernel"/> to use.</param> /// <param name="version">The ECMAScript <paramref name="version"/>.</param> /// <param name="wrap">If a specific <see cref="Wrap"/> should be used for the generated script model(s).</param> /// <returns></returns> public static ModelConverter CreateConverterForJavaScript(this ConversionKernel @this, JavaScriptVersion version, Wrap wrap = Wrap.None) { ILanguageSpecification language; switch (version) { case JavaScriptVersion.V6: language = new JavaScriptSpecification("JavaScript", new Version(6, 0)).UseTemplate(Resources.V6); break; case JavaScriptVersion.V5: language = new JavaScriptSpecification("JavaScript", new Version(5, 0)).UseTemplate(Resources.V5); break; default: throw Errors.LanguageNotFound(); } switch (wrap) { case Wrap.AMD: language = language.UseWrapTemplate(Resources.dependency_injection, WrapTemplateUsage.Global); break; case Wrap.SIAF: language = language.UseWrapTemplate(Resources.isolated_self_invokation, WrapTemplateUsage.Global); break; case Wrap.None: break; default: throw new ArgumentOutOfRangeException(nameof(wrap), wrap, null); } var converter = @this.CreateConverterForTemplate(language); return(converter); }
public void ModelPropertyRecognitionTest() { using (var kernel = new ConversionKernel(_assembly)) { var personModel = kernel.Models.SingleOrDefault(x => x.Name == nameof(PersonViewModel)); Assert.IsNotNull(personModel); // PersonModel has 2 properties Assert.AreEqual(2, personModel.Properties.Count); // The name property var name = personModel.Properties.SingleOrDefault(x => x.Name == nameof(PersonViewModel.Name)); Assert.IsNotNull(name); // The surname property var surname = personModel.Properties.SingleOrDefault(x => x.Name == nameof(PersonViewModel.Surname)); Assert.IsNotNull(surname); // Check their default values Assert.AreEqual("Jeroen", name.Value.ToString()); Assert.AreEqual("Vorsselman", surname.Value.ToString()); } }
/// <summary> /// Compile a model for JavaScript. /// </summary> protected static void CompileJavaScript(ConversionKernel kernel, JavaScriptVersion version, Func <ClassDescriptor, bool> predicate = null, string fileName = "ecmascript", bool minify = false, Wrap wrap = Wrap.None) { var converter = kernel.CreateConverterForJavaScript(version, wrap); var converted = converter.Convert(predicate); fileName += $".{version.ToString().ToLowerInvariant()}"; if (wrap != Wrap.None) { fileName += "." + wrap; } if (minify) { fileName += ".min"; } converter.WriteToFile(converted, FilePath, fileName, minify); }
/// <summary> /// Initialize a <see cref="ModelConverter"/> to work with TypeScript. /// </summary> /// <param name="this">The <see cref="ConversionKernel"/> to use.</param> /// <param name="specification">What <see cref="TypeScriptSpecification"/> you want to use.</param> /// <returns></returns> public static ModelConverter CreateConverterForTypeScript(this ConversionKernel @this, Enum.TypeScriptSpecification specification) { ILanguageSpecification language; switch (specification) { case Enum.TypeScriptSpecification.TypeScript: language = new TypeScriptSpecification(new Version(1, 0, 0)) .UseTemplate(Resources.template.GetString()); break; case Enum.TypeScriptSpecification.Declaration: language = new DefinitelyTypedSpecification() .UseTemplate(Resources.reference.GetString()); break; default: throw new ArgumentOutOfRangeException(nameof(specification), specification, null); } var converter = @this.CreateConverterForTemplate(language); return(converter); }
/// <summary> /// Simple fix to include the <see cref="ConversionKernel.CustomTypeHandling"/>. /// </summary> public static NativeType IncludeOverride(this NativeType @this, ConversionKernel kernel, Type type) => kernel.CustomTypeHandling.ContainsKey(type) ? kernel.CustomTypeHandling[type] : @this;
/// <inheritdoc /> public override IEnumerable <ScriptConditionDescriptor> FormatStatements(ConversionKernel kernel, List <PropertyDescriptor> properties) { yield break; }
/// <inheritdoc /> public override string GetDefaultForProperty(ConversionKernel kernel, PropertyDescriptor property) => string.Empty;
/// <inheritdoc /> public override string FormatValueForProperty(ConversionKernel kernel, PropertyDescriptor property, object value) => string.Empty;
/// <inheritdoc /> public override ScriptConditionDescriptor ArgumentUndefinedStatement(ConversionKernel kernel) { throw new System.NotImplementedException(); }
/// <inheritdoc /> public override ScriptConditionDescriptor CreateTypeCheckStatement(ConversionKernel kernel, PropertyDescriptor property) { throw new System.NotImplementedException(); }