From c524375a01be0c5e6baa77f95d84d5e84143047c Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Mon, 21 Aug 2023 10:51:22 +1200 Subject: [PATCH 1/3] add docs for codegen; stick it in the middle --- _docs/schema/codegen/close.md | 6 + _docs/schema/codegen/schema-codegen.md | 174 ++++++++++++++++++++++ _docs/schema/codegen/title.md | 7 + _docs/schema/datagen/close.md | 2 +- _docs/schema/datagen/schema-datagen.md | 2 +- _docs/schema/datagen/title.md | 2 +- _docs/schema/vocabs/close.md | 2 +- _docs/schema/vocabs/title.md | 2 +- _docs/schema/vocabs/vocabs-data-2022.md | 2 +- _docs/schema/vocabs/vocabs-openapi.md | 2 +- _docs/schema/vocabs/vocabs-unique-keys.md | 2 +- 11 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 _docs/schema/codegen/close.md create mode 100644 _docs/schema/codegen/schema-codegen.md create mode 100644 _docs/schema/codegen/title.md diff --git a/_docs/schema/codegen/close.md b/_docs/schema/codegen/close.md new file mode 100644 index 00000000..4df8c076 --- /dev/null +++ b/_docs/schema/codegen/close.md @@ -0,0 +1,6 @@ +--- +title: __close +close: true +permalink: /schema/codegen/:title/ +order: "1.6.9" +--- diff --git a/_docs/schema/codegen/schema-codegen.md b/_docs/schema/codegen/schema-codegen.md new file mode 100644 index 00000000..5f88c30b --- /dev/null +++ b/_docs/schema/codegen/schema-codegen.md @@ -0,0 +1,174 @@ +--- +layout: page +title: Generating Code from JSON Schema +bookmark: Basics +permalink: /schema/:title/ +icon: fas fa-tag +order: "1.6.1" +--- +*JsonSchema.Net.CodeGeneration* is a tool that can create C# code from JSON Schemas. + +For example, given the schema: + +```json +{ + "title": "MyObject", + "type": "object", + "properties": { + "Foo": { "type": "string" } + } +} +``` + +it can generate a C# class like + +```c# +public class MyObject +{ + public string Foo { get; set; } +} +``` + +## Capabilities {#schema-codegen-capabilities} + +The code generation is currently quite basic. It will generate types for simple custom objects and any named array or dictionary type. + +> Currently `$ref` is unsupported. +{: .prompt-warning } + +### Built-in types + +Built-in types, like strings and arrays, are supported by reference only. These generally will not have type declarations generated for them, however they can appear as types used within other declarations. For example, `string` in the example above is used for the `Foo` property, but there isn't a `string` type declaration included in the output because the type is built-in. + +There is an exception to this behavior for arrays and dictionaries, which is explained [below](#including-a-name). + +## Usage + +There is currently limited support for translating JSON Schema into code. However there is ongoing discussion for an official [JSON Schema code generation vocabulary](https://github.com/json-schema-org/vocab-idl). Please feel free to read up and join in on the effort there. + +### Custom objects + +Generating for custom objects is the real power behind code generation. Being able to read a schema produced by some other developer (e.g. from an OpenAPI document) and automatically create types can save developers a lot of time. + +This library generates custom types for schemas that declare an `object` type and include `title` (for a type name) and `properties` without `additionalProperties`. It will also automatically generate types found nested in the schema. For example + +```json +{ + "title": "MyCustomObject", + "type": "object", + "properties": { + "Foo": { "type": "string" }, + "Bar": { + "title": "Bar", + "type": "object", + "properties": { + "Baz": { "type": "integer" } + } + } + } +} +``` + +generates + +```c# +public class MyCustomObject +{ + public string Foo { get; set; } + public Bar Bar { get; set; } +} + +public class Bar +{ + public int Baz { get; set; } +} +``` + +There is some basic duplicate definition detection that serves two purposes: + +1. It avoids creating multiple declarations for the same type. For example, if `Foo` had `Bar1` and `Bar2` properties, only one `Bar` declaration would be generated. (Again, `$ref` isn't supported yet, so the subschema would need to be repeated for `Bar1` and `Bar2`.) +2. It prevents creating multiple types with the same name. For example, if there are two subschemas with the same name that define two different types, an exception would be thrown indicating the name re-use. + +> There is currently no string transformation logic for type or property names. +{: .prompt-warning } + +### Arrays + +When a schema declares an `array` type and includes an `items` keyword (in the single schema form, not an array of schemas), an array is used. + +```json +{ + "type": "array", + "items": { + "type": "integer" + } +} +``` + +produces no declaration, but using this schema appears as + +```c# +int[] +``` + +### Dictionaries + +When a schema declares an `object` type and only includes `additionalProperties` without `properties`, this models a dictionary. + +```json +{ + "title": "MyIntDictionary", + "type": "object", + "additionalProperties": { + "type": "integer" + } +} +``` + +This also produces no declaration, but using the schema appears as + +```c# +Dictionary +``` + +### Including a name on basic types {#including-a-name} + +When an array or dictionary schema has a `title` keyword, which supplies the name, + +```json +{ + "title": "MyIntArray", + "type": "array", + "items": { + "type": "integer" + } +} +``` + +or + +```json +{ + "title": "MyIntDictionary", + "type": "object", + "additionalProperties": { + "type": "integer" + } +} +``` + +you now get a type declaration inheriting from `List`: + +```c# +public class MyIntArray : List {} +``` + +and + +```c# +public class MyIntDictionary : Dictionary {} +``` + +and usages will correctly appear as `MyIntArray` and `MyIntDictionary`, respectively. + +Other basic types (e.g. strings) will ignore the `title` keyword as these types cannot be inherited. diff --git a/_docs/schema/codegen/title.md b/_docs/schema/codegen/title.md new file mode 100644 index 00000000..1288ceb8 --- /dev/null +++ b/_docs/schema/codegen/title.md @@ -0,0 +1,7 @@ +--- +title: __title +bookmark: Code Generation +permalink: /schema/datagen/:title/ +folder: true +order: "1.6" +--- diff --git a/_docs/schema/datagen/close.md b/_docs/schema/datagen/close.md index 86122ab2..8d522250 100644 --- a/_docs/schema/datagen/close.md +++ b/_docs/schema/datagen/close.md @@ -2,5 +2,5 @@ title: __close close: true permalink: /schema/datagen/:title/ -order: "1.6.9" +order: "1.7.9" --- diff --git a/_docs/schema/datagen/schema-datagen.md b/_docs/schema/datagen/schema-datagen.md index e97ce3ee..e3e4a4c5 100644 --- a/_docs/schema/datagen/schema-datagen.md +++ b/_docs/schema/datagen/schema-datagen.md @@ -4,7 +4,7 @@ title: Generating Sample JSON Data from a Schema bookmark: Basics permalink: /schema/:title/ icon: fas fa-tag -order: "1.6.1" +order: "1.7.1" --- *JsonSchema.Net.DataGeneration* is a tool that can create JSON data instances using a JSON schema as a framework. diff --git a/_docs/schema/datagen/title.md b/_docs/schema/datagen/title.md index 189c4230..b5b0d932 100644 --- a/_docs/schema/datagen/title.md +++ b/_docs/schema/datagen/title.md @@ -3,5 +3,5 @@ title: __title bookmark: Data Generation permalink: /schema/datagen/:title/ folder: true -order: "1.6" +order: "1.7" --- diff --git a/_docs/schema/vocabs/close.md b/_docs/schema/vocabs/close.md index ecf90fb7..8c41892f 100644 --- a/_docs/schema/vocabs/close.md +++ b/_docs/schema/vocabs/close.md @@ -2,5 +2,5 @@ title: __close permalink: /schema/vocabs/:title/ close: true -order: "1.7.9" +order: "1.8.9" --- diff --git a/_docs/schema/vocabs/title.md b/_docs/schema/vocabs/title.md index 89f42aec..9981ac77 100644 --- a/_docs/schema/vocabs/title.md +++ b/_docs/schema/vocabs/title.md @@ -3,5 +3,5 @@ title: __title bookmark: Prebuilt Vocabularies permalink: /schema/vocabs/:title/ folder: true -order: "1.7" +order: "1.8" --- diff --git a/_docs/schema/vocabs/vocabs-data-2022.md b/_docs/schema/vocabs/vocabs-data-2022.md index 407176e8..eecc7883 100644 --- a/_docs/schema/vocabs/vocabs-data-2022.md +++ b/_docs/schema/vocabs/vocabs-data-2022.md @@ -4,7 +4,7 @@ title: A Vocabulary for Accessing Data Stored in JSON bookmark: data permalink: /schema/vocabs/data-2022/ icon: fas fa-tag -order: "1.7.1" +order: "1.8.1" --- ## 1. Purpose {#schema-data-2022-purpose} diff --git a/_docs/schema/vocabs/vocabs-openapi.md b/_docs/schema/vocabs/vocabs-openapi.md index 473bf67c..64284b1a 100644 --- a/_docs/schema/vocabs/vocabs-openapi.md +++ b/_docs/schema/vocabs/vocabs-openapi.md @@ -4,7 +4,7 @@ title: OpenAPI v3.1 Vocabulary bookmark: Open API permalink: /schema/vocabs/openapi/ icon: fas fa-tag -order: "1.7.3" +order: "1.8.3" --- This library adds support for the vocabularies, meta-schemas, and keywords defined by the [OpenAPI v3.1 specification](https://spec.openapis.org/oas/latest.html). diff --git a/_docs/schema/vocabs/vocabs-unique-keys.md b/_docs/schema/vocabs/vocabs-unique-keys.md index 067b8094..e4aa7bda 100644 --- a/_docs/schema/vocabs/vocabs-unique-keys.md +++ b/_docs/schema/vocabs/vocabs-unique-keys.md @@ -4,7 +4,7 @@ title: A Vocabulary for Identifying Uniqueness of Array Items bookmark: uniqueKeys permalink: /schema/vocabs/uniquekeys/ icon: fas fa-tag -order: "1.7.2" +order: "1.8.2" --- ## 1. Purpose {#schema-uniquekeys-purpose} From 1564ed1aee968fa9135fef205926561e667682d6 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Tue, 22 Aug 2023 18:56:11 +1200 Subject: [PATCH 2/3] update for current support --- _docs/schema/codegen/schema-codegen.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/_docs/schema/codegen/schema-codegen.md b/_docs/schema/codegen/schema-codegen.md index 5f88c30b..9ec05afa 100644 --- a/_docs/schema/codegen/schema-codegen.md +++ b/_docs/schema/codegen/schema-codegen.md @@ -33,8 +33,7 @@ public class MyObject The code generation is currently quite basic. It will generate types for simple custom objects and any named array or dictionary type. -> Currently `$ref` is unsupported. -{: .prompt-warning } +`$ref` is generally supported, even for recursive models like linked lists and binary trees. ### Built-in types @@ -89,8 +88,17 @@ There is some basic duplicate definition detection that serves two purposes: 1. It avoids creating multiple declarations for the same type. For example, if `Foo` had `Bar1` and `Bar2` properties, only one `Bar` declaration would be generated. (Again, `$ref` isn't supported yet, so the subschema would need to be repeated for `Bar1` and `Bar2`.) 2. It prevents creating multiple types with the same name. For example, if there are two subschemas with the same name that define two different types, an exception would be thrown indicating the name re-use. -> There is currently no string transformation logic for type or property names. -{: .prompt-warning } +Some basic string transformation occurs: + +| Original | Transformed | +|:-|:-| +| `kebab-case` | `KebabCase` | +| `snake_case` | `SnakeCase` | +| `spaced words` |`SpacedWords` | +| `words-with-2-numbers` | `WordsWith2Numbers` | +| `just-a-letter` | `JustALetter` | + +Anything other conventions will likely result in undesirable code output or an exception. ### Arrays From 8b8182bf77f7feebc0bde277861da2bce25a4072 Mon Sep 17 00:00:00 2001 From: Greg Dennis Date: Wed, 23 Aug 2023 11:32:52 +1200 Subject: [PATCH 3/3] updated to include that $ref is supported --- _docs/schema/codegen/schema-codegen.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/_docs/schema/codegen/schema-codegen.md b/_docs/schema/codegen/schema-codegen.md index 9ec05afa..0b384142 100644 --- a/_docs/schema/codegen/schema-codegen.md +++ b/_docs/schema/codegen/schema-codegen.md @@ -33,7 +33,15 @@ public class MyObject The code generation is currently quite basic. It will generate types for simple custom objects and any named array or dictionary type. -`$ref` is generally supported, even for recursive models like linked lists and binary trees. +`$ref` is generally supported, even for recursive models like linked lists and binary trees, however there is no loop detection, so if you do something like this: + +```json +{ + "$ref": "#" +} +``` + +you'll just get a stack overflow exception. That's on you. Don't do that. ### Built-in types @@ -45,11 +53,13 @@ There is an exception to this behavior for arrays and dictionaries, which is exp There is currently limited support for translating JSON Schema into code. However there is ongoing discussion for an official [JSON Schema code generation vocabulary](https://github.com/json-schema-org/vocab-idl). Please feel free to read up and join in on the effort there. +Currently, the class name is derived from the `title` keyword. There is an open issue in the repository above to discuss using this keyword. It's currently leaning toward the vocabulary defining a custom keyword, but as nothing has been decided yet, `title` is used here for now. + ### Custom objects Generating for custom objects is the real power behind code generation. Being able to read a schema produced by some other developer (e.g. from an OpenAPI document) and automatically create types can save developers a lot of time. -This library generates custom types for schemas that declare an `object` type and include `title` (for a type name) and `properties` without `additionalProperties`. It will also automatically generate types found nested in the schema. For example +This library generates custom types for schemas that declare an `object` type and include `title` and `properties` without `additionalProperties`. It will also automatically generate types found nested in the schema. For example ```json { @@ -85,10 +95,10 @@ public class Bar There is some basic duplicate definition detection that serves two purposes: -1. It avoids creating multiple declarations for the same type. For example, if `Foo` had `Bar1` and `Bar2` properties, only one `Bar` declaration would be generated. (Again, `$ref` isn't supported yet, so the subschema would need to be repeated for `Bar1` and `Bar2`.) +1. It avoids creating multiple declarations for the same type. For example, if `Foo` had `Bar1` and `Bar2` properties, only one `Bar` declaration would be generated. Ideally this kind of duplication should be defined in the schema using a `$ref`. 2. It prevents creating multiple types with the same name. For example, if there are two subschemas with the same name that define two different types, an exception would be thrown indicating the name re-use. -Some basic string transformation occurs: +For type and property naming, some basic string transformation occurs: | Original | Transformed | |:-|:-| @@ -113,7 +123,7 @@ When a schema declares an `array` type and includes an `items` keyword (in the s } ``` -produces no declaration, but using this schema appears as +produces no declaration, but using this schema (e.g. to define object properties) appears as ```c# int[] @@ -141,7 +151,7 @@ Dictionary ### Including a name on basic types {#including-a-name} -When an array or dictionary schema has a `title` keyword, which supplies the name, +When you have an array or dictionary schema with a `title` keyword ```json { @@ -165,13 +175,13 @@ or } ``` -you now get a type declaration inheriting from `List`: +you now get a type declaration inheriting from `List` ```c# public class MyIntArray : List {} ``` -and +and `Dictionary` ```c# public class MyIntDictionary : Dictionary {}