├── Source ├── .nuget │ ├── NuGet.exe │ ├── packages.config │ ├── NuGet.Config │ └── NuGet.targets ├── Test │ ├── packages.config │ ├── App.config │ ├── Base.cs │ ├── Child.cs │ ├── Program.cs │ ├── DefaultClass.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Test.csproj ├── Cvent.SchemaToPoco.Core │ ├── Types │ │ ├── ExitCodes.cs │ │ ├── ArrayType.cs │ │ ├── AttributeType.cs │ │ └── TypeBuilderHelper.cs │ ├── packages.config │ ├── CodeToLanguage │ │ ├── CodeCompileUnitToCSharp.cs │ │ ├── CodeCompileUnitToVisualBasic.cs │ │ └── CodeCompileUnitToLanguageBase.cs │ ├── ValidationAttributes │ │ ├── MaxValueAttribute.cs │ │ └── MinValueAttribute.cs │ ├── Wrappers │ │ ├── EnumWrapper.cs │ │ ├── JsonSchemaWrapper.cs │ │ ├── ClassWrapper.cs │ │ ├── BaseWrapper.cs │ │ ├── NamespaceWrapper.cs │ │ └── PropertyWrapper.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── JsonSchemaToPocoConfiguration.cs │ ├── Util │ │ ├── TypeUtils.cs │ │ ├── IOUtils.cs │ │ ├── StringUtils.cs │ │ └── JsonSchemaUtils.cs │ ├── Cvent.SchemaToPoco.Core.csproj │ ├── JsonSchemaToPoco.cs │ ├── JsonSchemaToCodeUnit.cs │ └── JsonSchemaResolver.cs ├── Cvent.SchemaToPoco.Console │ ├── App.config │ ├── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── CommandLineSettings.cs │ ├── JsonSchemaToPocoCLExecutor.cs │ ├── Cvent.SchemaToPoco.Console.csproj │ └── Mono.Options │ │ └── Options.cs ├── Cvent.SchemaToPoco.Core.UnitTests │ ├── FunctionalTests │ │ ├── TypeTest.cs │ │ ├── TitleTest.cs │ │ ├── BaseTest.cs │ │ ├── EnumTest.cs │ │ ├── PropertyTest.cs │ │ ├── RequiredTest.cs │ │ ├── ItemTest.cs │ │ ├── MinMaxTest.cs │ │ ├── MinMaxLengthTest.cs │ │ ├── UniqueItemsTest.cs │ │ ├── DescriptionTest.cs │ │ ├── ExclusiveMinMaxTest.cs │ │ ├── MinMaxItems.cs │ │ ├── PatternTest.cs │ │ └── DefaultTest.cs │ ├── packages.config │ ├── TestUtils.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Cvent.SchemaToPoco.Core.UnitTests.csproj ├── packages │ └── repositories.config └── JsonSchemaToPoco.sln ├── Examples ├── Schemas │ ├── city.json │ ├── flag.json │ └── country.json └── Generated │ ├── com │ └── cvent │ │ └── country │ │ └── entities │ │ ├── Flag.cs │ │ └── City.cs │ └── generated │ └── Country.cs ├── .gitignore └── readme.md /Source/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codedemonuk/json-schema-to-poco/HEAD/Source/.nuget/NuGet.exe -------------------------------------------------------------------------------- /Source/.nuget/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/Test/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Types/ExitCodes.cs: -------------------------------------------------------------------------------- 1 | namespace Cvent.SchemaToPoco.Types 2 | { 3 | public enum ExitCodes 4 | { 5 | Ok = 0, 6 | AbnormalExit = 1 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Source/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Source/Test/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/Test/Base.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Test 8 | { 9 | public abstract class Base 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Source/Test/Child.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Test 8 | { 9 | public class Child : Base 10 | { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/TypeTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class TypeTest 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Types/ArrayType.cs: -------------------------------------------------------------------------------- 1 | namespace Cvent.SchemaToPoco.Core.Types 2 | { 3 | /// 4 | /// Abstraction for the different schema array types. 5 | /// 6 | public enum ArrayType 7 | { 8 | List, 9 | HashSet 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Source/packages/repositories.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Examples/Schemas/city.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "title": "City", 4 | "description": "A large town", 5 | "csharpType": "com.cvent.country.entities.City", 6 | "properties": { 7 | "population": { 8 | "type": "integer", 9 | "description": "The number of people inhabiting this city", 10 | "minimum": 100, 11 | "required": true 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Examples/Schemas/flag.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "title": "Flag", 4 | "description": "Used as the symbol or emblem of a country", 5 | "csharpType": "com.cvent.country.entities.Flag", 6 | "properties": { 7 | "colors": { 8 | "type": "array", 9 | "items": { 10 | "type": "string" 11 | }, 12 | "description": "Colors seen on the flag" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Types/AttributeType.cs: -------------------------------------------------------------------------------- 1 | namespace Cvent.SchemaToPoco.Core.Types 2 | { 3 | /// 4 | /// Determine type of annotation to generate. 5 | /// 6 | public enum AttributeType 7 | { 8 | /// 9 | /// Compatible with ASP.net WebAPI. 10 | /// 11 | SystemDefault = 1, 12 | 13 | /// 14 | /// Compatible with JSON.net deserialization. 15 | /// 16 | JsonDotNet = 2, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("Cvent.SchemaToPoco.Console")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("Cvent")] 8 | [assembly: AssemblyProduct("Cvent.SchemaToPoco.Console")] 9 | [assembly: AssemblyCopyright("Copyright © 2014 Cvent")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: ComVisible(false)] 13 | [assembly: Guid("d81b81d4-c2b9-4c31-b372-bd2c23fd7191")] 14 | [assembly: AssemblyVersion("1.2.*")] 15 | [assembly: AssemblyFileVersion("1.2.*")] 16 | -------------------------------------------------------------------------------- /Examples/Schemas/country.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "title": "Country", 4 | "description": "A nation with its own government, occupying a particular territory", 5 | "type": "object", 6 | "properties": { 7 | "flag": { 8 | "$ref": "flag.json" 9 | }, 10 | "cities": { 11 | "type": "array", 12 | "description": "A large town", 13 | "items": { 14 | "$ref": "city.json" 15 | }, 16 | "uniqueItems": true 17 | }, 18 | "population": { 19 | "type": "integer", 20 | "description": "The number of people inhabiting this country", 21 | "minimum": 1000, 22 | "required": true 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/TitleTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class TitleTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'title' : 'NewClassName', 13 | 'type' : 'object' 14 | }"; 15 | const string correctResult = @"namespace generated 16 | { 17 | using System; 18 | 19 | 20 | public class NewClassName 21 | { 22 | } 23 | }"; 24 | 25 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/Test/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using Cvent.SchemaToPoco.Core; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Schema; 6 | 7 | namespace Test 8 | { 9 | internal class Program 10 | { 11 | private static void Main(string[] args) 12 | { 13 | string json = @"{ 14 | 'fOo': [ 15 | 'User', 16 | 'Admin' 17 | ], 18 | 'str': 'asdfaasdfasdfasdf' 19 | }"; 20 | 21 | var def = JsonConvert.DeserializeObject(json); 22 | 23 | foreach(var s in def.Foo) 24 | Console.WriteLine(s); 25 | 26 | Console.WriteLine(def.Str); 27 | 28 | Console.ReadLine(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/BaseTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | /// 6 | /// Base test class with generic test cases. 7 | /// 8 | public abstract class BaseTest 9 | { 10 | /// 11 | /// Generic test to test equivalence between expected and actual C# code. 12 | /// 13 | /// Expected C# code. 14 | /// Generated C# code. 15 | public void TestBasicEquals(string expectedJson, string actualJson) 16 | { 17 | Assert.AreEqual(TestUtils.SanitizeCSharpCode(expectedJson), TestUtils.SanitizeCSharpCode(actualJson)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/CommandLineSettings.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Cvent.SchemaToPoco.Core; 3 | 4 | namespace Cvent.SchemaToPoco.Console 5 | { 6 | /// 7 | /// Command line settings. 8 | /// 9 | internal class CommandLineSettings 10 | { 11 | public CommandLineSettings() 12 | { 13 | // Meaningful defaults 14 | Config = new JsonSchemaToPocoConfiguration(); 15 | ShowHelp = false; 16 | } 17 | 18 | /// 19 | /// Configuration for JsonSchemaToPoco. 20 | /// 21 | public JsonSchemaToPocoConfiguration Config { get; set; } 22 | 23 | /// 24 | /// Show command line help. 25 | /// 26 | public bool ShowHelp { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/CodeToLanguage/CodeCompileUnitToCSharp.cs: -------------------------------------------------------------------------------- 1 | using System.CodeDom; 2 | using Microsoft.CSharp; 3 | 4 | namespace Cvent.SchemaToPoco.Core.CodeToLanguage 5 | { 6 | /// 7 | /// Compile a CodeCompileUnit to C# code. 8 | /// 9 | public class CodeCompileUnitToCSharp : CodeCompileUnitToLanguageBase 10 | { 11 | public CodeCompileUnitToCSharp(CodeCompileUnit codeCompileUnit) : base(codeCompileUnit) 12 | { 13 | } 14 | 15 | /// 16 | /// Main executor function. 17 | /// 18 | /// A string of generated C# code. 19 | public string Execute() 20 | { 21 | using (var codeProvider = new CSharpCodeProvider()) 22 | { 23 | return CodeUnitToLanguage(codeProvider); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/Test/DefaultClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Newtonsoft.Json; 8 | 9 | namespace Test 10 | { 11 | class DefaultClass 12 | { 13 | private List _foo; 14 | 15 | private string _str; 16 | 17 | public virtual List Foo 18 | { 19 | get 20 | { 21 | return _foo; 22 | } 23 | set 24 | { 25 | _foo = value; 26 | } 27 | } 28 | 29 | [Required()] 30 | [StringLength(10)] 31 | [JsonProperty(PropertyName = "str")] 32 | public virtual string Str 33 | { 34 | get { return _str; } 35 | set { _str = value; } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/CodeToLanguage/CodeCompileUnitToVisualBasic.cs: -------------------------------------------------------------------------------- 1 | using System.CodeDom; 2 | using Microsoft.VisualBasic; 3 | 4 | namespace Cvent.SchemaToPoco.Core.CodeToLanguage 5 | { 6 | /// 7 | /// Compile a CodeCompileUnit to VB.net code. 8 | /// 9 | public class CodeCompileUnitToVisualBasic : CodeCompileUnitToLanguageBase 10 | { 11 | public CodeCompileUnitToVisualBasic(CodeCompileUnit codeCompileUnit) : base(codeCompileUnit) 12 | { 13 | } 14 | 15 | /// 16 | /// Main executor function. 17 | /// 18 | /// A string of generated VB.net code. 19 | public string Execute() 20 | { 21 | using (var codeProvider = new VBCodeProvider()) 22 | { 23 | return CodeUnitToLanguage(codeProvider); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/EnumTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class EnumTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'object', 16 | 'enum' : ['one', '2two2', 'Three_ _third_'] 17 | } 18 | } 19 | }"; 20 | const string correctResult = @"namespace generated 21 | { 22 | using System; 23 | 24 | 25 | public enum Foo 26 | { 27 | 28 | One, 29 | 30 | _2two2, 31 | 32 | Three__third_, 33 | } 34 | 35 | public class DefaultClassName 36 | { 37 | } 38 | }"; 39 | 40 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/PropertyTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class PropertyTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'string' 16 | } 17 | } 18 | }"; 19 | const string correctResult = @"namespace generated 20 | { 21 | using System; 22 | 23 | 24 | public class DefaultClassName 25 | { 26 | 27 | private string _foo; 28 | 29 | public virtual string Foo 30 | { 31 | get 32 | { 33 | return _foo; 34 | } 35 | set 36 | { 37 | _foo = value; 38 | } 39 | } 40 | } 41 | }"; 42 | 43 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/ValidationAttributes/MaxValueAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Cvent.SchemaToPoco.Core.ValidationAttributes 4 | { 5 | /// 6 | /// An attribute restricting a maximum value, inclusive for an integer. 7 | /// 8 | public class MaxValueAttribute : ValidationAttribute 9 | { 10 | /// 11 | /// The maximum value. 12 | /// 13 | private readonly int _maxValue; 14 | 15 | public MaxValueAttribute(int val) 16 | { 17 | _maxValue = val; 18 | ErrorMessage = "Enter a value greater than or equal to " + _maxValue; 19 | } 20 | 21 | /// 22 | /// Check if the given integer is valid. 23 | /// 24 | /// The integer. 25 | /// True if it is valid. 26 | public override bool IsValid(object value) 27 | { 28 | return (int) value >= _maxValue; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/ValidationAttributes/MinValueAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Cvent.SchemaToPoco.Core.ValidationAttributes 4 | { 5 | /// 6 | /// An attribute restricting a minimum value, inclusive, for an integer. 7 | /// 8 | public class MinValueAttribute : ValidationAttribute 9 | { 10 | /// 11 | /// The minimum value. 12 | /// 13 | private readonly int _minValue; 14 | 15 | public MinValueAttribute(int val) 16 | { 17 | _minValue = val; 18 | ErrorMessage = "Enter a value greater than or equal to " + _minValue; 19 | } 20 | 21 | /// 22 | /// Check if the given integer is valid. 23 | /// 24 | /// The integer. 25 | /// True if it is valid. 26 | public override bool IsValid(object value) 27 | { 28 | return (int) value >= _minValue; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Examples/Generated/com/cvent/country/entities/Flag.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18444 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace com.cvent.country.entities 12 | { 13 | using System; 14 | using System.Collections.Generic; 15 | 16 | 17 | // Used as the symbol or emblem of a country 18 | public class Flag 19 | { 20 | 21 | // Colors seen on the flag 22 | private List _colors; 23 | 24 | // Colors seen on the flag 25 | public virtual List Colors 26 | { 27 | get 28 | { 29 | return _colors; 30 | } 31 | set 32 | { 33 | _colors = value; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/RequiredTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class RequiredTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'string', 16 | 'required' : true 17 | } 18 | } 19 | }"; 20 | const string correctResult = @"namespace generated 21 | { 22 | using System; 23 | using System.ComponentModel.DataAnnotations; 24 | 25 | 26 | public class DefaultClassName 27 | { 28 | 29 | private string _foo; 30 | 31 | [Required()] 32 | public virtual string Foo 33 | { 34 | get 35 | { 36 | return _foo; 37 | } 38 | set 39 | { 40 | _foo = value; 41 | } 42 | } 43 | } 44 | }"; 45 | 46 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/ItemTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class ItemTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'array', 16 | 'items' : { 17 | 'type' : 'string' 18 | } 19 | } 20 | } 21 | }"; 22 | const string correctResult = @"namespace generated 23 | { 24 | using System; 25 | using System.Collections.Generic; 26 | 27 | public class DefaultClassName 28 | { 29 | 30 | private List _foo; 31 | 32 | public virtual List Foo 33 | { 34 | get 35 | { 36 | return _foo; 37 | } 38 | set 39 | { 40 | _foo = value; 41 | } 42 | } 43 | } 44 | }"; 45 | 46 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Examples/Generated/com/cvent/country/entities/City.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18444 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace com.cvent.country.entities 12 | { 13 | using System; 14 | using Cvent.SchemaToPoco.Core.ValidationAttributes; 15 | using System.ComponentModel.DataAnnotations; 16 | 17 | 18 | // A large town 19 | public class City 20 | { 21 | 22 | // The number of people inhabiting this city 23 | private int _population; 24 | 25 | // The number of people inhabiting this city 26 | [Required()] 27 | [MinValue(100)] 28 | public virtual int Population 29 | { 30 | get 31 | { 32 | return _population; 33 | } 34 | set 35 | { 36 | _population = value; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/MinMaxTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class MinMaxTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'integer', 16 | 'minimum' : 10, 17 | 'maximum' : 15 18 | } 19 | } 20 | }"; 21 | const string correctResult = @"namespace generated 22 | { 23 | using System; 24 | using Cvent.SchemaToPoco.Core.ValidationAttributes; 25 | 26 | 27 | public class DefaultClassName 28 | { 29 | 30 | private int _foo; 31 | 32 | [MinValue(10)] 33 | [MaxValue(15)] 34 | public virtual int Foo 35 | { 36 | get 37 | { 38 | return _foo; 39 | } 40 | set 41 | { 42 | _foo = value; 43 | } 44 | } 45 | } 46 | }"; 47 | 48 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/MinMaxLengthTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class MinMaxLengthTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'string', 16 | 'maxLength' : 10, 17 | 'minLength' : 2 18 | } 19 | } 20 | }"; 21 | const string correctResult = @"namespace generated 22 | { 23 | using System; 24 | using System.ComponentModel.DataAnnotations; 25 | 26 | 27 | public class DefaultClassName 28 | { 29 | 30 | private string _foo; 31 | 32 | [StringLength(10, MinimumLength=2)] 33 | public virtual string Foo 34 | { 35 | get 36 | { 37 | return _foo; 38 | } 39 | set 40 | { 41 | _foo = value; 42 | } 43 | } 44 | } 45 | }"; 46 | 47 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/UniqueItemsTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class UniqueItemsTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'array', 16 | 'items' : { 17 | 'type' : 'string' 18 | }, 19 | 'uniqueItems' : true 20 | } 21 | } 22 | }"; 23 | const string correctResult = @"namespace generated 24 | { 25 | using System; 26 | using System.Collections.Generic; 27 | 28 | 29 | public class DefaultClassName 30 | { 31 | 32 | private HashSet _foo; 33 | 34 | public virtual HashSet Foo 35 | { 36 | get 37 | { 38 | return _foo; 39 | } 40 | set 41 | { 42 | _foo = value; 43 | } 44 | } 45 | } 46 | }"; 47 | 48 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/DescriptionTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class DescriptionTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'title' : 'NewClassName', 13 | 'type' : 'object', 14 | 'description' : 'Description for class!', 15 | 'properties' : { 16 | 'foo' : { 17 | 'type' : 'string', 18 | 'description' : 'Description for foo!' 19 | } 20 | } 21 | }"; 22 | const string correctResult = @"namespace generated 23 | { 24 | using System; 25 | 26 | 27 | // Description for class! 28 | public class NewClassName 29 | { 30 | 31 | // Description for foo! 32 | private string _foo; 33 | 34 | // Description for foo! 35 | public virtual string Foo 36 | { 37 | get 38 | { 39 | return _foo; 40 | } 41 | set 42 | { 43 | _foo = value; 44 | } 45 | } 46 | } 47 | }"; 48 | 49 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/ExclusiveMinMaxTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class ExclusiveMinMaxTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'integer', 16 | 'minimum' : 10, 17 | 'maximum' : 15, 18 | 'exclusiveMinimum' : true, 19 | 'exclusiveMaximum' : false 20 | } 21 | } 22 | }"; 23 | const string correctResult = @"namespace generated 24 | { 25 | using System; 26 | using Cvent.SchemaToPoco.Core.ValidationAttributes; 27 | 28 | 29 | public class DefaultClassName 30 | { 31 | 32 | private int _foo; 33 | 34 | [MinValue(11)] 35 | [MaxValue(15)] 36 | public virtual int Foo 37 | { 38 | get 39 | { 40 | return _foo; 41 | } 42 | set 43 | { 44 | _foo = value; 45 | } 46 | } 47 | } 48 | }"; 49 | 50 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Wrappers/EnumWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | 6 | namespace Cvent.SchemaToPoco.Core.Wrappers 7 | { 8 | /// 9 | /// Wrapper for a CodeDom enum. 10 | /// 11 | public class EnumWrapper : BaseWrapper 12 | { 13 | /// 14 | /// Name of the enum. 15 | /// 16 | private readonly string _name; 17 | 18 | public EnumWrapper(CodeTypeDeclaration cl) 19 | : base(cl) 20 | { 21 | Property.IsEnum = true; 22 | _name = Property.Name.ToString(CultureInfo.InvariantCulture); 23 | } 24 | 25 | /// 26 | /// Add a field to the enum. 27 | /// 28 | /// 29 | public void AddMember(String s) 30 | { 31 | Property.Members.Add(new CodeMemberField(_name, s)); 32 | } 33 | 34 | /// 35 | /// Add fields to the enum. 36 | /// 37 | /// 38 | public void AddMembers(List s) 39 | { 40 | foreach (string s2 in s) 41 | { 42 | AddMember(s2); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/MinMaxItems.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class MinMaxItems : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'array', 16 | 'items' : { 17 | 'type' : 'string' 18 | }, 19 | 'minItems' : 10, 20 | 'maxItems' : 20 21 | } 22 | } 23 | }"; 24 | const string correctResult = @"namespace generated 25 | { 26 | using System; 27 | using System.Collections.Generic; 28 | using System.ComponentModel.DataAnnotations; 29 | 30 | 31 | public class DefaultClassName 32 | { 33 | 34 | private List _foo; 35 | 36 | [MinLength(10)] 37 | [MaxLength(20)] 38 | public virtual List Foo 39 | { 40 | get 41 | { 42 | return _foo; 43 | } 44 | set 45 | { 46 | _foo = value; 47 | } 48 | } 49 | } 50 | }"; 51 | 52 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/PatternTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class PatternTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type' : 'string', 16 | 'description' : 'Match the regex \\\""dev\""\'[a-c] ', 17 | 'pattern' : '^\\\""dev\""\'[a-c]\\s$' 18 | } 19 | } 20 | }"; 21 | const string correctResult = @"namespace generated 22 | { 23 | using System; 24 | using System.ComponentModel.DataAnnotations; 25 | 26 | 27 | public class DefaultClassName 28 | { 29 | 30 | // Match the regex ""dev""'[a-c] 31 | private string _foo; 32 | 33 | // Match the regex ""dev""'[a-c] 34 | [RegularExpression(@""^\\\""""dev\""""\'[a-c]\s$"")] 35 | public virtual string Foo 36 | { 37 | get 38 | { 39 | return _foo; 40 | } 41 | set 42 | { 43 | _foo = value; 44 | } 45 | } 46 | } 47 | }"; 48 | 49 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/TestUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Cvent.SchemaToPoco.Core.UnitTests 5 | { 6 | /// 7 | /// Handy utilities for unit tests. 8 | /// 9 | internal static class TestUtils 10 | { 11 | /// 12 | /// Standardize the generated C# code by removing comments and whitespace. 13 | /// 14 | /// The C# code to sanitize. 15 | /// Sanitized C# code. 16 | internal static string SanitizeCSharpCode(string code) 17 | { 18 | var lines = new List(code.Split('\n')); 19 | for (int i = lines.Count - 1; i >= 0; i--) 20 | { 21 | if (lines[i].StartsWith("//")) 22 | { 23 | lines.RemoveAt(i); 24 | } 25 | } 26 | return RemoveAllWhitespace(string.Join("\n", lines)); 27 | } 28 | 29 | /// 30 | /// Remove all whitespace from a string to more easily test code. This includes newlines. 31 | /// 32 | /// The string to sanitize. 33 | /// The string with all whitespace removed. 34 | private static string RemoveAllWhitespace(string s) 35 | { 36 | return Regex.Replace(s, @"\s+", ""); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("81306c81-22a8-41ee-b2e6-c21d3e9d6e2c")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.2.*")] 39 | [assembly: AssemblyFileVersion("1.2.*")] 40 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("Cvent.SchemaToPoco.Core")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Cvent")] 12 | [assembly: AssemblyProduct("Cvent.SchemaToPoco.Core")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("68908f8a-2974-47be-a4e6-d2cf580c0b6b")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.2.*")] 39 | [assembly: AssemblyFileVersion("1.2.*")] 40 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | 8 | [assembly: AssemblyTitle("Cvent.SchemaToPoco.Core.UnitTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Cvent.SchemaToPoco.Core.UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | 25 | [assembly: Guid("94d11471-bd70-45d8-b266-d2bc5ad2a339")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [assembly: AssemblyVersion("1.0.*")] 37 | 38 | [assembly: AssemblyVersion("1.2.*")] 39 | [assembly: AssemblyFileVersion("1.2.*")] 40 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/JsonSchemaToPocoConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Cvent.SchemaToPoco.Core.Types; 3 | 4 | namespace Cvent.SchemaToPoco.Core 5 | { 6 | /// 7 | /// Configuration class for JsonSchemaToPoco. 8 | /// 9 | public class JsonSchemaToPocoConfiguration 10 | { 11 | /// 12 | /// Assign default values. 13 | /// 14 | public JsonSchemaToPocoConfiguration() 15 | { 16 | Namespace = "generated"; 17 | OutputDirectory = Directory.GetCurrentDirectory(); 18 | Verbose = false; 19 | AttributeType = AttributeType.SystemDefault; 20 | } 21 | 22 | /// 23 | /// Location of root JSON schema file. 24 | /// 25 | public string JsonSchemaFileLocation { get; set; } 26 | 27 | /// 28 | /// Namespace to set for generated files. 29 | /// 30 | public string Namespace { get; set; } 31 | 32 | /// 33 | /// Directory to output generated files. 34 | /// 35 | public string OutputDirectory { get; set; } 36 | 37 | /// 38 | /// Whether or not to just print out files in console without generating. 39 | /// 40 | public bool Verbose { get; set; } 41 | 42 | /// 43 | /// Type of validation attribute to use. 44 | /// 45 | public AttributeType AttributeType { get; set; } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Types/TypeBuilderHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Reflection.Emit; 4 | using System.Threading; 5 | using Cvent.SchemaToPoco.Core.Util; 6 | 7 | namespace Cvent.SchemaToPoco.Core.Types 8 | { 9 | /// 10 | /// Type builder to build custom Type objects. 11 | /// 12 | public class TypeBuilderHelper 13 | { 14 | /// 15 | /// The common namespace for this builder. 16 | /// 17 | private readonly string _ns; 18 | 19 | private AssemblyBuilder _ab; 20 | private ModuleBuilder _mb; 21 | 22 | public TypeBuilderHelper(string ns) 23 | { 24 | _ns = ns; 25 | Init(); 26 | } 27 | 28 | private void Init() 29 | { 30 | var name = new AssemblyName {Name = "TmpAssembly"}; 31 | _ab = Thread.GetDomain().DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); 32 | _mb = _ab.DefineDynamicModule("ModuleOne", false); 33 | } 34 | 35 | /// 36 | /// Get a custom Type object. 37 | /// 38 | /// The name of the type. 39 | /// Whether or not to include the namespace. 40 | /// A custom Type object. 41 | public Type GetCustomType(string type, bool includeNs) 42 | { 43 | type = type.SanitizeIdentifier(); 44 | return _mb.DefineType(includeNs ? _ns + "." + type : type).CreateType(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/FunctionalTests/DefaultTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Cvent.SchemaToPoco.Core.UnitTests.FunctionalTests 4 | { 5 | [TestFixture] 6 | public class DefaultTest : BaseTest 7 | { 8 | [Test] 9 | public void TestBasic() 10 | { 11 | const string schema = @"{ 12 | 'type' : 'object', 13 | 'properties' : { 14 | 'foo' : { 15 | 'type': 'string', 16 | 'default': 'hello' 17 | }, 18 | 'number' : { 19 | 'type': 'integer', 20 | 'default': 10 21 | } 22 | } 23 | }"; 24 | const string correctResult = @"namespace generated 25 | { 26 | using System; 27 | 28 | 29 | public class DefaultClassName 30 | { 31 | 32 | private string _foo; 33 | 34 | private int _number; 35 | 36 | public DefaultClassName() 37 | { 38 | _foo = ""hello""; 39 | _number = 10; 40 | } 41 | 42 | public virtual string Foo 43 | { 44 | get 45 | { 46 | return _foo; 47 | } 48 | set 49 | { 50 | _foo = value; 51 | } 52 | } 53 | 54 | public virtual int Number 55 | { 56 | get 57 | { 58 | return _number; 59 | } 60 | set 61 | { 62 | _number = value; 63 | } 64 | } 65 | } 66 | }"; 67 | 68 | TestBasicEquals(correctResult, JsonSchemaToPoco.Generate(schema)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/CodeToLanguage/CodeCompileUnitToLanguageBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.CodeDom.Compiler; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace Cvent.SchemaToPoco.Core.CodeToLanguage 8 | { 9 | /// 10 | /// Controller for converting a CodeCompileUnit to code given a code provider. 11 | /// 12 | public class CodeCompileUnitToLanguageBase 13 | { 14 | /// 15 | /// Constant represented a tab. 16 | /// 17 | private const string TAB_CHARACTER = "\t"; 18 | 19 | /// 20 | /// The abstract representation of the code. 21 | /// 22 | private readonly CodeCompileUnit _codeCompileUnit; 23 | 24 | public CodeCompileUnitToLanguageBase(CodeCompileUnit codeCompileUnit) 25 | { 26 | if (codeCompileUnit == null) 27 | { 28 | throw new ArgumentNullException("codeCompileUnit"); 29 | } 30 | _codeCompileUnit = codeCompileUnit; 31 | } 32 | 33 | /// 34 | /// Convert the abstract representation of the code to functional code given a code provider. 35 | /// 36 | /// The code provider. 37 | /// The code as a string. 38 | protected string CodeUnitToLanguage(CodeDomProvider codeProvider) 39 | { 40 | var stringBuilder = new StringBuilder(); 41 | var stringWriter = new StringWriter(stringBuilder); 42 | var writer = new IndentedTextWriter(stringWriter, TAB_CHARACTER); 43 | codeProvider.GenerateCodeFromCompileUnit(_codeCompileUnit, writer, new CodeGeneratorOptions 44 | { 45 | BlankLinesBetweenMembers = true, 46 | VerbatimOrder = false, 47 | BracingStyle = "C" 48 | }); 49 | 50 | string output = stringBuilder.ToString(); 51 | return output; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Examples/Generated/generated/Country.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18444 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace generated 12 | { 13 | using System; 14 | using com.cvent.country.entities; 15 | using generated; 16 | using System.Collections.Generic; 17 | using Cvent.SchemaToPoco.Core.ValidationAttributes; 18 | using System.ComponentModel.DataAnnotations; 19 | 20 | 21 | // A nation with its own government, occupying a particular territory 22 | public class Country 23 | { 24 | 25 | // Used as the symbol or emblem of a country 26 | private Flag _flag; 27 | 28 | // A large town 29 | private HashSet _cities; 30 | 31 | // The number of people inhabiting this country 32 | private int _population; 33 | 34 | // Used as the symbol or emblem of a country 35 | public virtual Flag Flag 36 | { 37 | get 38 | { 39 | return _flag; 40 | } 41 | set 42 | { 43 | _flag = value; 44 | } 45 | } 46 | 47 | // A large town 48 | public virtual HashSet Cities 49 | { 50 | get 51 | { 52 | return _cities; 53 | } 54 | set 55 | { 56 | _cities = value; 57 | } 58 | } 59 | 60 | // The number of people inhabiting this country 61 | [Required()] 62 | [MinValue(1000)] 63 | public virtual int Population 64 | { 65 | get 66 | { 67 | return _population; 68 | } 69 | set 70 | { 71 | _population = value; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Util/TypeUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Newtonsoft.Json.Schema; 4 | 5 | namespace Cvent.SchemaToPoco.Core.Util 6 | { 7 | //TODO 8 | public static class TypeUtils 9 | { 10 | /// 11 | /// What primitive objects map to in C#. 12 | /// 13 | private static readonly Dictionary Primitives = new Dictionary 14 | { 15 | {"String", "System.String"}, 16 | {"Float", "System.Single"}, 17 | {"Integer", "System.Int32"}, 18 | {"Boolean", "System.Boolean"}, 19 | {"Object", "System.Object"} 20 | }; 21 | 22 | /// 23 | /// Check if a type is a primitive, or can be treated like one (ie. lowercased type). 24 | /// 25 | /// The type. 26 | /// Whether or not it is a primitive type. 27 | public static bool IsPrimitive(Type t) 28 | { 29 | return t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || t == typeof(Object); 30 | } 31 | 32 | /// 33 | /// Get the primitive name of a type if it exists. 34 | /// 35 | /// The type. 36 | /// The primitive type as a string, if it exists. 37 | public static string GetPrimitiveTypeAsString(JsonSchemaType? type) 38 | { 39 | string sType = type.ToString(); 40 | return Primitives.ContainsKey(sType) ? Primitives[sType] : "System.Object"; 41 | } 42 | 43 | /// 44 | /// Get the primitive name of a type if it exists. 45 | /// 46 | /// The type. 47 | /// The primitive type, if it exists. 48 | public static string GetPrimitiveType(Type type) 49 | { 50 | string sType = type.ToString(); 51 | Console.WriteLine(sType); 52 | 53 | return Primitives.ContainsKey(sType) ? Primitives[sType] : sType; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Wrappers/JsonSchemaWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Cvent.SchemaToPoco.Core.Util; 4 | using Newtonsoft.Json.Schema; 5 | 6 | namespace Cvent.SchemaToPoco.Core.Wrappers 7 | { 8 | /// 9 | /// Wrapper for a JsonSchema. 10 | /// 11 | public class JsonSchemaWrapper 12 | { 13 | /// 14 | /// Set defaults for required fields. 15 | /// 16 | public const string DEFAULT_CLASS_NAME = "DefaultClassName"; 17 | 18 | public JsonSchemaWrapper(JsonSchema schema) 19 | { 20 | Schema = schema; 21 | 22 | // Initialize defaults 23 | ToCreate = true; 24 | Interfaces = new List(); 25 | Dependencies = new List(); 26 | 27 | // Set the schema title if it does not exist 28 | // TODO this can probably use the GetType in JsonSchemaUtils 29 | if (string.IsNullOrEmpty(Schema.Title)) 30 | { 31 | if (Schema.Items != null && Schema.Items.Count > 0 && Schema.Items[0].Title != null) 32 | { 33 | Schema.Title = Schema.Items[0].Title.SanitizeIdentifier(); 34 | } 35 | else 36 | { 37 | Schema.Title = DEFAULT_CLASS_NAME; 38 | } 39 | } 40 | } 41 | 42 | /// 43 | /// The JsonSchema. 44 | /// 45 | public JsonSchema Schema { get; set; } 46 | 47 | /// 48 | /// Namespace for this JSON schema to use. 49 | /// 50 | public string Namespace { get; set; } 51 | 52 | /// 53 | /// Whether or not this schema should be generated or just referenced. 54 | /// 55 | public bool ToCreate { get; set; } 56 | 57 | /// 58 | /// List of interfaces. 59 | /// 60 | public List Interfaces { get; set; } 61 | 62 | /// 63 | /// List of other JsonSchemaWrappers this wrapper depends on. 64 | /// 65 | public List Dependencies { get; set; } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Wrappers/ClassWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.CodeDom; 2 | 3 | namespace Cvent.SchemaToPoco.Core.Wrappers 4 | { 5 | /// 6 | /// Wrapper for a CodeDom class. 7 | /// 8 | public class ClassWrapper : BaseWrapper 9 | { 10 | public ClassWrapper(CodeTypeDeclaration cl) 11 | : base(cl) 12 | { 13 | Property.IsClass = true; 14 | } 15 | 16 | /// 17 | /// The constructor for this class. 18 | /// 19 | public CodeConstructor Constructor { get; set; } 20 | 21 | /// 22 | /// Add an interface that this class will implement. 23 | /// 24 | /// Interface name. 25 | public void AddInterface(string name) 26 | { 27 | Property.BaseTypes.Add(new CodeTypeReference(name)); 28 | } 29 | 30 | /// 31 | /// Add a default value to a property. 32 | /// 33 | /// The property name. 34 | /// The type of the property. 35 | /// The value to initialize with. 36 | public void AddDefault(string property, CodeTypeReference type, string value) 37 | { 38 | // Create constructor if doesn't already exist 39 | if (Constructor == null) 40 | { 41 | Constructor = new CodeConstructor {Attributes = MemberAttributes.Public}; 42 | Property.Members.Add(Constructor); 43 | } 44 | 45 | var reference = new CodeFieldReferenceExpression(null, property); 46 | CodeExpression exp; 47 | int n; 48 | double m; 49 | bool b; 50 | 51 | // Check for int 52 | if (int.TryParse(value, out n)) 53 | { 54 | exp = new CodePrimitiveExpression(n); 55 | } 56 | // Check for double 57 | else if (double.TryParse(value, out m)) 58 | { 59 | exp = new CodePrimitiveExpression(m); 60 | } 61 | // Check for bool 62 | else if (bool.TryParse(value, out b)) 63 | { 64 | exp = new CodePrimitiveExpression(b); 65 | } 66 | // Check for {} 67 | else if (value.Equals("{}")) 68 | { 69 | exp = new CodeObjectCreateExpression(type); 70 | } 71 | else 72 | { 73 | exp = new CodePrimitiveExpression(value); 74 | } 75 | 76 | Constructor.Statements.Add(new CodeAssignStatement(reference, exp)); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Wrappers/BaseWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | 4 | namespace Cvent.SchemaToPoco.Core.Wrappers 5 | { 6 | /// 7 | /// Generic wrapper for property-type objects ie. classes and properties. 8 | /// 9 | /// Type of the property. 10 | public abstract class BaseWrapper where T : CodeTypeMember 11 | { 12 | /// 13 | /// The property. 14 | /// 15 | private T _property; 16 | 17 | protected BaseWrapper(T member) 18 | { 19 | _property = member; 20 | } 21 | 22 | public T Property 23 | { 24 | get { return _property; } 25 | set { _property = value; } 26 | } 27 | 28 | /// 29 | /// Add comment to property. 30 | /// 31 | /// The comment. 32 | public void AddComment(string s) 33 | { 34 | _property.Comments.Add(new CodeCommentStatement(s)); 35 | } 36 | 37 | /// 38 | /// Add attribute to property. 39 | /// 40 | /// The attribute. 41 | public void AddAttribute(string name) 42 | { 43 | _property.CustomAttributes.Add(new CodeAttributeDeclaration(name)); 44 | } 45 | 46 | /// 47 | /// Add attribute to property with an argument. 48 | /// 49 | /// The attribute. 50 | /// The argument to pass in. 51 | public void AddAttribute(string name, Object arg) 52 | { 53 | _property.CustomAttributes.Add(new CodeAttributeDeclaration(name, 54 | new CodeAttributeArgument(new CodePrimitiveExpression(arg)))); 55 | } 56 | 57 | /// 58 | /// Add attribute to property with an argument. 59 | /// 60 | /// The attribute. 61 | /// The arguments to pass in. 62 | public void AddAttribute(string name, CodeAttributeArgument args) 63 | { 64 | _property.CustomAttributes.Add(new CodeAttributeDeclaration(name, args)); 65 | } 66 | 67 | /// 68 | /// Add attribute to property with a list of arguments. 69 | /// 70 | /// The attribute. 71 | /// The arguments to pass in. 72 | public void AddAttribute(string name, CodeAttributeArgument[] args) 73 | { 74 | _property.CustomAttributes.Add(new CodeAttributeDeclaration(name, args)); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Source/JsonSchemaToPoco.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{E9B2CAF5-CF94-481D-8A9E-98F325BD362A}" 5 | ProjectSection(SolutionItems) = preProject 6 | ..\readme.md = ..\readme.md 7 | EndProjectSection 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cvent.SchemaToPoco.Console", "Cvent.SchemaToPoco.Console\Cvent.SchemaToPoco.Console.csproj", "{3AEFFCC7-E21D-4699-B40E-09CB2965F328}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cvent.SchemaToPoco.Core", "Cvent.SchemaToPoco.Core\Cvent.SchemaToPoco.Core.csproj", "{B504BB29-7224-4F82-80ED-BDB344ACABEF}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cvent.SchemaToPoco.Core.UnitTests", "Cvent.SchemaToPoco.Core.UnitTests\Cvent.SchemaToPoco.Core.UnitTests.csproj", "{CD63E22C-2545-4BAB-BE8A-BD15B59BF8E0}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{28437266-1EBB-49AB-8101-5D784BC7715C}" 16 | EndProject 17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{9D427228-226A-4B26-BD09-87AE6B337A2C}" 18 | ProjectSection(SolutionItems) = preProject 19 | .nuget\NuGet.Config = .nuget\NuGet.Config 20 | .nuget\NuGet.targets = .nuget\NuGet.targets 21 | .nuget\packages.config = .nuget\packages.config 22 | EndProjectSection 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {3AEFFCC7-E21D-4699-B40E-09CB2965F328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {3AEFFCC7-E21D-4699-B40E-09CB2965F328}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {3AEFFCC7-E21D-4699-B40E-09CB2965F328}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {3AEFFCC7-E21D-4699-B40E-09CB2965F328}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {B504BB29-7224-4F82-80ED-BDB344ACABEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {B504BB29-7224-4F82-80ED-BDB344ACABEF}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {B504BB29-7224-4F82-80ED-BDB344ACABEF}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {B504BB29-7224-4F82-80ED-BDB344ACABEF}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {CD63E22C-2545-4BAB-BE8A-BD15B59BF8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {CD63E22C-2545-4BAB-BE8A-BD15B59BF8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {CD63E22C-2545-4BAB-BE8A-BD15B59BF8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {CD63E22C-2545-4BAB-BE8A-BD15B59BF8E0}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {28437266-1EBB-49AB-8101-5D784BC7715C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {28437266-1EBB-49AB-8101-5D784BC7715C}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {28437266-1EBB-49AB-8101-5D784BC7715C}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {28437266-1EBB-49AB-8101-5D784BC7715C}.Release|Any CPU.Build.0 = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Wrappers/NamespaceWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using Cvent.SchemaToPoco.Core.Util; 4 | using Newtonsoft.Json.Schema; 5 | 6 | namespace Cvent.SchemaToPoco.Core.Wrappers 7 | { 8 | /// 9 | /// Wrapper for a CodeDom namespace. 10 | /// 11 | public class NamespaceWrapper 12 | { 13 | public NamespaceWrapper(CodeNamespace ns) 14 | { 15 | Namespace = ns; 16 | AddDefaultImports(); 17 | } 18 | 19 | /// 20 | /// The namespace. 21 | /// 22 | public CodeNamespace Namespace { get; set; } 23 | 24 | /// 25 | /// Add an import to the namespace sorted. 26 | /// 27 | /// The namespace to import. 28 | public void AddImport(string import) 29 | { 30 | Namespace.Imports.Add(new CodeNamespaceImport(import)); 31 | } 32 | 33 | /// 34 | /// Add a class to the namespace. 35 | /// 36 | /// The CodeDom class to add. 37 | public void AddClass(CodeTypeDeclaration cl) 38 | { 39 | Namespace.Types.Add(cl); 40 | } 41 | 42 | /// 43 | /// Adds imports for attributes and lists. 44 | /// 45 | /// The schema to import from. 46 | public void AddImportsFromSchema(JsonSchema schema) 47 | { 48 | // Arrays 49 | if (JsonSchemaUtils.IsArray(schema)) 50 | { 51 | AddImport("System.Collections.Generic"); 52 | } 53 | 54 | // MinValue | MaxValue 55 | if (schema.Minimum != null || schema.Maximum != null) 56 | { 57 | AddImport("Cvent.SchemaToPoco.Core.ValidationAttributes"); 58 | } 59 | 60 | // Required | StringLength | MinItems | MaxItems | Pattern 61 | if ((schema.Required != null && schema.Required.Value) || schema.MaximumLength != null || 62 | schema.MinimumLength != null 63 | || schema.MinimumItems != null || schema.MaximumItems != null || schema.Pattern != null) 64 | { 65 | AddImport("System.ComponentModel.DataAnnotations"); 66 | } 67 | } 68 | 69 | /// 70 | /// Add imports for dependencies and interfaces. 71 | /// 72 | /// 73 | public void AddImportsFromWrapper(JsonSchemaWrapper wrapper) 74 | { 75 | foreach (Type i in wrapper.Interfaces) 76 | { 77 | AddImport(i.Namespace); 78 | } 79 | 80 | foreach (JsonSchemaWrapper i in wrapper.Dependencies) 81 | { 82 | AddImport(i.Namespace); 83 | } 84 | } 85 | 86 | /// 87 | /// Add default imports to the namespace. 88 | /// 89 | private void AddDefaultImports() 90 | { 91 | AddImport("System"); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Util/IOUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | 5 | namespace Cvent.SchemaToPoco.Core.Util 6 | { 7 | /// 8 | /// General IO Utilities. 9 | /// 10 | public static class IoUtils 11 | { 12 | /// 13 | /// Generate all the directories to the path if they do not exist. 14 | /// 15 | /// Absolute path to the base generated directory. 16 | /// Namespace ie. com.cvent 17 | public static void CreateDirectoryFromNamespace(string baseDir, string ns) 18 | { 19 | string nsDir = ns.Replace('.', '\\'); 20 | Directory.CreateDirectory(baseDir + @"\" + nsDir); 21 | } 22 | 23 | /// 24 | /// Write to a file. 25 | /// 26 | /// Data to write to the file. 27 | /// Path to the file. 28 | public static void GenerateFile(string data, string path) 29 | { 30 | var sw = new StreamWriter(File.Open(path, FileMode.Create)); 31 | sw.Write(data); 32 | sw.Close(); 33 | } 34 | 35 | /// 36 | /// Read data from a Uri path. 37 | /// 38 | /// The path to read from. 39 | /// The string contents of that path. 40 | public static string ReadFromPath(Uri path) 41 | { 42 | // file://, relative, and absolute paths 43 | if (path.IsFile) 44 | { 45 | return File.ReadAllText(path.AbsolutePath); 46 | } 47 | 48 | // http://, https:// 49 | if (path.ToString().StartsWith("http")) 50 | { 51 | using (var client = new WebClient()) 52 | { 53 | return client.DownloadString(path); 54 | } 55 | } 56 | 57 | throw new ArgumentException("Cannot read from the path: " + path); 58 | } 59 | 60 | /// 61 | /// Get an absolute Uri given a relative Uri. If the relative Uri is absolute, then return that. 62 | /// 63 | /// The base, or parent Uri. 64 | /// The relative Uri to combine. 65 | /// Leave the baseUri and relativeUri slashes untouched. If false, the relativeUri is guaranteed to be relative to the baseUri. 66 | /// An absolute Uri. 67 | public static Uri GetAbsoluteUri(Uri baseUri, Uri relativeUri, bool preserveSlashes = true) 68 | { 69 | if (relativeUri.IsAbsoluteUri) 70 | { 71 | return relativeUri; 72 | } 73 | 74 | if (!preserveSlashes) 75 | { 76 | if (!baseUri.ToString().EndsWith(@"\")) 77 | { 78 | baseUri = new Uri(baseUri + @"\"); 79 | } 80 | } 81 | 82 | return new Uri(baseUri, relativeUri); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Source/Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {28437266-1EBB-49AB-8101-5D784BC7715C} 8 | Exe 9 | Properties 10 | Test 11 | Test 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {b504bb29-7224-4f82-80ed-bdb344acabef} 61 | Cvent.SchemaToPoco.Core 62 | 63 | 64 | 65 | 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # MSTest test Results 20 | [Tt]est[Rr]esult*/ 21 | [Bb]uild[Ll]og.* 22 | 23 | #NUNIT 24 | *.VisualState.xml 25 | TestResult.xml 26 | 27 | # Build Results of an ATL Project 28 | [Dd]ebugPS/ 29 | [Rr]eleasePS/ 30 | dlldata.c 31 | 32 | *_i.c 33 | *_p.c 34 | *_i.h 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.tmp_proj 49 | *.log 50 | *.vspscc 51 | *.vssscc 52 | .builds 53 | *.pidb 54 | *.svclog 55 | *.scc 56 | 57 | # Chutzpah Test files 58 | _Chutzpah* 59 | 60 | # Visual C++ cache files 61 | ipch/ 62 | *.aps 63 | *.ncb 64 | *.opensdf 65 | *.sdf 66 | *.cachefile 67 | 68 | # Visual Studio profiler 69 | *.psess 70 | *.vsp 71 | *.vspx 72 | 73 | # TFS 2012 Local Workspace 74 | $tf/ 75 | 76 | # Guidance Automation Toolkit 77 | *.gpState 78 | 79 | # ReSharper is a .NET coding add-in 80 | _ReSharper*/ 81 | *.[Rr]e[Ss]harper 82 | *.DotSettings.user 83 | 84 | # JustCode is a .NET coding addin-in 85 | .JustCode 86 | 87 | # TeamCity is a build add-in 88 | _TeamCity* 89 | 90 | # DotCover is a Code Coverage Tool 91 | *.dotCover 92 | 93 | # NCrunch 94 | _NCrunch_* 95 | .*crunch*.local.xml 96 | 97 | # MightyMoose 98 | *.mm.* 99 | AutoTest.Net/ 100 | 101 | # Web workbench (sass) 102 | .sass-cache/ 103 | 104 | # Installshield output folder 105 | [Ee]xpress/ 106 | 107 | # DocProject is a documentation generator add-in 108 | DocProject/buildhelp/ 109 | DocProject/Help/*.HxT 110 | DocProject/Help/*.HxC 111 | DocProject/Help/*.hhc 112 | DocProject/Help/*.hhk 113 | DocProject/Help/*.hhp 114 | DocProject/Help/Html2 115 | DocProject/Help/html 116 | 117 | # Click-Once directory 118 | publish/ 119 | 120 | # Publish Web Output 121 | *.[Pp]ublish.xml 122 | *.azurePubxml 123 | ## TODO: Comment the next line if you want to checkin your web deploy settings but do note that will include unencrypted passwords 124 | *.pubxml 125 | 126 | # NuGet Packages Directory 127 | packages/* 128 | Source/packages/* 129 | ## TODO: If the tool you use requires repositories.config uncomment the next line 130 | !packages/repositories.config 131 | 132 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 133 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 134 | !packages/build/ 135 | 136 | # Windows Azure Build Output 137 | csx/ 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.dbproj.schemaview 152 | *.pfx 153 | *.publishsettings 154 | node_modules/ 155 | 156 | # RIA/Silverlight projects 157 | Generated_Code/ 158 | 159 | # Backup & report files from converting an old project file to a newer 160 | # Visual Studio version. Backup files are not needed, because we have git ;-) 161 | _UpgradeReport_Files/ 162 | Backup*/ 163 | UpgradeLog*.XML 164 | UpgradeLog*.htm 165 | 166 | # SQL Server files 167 | *.mdf 168 | *.ldf 169 | 170 | # Business Intelligence projects 171 | *.rdl.data 172 | *.bim.layout 173 | *.bim_*.settings 174 | 175 | # Microsoft Fakes 176 | FakesAssemblies/ 177 | 178 | Source/Schema* 179 | generated/* -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/JsonSchemaToPocoCLExecutor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using Cvent.SchemaToPoco.Core; 6 | using Cvent.SchemaToPoco.Core.Types; 7 | using Cvent.SchemaToPoco.Types; 8 | using NDesk.Options; 9 | 10 | namespace Cvent.SchemaToPoco.Console 11 | { 12 | /// 13 | /// Main executor class for the CLI. 14 | /// 15 | public class JsonSchemaToPocoCLExecutor 16 | { 17 | /// 18 | /// Main controller. 19 | /// 20 | private readonly JsonSchemaToPoco _controller; 21 | 22 | /// 23 | /// Arguments from command line, raw format. 24 | /// 25 | private OptionSet _options; 26 | 27 | /// 28 | /// Arguments from command line. 29 | /// 30 | private readonly CommandLineSettings _settings; 31 | 32 | /// 33 | /// Constructor taking in command line arguments. 34 | /// 35 | /// Command line arguments. 36 | public JsonSchemaToPocoCLExecutor(IEnumerable args) 37 | { 38 | _settings = ConfigureCommandLineOptions(args); 39 | 40 | _controller = new JsonSchemaToPoco(_settings.Config); 41 | } 42 | 43 | /// 44 | /// Configure command line options. 45 | /// 46 | /// Arguments from the command line. 47 | /// The command line options. 48 | private CommandLineSettings ConfigureCommandLineOptions(IEnumerable arguements) 49 | { 50 | var settings = new CommandLineSettings(); 51 | 52 | _options = new OptionSet 53 | { 54 | {"n=|namespace=", "Namespace contaning all of the generated classes", ns => settings.Config.Namespace = ns}, 55 | {"s=|schema=", "File path to the schema file", s => settings.Config.JsonSchemaFileLocation = s}, 56 | {"o=|output=", "Directory to save files", fn => settings.Config.OutputDirectory = fn}, 57 | { 58 | "v|verbose", "Print out files in console without generating", 59 | v => settings.Config.Verbose = !string.IsNullOrWhiteSpace(v) 60 | }, 61 | { 62 | "a=|attribute=", "Attribute type (1 - Default DataAnnotations, 2 - JSON.net compatible attributes", 63 | fn => settings.Config.AttributeType = (AttributeType) Enum.Parse(typeof(AttributeType), fn) 64 | }, 65 | {"?|help", "Show this help message", h => settings.ShowHelp = !string.IsNullOrWhiteSpace(h)} 66 | }; 67 | 68 | _options.Parse(arguements); 69 | 70 | return settings; 71 | } 72 | 73 | /// 74 | /// Main executor method. 75 | /// 76 | /// Status code. 77 | private int Execute() 78 | { 79 | if (_settings.ShowHelp) 80 | { 81 | var description = 82 | new StringBuilder("JSON schema to POCO\nhttps://github.com/cvent/json-schema-2-poco\n\n"); 83 | _options.WriteOptionDescriptions(new StringWriter(description)); 84 | System.Console.WriteLine(description.ToString()); 85 | 86 | return (int)ExitCodes.Ok; 87 | } 88 | 89 | return _controller.Execute(); 90 | } 91 | 92 | /// 93 | /// Main method. 94 | /// 95 | /// Arguments from command line. 96 | /// An exit code. 97 | public static Int32 Main(string[] args) 98 | { 99 | return new JsonSchemaToPocoCLExecutor(args).Execute(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Util/StringUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.CodeDom.Compiler; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace Cvent.SchemaToPoco.Core.Util 8 | { 9 | /// 10 | /// Common string utilities. 11 | /// 12 | public static class StringUtils 13 | { 14 | private static readonly char[] EscapeChars = 15 | { 16 | 'w', 17 | 'W', 18 | 'd', 19 | 'D', 20 | 's', 21 | 'S' 22 | }; 23 | 24 | /// 25 | /// Capitalize the first letter in a string. 26 | /// 27 | /// The string. 28 | /// A capitalized string. 29 | public static string Capitalize(this string s) 30 | { 31 | if (string.IsNullOrEmpty(s)) 32 | { 33 | return s; 34 | } 35 | 36 | char[] arr = s.ToCharArray(); 37 | arr[0] = Char.ToUpper(arr[0]); 38 | return new string(arr); 39 | } 40 | 41 | /// 42 | /// Sanitize a string for use as an identifier by capitalizing all words and removing whitespace. 43 | /// 44 | /// The string. 45 | /// A sanitized string. 46 | public static string SanitizeIdentifier(this string s) 47 | { 48 | if (string.IsNullOrEmpty(s)) 49 | { 50 | return s; 51 | } 52 | 53 | // Capitalize all words 54 | string[] arr = s.Split(null); 55 | 56 | for (int i = 0; i < arr.Length; i++) 57 | { 58 | arr[i] = Capitalize(arr[i]); 59 | } 60 | 61 | // Remove whitespace 62 | string ret = string.Join(null, arr); 63 | 64 | // Make sure it begins with a letter or underscore 65 | if (!Char.IsLetter(ret[0]) && ret[0] != '_') 66 | { 67 | ret = "_" + ret; 68 | } 69 | 70 | return ret; 71 | } 72 | 73 | /// 74 | /// Sanitize a regular expression 75 | /// 76 | /// The regex. 77 | /// Whether or not to sanitize for use as a string literal. 78 | /// A sanitized regular expression 79 | public static string SanitizeRegex(this string s, bool literal) 80 | { 81 | return literal ? ToLiteral(s, true).Replace("\"", "\"\"") : Regex.Escape(s); 82 | } 83 | 84 | /// 85 | /// Convert a string to a literal string. 86 | /// 87 | /// The string. 88 | /// Whether or not to preserve regex escape sequences. 89 | /// An escaped string. 90 | public static string ToLiteral(this string input, bool preserveEscapes) 91 | { 92 | using (var writer = new StringWriter()) 93 | { 94 | using (var provider = CodeDomProvider.CreateProvider("CSharp")) 95 | { 96 | provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null); 97 | string s = writer.ToString(); 98 | 99 | // Remove quotes from beginning and end 100 | s = s.TrimStart(new[] { '"' }).TrimEnd(new[] { '"' }); 101 | 102 | // Preserve escape sequences 103 | if (preserveEscapes) 104 | { 105 | foreach (char c in EscapeChars) 106 | { 107 | s = s.Replace(@"\\" + c, @"\" + c); 108 | } 109 | } 110 | 111 | return s; 112 | } 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Cvent.SchemaToPoco.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B504BB29-7224-4F82-80ED-BDB344ACABEF} 8 | Library 9 | Properties 10 | Cvent.SchemaToPoco.Core 11 | Cvent.SchemaToPoco.Core 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 35 | 36 | 37 | ..\packages\NLog.3.1.0.0\lib\net45\NLog.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # JSON Schema to POCO 2 | The purpose of this tool is to convert JSON schemas based on the [official JSON schema standard](http://json-schema.org/) into C# POCOs. This tool uses JSON.net as a JSON deserializer, and currently supports up to the [v3 draft](http://tools.ietf.org/html/draft-zyp-json-schema-03). 3 | 4 | Turn this JSON schema: 5 | ```json 6 | { 7 | "$schema": "http://json-schema.org/draft-03/schema#", 8 | "title": "Country", 9 | "description": "A nation with its own government, occupying a particular territory", 10 | "type": "object", 11 | "properties": { 12 | "flag": { 13 | "$ref": "flag.json" 14 | }, 15 | "cities": { 16 | "type": "array", 17 | "description": "A large town", 18 | "items": { 19 | "$ref": "city.json" 20 | }, 21 | "uniqueItems": true 22 | }, 23 | "population": { 24 | "type": "integer", 25 | "description": "The number of people inhabiting this country", 26 | "minimum": 1000, 27 | "required": true 28 | } 29 | } 30 | } 31 | ``` 32 | Into this! (with all references generated in separate files) 33 | ```csharp 34 | namespace generated 35 | { 36 | using System; 37 | using com.cvent.country.entities; 38 | using generated; 39 | using System.Collections.Generic; 40 | using Cvent.SchemaToPoco.Core.ValidationAttributes; 41 | using System.ComponentModel.DataAnnotations; 42 | 43 | // A nation with its own government, occupying a particular territory 44 | public class Country 45 | { 46 | // Used as the symbol or emblem of a country 47 | private Flag _flag; 48 | 49 | // A large town 50 | private HashSet _cities; 51 | 52 | // The number of people inhabiting this country 53 | private int _population; 54 | 55 | // Used as the symbol or emblem of a country 56 | public virtual Flag Flag 57 | { 58 | get 59 | { 60 | return _flag; 61 | } 62 | set 63 | { 64 | _flag = value; 65 | } 66 | } 67 | 68 | // A large town 69 | public virtual HashSet Cities 70 | { 71 | get 72 | { 73 | return _cities; 74 | } 75 | set 76 | { 77 | _cities = value; 78 | } 79 | } 80 | 81 | // The number of people inhabiting this country 82 | [Required()] 83 | [MinValue(1000)] 84 | public virtual int Population 85 | { 86 | get 87 | { 88 | return _population; 89 | } 90 | set 91 | { 92 | _population = value; 93 | } 94 | } 95 | } 96 | } 97 | ``` 98 | 99 | ## Usage (CLI) 100 | 101 | ### Requirements 102 | * [.NET Framework 4.5](http://www.microsoft.com/en-us/download/details.aspx?id=30653) or later 103 | 104 | ### Instructions 105 | 1. [Download the latest executable](https://github.com/cvent/json-schema-2-poco/releases/latest), build the solution in Visual Studio (Ctrl+Shift+B), or run `msbuild \Path\to\.sln`. 106 | 2. Run the following command: 107 | ``` 108 | Cvent.SchemaToPoco.Console.exe -s \Location\To\Json\Schema 109 | ``` 110 | 111 | ### Optional Flags 112 | 113 | ``` 114 | -n name.for.namespace 115 | ``` 116 | Default: `generated` 117 | 118 | ``` 119 | -o \Location\To\Generate\Files 120 | ``` 121 | Default: `\generated` 122 | 123 | ``` 124 | -v 125 | ``` 126 | Prints out generated code without generating files 127 | 128 | ## Usage (Library) 129 | 130 | [Download the latest DLL](https://github.com/cvent/json-schema-2-poco/releases), and add it to your project as a reference. 131 | 132 | ### Basic Usage 133 | 134 | ```csharp 135 | // To generate files: 136 | // The location can be a web address, an absolute path, or a relative path. 137 | var controller = new JsonSchemaToPoco("/location/to/schema"); 138 | int status = controller.Execute(); 139 | 140 | // To get the C# code as a string: 141 | string code = JsonSchemaToPoco.Generate("/location/to/schema"); 142 | ``` 143 | 144 | ## [Reference](https://github.com/cvent/json-schema-2-poco/wiki/Reference) 145 | Current version: 1.2 (Alpha) 146 | 147 | [View changelog](https://github.com/cvent/json-schema-2-poco/wiki/Changelog) 148 | 149 | ## [Troubleshooting](https://github.com/cvent/json-schema-2-poco/wiki/Troubleshooting) 150 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Util/JsonSchemaUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cvent.SchemaToPoco.Core.Types; 3 | using Newtonsoft.Json.Schema; 4 | 5 | namespace Cvent.SchemaToPoco.Core.Util 6 | { 7 | /// 8 | /// Common utilities for a JsonSchema. 9 | /// 10 | public static class JsonSchemaUtils 11 | { 12 | /// 13 | /// Default type to set to if not specified elsewhere. 14 | /// 15 | private const string DEFAULT_TYPE = "System.Object"; 16 | 17 | /// 18 | /// Check if the schema is an integer type. 19 | /// 20 | /// The JSON shema. 21 | /// True if it is an integer. 22 | public static bool IsNumber(JsonSchema schema) 23 | { 24 | return schema.Type != null && 25 | (schema.Type.Value.ToString().Equals("Integer") || schema.Type.Value.ToString().Equals("Float")); 26 | } 27 | 28 | /// 29 | /// Check if the schema is an string type. 30 | /// 31 | /// The JSON shema. 32 | /// True if it is an string. 33 | public static bool IsString(JsonSchema schema) 34 | { 35 | return schema.Type != null && schema.Type.Value.ToString().Equals("String"); 36 | } 37 | 38 | /// 39 | /// Check if the schema is an array type. 40 | /// 41 | /// The JSON shema. 42 | /// True if it is an array. 43 | public static bool IsArray(JsonSchema schema) 44 | { 45 | return schema.Type != null && schema.Type.Value.ToString().Equals("Array"); 46 | } 47 | 48 | /// 49 | /// Get the array type for the given schema. 50 | /// 51 | /// The schema. 52 | /// Thrown when given schema is not an array type. 53 | /// The array type of the schema. 54 | public static ArrayType GetArrayType(JsonSchema schema) 55 | { 56 | if (!IsArray(schema)) 57 | { 58 | throw new NotSupportedException(); 59 | } 60 | 61 | return schema.UniqueItems ? ArrayType.HashSet : ArrayType.List; 62 | } 63 | 64 | /// 65 | /// Get the type of the schema. If it is an array, get the array type. 66 | /// 67 | /// The JSON schema. 68 | /// The namespace. 69 | /// The type of the schema. 70 | public static Type GetType(JsonSchema schema, string ns = "") 71 | { 72 | string toRet = DEFAULT_TYPE; 73 | var builder = new TypeBuilderHelper(ns); 74 | 75 | // Set the type to the type if it is not an array 76 | if (!IsArray(schema)) 77 | { 78 | if (schema.Title != null) 79 | { 80 | return builder.GetCustomType(schema.Title, true); 81 | } 82 | if (schema.Type != null) 83 | { 84 | toRet = TypeUtils.GetPrimitiveTypeAsString(schema.Type); 85 | } 86 | } 87 | else 88 | { 89 | // Set the type to the title if it exists 90 | if (schema.Title != null) 91 | { 92 | return builder.GetCustomType(schema.Title, true); 93 | } 94 | if (schema.Items != null && schema.Items.Count > 0) 95 | { 96 | // Set the type to the title of the items 97 | if (schema.Items[0].Title != null) 98 | { 99 | return builder.GetCustomType(schema.Items[0].Title, true); 100 | } 101 | // Set the type to the type of the items 102 | if (schema.Items[0].Type != null) 103 | { 104 | toRet = TypeUtils.GetPrimitiveTypeAsString(schema.Items[0].Type); 105 | } 106 | } 107 | } 108 | 109 | return Type.GetType(toRet, true); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core.UnitTests/Cvent.SchemaToPoco.Core.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CD63E22C-2545-4BAB-BE8A-BD15B59BF8E0} 8 | Library 9 | Properties 10 | Cvent.SchemaToPoco.Core.UnitTests 11 | Cvent.SchemaToPoco.Core.UnitTests 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 35 | 36 | 37 | False 38 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | {3aeffcc7-e21d-4699-b40e-09cb2965f328} 73 | Cvent.SchemaToPoco.Console 74 | 75 | 76 | {B504BB29-7224-4F82-80ED-BDB344ACABEF} 77 | Cvent.SchemaToPoco.Core 78 | 79 | 80 | 81 | 82 | "..\..\..\packages\NUnit.Runners.2.6.3\tools\nunit-console.exe" $(TargetPath) 83 | 84 | 91 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/Wrappers/PropertyWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.Collections.Generic; 4 | using Cvent.SchemaToPoco.Core.Types; 5 | using Cvent.SchemaToPoco.Core.Util; 6 | using Newtonsoft.Json.Schema; 7 | 8 | namespace Cvent.SchemaToPoco.Core.Wrappers 9 | { 10 | /// 11 | /// Wrapper for an automatic property. 12 | /// 13 | internal class PropertyWrapper : BaseWrapper 14 | { 15 | public PropertyWrapper(CodeMemberProperty p) : base(p) 16 | { 17 | } 18 | 19 | /// 20 | /// Add all comments and attributes. 21 | /// 22 | /// The JsonSchema. 23 | /// Annotation type to generate. 24 | public void Populate(JsonSchema schema, AttributeType type) 25 | { 26 | // Add description 27 | if (schema.Description != null) 28 | { 29 | AddComment(schema.Description); 30 | } 31 | 32 | // Add required attribute 33 | if (schema.Required != null && schema.Required.Value) 34 | { 35 | /*switch (type) 36 | { 37 | case AttributeType.SystemDefault: 38 | AddAttribute("Required"); 39 | break; 40 | case AttributeType.JsonDotNet: 41 | AddAttribute("JsonProperty", 42 | new CodeAttributeArgument("Required", new CodeSnippetExpression("Required.Always"))); 43 | break; 44 | }*/ 45 | 46 | AddAttribute("Required"); 47 | } 48 | 49 | // Number only flags 50 | if (JsonSchemaUtils.IsNumber(schema)) 51 | { 52 | if (schema.Minimum != null) 53 | { 54 | if (schema.ExclusiveMinimum != null && schema.ExclusiveMinimum.Value) 55 | { 56 | AddAttribute("MinValue", (int) schema.Minimum.Value + 1); 57 | } 58 | else 59 | { 60 | AddAttribute("MinValue", (int) schema.Minimum.Value); 61 | } 62 | } 63 | if (schema.Maximum != null) 64 | { 65 | if (schema.ExclusiveMaximum != null && schema.ExclusiveMaximum.Value) 66 | { 67 | AddAttribute("MaxValue", (int) schema.Maximum.Value - 1); 68 | } 69 | else 70 | { 71 | AddAttribute("MaxValue", (int) schema.Maximum.Value); 72 | } 73 | } 74 | } 75 | 76 | // String only flags 77 | if (JsonSchemaUtils.IsString(schema)) 78 | { 79 | var args = new List(); 80 | bool flag = false; 81 | 82 | if (schema.MaximumLength != null) 83 | { 84 | args.Add(new CodeAttributeArgument(new CodePrimitiveExpression(schema.MaximumLength.Value))); 85 | flag = true; 86 | } 87 | 88 | if (schema.MinimumLength != null) 89 | { 90 | args.Add(new CodeAttributeArgument("MinimumLength", 91 | new CodePrimitiveExpression(schema.MinimumLength.Value))); 92 | flag = true; 93 | } 94 | 95 | if (flag) 96 | { 97 | AddAttribute("StringLength", args.ToArray()); 98 | } 99 | 100 | if (!String.IsNullOrEmpty(schema.Pattern)) 101 | { 102 | AddAttribute("RegularExpression", 103 | new CodeAttributeArgument(new CodeSnippetExpression(string.Format(@"@""{0}""", 104 | schema.Pattern.SanitizeRegex(true))))); 105 | } 106 | } 107 | 108 | // Array only flags 109 | if (JsonSchemaUtils.IsArray(schema)) 110 | { 111 | if (schema.MinimumItems != null) 112 | { 113 | AddAttribute("MinLength", schema.MinimumItems.Value); 114 | } 115 | if (schema.MaximumItems != null) 116 | { 117 | AddAttribute("MaxLength", schema.MaximumItems.Value); 118 | } 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/Cvent.SchemaToPoco.Console.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3AEFFCC7-E21D-4699-B40E-09CB2965F328} 8 | Exe 9 | Properties 10 | Cvent.SchemaToPoco.Console 11 | Cvent.SchemaToPoco.Console 12 | v4.5 13 | 512 14 | publish\ 15 | true 16 | Disk 17 | false 18 | Foreground 19 | 7 20 | Days 21 | false 22 | false 23 | true 24 | 0 25 | 1.0.0.%2a 26 | false 27 | false 28 | true 29 | 30 | 31 | AnyCPU 32 | true 33 | full 34 | false 35 | bin\Debug\ 36 | DEBUG;TRACE 37 | prompt 38 | 4 39 | 40 | 41 | AnyCPU 42 | pdbonly 43 | true 44 | bin\Release\ 45 | TRACE 46 | prompt 47 | 4 48 | 49 | 50 | 51 | ..\packages\NDesk.Options.0.2.1\lib\NDesk.Options.dll 52 | 53 | 54 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll 55 | 56 | 57 | ..\packages\NLog.3.1.0.0\lib\net45\NLog.dll 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {B504BB29-7224-4F82-80ED-BDB344ACABEF} 80 | Cvent.SchemaToPoco.Core 81 | 82 | 83 | 84 | 85 | False 86 | Microsoft .NET Framework 4.5 %28x86 and x64%29 87 | true 88 | 89 | 90 | False 91 | .NET Framework 3.5 SP1 Client Profile 92 | false 93 | 94 | 95 | False 96 | .NET Framework 3.5 SP1 97 | false 98 | 99 | 100 | 101 | 108 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/JsonSchemaToPoco.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.Collections.Generic; 4 | using Cvent.SchemaToPoco.Core.CodeToLanguage; 5 | using Cvent.SchemaToPoco.Core.Types; 6 | using Cvent.SchemaToPoco.Core.Util; 7 | using Cvent.SchemaToPoco.Core.Wrappers; 8 | using Cvent.SchemaToPoco.Types; 9 | using NLog; 10 | using NLog.Config; 11 | using NLog.Targets; 12 | 13 | namespace Cvent.SchemaToPoco.Core 14 | { 15 | /// 16 | /// Main controller. 17 | /// 18 | public class JsonSchemaToPoco 19 | { 20 | /// 21 | /// Logger. 22 | /// 23 | private Logger _log; 24 | 25 | /// 26 | /// Configuration. 27 | /// 28 | private readonly JsonSchemaToPocoConfiguration _configuration; 29 | 30 | /// 31 | /// Keeps track of the found schemas. 32 | /// 33 | private Dictionary _schemas = new Dictionary(); 34 | 35 | /// 36 | /// Initialize settings. 37 | /// 38 | public JsonSchemaToPoco(JsonSchemaToPocoConfiguration configuration) 39 | { 40 | _configuration = configuration; 41 | } 42 | 43 | /// 44 | /// Main executor method. 45 | /// 46 | /// A status code. 47 | public int Execute() 48 | { 49 | try 50 | { 51 | ConfigureLogging(); 52 | 53 | // Load schemas given a json file or directory 54 | LoadSchemas(); 55 | 56 | // Generate code 57 | Generate(); 58 | 59 | return (int)ExitCodes.Ok; 60 | } 61 | catch (Exception e) 62 | { 63 | _log.Fatal(e); 64 | return (int)ExitCodes.AbnormalExit; 65 | } 66 | } 67 | 68 | /// 69 | /// Configuring the logger. 70 | /// 71 | private void ConfigureLogging() 72 | { 73 | var coloredConsoleTarget = new ColoredConsoleTarget 74 | { 75 | Layout = "${date:format=yyyy-MM-dd} ${time:format=hh:mm:ss} [${level}] ${message}" 76 | }; 77 | var loggingRule = new LoggingRule("*", LogLevel.Debug, coloredConsoleTarget); 78 | LogManager.Configuration = new LoggingConfiguration(); 79 | LogManager.Configuration.AddTarget("Console", coloredConsoleTarget); 80 | LogManager.Configuration.LoggingRules.Add(loggingRule); 81 | LogManager.ReconfigExistingLoggers(); 82 | 83 | _log = LogManager.GetCurrentClassLogger(); 84 | } 85 | 86 | /// 87 | /// Load all the schemas from a file. 88 | /// 89 | private void LoadSchemas() 90 | { 91 | var resolver = new JsonSchemaResolver(_configuration.Namespace, !_configuration.Verbose, _configuration.OutputDirectory); 92 | _schemas = resolver.ResolveSchemas(_configuration.JsonSchemaFileLocation); 93 | } 94 | 95 | /// 96 | /// Generate C# code. 97 | /// 98 | private void Generate() 99 | { 100 | var generatedCode = GenerateHelper(); 101 | 102 | // Create directory to generate files 103 | if (!_configuration.Verbose) 104 | { 105 | IoUtils.CreateDirectoryFromNamespace(_configuration.OutputDirectory, _configuration.Namespace); 106 | } 107 | 108 | foreach (var entry in generatedCode) 109 | { 110 | if (!_configuration.Verbose) 111 | { 112 | string saveLoc = _configuration.OutputDirectory + @"\" + entry.Key.Namespace.Replace('.', '\\') + @"\" + entry.Key.Schema.Title + 113 | ".cs"; 114 | IoUtils.GenerateFile(entry.Value, saveLoc); 115 | Console.WriteLine("Wrote " + saveLoc); 116 | } 117 | else 118 | { 119 | Console.WriteLine(entry.Value); 120 | } 121 | } 122 | } 123 | 124 | /// 125 | /// Return a Dictionary containing a map of the generated JsonSchemaWrappers with the generated code as a string. 126 | /// 127 | /// A mapping of all the JSON schemas and the generated code. 128 | private Dictionary GenerateHelper() 129 | { 130 | var generatedCode = new Dictionary(); 131 | 132 | foreach (JsonSchemaWrapper s in _schemas.Values) 133 | { 134 | if (s.ToCreate) 135 | { 136 | var jsonSchemaToCodeUnit = new JsonSchemaToCodeUnit(s, s.Namespace, _configuration.AttributeType); 137 | CodeCompileUnit codeUnit = jsonSchemaToCodeUnit.Execute(); 138 | var csharpGenerator = new CodeCompileUnitToCSharp(codeUnit); 139 | 140 | generatedCode.Add(s, csharpGenerator.Execute()); 141 | } 142 | } 143 | 144 | return generatedCode; 145 | } 146 | 147 | /// 148 | /// Static method to return a Dictionary of JsonSchemaWrapper and its corresponding C# generated code. 149 | /// 150 | /// Location of JSON schema. 151 | /// A mapping of all the JSON schemas and the generated code. 152 | public static Dictionary GenerateFromFile(string schemaLoc) 153 | { 154 | var controller = new JsonSchemaToPoco( 155 | new JsonSchemaToPocoConfiguration 156 | { 157 | JsonSchemaFileLocation = schemaLoc 158 | } 159 | ); 160 | controller.LoadSchemas(); 161 | return controller.GenerateHelper(); 162 | } 163 | 164 | /// 165 | /// Static method to return generated code for a single JSON schema with no references. 166 | /// 167 | /// Configuration. 168 | /// The generated code. 169 | public static string Generate(JsonSchemaToPocoConfiguration configuration) 170 | { 171 | return Generate(configuration.JsonSchemaFileLocation, configuration.Namespace, configuration.AttributeType); 172 | } 173 | 174 | /// 175 | /// Static method to return generated code for a single JSON schema with no references. 176 | /// 177 | /// Location of schema file. 178 | /// The namespace. 179 | /// The attribute type. 180 | /// The generated code. 181 | public static string Generate(string schema, string ns = "generated", AttributeType type = AttributeType.SystemDefault) 182 | { 183 | var jsonSchemaToCodeUnit = new JsonSchemaToCodeUnit(JsonSchemaResolver.ConvertToWrapper(schema), ns, type); 184 | CodeCompileUnit codeUnit = jsonSchemaToCodeUnit.Execute(); 185 | var csharpGenerator = new CodeCompileUnitToCSharp(codeUnit); 186 | return csharpGenerator.Execute(); 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /Source/.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/JsonSchemaToCodeUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.Text.RegularExpressions; 4 | using Cvent.SchemaToPoco.Core.Types; 5 | using Cvent.SchemaToPoco.Core.Util; 6 | using Cvent.SchemaToPoco.Core.Wrappers; 7 | using Microsoft.CSharp; 8 | using Newtonsoft.Json.Linq; 9 | using Newtonsoft.Json.Schema; 10 | 11 | namespace Cvent.SchemaToPoco.Core 12 | { 13 | /// 14 | /// Model for converting a JsonSchema to a CodeCompileUnit 15 | /// 16 | public class JsonSchemaToCodeUnit 17 | { 18 | /// 19 | /// The namespace for the document. 20 | /// 21 | private readonly string _codeNamespace; 22 | 23 | /// 24 | /// The JsonSchema, for easy access. 25 | /// 26 | private readonly JsonSchema _schemaDocument; 27 | 28 | /// 29 | /// The extended JsonSchema wrapper. 30 | /// 31 | private readonly JsonSchemaWrapper _schemaWrapper; 32 | 33 | /// 34 | /// The annotation type. 35 | /// 36 | private readonly AttributeType _attributeType; 37 | 38 | public JsonSchemaToCodeUnit(JsonSchemaWrapper schema, string requestedNamespace, AttributeType attributeType) 39 | { 40 | if (schema == null || schema.Schema == null) 41 | { 42 | throw new ArgumentNullException("schema"); 43 | } 44 | 45 | _schemaWrapper = schema; 46 | _schemaDocument = schema.Schema; 47 | _codeNamespace = requestedNamespace; 48 | _attributeType = attributeType; 49 | } 50 | 51 | public JsonSchemaToCodeUnit(JsonSchemaWrapper schema) 52 | : this(schema, "", AttributeType.SystemDefault) 53 | { 54 | } 55 | 56 | /// 57 | /// Main executor function. 58 | /// 59 | /// A CodeCompileUnit. 60 | public CodeCompileUnit Execute() 61 | { 62 | var codeCompileUnit = new CodeCompileUnit(); 63 | 64 | // Set namespace 65 | var nsWrap = new NamespaceWrapper(new CodeNamespace(_codeNamespace)); 66 | 67 | // Set class 68 | var codeClass = new CodeTypeDeclaration(_schemaDocument.Title) {Attributes = MemberAttributes.Public}; 69 | var clWrap = new ClassWrapper(codeClass); 70 | 71 | // Add imports for interfaces and dependencies 72 | nsWrap.AddImportsFromWrapper(_schemaWrapper); 73 | 74 | // Add comments and attributes for class 75 | if (!String.IsNullOrEmpty(_schemaDocument.Description)) 76 | { 77 | clWrap.AddComment(_schemaDocument.Description); 78 | } 79 | 80 | // Add extended class 81 | if (_schemaDocument.Extends != null && _schemaDocument.Extends.Count > 0) 82 | { 83 | clWrap.AddInterface(JsonSchemaUtils.GetType(_schemaDocument.Extends[0], _codeNamespace).Name); 84 | } 85 | 86 | // Add interfaces 87 | foreach (Type t in _schemaWrapper.Interfaces) 88 | { 89 | clWrap.AddInterface(t.Name); 90 | } 91 | 92 | // Add properties with getters/setters 93 | if (_schemaDocument.Properties != null) 94 | { 95 | foreach (var i in _schemaDocument.Properties) 96 | { 97 | JsonSchema schema = i.Value; 98 | 99 | // Sanitize inputs 100 | if (!String.IsNullOrEmpty(schema.Description)) 101 | { 102 | schema.Description = Regex.Unescape(schema.Description); 103 | } 104 | 105 | // If it is an enum 106 | if (schema.Enum != null) 107 | { 108 | string name = i.Key.Capitalize(); 109 | var enumField = new CodeTypeDeclaration(name); 110 | var enumWrap = new EnumWrapper(enumField); 111 | 112 | // Add comment if not null 113 | if (!String.IsNullOrEmpty(schema.Description)) 114 | { 115 | enumField.Comments.Add(new CodeCommentStatement(schema.Description)); 116 | } 117 | 118 | foreach (JToken j in schema.Enum) 119 | { 120 | enumWrap.AddMember(j.ToString().SanitizeIdentifier()); 121 | } 122 | 123 | // Add to namespace 124 | nsWrap.AddClass(enumWrap.Property); 125 | } 126 | else 127 | { 128 | // WARNING: This assumes the namespace of the property is the same as the parent. 129 | // This should not be a problem since imports are handled for all dependencies at the beginning. 130 | Type type = JsonSchemaUtils.GetType(schema, _codeNamespace); 131 | bool isCustomType = type.Namespace != null && type.Namespace.Equals(_codeNamespace); 132 | string strType = String.Empty; 133 | 134 | // Add imports 135 | nsWrap.AddImport(type.Namespace); 136 | nsWrap.AddImportsFromSchema(schema); 137 | 138 | // Get the property type 139 | if (isCustomType) 140 | { 141 | strType = JsonSchemaUtils.IsArray(schema) ? string.Format("{0}<{1}>", JsonSchemaUtils.GetArrayType(schema), type.Name) : type.Name; 142 | } 143 | else if (JsonSchemaUtils.IsArray(schema)) 144 | { 145 | strType = string.Format("{0}<{1}>", JsonSchemaUtils.GetArrayType(schema), 146 | new CSharpCodeProvider().GetTypeOutput(new CodeTypeReference(type))); 147 | } 148 | 149 | var field = new CodeMemberField 150 | { 151 | Attributes = MemberAttributes.Private, 152 | Name = "_" + i.Key, 153 | Type = 154 | TypeUtils.IsPrimitive(type) && !JsonSchemaUtils.IsArray(schema) 155 | ? new CodeTypeReference(type) 156 | : new CodeTypeReference(strType) 157 | }; 158 | 159 | // Add comment if not null 160 | if (!String.IsNullOrEmpty(schema.Description)) 161 | { 162 | field.Comments.Add(new CodeCommentStatement(schema.Description)); 163 | } 164 | 165 | clWrap.Property.Members.Add(field); 166 | 167 | // Add setters/getters 168 | CodeMemberProperty property = CreateProperty("_" + i.Key, 169 | i.Key.Capitalize(), field.Type.BaseType); 170 | var prWrap = new PropertyWrapper(property); 171 | 172 | // Add comments and attributes 173 | prWrap.Populate(schema, _attributeType); 174 | 175 | // Add default, if any 176 | if (schema.Default != null) 177 | { 178 | clWrap.AddDefault(field.Name, field.Type, schema.Default.ToString()); 179 | } 180 | 181 | clWrap.Property.Members.Add(property); 182 | } 183 | } 184 | } 185 | 186 | // Add class to namespace 187 | nsWrap.AddClass(clWrap.Property); 188 | codeCompileUnit.Namespaces.Add(nsWrap.Namespace); 189 | 190 | return codeCompileUnit; 191 | } 192 | 193 | /// 194 | /// Creates a public property with getters and setters that wrap the 195 | /// specified field. 196 | /// 197 | /// The field to get and set. 198 | /// The name of the property. 199 | /// The type of the property. 200 | /// The property. 201 | public static CodeMemberProperty CreateProperty(string field, string name, string type) 202 | { 203 | var property = new CodeMemberProperty 204 | { 205 | Name = name, 206 | Type = new CodeTypeReference(type), 207 | Attributes = MemberAttributes.Public 208 | }; 209 | 210 | property.SetStatements.Add( 211 | new CodeAssignStatement( 212 | new CodeFieldReferenceExpression(null, field), 213 | new CodePropertySetValueReferenceExpression())); 214 | 215 | property.GetStatements.Add( 216 | new CodeMethodReturnStatement( 217 | new CodeFieldReferenceExpression(null, field))); 218 | 219 | return property; 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Core/JsonSchemaResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text.RegularExpressions; 5 | using Cvent.SchemaToPoco.Core.Types; 6 | using Cvent.SchemaToPoco.Core.Util; 7 | using Cvent.SchemaToPoco.Core.Wrappers; 8 | using Newtonsoft.Json; 9 | using Newtonsoft.Json.Linq; 10 | using Newtonsoft.Json.Schema; 11 | using NLog; 12 | 13 | namespace Cvent.SchemaToPoco.Core 14 | { 15 | /// 16 | /// Resolve JSON schema $ref attributes 17 | /// 18 | public class JsonSchemaResolver 19 | { 20 | /// 21 | /// Logger. 22 | /// 23 | private readonly Logger _log = LogManager.GetCurrentClassLogger(); 24 | 25 | /// 26 | /// The absolute path to the base generated directory. 27 | /// 28 | private readonly string _baseDir; 29 | 30 | /// 31 | /// Whether or not to create directories. 32 | /// 33 | private readonly bool _createDirs; 34 | 35 | /// 36 | /// The namespace. 37 | /// 38 | private readonly string _ns; 39 | 40 | /// 41 | /// Resolving schemas so that they can be parsed. 42 | /// 43 | private readonly Newtonsoft.Json.Schema.JsonSchemaResolver _resolver = new Newtonsoft.Json.Schema.JsonSchemaResolver(); 44 | 45 | /// 46 | /// Keeps track of the found schemas. 47 | /// 48 | private readonly Dictionary _schemas = new Dictionary(); 49 | 50 | /// 51 | /// Constructor. 52 | /// 53 | /// settings.Namespace 54 | /// settings.Verbose 55 | /// The base directory of the generated files. 56 | public JsonSchemaResolver(string ns, bool createDirs, string baseDir) 57 | { 58 | _ns = ns; 59 | _createDirs = createDirs; 60 | _baseDir = baseDir; 61 | } 62 | 63 | /// 64 | /// Resolve all schemas. 65 | /// 66 | /// Path to the current file. 67 | /// A Dictionary containing all resolved schemas. 68 | public Dictionary ResolveSchemas(string filePath) 69 | { 70 | var uri = IoUtils.GetAbsoluteUri(new Uri(Directory.GetCurrentDirectory()), new Uri(filePath, UriKind.RelativeOrAbsolute), false); 71 | 72 | // Resolve the root schema 73 | JsonSchemaWrapper schema = ResolveSchemaHelper(uri, uri); 74 | _schemas.Add(uri, schema); 75 | return _schemas; 76 | } 77 | 78 | /// 79 | /// Recursively resolve all schemas. All references to external schemas must have .json extension. 80 | /// This is done by: 81 | /// 1. Scanning the schema for $ref attributes. 82 | /// 2. Attempting to construct a Uri object to represent the reference. 83 | /// 3. Passing it into a resolver to create a network of schemas. 84 | /// 4. Modifying the original schema's $ref attributes with the full, unique Uri. 85 | /// 5. Setting the id of the referenced schemas to its full, unique Uri. 86 | /// 87 | /// Path to the parent file. 88 | /// Path to the current file. 89 | /// An extended wrapper for the JsonSchema. 90 | /// TODO check if parent is needed - right now it assumes parent for all children 91 | private JsonSchemaWrapper ResolveSchemaHelper(Uri parent, Uri current) 92 | { 93 | var uri = IoUtils.GetAbsoluteUri(parent, current, true); 94 | var data = IoUtils.ReadFromPath(uri); 95 | 96 | return ResolveSchemaHelper(uri, parent, data); 97 | } 98 | 99 | private JsonSchemaWrapper ResolveSchemaHelper(Uri curr, Uri parent, string data) 100 | { 101 | var definition = new 102 | { 103 | csharpType = string.Empty, 104 | csharpInterfaces = new string[] { }, 105 | properties = new Dictionary() 106 | }; 107 | var deserialized = JsonConvert.DeserializeAnonymousType(data, definition); 108 | var dependencies = new List(); 109 | 110 | MatchCollection matches = Regex.Matches(data, @"\""\$ref\""\s*:\s*\""(.*.json)\"""); 111 | foreach (Match match in matches) 112 | { 113 | // Get the full path to the file, and change the reference to match 114 | var currPath = new Uri(match.Groups[1].Value, UriKind.RelativeOrAbsolute); 115 | var currUri = IoUtils.GetAbsoluteUri(parent, currPath, true); 116 | 117 | JsonSchemaWrapper schema; 118 | 119 | if (!_schemas.ContainsKey(currUri)) 120 | { 121 | schema = ResolveSchemaHelper(parent, currUri); 122 | _schemas.Add(currUri, schema); 123 | } 124 | else 125 | { 126 | schema = _schemas[currUri]; 127 | } 128 | 129 | // Add schema to dependencies 130 | dependencies.Add(schema); 131 | } 132 | 133 | // Go through properties to see if there needs to be more resolving 134 | if (deserialized != null && deserialized.properties != null) 135 | { 136 | foreach (var s in deserialized.properties) 137 | { 138 | var properties = s.Value.Properties(); 139 | 140 | // Check that the property also has a top level key called properties or items 141 | foreach (var prop in properties) 142 | { 143 | var isProp = prop.Name.Equals("properties"); 144 | var isItem = prop.Name.Equals("items"); 145 | 146 | // TODO ehhhh let's avoid hardcoding this 147 | if (isProp || (isItem && prop.Value.ToString().Contains("\"properties\""))) 148 | { 149 | var propData = isProp ? s.Value.ToString() : prop.Value.ToString(); 150 | 151 | // Create dummy internal Uri 152 | var dummyUri = new Uri(new Uri(curr + "/"), s.Key); 153 | 154 | JsonSchemaWrapper schema = ResolveSchemaHelper(dummyUri, curr, propData); 155 | 156 | if (!_schemas.ContainsKey(dummyUri)) 157 | { 158 | _schemas.Add(dummyUri, schema); 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | // Set up schema and wrapper to return 166 | JsonSchema parsed; 167 | 168 | try 169 | { 170 | parsed = JsonSchema.Parse(StandardizeReferences(parent, data), _resolver); 171 | } 172 | catch (Exception) 173 | { 174 | _log.Error("Could not parse the schema: " + curr + "\nMake sure your schema is compatible." + 175 | "Examine the stack trace below."); 176 | throw; 177 | } 178 | 179 | parsed.Id = curr.ToString(); 180 | parsed.Title = parsed.Title.SanitizeIdentifier(); 181 | var toReturn = new JsonSchemaWrapper(parsed) { Namespace = _ns, Dependencies = dependencies }; 182 | 183 | // If csharpType is specified 184 | if (deserialized != null && !string.IsNullOrEmpty(deserialized.csharpType)) 185 | { 186 | // Create directories and set namespace 187 | int lastIndex = deserialized.csharpType.LastIndexOf('.'); 188 | string cType = deserialized.csharpType.Substring(lastIndex == -1 ? 0 : lastIndex + 1); 189 | 190 | toReturn.Namespace = deserialized.csharpType.Substring(0, lastIndex); 191 | toReturn.Schema.Title = cType; 192 | 193 | if (_createDirs) 194 | { 195 | IoUtils.CreateDirectoryFromNamespace(_baseDir, toReturn.Namespace); 196 | } 197 | } 198 | 199 | // If csharpInterfaces is specified 200 | if (deserialized != null && deserialized.csharpInterfaces != null) 201 | { 202 | foreach (string s in deserialized.csharpInterfaces) 203 | { 204 | // Try to resolve the type 205 | Type t = Type.GetType(s, false); 206 | 207 | // If type cannot be found, create a new type 208 | if (t == null) 209 | { 210 | var builder = new TypeBuilderHelper(toReturn.Namespace); 211 | t = builder.GetCustomType(s, !s.Contains(".")); 212 | } 213 | 214 | toReturn.Interfaces.Add(t); 215 | } 216 | } 217 | 218 | return toReturn; 219 | } 220 | 221 | /// 222 | /// Convert all $ref attributes to absolute paths. 223 | /// 224 | /// The parent Uri to resolve relative paths against. 225 | /// The JSON schema. 226 | /// The JSON schema with standardized $ref attributes. 227 | private string StandardizeReferences(Uri parentUri, string data) 228 | { 229 | var lines = new List(data.Split('\n')); 230 | var pattern = new Regex(@"(\""\$ref\""\s*:\s*\"")(.*.json)(\"")"); 231 | 232 | for (int i = lines.Count - 1; i >= 0; i--) 233 | { 234 | if (pattern.IsMatch(lines[i])) 235 | { 236 | var matched = pattern.Match(lines[i]); 237 | var matchedPath = matched.Groups[2].Value; 238 | var absPath = IoUtils.GetAbsoluteUri(parentUri, new Uri(matchedPath, UriKind.RelativeOrAbsolute), true); 239 | lines[i] = matched.Groups[1].Value + absPath + matched.Groups[3].Value + ","; 240 | } 241 | } 242 | 243 | return string.Join("\n", lines); 244 | } 245 | 246 | /// 247 | /// Convert a schema with no references to a JsonSchemaWrapper. 248 | /// 249 | /// The JSON schema. 250 | public static JsonSchemaWrapper ConvertToWrapper(string data) 251 | { 252 | return new JsonSchemaWrapper(JsonSchema.Parse(data)); 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /Source/Cvent.SchemaToPoco.Console/Mono.Options/Options.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Options.cs 3 | // 4 | // Authors: 5 | // Jonathan Pryor 6 | // Federico Di Gregorio 7 | // Rolf Bjarne Kvinge 8 | // 9 | // Copyright (C) 2008 Novell (http://www.novell.com) 10 | // Copyright (C) 2009 Federico Di Gregorio. 11 | // Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com) 12 | // 13 | // Permission is hereby granted, free of charge, to any person obtaining 14 | // a copy of this software and associated documentation files (the 15 | // "Software"), to deal in the Software without restriction, including 16 | // without limitation the rights to use, copy, modify, merge, publish, 17 | // distribute, sublicense, and/or sell copies of the Software, and to 18 | // permit persons to whom the Software is furnished to do so, subject to 19 | // the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be 22 | // included in all copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | // Compile With: 34 | // gmcs -debug+ -r:System.Core Options.cs -o:NDesk.Options.dll 35 | // gmcs -debug+ -d:LINQ -r:System.Core Options.cs -o:NDesk.Options.dll 36 | // 37 | // The LINQ version just changes the implementation of 38 | // OptionSet.Parse(IEnumerable), and confers no semantic changes. 39 | 40 | // 41 | // A Getopt::Long-inspired option parsing library for C#. 42 | // 43 | // NDesk.Options.OptionSet is built upon a key/value table, where the 44 | // key is a option format string and the value is a delegate that is 45 | // invoked when the format string is matched. 46 | // 47 | // Option format strings: 48 | // Regex-like BNF Grammar: 49 | // name: .+ 50 | // type: [=:] 51 | // sep: ( [^{}]+ | '{' .+ '}' )? 52 | // aliases: ( name type sep ) ( '|' name type sep )* 53 | // 54 | // Each '|'-delimited name is an alias for the associated action. If the 55 | // format string ends in a '=', it has a required value. If the format 56 | // string ends in a ':', it has an optional value. If neither '=' or ':' 57 | // is present, no value is supported. `=' or `:' need only be defined on one 58 | // alias, but if they are provided on more than one they must be consistent. 59 | // 60 | // Each alias portion may also end with a "key/value separator", which is used 61 | // to split option values if the option accepts > 1 value. If not specified, 62 | // it defaults to '=' and ':'. If specified, it can be any character except 63 | // '{' and '}' OR the *string* between '{' and '}'. If no separator should be 64 | // used (i.e. the separate values should be distinct arguments), then "{}" 65 | // should be used as the separator. 66 | // 67 | // Options are extracted either from the current option by looking for 68 | // the option name followed by an '=' or ':', or is taken from the 69 | // following option IFF: 70 | // - The current option does not contain a '=' or a ':' 71 | // - The current option requires a value (i.e. not a Option type of ':') 72 | // 73 | // The `name' used in the option format string does NOT include any leading 74 | // option indicator, such as '-', '--', or '/'. All three of these are 75 | // permitted/required on any named option. 76 | // 77 | // Option bundling is permitted so long as: 78 | // - '-' is used to start the option group 79 | // - all of the bundled options are a single character 80 | // - at most one of the bundled options accepts a value, and the value 81 | // provided starts from the next character to the end of the string. 82 | // 83 | // This allows specifying '-a -b -c' as '-abc', and specifying '-D name=value' 84 | // as '-Dname=value'. 85 | // 86 | // Option processing is disabled by specifying "--". All options after "--" 87 | // are returned by OptionSet.Parse() unchanged and unprocessed. 88 | // 89 | // Unprocessed options are returned from OptionSet.Parse(). 90 | // 91 | // Examples: 92 | // int verbose = 0; 93 | // OptionSet p = new OptionSet () 94 | // .Add ("v", v => ++verbose) 95 | // .Add ("name=|value=", v => Console.WriteLine (v)); 96 | // p.Parse (new string[]{"-v", "--v", "/v", "-name=A", "/name", "B", "extra"}); 97 | // 98 | // The above would parse the argument string array, and would invoke the 99 | // lambda expression three times, setting `verbose' to 3 when complete. 100 | // It would also print out "A" and "B" to standard output. 101 | // The returned array would contain the string "extra". 102 | // 103 | // C# 3.0 collection initializers are supported and encouraged: 104 | // var p = new OptionSet () { 105 | // { "h|?|help", v => ShowHelp () }, 106 | // }; 107 | // 108 | // System.ComponentModel.TypeConverter is also supported, allowing the use of 109 | // custom data types in the callback type; TypeConverter.ConvertFromString() 110 | // is used to convert the value option to an instance of the specified 111 | // type: 112 | // 113 | // var p = new OptionSet () { 114 | // { "foo=", (Foo f) => Console.WriteLine (f.ToString ()) }, 115 | // }; 116 | // 117 | // Random other tidbits: 118 | // - Boolean options (those w/o '=' or ':' in the option format string) 119 | // are explicitly enabled if they are followed with '+', and explicitly 120 | // disabled if they are followed with '-': 121 | // string a = null; 122 | // var p = new OptionSet () { 123 | // { "a", s => a = s }, 124 | // }; 125 | // p.Parse (new string[]{"-a"}); // sets v != null 126 | // p.Parse (new string[]{"-a+"}); // sets v != null 127 | // p.Parse (new string[]{"-a-"}); // sets v == null 128 | // 129 | 130 | using System; 131 | using System.Collections; 132 | using System.Collections.Generic; 133 | using System.Collections.ObjectModel; 134 | using System.ComponentModel; 135 | using System.Globalization; 136 | using System.IO; 137 | using System.Runtime.Serialization; 138 | using System.Security.Permissions; 139 | using System.Text; 140 | using System.Text.RegularExpressions; 141 | 142 | #if LINQ 143 | using System.Linq; 144 | #endif 145 | 146 | #if TEST 147 | using NDesk.Options; 148 | #endif 149 | 150 | #if NDESK_OPTIONS 151 | namespace NDesk.Options 152 | #else 153 | namespace Mono.Options 154 | #endif 155 | { 156 | static class StringCoda { 157 | 158 | public static IEnumerable WrappedLines (string self, params int[] widths) 159 | { 160 | IEnumerable w = widths; 161 | return WrappedLines (self, w); 162 | } 163 | 164 | public static IEnumerable WrappedLines (string self, IEnumerable widths) 165 | { 166 | if (widths == null) 167 | throw new ArgumentNullException ("widths"); 168 | return CreateWrappedLinesIterator (self, widths); 169 | } 170 | 171 | private static IEnumerable CreateWrappedLinesIterator (string self, IEnumerable widths) 172 | { 173 | if (string.IsNullOrEmpty (self)) { 174 | yield return string.Empty; 175 | yield break; 176 | } 177 | using (IEnumerator ewidths = widths.GetEnumerator ()) { 178 | bool? hw = null; 179 | int width = GetNextWidth (ewidths, int.MaxValue, ref hw); 180 | int start = 0, end; 181 | do { 182 | end = GetLineEnd (start, width, self); 183 | char c = self [end-1]; 184 | if (char.IsWhiteSpace (c)) 185 | --end; 186 | bool needContinuation = end != self.Length && !IsEolChar (c); 187 | string continuation = ""; 188 | if (needContinuation) { 189 | --end; 190 | continuation = "-"; 191 | } 192 | string line = self.Substring (start, end - start) + continuation; 193 | yield return line; 194 | start = end; 195 | if (char.IsWhiteSpace (c)) 196 | ++start; 197 | width = GetNextWidth (ewidths, width, ref hw); 198 | } while (start < self.Length); 199 | } 200 | } 201 | 202 | private static int GetNextWidth (IEnumerator ewidths, int curWidth, ref bool? eValid) 203 | { 204 | if (!eValid.HasValue || (eValid.HasValue && eValid.Value)) { 205 | curWidth = (eValid = ewidths.MoveNext ()).Value ? ewidths.Current : curWidth; 206 | // '.' is any character, - is for a continuation 207 | const string minWidth = ".-"; 208 | if (curWidth < minWidth.Length) 209 | throw new ArgumentOutOfRangeException ("widths", 210 | string.Format ("Element must be >= {0}, was {1}.", minWidth.Length, curWidth)); 211 | return curWidth; 212 | } 213 | // no more elements, use the last element. 214 | return curWidth; 215 | } 216 | 217 | private static bool IsEolChar (char c) 218 | { 219 | return !char.IsLetterOrDigit (c); 220 | } 221 | 222 | private static int GetLineEnd (int start, int length, string description) 223 | { 224 | int end = System.Math.Min (start + length, description.Length); 225 | int sep = -1; 226 | for (int i = start; i < end; ++i) { 227 | if (description [i] == '\n') 228 | return i+1; 229 | if (IsEolChar (description [i])) 230 | sep = i+1; 231 | } 232 | if (sep == -1 || end == description.Length) 233 | return end; 234 | return sep; 235 | } 236 | } 237 | 238 | public class OptionValueCollection : IList, IList { 239 | 240 | List values = new List (); 241 | OptionContext c; 242 | 243 | internal OptionValueCollection (OptionContext c) 244 | { 245 | this.c = c; 246 | } 247 | 248 | #region ICollection 249 | void ICollection.CopyTo (Array array, int index) {(values as ICollection).CopyTo (array, index);} 250 | bool ICollection.IsSynchronized {get {return (values as ICollection).IsSynchronized;}} 251 | object ICollection.SyncRoot {get {return (values as ICollection).SyncRoot;}} 252 | #endregion 253 | 254 | #region ICollection 255 | public void Add (string item) {values.Add (item);} 256 | public void Clear () {values.Clear ();} 257 | public bool Contains (string item) {return values.Contains (item);} 258 | public void CopyTo (string[] array, int arrayIndex) {values.CopyTo (array, arrayIndex);} 259 | public bool Remove (string item) {return values.Remove (item);} 260 | public int Count {get {return values.Count;}} 261 | public bool IsReadOnly {get {return false;}} 262 | #endregion 263 | 264 | #region IEnumerable 265 | IEnumerator IEnumerable.GetEnumerator () {return values.GetEnumerator ();} 266 | #endregion 267 | 268 | #region IEnumerable 269 | public IEnumerator GetEnumerator () {return values.GetEnumerator ();} 270 | #endregion 271 | 272 | #region IList 273 | int IList.Add (object value) {return (values as IList).Add (value);} 274 | bool IList.Contains (object value) {return (values as IList).Contains (value);} 275 | int IList.IndexOf (object value) {return (values as IList).IndexOf (value);} 276 | void IList.Insert (int index, object value) {(values as IList).Insert (index, value);} 277 | void IList.Remove (object value) {(values as IList).Remove (value);} 278 | void IList.RemoveAt (int index) {(values as IList).RemoveAt (index);} 279 | bool IList.IsFixedSize {get {return false;}} 280 | object IList.this [int index] {get {return this [index];} set {(values as IList)[index] = value;}} 281 | #endregion 282 | 283 | #region IList 284 | public int IndexOf (string item) {return values.IndexOf (item);} 285 | public void Insert (int index, string item) {values.Insert (index, item);} 286 | public void RemoveAt (int index) {values.RemoveAt (index);} 287 | 288 | private void AssertValid (int index) 289 | { 290 | if (c.Option == null) 291 | throw new InvalidOperationException ("OptionContext.Option is null."); 292 | if (index >= c.Option.MaxValueCount) 293 | throw new ArgumentOutOfRangeException ("index"); 294 | if (c.Option.OptionValueType == OptionValueType.Required && 295 | index >= values.Count) 296 | throw new OptionException (string.Format ( 297 | c.OptionSet.MessageLocalizer ("Missing required value for option '{0}'."), c.OptionName), 298 | c.OptionName); 299 | } 300 | 301 | public string this [int index] { 302 | get { 303 | AssertValid (index); 304 | return index >= values.Count ? null : values [index]; 305 | } 306 | set { 307 | values [index] = value; 308 | } 309 | } 310 | #endregion 311 | 312 | public List ToList () 313 | { 314 | return new List (values); 315 | } 316 | 317 | public string[] ToArray () 318 | { 319 | return values.ToArray (); 320 | } 321 | 322 | public override string ToString () 323 | { 324 | return string.Join (", ", values.ToArray ()); 325 | } 326 | } 327 | 328 | public class OptionContext { 329 | private Option option; 330 | private string name; 331 | private int index; 332 | private OptionSet set; 333 | private OptionValueCollection c; 334 | 335 | public OptionContext (OptionSet set) 336 | { 337 | this.set = set; 338 | this.c = new OptionValueCollection (this); 339 | } 340 | 341 | public Option Option { 342 | get {return option;} 343 | set {option = value;} 344 | } 345 | 346 | public string OptionName { 347 | get {return name;} 348 | set {name = value;} 349 | } 350 | 351 | public int OptionIndex { 352 | get {return index;} 353 | set {index = value;} 354 | } 355 | 356 | public OptionSet OptionSet { 357 | get {return set;} 358 | } 359 | 360 | public OptionValueCollection OptionValues { 361 | get {return c;} 362 | } 363 | } 364 | 365 | public enum OptionValueType { 366 | None, 367 | Optional, 368 | Required, 369 | } 370 | 371 | public abstract class Option { 372 | string prototype, description; 373 | string[] names; 374 | OptionValueType type; 375 | int count; 376 | string[] separators; 377 | bool hidden; 378 | 379 | protected Option (string prototype, string description) 380 | : this (prototype, description, 1, false) 381 | { 382 | } 383 | 384 | protected Option (string prototype, string description, int maxValueCount) 385 | : this (prototype, description, maxValueCount, false) 386 | { 387 | } 388 | 389 | protected Option (string prototype, string description, int maxValueCount, bool hidden) 390 | { 391 | if (prototype == null) 392 | throw new ArgumentNullException ("prototype"); 393 | if (prototype.Length == 0) 394 | throw new ArgumentException ("Cannot be the empty string.", "prototype"); 395 | if (maxValueCount < 0) 396 | throw new ArgumentOutOfRangeException ("maxValueCount"); 397 | 398 | this.prototype = prototype; 399 | this.description = description; 400 | this.count = maxValueCount; 401 | this.names = (this is OptionSet.Category) 402 | // append GetHashCode() so that "duplicate" categories have distinct 403 | // names, e.g. adding multiple "" categories should be valid. 404 | ? new[]{prototype + this.GetHashCode ()} 405 | : prototype.Split ('|'); 406 | 407 | if (this is OptionSet.Category) 408 | return; 409 | 410 | this.type = ParsePrototype (); 411 | this.hidden = hidden; 412 | 413 | if (this.count == 0 && type != OptionValueType.None) 414 | throw new ArgumentException ( 415 | "Cannot provide maxValueCount of 0 for OptionValueType.Required or " + 416 | "OptionValueType.Optional.", 417 | "maxValueCount"); 418 | if (this.type == OptionValueType.None && maxValueCount > 1) 419 | throw new ArgumentException ( 420 | string.Format ("Cannot provide maxValueCount of {0} for OptionValueType.None.", maxValueCount), 421 | "maxValueCount"); 422 | if (Array.IndexOf (names, "<>") >= 0 && 423 | ((names.Length == 1 && this.type != OptionValueType.None) || 424 | (names.Length > 1 && this.MaxValueCount > 1))) 425 | throw new ArgumentException ( 426 | "The default option handler '<>' cannot require values.", 427 | "prototype"); 428 | } 429 | 430 | public string Prototype {get {return prototype;}} 431 | public string Description {get {return description;}} 432 | public OptionValueType OptionValueType {get {return type;}} 433 | public int MaxValueCount {get {return count;}} 434 | public bool Hidden {get {return hidden;}} 435 | 436 | public string[] GetNames () 437 | { 438 | return (string[]) names.Clone (); 439 | } 440 | 441 | public string[] GetValueSeparators () 442 | { 443 | if (separators == null) 444 | return new string [0]; 445 | return (string[]) separators.Clone (); 446 | } 447 | 448 | protected static T Parse (string value, OptionContext c) 449 | { 450 | Type tt = typeof (T); 451 | bool nullable = tt.IsValueType && tt.IsGenericType && 452 | !tt.IsGenericTypeDefinition && 453 | tt.GetGenericTypeDefinition () == typeof (Nullable<>); 454 | Type targetType = nullable ? tt.GetGenericArguments () [0] : typeof (T); 455 | TypeConverter conv = TypeDescriptor.GetConverter (targetType); 456 | T t = default (T); 457 | try { 458 | if (value != null) 459 | t = (T) conv.ConvertFromString (value); 460 | } 461 | catch (Exception e) { 462 | throw new OptionException ( 463 | string.Format ( 464 | c.OptionSet.MessageLocalizer ("Could not convert string `{0}' to type {1} for option `{2}'."), 465 | value, targetType.Name, c.OptionName), 466 | c.OptionName, e); 467 | } 468 | return t; 469 | } 470 | 471 | internal string[] Names {get {return names;}} 472 | internal string[] ValueSeparators {get {return separators;}} 473 | 474 | static readonly char[] NameTerminator = new char[]{'=', ':'}; 475 | 476 | private OptionValueType ParsePrototype () 477 | { 478 | char type = '\0'; 479 | List seps = new List (); 480 | for (int i = 0; i < names.Length; ++i) { 481 | string name = names [i]; 482 | if (name.Length == 0) 483 | throw new ArgumentException ("Empty option names are not supported.", "prototype"); 484 | 485 | int end = name.IndexOfAny (NameTerminator); 486 | if (end == -1) 487 | continue; 488 | names [i] = name.Substring (0, end); 489 | if (type == '\0' || type == name [end]) 490 | type = name [end]; 491 | else 492 | throw new ArgumentException ( 493 | string.Format ("Conflicting option types: '{0}' vs. '{1}'.", type, name [end]), 494 | "prototype"); 495 | AddSeparators (name, end, seps); 496 | } 497 | 498 | if (type == '\0') 499 | return OptionValueType.None; 500 | 501 | if (count <= 1 && seps.Count != 0) 502 | throw new ArgumentException ( 503 | string.Format ("Cannot provide key/value separators for Options taking {0} value(s).", count), 504 | "prototype"); 505 | if (count > 1) { 506 | if (seps.Count == 0) 507 | this.separators = new string[]{":", "="}; 508 | else if (seps.Count == 1 && seps [0].Length == 0) 509 | this.separators = null; 510 | else 511 | this.separators = seps.ToArray (); 512 | } 513 | 514 | return type == '=' ? OptionValueType.Required : OptionValueType.Optional; 515 | } 516 | 517 | private static void AddSeparators (string name, int end, ICollection seps) 518 | { 519 | int start = -1; 520 | for (int i = end+1; i < name.Length; ++i) { 521 | switch (name [i]) { 522 | case '{': 523 | if (start != -1) 524 | throw new ArgumentException ( 525 | string.Format ("Ill-formed name/value separator found in \"{0}\".", name), 526 | "prototype"); 527 | start = i+1; 528 | break; 529 | case '}': 530 | if (start == -1) 531 | throw new ArgumentException ( 532 | string.Format ("Ill-formed name/value separator found in \"{0}\".", name), 533 | "prototype"); 534 | seps.Add (name.Substring (start, i-start)); 535 | start = -1; 536 | break; 537 | default: 538 | if (start == -1) 539 | seps.Add (name [i].ToString ()); 540 | break; 541 | } 542 | } 543 | if (start != -1) 544 | throw new ArgumentException ( 545 | string.Format ("Ill-formed name/value separator found in \"{0}\".", name), 546 | "prototype"); 547 | } 548 | 549 | public void Invoke (OptionContext c) 550 | { 551 | OnParseComplete (c); 552 | c.OptionName = null; 553 | c.Option = null; 554 | c.OptionValues.Clear (); 555 | } 556 | 557 | protected abstract void OnParseComplete (OptionContext c); 558 | 559 | public override string ToString () 560 | { 561 | return Prototype; 562 | } 563 | } 564 | 565 | public abstract class ArgumentSource { 566 | 567 | protected ArgumentSource () 568 | { 569 | } 570 | 571 | public abstract string[] GetNames (); 572 | public abstract string Description { get; } 573 | public abstract bool GetArguments (string value, out IEnumerable replacement); 574 | 575 | public static IEnumerable GetArgumentsFromFile (string file) 576 | { 577 | return GetArguments (File.OpenText (file), true); 578 | } 579 | 580 | public static IEnumerable GetArguments (TextReader reader) 581 | { 582 | return GetArguments (reader, false); 583 | } 584 | 585 | // Cribbed from mcs/driver.cs:LoadArgs(string) 586 | static IEnumerable GetArguments (TextReader reader, bool close) 587 | { 588 | try { 589 | StringBuilder arg = new StringBuilder (); 590 | 591 | string line; 592 | while ((line = reader.ReadLine ()) != null) { 593 | int t = line.Length; 594 | 595 | for (int i = 0; i < t; i++) { 596 | char c = line [i]; 597 | 598 | if (c == '"' || c == '\'') { 599 | char end = c; 600 | 601 | for (i++; i < t; i++){ 602 | c = line [i]; 603 | 604 | if (c == end) 605 | break; 606 | arg.Append (c); 607 | } 608 | } else if (c == ' ') { 609 | if (arg.Length > 0) { 610 | yield return arg.ToString (); 611 | arg.Length = 0; 612 | } 613 | } else 614 | arg.Append (c); 615 | } 616 | if (arg.Length > 0) { 617 | yield return arg.ToString (); 618 | arg.Length = 0; 619 | } 620 | } 621 | } 622 | finally { 623 | if (close) 624 | reader.Close (); 625 | } 626 | } 627 | } 628 | 629 | public class ResponseFileSource : ArgumentSource { 630 | 631 | public override string[] GetNames () 632 | { 633 | return new string[]{"@file"}; 634 | } 635 | 636 | public override string Description { 637 | get {return "Read response file for more options.";} 638 | } 639 | 640 | public override bool GetArguments (string value, out IEnumerable replacement) 641 | { 642 | if (string.IsNullOrEmpty (value) || !value.StartsWith ("@")) { 643 | replacement = null; 644 | return false; 645 | } 646 | replacement = ArgumentSource.GetArgumentsFromFile (value.Substring (1)); 647 | return true; 648 | } 649 | } 650 | 651 | [Serializable] 652 | public class OptionException : Exception { 653 | private string option; 654 | 655 | public OptionException () 656 | { 657 | } 658 | 659 | public OptionException (string message, string optionName) 660 | : base (message) 661 | { 662 | this.option = optionName; 663 | } 664 | 665 | public OptionException (string message, string optionName, Exception innerException) 666 | : base (message, innerException) 667 | { 668 | this.option = optionName; 669 | } 670 | 671 | protected OptionException (SerializationInfo info, StreamingContext context) 672 | : base (info, context) 673 | { 674 | this.option = info.GetString ("OptionName"); 675 | } 676 | 677 | public string OptionName { 678 | get {return this.option;} 679 | } 680 | 681 | [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)] 682 | public override void GetObjectData (SerializationInfo info, StreamingContext context) 683 | { 684 | base.GetObjectData (info, context); 685 | info.AddValue ("OptionName", option); 686 | } 687 | } 688 | 689 | public delegate void OptionAction (TKey key, TValue value); 690 | 691 | public class OptionSet : KeyedCollection 692 | { 693 | public OptionSet () 694 | : this (delegate (string f) {return f;}) 695 | { 696 | } 697 | 698 | public OptionSet (Converter localizer) 699 | { 700 | this.localizer = localizer; 701 | this.roSources = new ReadOnlyCollection(sources); 702 | } 703 | 704 | Converter localizer; 705 | 706 | public Converter MessageLocalizer { 707 | get {return localizer;} 708 | } 709 | 710 | List sources = new List (); 711 | ReadOnlyCollection roSources; 712 | 713 | public ReadOnlyCollection ArgumentSources { 714 | get {return roSources;} 715 | } 716 | 717 | 718 | protected override string GetKeyForItem (Option item) 719 | { 720 | if (item == null) 721 | throw new ArgumentNullException ("option"); 722 | if (item.Names != null && item.Names.Length > 0) 723 | return item.Names [0]; 724 | // This should never happen, as it's invalid for Option to be 725 | // constructed w/o any names. 726 | throw new InvalidOperationException ("Option has no names!"); 727 | } 728 | 729 | [Obsolete ("Use KeyedCollection.this[string]")] 730 | protected Option GetOptionForName (string option) 731 | { 732 | if (option == null) 733 | throw new ArgumentNullException ("option"); 734 | try { 735 | return base [option]; 736 | } 737 | catch (KeyNotFoundException) { 738 | return null; 739 | } 740 | } 741 | 742 | protected override void InsertItem (int index, Option item) 743 | { 744 | base.InsertItem (index, item); 745 | AddImpl (item); 746 | } 747 | 748 | protected override void RemoveItem (int index) 749 | { 750 | Option p = Items [index]; 751 | base.RemoveItem (index); 752 | // KeyedCollection.RemoveItem() handles the 0th item 753 | for (int i = 1; i < p.Names.Length; ++i) { 754 | Dictionary.Remove (p.Names [i]); 755 | } 756 | } 757 | 758 | protected override void SetItem (int index, Option item) 759 | { 760 | base.SetItem (index, item); 761 | AddImpl (item); 762 | } 763 | 764 | private void AddImpl (Option option) 765 | { 766 | if (option == null) 767 | throw new ArgumentNullException ("option"); 768 | List added = new List (option.Names.Length); 769 | try { 770 | // KeyedCollection.InsertItem/SetItem handle the 0th name. 771 | for (int i = 1; i < option.Names.Length; ++i) { 772 | Dictionary.Add (option.Names [i], option); 773 | added.Add (option.Names [i]); 774 | } 775 | } 776 | catch (Exception) { 777 | foreach (string name in added) 778 | Dictionary.Remove (name); 779 | throw; 780 | } 781 | } 782 | 783 | public OptionSet Add (string header) 784 | { 785 | if (header == null) 786 | throw new ArgumentNullException ("header"); 787 | Add (new Category (header)); 788 | return this; 789 | } 790 | 791 | internal sealed class Category : Option { 792 | 793 | // Prototype starts with '=' because this is an invalid prototype 794 | // (see Option.ParsePrototype(), and thus it'll prevent Category 795 | // instances from being accidentally used as normal options. 796 | public Category (string description) 797 | : base ("=:Category:= " + description, description) 798 | { 799 | } 800 | 801 | protected override void OnParseComplete (OptionContext c) 802 | { 803 | throw new NotSupportedException ("Category.OnParseComplete should not be invoked."); 804 | } 805 | } 806 | 807 | 808 | public new OptionSet Add (Option option) 809 | { 810 | base.Add (option); 811 | return this; 812 | } 813 | 814 | sealed class ActionOption : Option { 815 | Action action; 816 | 817 | public ActionOption (string prototype, string description, int count, Action action) 818 | : this (prototype, description, count, action, false) 819 | { 820 | } 821 | 822 | public ActionOption (string prototype, string description, int count, Action action, bool hidden) 823 | : base (prototype, description, count, hidden) 824 | { 825 | if (action == null) 826 | throw new ArgumentNullException ("action"); 827 | this.action = action; 828 | } 829 | 830 | protected override void OnParseComplete (OptionContext c) 831 | { 832 | action (c.OptionValues); 833 | } 834 | } 835 | 836 | public OptionSet Add (string prototype, Action action) 837 | { 838 | return Add (prototype, null, action); 839 | } 840 | 841 | public OptionSet Add (string prototype, string description, Action action) 842 | { 843 | return Add (prototype, description, action, false); 844 | } 845 | 846 | public OptionSet Add (string prototype, string description, Action action, bool hidden) 847 | { 848 | if (action == null) 849 | throw new ArgumentNullException ("action"); 850 | Option p = new ActionOption (prototype, description, 1, 851 | delegate (OptionValueCollection v) { action (v [0]); }, hidden); 852 | base.Add (p); 853 | return this; 854 | } 855 | 856 | public OptionSet Add (string prototype, OptionAction action) 857 | { 858 | return Add (prototype, null, action); 859 | } 860 | 861 | public OptionSet Add (string prototype, string description, OptionAction action) 862 | { 863 | return Add (prototype, description, action, false); 864 | } 865 | 866 | public OptionSet Add (string prototype, string description, OptionAction action, bool hidden) { 867 | if (action == null) 868 | throw new ArgumentNullException ("action"); 869 | Option p = new ActionOption (prototype, description, 2, 870 | delegate (OptionValueCollection v) {action (v [0], v [1]);}, hidden); 871 | base.Add (p); 872 | return this; 873 | } 874 | 875 | sealed class ActionOption : Option { 876 | Action action; 877 | 878 | public ActionOption (string prototype, string description, Action action) 879 | : base (prototype, description, 1) 880 | { 881 | if (action == null) 882 | throw new ArgumentNullException ("action"); 883 | this.action = action; 884 | } 885 | 886 | protected override void OnParseComplete (OptionContext c) 887 | { 888 | action (Parse (c.OptionValues [0], c)); 889 | } 890 | } 891 | 892 | sealed class ActionOption : Option { 893 | OptionAction action; 894 | 895 | public ActionOption (string prototype, string description, OptionAction action) 896 | : base (prototype, description, 2) 897 | { 898 | if (action == null) 899 | throw new ArgumentNullException ("action"); 900 | this.action = action; 901 | } 902 | 903 | protected override void OnParseComplete (OptionContext c) 904 | { 905 | action ( 906 | Parse (c.OptionValues [0], c), 907 | Parse (c.OptionValues [1], c)); 908 | } 909 | } 910 | 911 | public OptionSet Add (string prototype, Action action) 912 | { 913 | return Add (prototype, null, action); 914 | } 915 | 916 | public OptionSet Add (string prototype, string description, Action action) 917 | { 918 | return Add (new ActionOption (prototype, description, action)); 919 | } 920 | 921 | public OptionSet Add (string prototype, OptionAction action) 922 | { 923 | return Add (prototype, null, action); 924 | } 925 | 926 | public OptionSet Add (string prototype, string description, OptionAction action) 927 | { 928 | return Add (new ActionOption (prototype, description, action)); 929 | } 930 | 931 | public OptionSet Add (ArgumentSource source) 932 | { 933 | if (source == null) 934 | throw new ArgumentNullException ("source"); 935 | sources.Add (source); 936 | return this; 937 | } 938 | 939 | protected virtual OptionContext CreateOptionContext () 940 | { 941 | return new OptionContext (this); 942 | } 943 | 944 | public List Parse (IEnumerable arguments) 945 | { 946 | if (arguments == null) 947 | throw new ArgumentNullException ("arguments"); 948 | OptionContext c = CreateOptionContext (); 949 | c.OptionIndex = -1; 950 | bool process = true; 951 | List unprocessed = new List (); 952 | Option def = Contains ("<>") ? this ["<>"] : null; 953 | ArgumentEnumerator ae = new ArgumentEnumerator (arguments); 954 | foreach (string argument in ae) { 955 | ++c.OptionIndex; 956 | if (argument == "--") { 957 | process = false; 958 | continue; 959 | } 960 | if (!process) { 961 | Unprocessed (unprocessed, def, c, argument); 962 | continue; 963 | } 964 | if (AddSource (ae, argument)) 965 | continue; 966 | if (!Parse (argument, c)) 967 | Unprocessed (unprocessed, def, c, argument); 968 | } 969 | if (c.Option != null) 970 | c.Option.Invoke (c); 971 | return unprocessed; 972 | } 973 | 974 | class ArgumentEnumerator : IEnumerable { 975 | List> sources = new List> (); 976 | 977 | public ArgumentEnumerator (IEnumerable arguments) 978 | { 979 | sources.Add (arguments.GetEnumerator ()); 980 | } 981 | 982 | public void Add (IEnumerable arguments) 983 | { 984 | sources.Add (arguments.GetEnumerator ()); 985 | } 986 | 987 | public IEnumerator GetEnumerator () 988 | { 989 | do { 990 | IEnumerator c = sources [sources.Count-1]; 991 | if (c.MoveNext ()) 992 | yield return c.Current; 993 | else { 994 | c.Dispose (); 995 | sources.RemoveAt (sources.Count-1); 996 | } 997 | } while (sources.Count > 0); 998 | } 999 | 1000 | IEnumerator IEnumerable.GetEnumerator () 1001 | { 1002 | return GetEnumerator (); 1003 | } 1004 | } 1005 | 1006 | bool AddSource (ArgumentEnumerator ae, string argument) 1007 | { 1008 | foreach (ArgumentSource source in sources) { 1009 | IEnumerable replacement; 1010 | if (!source.GetArguments (argument, out replacement)) 1011 | continue; 1012 | ae.Add (replacement); 1013 | return true; 1014 | } 1015 | return false; 1016 | } 1017 | 1018 | private static bool Unprocessed (ICollection extra, Option def, OptionContext c, string argument) 1019 | { 1020 | if (def == null) { 1021 | extra.Add (argument); 1022 | return false; 1023 | } 1024 | c.OptionValues.Add (argument); 1025 | c.Option = def; 1026 | c.Option.Invoke (c); 1027 | return false; 1028 | } 1029 | 1030 | private readonly Regex ValueOption = new Regex ( 1031 | @"^(?--|-|/)(?[^:=]+)((?[:=])(?.*))?$"); 1032 | 1033 | protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value) 1034 | { 1035 | if (argument == null) 1036 | throw new ArgumentNullException ("argument"); 1037 | 1038 | flag = name = sep = value = null; 1039 | Match m = ValueOption.Match (argument); 1040 | if (!m.Success) { 1041 | return false; 1042 | } 1043 | flag = m.Groups ["flag"].Value; 1044 | name = m.Groups ["name"].Value; 1045 | if (m.Groups ["sep"].Success && m.Groups ["value"].Success) { 1046 | sep = m.Groups ["sep"].Value; 1047 | value = m.Groups ["value"].Value; 1048 | } 1049 | return true; 1050 | } 1051 | 1052 | protected virtual bool Parse (string argument, OptionContext c) 1053 | { 1054 | if (c.Option != null) { 1055 | ParseValue (argument, c); 1056 | return true; 1057 | } 1058 | 1059 | string f, n, s, v; 1060 | if (!GetOptionParts (argument, out f, out n, out s, out v)) 1061 | return false; 1062 | 1063 | Option p; 1064 | if (Contains (n)) { 1065 | p = this [n]; 1066 | c.OptionName = f + n; 1067 | c.Option = p; 1068 | switch (p.OptionValueType) { 1069 | case OptionValueType.None: 1070 | c.OptionValues.Add (n); 1071 | c.Option.Invoke (c); 1072 | break; 1073 | case OptionValueType.Optional: 1074 | case OptionValueType.Required: 1075 | ParseValue (v, c); 1076 | break; 1077 | } 1078 | return true; 1079 | } 1080 | // no match; is it a bool option? 1081 | if (ParseBool (argument, n, c)) 1082 | return true; 1083 | // is it a bundled option? 1084 | if (ParseBundledValue (f, string.Concat (n + s + v), c)) 1085 | return true; 1086 | 1087 | return false; 1088 | } 1089 | 1090 | private void ParseValue (string option, OptionContext c) 1091 | { 1092 | if (option != null) 1093 | foreach (string o in c.Option.ValueSeparators != null 1094 | ? option.Split (c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None) 1095 | : new string[]{option}) { 1096 | c.OptionValues.Add (o); 1097 | } 1098 | if (c.OptionValues.Count == c.Option.MaxValueCount || 1099 | c.Option.OptionValueType == OptionValueType.Optional) 1100 | c.Option.Invoke (c); 1101 | else if (c.OptionValues.Count > c.Option.MaxValueCount) { 1102 | throw new OptionException (localizer (string.Format ( 1103 | "Error: Found {0} option values when expecting {1}.", 1104 | c.OptionValues.Count, c.Option.MaxValueCount)), 1105 | c.OptionName); 1106 | } 1107 | } 1108 | 1109 | private bool ParseBool (string option, string n, OptionContext c) 1110 | { 1111 | Option p; 1112 | string rn; 1113 | if (n.Length >= 1 && (n [n.Length-1] == '+' || n [n.Length-1] == '-') && 1114 | Contains ((rn = n.Substring (0, n.Length-1)))) { 1115 | p = this [rn]; 1116 | string v = n [n.Length-1] == '+' ? option : null; 1117 | c.OptionName = option; 1118 | c.Option = p; 1119 | c.OptionValues.Add (v); 1120 | p.Invoke (c); 1121 | return true; 1122 | } 1123 | return false; 1124 | } 1125 | 1126 | private bool ParseBundledValue (string f, string n, OptionContext c) 1127 | { 1128 | if (f != "-") 1129 | return false; 1130 | for (int i = 0; i < n.Length; ++i) { 1131 | Option p; 1132 | string opt = f + n [i].ToString (); 1133 | string rn = n [i].ToString (); 1134 | if (!Contains (rn)) { 1135 | if (i == 0) 1136 | return false; 1137 | throw new OptionException (string.Format (localizer ( 1138 | "Cannot bundle unregistered option '{0}'."), opt), opt); 1139 | } 1140 | p = this [rn]; 1141 | switch (p.OptionValueType) { 1142 | case OptionValueType.None: 1143 | Invoke (c, opt, n, p); 1144 | break; 1145 | case OptionValueType.Optional: 1146 | case OptionValueType.Required: { 1147 | string v = n.Substring (i+1); 1148 | c.Option = p; 1149 | c.OptionName = opt; 1150 | ParseValue (v.Length != 0 ? v : null, c); 1151 | return true; 1152 | } 1153 | default: 1154 | throw new InvalidOperationException ("Unknown OptionValueType: " + p.OptionValueType); 1155 | } 1156 | } 1157 | return true; 1158 | } 1159 | 1160 | private static void Invoke (OptionContext c, string name, string value, Option option) 1161 | { 1162 | c.OptionName = name; 1163 | c.Option = option; 1164 | c.OptionValues.Add (value); 1165 | option.Invoke (c); 1166 | } 1167 | 1168 | private const int OptionWidth = 29; 1169 | private const int Description_FirstWidth = 80 - OptionWidth; 1170 | private const int Description_RemWidth = 80 - OptionWidth - 2; 1171 | 1172 | public void WriteOptionDescriptions (TextWriter o) 1173 | { 1174 | foreach (Option p in this) { 1175 | int written = 0; 1176 | 1177 | if (p.Hidden) 1178 | continue; 1179 | 1180 | Category c = p as Category; 1181 | if (c != null) { 1182 | WriteDescription (o, p.Description, "", 80, 80); 1183 | continue; 1184 | } 1185 | 1186 | if (!WriteOptionPrototype (o, p, ref written)) 1187 | continue; 1188 | 1189 | if (written < OptionWidth) 1190 | o.Write (new string (' ', OptionWidth - written)); 1191 | else { 1192 | o.WriteLine (); 1193 | o.Write (new string (' ', OptionWidth)); 1194 | } 1195 | 1196 | WriteDescription (o, p.Description, new string (' ', OptionWidth+2), 1197 | Description_FirstWidth, Description_RemWidth); 1198 | } 1199 | 1200 | foreach (ArgumentSource s in sources) { 1201 | string[] names = s.GetNames (); 1202 | if (names == null || names.Length == 0) 1203 | continue; 1204 | 1205 | int written = 0; 1206 | 1207 | Write (o, ref written, " "); 1208 | Write (o, ref written, names [0]); 1209 | for (int i = 1; i < names.Length; ++i) { 1210 | Write (o, ref written, ", "); 1211 | Write (o, ref written, names [i]); 1212 | } 1213 | 1214 | if (written < OptionWidth) 1215 | o.Write (new string (' ', OptionWidth - written)); 1216 | else { 1217 | o.WriteLine (); 1218 | o.Write (new string (' ', OptionWidth)); 1219 | } 1220 | 1221 | WriteDescription (o, s.Description, new string (' ', OptionWidth+2), 1222 | Description_FirstWidth, Description_RemWidth); 1223 | } 1224 | } 1225 | 1226 | void WriteDescription (TextWriter o, string value, string prefix, int firstWidth, int remWidth) 1227 | { 1228 | bool indent = false; 1229 | foreach (string line in GetLines (localizer (GetDescription (value)), firstWidth, remWidth)) { 1230 | if (indent) 1231 | o.Write (prefix); 1232 | o.WriteLine (line); 1233 | indent = true; 1234 | } 1235 | } 1236 | 1237 | bool WriteOptionPrototype (TextWriter o, Option p, ref int written) 1238 | { 1239 | string[] names = p.Names; 1240 | 1241 | int i = GetNextOptionIndex (names, 0); 1242 | if (i == names.Length) 1243 | return false; 1244 | 1245 | if (names [i].Length == 1) { 1246 | Write (o, ref written, " -"); 1247 | Write (o, ref written, names [0]); 1248 | } 1249 | else { 1250 | Write (o, ref written, " --"); 1251 | Write (o, ref written, names [0]); 1252 | } 1253 | 1254 | for ( i = GetNextOptionIndex (names, i+1); 1255 | i < names.Length; i = GetNextOptionIndex (names, i+1)) { 1256 | Write (o, ref written, ", "); 1257 | Write (o, ref written, names [i].Length == 1 ? "-" : "--"); 1258 | Write (o, ref written, names [i]); 1259 | } 1260 | 1261 | if (p.OptionValueType == OptionValueType.Optional || 1262 | p.OptionValueType == OptionValueType.Required) { 1263 | if (p.OptionValueType == OptionValueType.Optional) { 1264 | Write (o, ref written, localizer ("[")); 1265 | } 1266 | Write (o, ref written, localizer ("=" + GetArgumentName (0, p.MaxValueCount, p.Description))); 1267 | string sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0 1268 | ? p.ValueSeparators [0] 1269 | : " "; 1270 | for (int c = 1; c < p.MaxValueCount; ++c) { 1271 | Write (o, ref written, localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description))); 1272 | } 1273 | if (p.OptionValueType == OptionValueType.Optional) { 1274 | Write (o, ref written, localizer ("]")); 1275 | } 1276 | } 1277 | return true; 1278 | } 1279 | 1280 | static int GetNextOptionIndex (string[] names, int i) 1281 | { 1282 | while (i < names.Length && names [i] == "<>") { 1283 | ++i; 1284 | } 1285 | return i; 1286 | } 1287 | 1288 | static void Write (TextWriter o, ref int n, string s) 1289 | { 1290 | n += s.Length; 1291 | o.Write (s); 1292 | } 1293 | 1294 | private static string GetArgumentName (int index, int maxIndex, string description) 1295 | { 1296 | if (description == null) 1297 | return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1); 1298 | string[] nameStart; 1299 | if (maxIndex == 1) 1300 | nameStart = new string[]{"{0:", "{"}; 1301 | else 1302 | nameStart = new string[]{"{" + index + ":"}; 1303 | for (int i = 0; i < nameStart.Length; ++i) { 1304 | int start, j = 0; 1305 | do { 1306 | start = description.IndexOf (nameStart [i], j); 1307 | } while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false); 1308 | if (start == -1) 1309 | continue; 1310 | int end = description.IndexOf ("}", start); 1311 | if (end == -1) 1312 | continue; 1313 | return description.Substring (start + nameStart [i].Length, end - start - nameStart [i].Length); 1314 | } 1315 | return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1); 1316 | } 1317 | 1318 | private static string GetDescription (string description) 1319 | { 1320 | if (description == null) 1321 | return string.Empty; 1322 | StringBuilder sb = new StringBuilder (description.Length); 1323 | int start = -1; 1324 | for (int i = 0; i < description.Length; ++i) { 1325 | switch (description [i]) { 1326 | case '{': 1327 | if (i == start) { 1328 | sb.Append ('{'); 1329 | start = -1; 1330 | } 1331 | else if (start < 0) 1332 | start = i + 1; 1333 | break; 1334 | case '}': 1335 | if (start < 0) { 1336 | if ((i+1) == description.Length || description [i+1] != '}') 1337 | throw new InvalidOperationException ("Invalid option description: " + description); 1338 | ++i; 1339 | sb.Append ("}"); 1340 | } 1341 | else { 1342 | sb.Append (description.Substring (start, i - start)); 1343 | start = -1; 1344 | } 1345 | break; 1346 | case ':': 1347 | if (start < 0) 1348 | goto default; 1349 | start = i + 1; 1350 | break; 1351 | default: 1352 | if (start < 0) 1353 | sb.Append (description [i]); 1354 | break; 1355 | } 1356 | } 1357 | return sb.ToString (); 1358 | } 1359 | 1360 | private static IEnumerable GetLines (string description, int firstWidth, int remWidth) 1361 | { 1362 | return StringCoda.WrappedLines (description, firstWidth, remWidth); 1363 | } 1364 | } 1365 | } 1366 | 1367 | --------------------------------------------------------------------------------