├── 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 |
--------------------------------------------------------------------------------