From 3c9946b3651f3d3cab180770f83215937253e2ab Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Tue, 13 Feb 2024 19:19:58 +0100 Subject: [PATCH 1/8] feat: add constant constrainer --- .../csharp/constrainer/ConstantConstrainer.ts | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/generators/csharp/constrainer/ConstantConstrainer.ts b/src/generators/csharp/constrainer/ConstantConstrainer.ts index 797006c4ec..a00d7a8adc 100644 --- a/src/generators/csharp/constrainer/ConstantConstrainer.ts +++ b/src/generators/csharp/constrainer/ConstantConstrainer.ts @@ -1,7 +1,53 @@ +import { + ConstrainedEnumModel, + ConstrainedMetaModel, + ConstrainedMetaModelOptionsConst, + ConstrainedReferenceModel, + ConstrainedStringModel +} from '../../../models'; import { CSharpConstantConstraint } from '../CSharpGenerator'; +const getConstrainedEnumModelConstant = (args: { + constrainedMetaModel: ConstrainedMetaModel; + constrainedEnumModel: ConstrainedEnumModel; + constOptions: ConstrainedMetaModelOptionsConst; +}) => { + const constrainedEnumValueModel = args.constrainedEnumModel.values.find( + (value) => value.originalInput === args.constOptions.originalInput + ); + + if (constrainedEnumValueModel) { + return `${args.constrainedMetaModel.type}.${constrainedEnumValueModel.key}`; + } +}; + export function defaultConstantConstraints(): CSharpConstantConstraint { - return () => { + return ({ constrainedMetaModel }) => { + const constOptions = constrainedMetaModel.options.const; + + if (!constOptions) { + return undefined; + } + + if ( + constrainedMetaModel instanceof ConstrainedReferenceModel && + constrainedMetaModel.ref instanceof ConstrainedEnumModel + ) { + return getConstrainedEnumModelConstant({ + constrainedMetaModel, + constrainedEnumModel: constrainedMetaModel.ref, + constOptions + }); + } else if (constrainedMetaModel instanceof ConstrainedEnumModel) { + return getConstrainedEnumModelConstant({ + constrainedMetaModel, + constrainedEnumModel: constrainedMetaModel, + constOptions + }); + } else if (constrainedMetaModel instanceof ConstrainedStringModel) { + return `"${constOptions.originalInput}"`; + } + return undefined; }; } From 8c8282c2840250101c4380a931bac9d9d9279c64 Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Tue, 13 Feb 2024 19:20:15 +0100 Subject: [PATCH 2/8] feat: enable renderers to handle constants --- src/generators/csharp/renderers/ClassRenderer.ts | 10 ++++++++++ src/generators/csharp/renderers/RecordRenderer.ts | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/generators/csharp/renderers/ClassRenderer.ts b/src/generators/csharp/renderers/ClassRenderer.ts index f0dc96e8ad..e32b7f7df1 100644 --- a/src/generators/csharp/renderers/ClassRenderer.ts +++ b/src/generators/csharp/renderers/ClassRenderer.ts @@ -115,11 +115,21 @@ export const CSHARP_DEFAULT_CLASS_PRESET: CsharpClassPreset = { const getter = await renderer.runGetterPreset(property); const setter = await renderer.runSetterPreset(property); + if (property.property.options.const) { + return `public const ${property.property.type} ${pascalCase( + property.propertyName + )} { ${getter} } = ${property.property.options.const.value};`; + } + const semiColon = nullablePropertyEnding !== '' ? ';' : ''; return `public ${property.property.type} ${pascalCase( property.propertyName )} { ${getter} ${setter} }${nullablePropertyEnding}${semiColon}`; } + + if (property.property.options.const) { + return `private const ${property.property.type} ${property.propertyName} = ${property.property.options.const.value};`; + } return `private ${property.property.type} ${property.propertyName}${nullablePropertyEnding};`; }, async accessor({ renderer, options, property }) { diff --git a/src/generators/csharp/renderers/RecordRenderer.ts b/src/generators/csharp/renderers/RecordRenderer.ts index eb2fe1c088..b04e5474af 100644 --- a/src/generators/csharp/renderers/RecordRenderer.ts +++ b/src/generators/csharp/renderers/RecordRenderer.ts @@ -77,6 +77,11 @@ export const CSHARP_DEFAULT_RECORD_PRESET: CsharpRecordPreset = { async property({ renderer, property }) { const getter = await renderer.runGetterPreset(property); const setter = await renderer.runSetterPreset(property); + if (property.property.options.const) { + return `public const ${property.property.type} ${pascalCase( + property.propertyName + )} = ${property.property.options.const.value};`; + } return `public ${property.required ? 'required ' : ''}${ property.property.type } ${pascalCase(property.propertyName)} { ${getter} ${setter} }`; From b79a2b156738aea0f6804e0c74104a07ba04cd93 Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Tue, 13 Feb 2024 19:20:22 +0100 Subject: [PATCH 3/8] feat: add tests --- .../generators/csharp/CSharpGenerator.spec.ts | 48 ++++++++++++++++++- .../CSharpGenerator.spec.ts.snap | 28 +++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/test/generators/csharp/CSharpGenerator.spec.ts b/test/generators/csharp/CSharpGenerator.spec.ts index 6bf12515ae..86f81aa603 100644 --- a/test/generators/csharp/CSharpGenerator.spec.ts +++ b/test/generators/csharp/CSharpGenerator.spec.ts @@ -148,6 +148,28 @@ describe('CSharpGenerator', () => { ]); }); + test('should generate a const string in record', async () => { + const doc = { + $id: '_address', + type: 'object', + properties: { + property: { type: 'string', const: 'test' } + }, + required: ['property'], + additionalProperties: { + type: 'string' + } + }; + + generator.options.modelType = 'record'; + const models = await generator.generate(doc); + expect(models).toHaveLength(1); + expect(models[0].result).toMatchSnapshot(); + expect(models[0].dependencies).toEqual([ + 'using System.Collections.Generic;' + ]); + }); + test('should render `enum` type', async () => { const doc = { $id: 'Things', @@ -166,8 +188,7 @@ describe('CSharpGenerator', () => { enum: ['test+', 'test', 'test-', 'test?!', '*test'] }; - generator = new CSharpGenerator(); - + generator.options.modelType = 'record'; const models = await generator.generate(doc); expect(models).toHaveLength(1); expect(models[0].result).toMatchSnapshot(); @@ -304,5 +325,28 @@ describe('CSharpGenerator', () => { 'using System.Collections.Generic;' ]); }); + + test('should generate a const string', async () => { + const doc = { + $id: 'CustomClass', + type: 'object', + properties: { + property: { type: 'string', const: 'test' } + }, + additionalProperties: { + type: 'string' + }, + required: ['property'] + }; + + generator = new CSharpGenerator(); + + const models = await generator.generate(doc); + expect(models).toHaveLength(1); + expect(models[0].result).toMatchSnapshot(); + expect(models[0].dependencies).toEqual([ + 'using System.Collections.Generic;' + ]); + }); }); }); diff --git a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap index 995ae5e001..9c4c33600f 100644 --- a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap +++ b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap @@ -32,6 +32,34 @@ exports[`CSharpGenerator class renderer should be able to overwrite property pre }" `; +exports[`CSharpGenerator class renderer should generate a const string 1`] = ` +"public partial class CustomClass +{ + private const string property = \\"test\\"; + private Dictionary? additionalProperties; + + public string Property + { + get { return property; } + set { property = value; } + } + + public Dictionary? AdditionalProperties + { + get { return additionalProperties; } + set { additionalProperties = value; } + } +}" +`; + +exports[`CSharpGenerator should generate a const string in record 1`] = ` +"public partial record Address +{ + public const string Property = \\"test\\"; + public Dictionary? AdditionalProperties { get; init; } +}" +`; + exports[`CSharpGenerator should render \`class\` type 1`] = ` "public partial class Address { From 188b480f06e0270435bc160541d158ee5eebf6e5 Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Tue, 13 Feb 2024 19:33:42 +0100 Subject: [PATCH 4/8] fix: dont generate setter for const property --- src/generators/csharp/renderers/ClassRenderer.ts | 7 +++++++ .../csharp/__snapshots__/CSharpGenerator.spec.ts.snap | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/generators/csharp/renderers/ClassRenderer.ts b/src/generators/csharp/renderers/ClassRenderer.ts index e32b7f7df1..a5fc421572 100644 --- a/src/generators/csharp/renderers/ClassRenderer.ts +++ b/src/generators/csharp/renderers/ClassRenderer.ts @@ -138,6 +138,13 @@ export const CSHARP_DEFAULT_CLASS_PRESET: CsharpClassPreset = { return ''; } + if (property.property.options.const) { + return `public ${property.property.type} ${formattedAccessorName} +{ + ${await renderer.runGetterPreset(property)} +}`; + } + return `public ${property.property.type} ${formattedAccessorName} { ${await renderer.runGetterPreset(property)} diff --git a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap index 9c4c33600f..ca19fd4373 100644 --- a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap +++ b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap @@ -41,7 +41,6 @@ exports[`CSharpGenerator class renderer should generate a const string 1`] = ` public string Property { get { return property; } - set { property = value; } } public Dictionary? AdditionalProperties From 573e9ed3b10d9554a133652f2eb1742ee135840c Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Sun, 18 Feb 2024 12:22:09 +0100 Subject: [PATCH 5/8] fix: jsonSerializerPreset should not set const instance property --- .../csharp/presets/JsonSerializerPreset.ts | 3 +++ .../csharp/presets/JsonSerializerPreset.spec.ts | 1 + .../__snapshots__/JsonSerializerPreset.spec.ts.snap | 12 ++++++++++++ 3 files changed, 16 insertions(+) diff --git a/src/generators/csharp/presets/JsonSerializerPreset.ts b/src/generators/csharp/presets/JsonSerializerPreset.ts index 2299cfbec0..f495859761 100644 --- a/src/generators/csharp/presets/JsonSerializerPreset.ts +++ b/src/generators/csharp/presets/JsonSerializerPreset.ts @@ -145,6 +145,9 @@ function renderDeserializeProperties(model: ConstrainedObjectModel) { instance.${pascalProp}.Add(propertyName, deserializedValue); continue;`; } + if (propModel.property.options.const) { + return ''; + } return `if (propertyName == "${propModel.unconstrainedPropertyName}") { var value = ${renderDeserializeProperty(propModel)}; diff --git a/test/generators/csharp/presets/JsonSerializerPreset.spec.ts b/test/generators/csharp/presets/JsonSerializerPreset.spec.ts index b7cc944833..e801b9f087 100644 --- a/test/generators/csharp/presets/JsonSerializerPreset.spec.ts +++ b/test/generators/csharp/presets/JsonSerializerPreset.spec.ts @@ -9,6 +9,7 @@ const doc = { required: ['string prop'], properties: { 'string prop': { type: 'string' }, + 'const string prop': { type: 'string', const: 'abc' }, numberProp: { type: 'number' }, enumProp: { $id: 'EnumTest', diff --git a/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap b/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap index 21ac576590..f4138ec308 100644 --- a/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap +++ b/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap @@ -5,6 +5,7 @@ exports[`JSON serializer preset should render serialize and deserialize converte public partial class Test { private string stringProp; + private const string? constStringProp = \\"abc\\"; private double? numberProp; private EnumTest? enumProp; private NestedTest? objectProp; @@ -16,6 +17,11 @@ public partial class Test set { stringProp = value; } } + public string? ConstStringProp + { + get { return constStringProp; } + } + public double? NumberProp { get { return numberProp; } @@ -77,6 +83,7 @@ internal class TestConverter : JsonConverter instance.StringProp = value; continue; } + if (propertyName == \\"numberProp\\") { var value = JsonSerializer.Deserialize(ref reader, options); @@ -119,6 +126,11 @@ internal class TestConverter : JsonConverter writer.WritePropertyName(\\"string prop\\"); JsonSerializer.Serialize(writer, value.StringProp, options); } + if(value.ConstStringProp != null) { + // write property name and let the serializer serialize the value itself + writer.WritePropertyName(\\"const string prop\\"); + JsonSerializer.Serialize(writer, value.ConstStringProp, options); + } if(value.NumberProp != null) { // write property name and let the serializer serialize the value itself writer.WritePropertyName(\\"numberProp\\"); From f7e33bb4ec5acf0bd41e563320d751e944166e4a Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Sun, 18 Feb 2024 12:45:00 +0100 Subject: [PATCH 6/8] feat: newtonsoftSerializerPreset should not set const instance property --- .../csharp/presets/NewtonsoftSerializerPreset.ts | 3 +++ .../presets/NewtonsoftSerializerPreset.spec.ts | 1 + .../NewtonsoftSerializerPreset.spec.ts.snap | 13 ++++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts b/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts index 8c803ae484..a9de079369 100644 --- a/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts +++ b/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts @@ -94,6 +94,9 @@ function renderDeserialize({ ) { toValue = `${prop.property.name}Extensions.To${prop.property.name}(jo["${prop.unconstrainedPropertyName}"].ToString())`; } + if (prop.property.options.const) { + return ''; + } return `if(jo["${prop.unconstrainedPropertyName}"] != null) { value.${propertyAccessor} = ${toValue}; }`; diff --git a/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts b/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts index 08eae68dfb..b6633ee4f4 100644 --- a/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts +++ b/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts @@ -9,6 +9,7 @@ const doc = { required: ['string prop'], properties: { 'string prop': { type: 'string' }, + 'const string prop': { type: 'string', const: 'abc' }, numberProp: { type: 'number' }, enumProp: { $id: 'EnumTest', diff --git a/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap b/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap index 3f7da982d8..413ce97df9 100644 --- a/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap +++ b/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap @@ -5,6 +5,7 @@ exports[`Newtonsoft JSON serializer preset should render serialize and deseriali public partial class Test { private string stringProp; + private const string? constStringProp = \\"abc\\"; private double? numberProp; private EnumTest? enumProp; private NestedTest? objectProp; @@ -16,6 +17,11 @@ public partial class Test set { stringProp = value; } } + public string? ConstStringProp + { + get { return constStringProp; } + } + public double? NumberProp { get { return numberProp; } @@ -51,6 +57,7 @@ public class TestConverter : JsonConverter if(jo[\\"string prop\\"] != null) { value.StringProp = jo[\\"string prop\\"].ToObject(serializer); } + if(jo[\\"numberProp\\"] != null) { value.NumberProp = jo[\\"numberProp\\"].ToObject(serializer); } @@ -61,7 +68,7 @@ if(jo[\\"objectProp\\"] != null) { value.ObjectProp = jo[\\"objectProp\\"].ToObject(serializer); } - var additionalProperties = jo.Properties().Where((prop) => prop.Name != \\"string prop\\" || prop.Name != \\"numberProp\\" || prop.Name != \\"enumProp\\" || prop.Name != \\"objectProp\\"); + var additionalProperties = jo.Properties().Where((prop) => prop.Name != \\"string prop\\" || prop.Name != \\"const string prop\\" || prop.Name != \\"numberProp\\" || prop.Name != \\"enumProp\\" || prop.Name != \\"objectProp\\"); value.AdditionalProperties = new Dictionary(); foreach (var additionalProperty in additionalProperties) @@ -78,6 +85,10 @@ if(jo[\\"objectProp\\"] != null) { { jo.Add(\\"string prop\\", JToken.FromObject(value.StringProp, serializer)); } +if (value.ConstStringProp != null) +{ + jo.Add(\\"const string prop\\", JToken.FromObject(value.ConstStringProp, serializer)); +} if (value.NumberProp != null) { jo.Add(\\"numberProp\\", JToken.FromObject(value.NumberProp, serializer)); From abd2fab918777b1798bc4d9db61ddd989bfa7ed7 Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Sun, 18 Feb 2024 12:48:34 +0100 Subject: [PATCH 7/8] feat: dont render unnecessary empty line for const props --- .../csharp/presets/JsonSerializerPreset.ts | 34 ++++++++++--------- .../presets/NewtonsoftSerializerPreset.ts | 30 ++++++++-------- .../JsonSerializerPreset.spec.ts.snap | 1 - .../NewtonsoftSerializerPreset.spec.ts.snap | 1 - 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/generators/csharp/presets/JsonSerializerPreset.ts b/src/generators/csharp/presets/JsonSerializerPreset.ts index f495859761..3fbde99d18 100644 --- a/src/generators/csharp/presets/JsonSerializerPreset.ts +++ b/src/generators/csharp/presets/JsonSerializerPreset.ts @@ -131,30 +131,32 @@ function renderDeserializeProperty(model: ConstrainedObjectPropertyModel) { function renderDeserializeProperties(model: ConstrainedObjectModel) { const propertyEntries = Object.entries(model.properties || {}); - const deserializeProperties = propertyEntries.map(([prop, propModel]) => { - const pascalProp = pascalCase(prop); - //Unwrapped dictionary properties, need to be unwrapped in JSON - if ( - propModel.property instanceof ConstrainedDictionaryModel && - propModel.property.serializationType === 'unwrap' - ) { - return `if(instance.${pascalProp} == null) { instance.${pascalProp} = new Dictionary<${ - propModel.property.key.type - }, ${propModel.property.value.type}>(); } + const deserializeProperties = propertyEntries + .map(([prop, propModel]) => { + const pascalProp = pascalCase(prop); + //Unwrapped dictionary properties, need to be unwrapped in JSON + if ( + propModel.property instanceof ConstrainedDictionaryModel && + propModel.property.serializationType === 'unwrap' + ) { + return `if(instance.${pascalProp} == null) { instance.${pascalProp} = new Dictionary<${ + propModel.property.key.type + }, ${propModel.property.value.type}>(); } var deserializedValue = ${renderDeserializeProperty(propModel)}; instance.${pascalProp}.Add(propertyName, deserializedValue); continue;`; - } - if (propModel.property.options.const) { - return ''; - } - return `if (propertyName == "${propModel.unconstrainedPropertyName}") + } + if (propModel.property.options.const) { + return undefined; + } + return `if (propertyName == "${propModel.unconstrainedPropertyName}") { var value = ${renderDeserializeProperty(propModel)}; instance.${pascalProp} = value; continue; }`; - }); + }) + .filter((prop): prop is string => !!prop); return deserializeProperties.join('\n'); } diff --git a/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts b/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts index a9de079369..d36f3ae4ba 100644 --- a/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts +++ b/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts @@ -85,22 +85,24 @@ function renderDeserialize({ !(prop.property instanceof ConstrainedDictionaryModel) || prop.property.serializationType === 'normal' ); - const corePropsRead = coreProps.map((prop) => { - const propertyAccessor = pascalCase(prop.propertyName); - let toValue = `jo["${prop.unconstrainedPropertyName}"].ToObject<${prop.property.type}>(serializer)`; - if ( - prop.property instanceof ConstrainedReferenceModel && - prop.property.ref instanceof ConstrainedEnumModel - ) { - toValue = `${prop.property.name}Extensions.To${prop.property.name}(jo["${prop.unconstrainedPropertyName}"].ToString())`; - } - if (prop.property.options.const) { - return ''; - } - return `if(jo["${prop.unconstrainedPropertyName}"] != null) { + const corePropsRead = coreProps + .map((prop) => { + const propertyAccessor = pascalCase(prop.propertyName); + let toValue = `jo["${prop.unconstrainedPropertyName}"].ToObject<${prop.property.type}>(serializer)`; + if ( + prop.property instanceof ConstrainedReferenceModel && + prop.property.ref instanceof ConstrainedEnumModel + ) { + toValue = `${prop.property.name}Extensions.To${prop.property.name}(jo["${prop.unconstrainedPropertyName}"].ToString())`; + } + if (prop.property.options.const) { + return undefined; + } + return `if(jo["${prop.unconstrainedPropertyName}"] != null) { value.${propertyAccessor} = ${toValue}; }`; - }); + }) + .filter((prop): prop is string => !!prop); const nonDictionaryPropCheck = coreProps.map((prop) => { return `prop.Name != "${prop.unconstrainedPropertyName}"`; }); diff --git a/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap b/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap index f4138ec308..4a55715ab4 100644 --- a/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap +++ b/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap @@ -83,7 +83,6 @@ internal class TestConverter : JsonConverter instance.StringProp = value; continue; } - if (propertyName == \\"numberProp\\") { var value = JsonSerializer.Deserialize(ref reader, options); diff --git a/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap b/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap index 413ce97df9..99660f9e86 100644 --- a/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap +++ b/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap @@ -57,7 +57,6 @@ public class TestConverter : JsonConverter if(jo[\\"string prop\\"] != null) { value.StringProp = jo[\\"string prop\\"].ToObject(serializer); } - if(jo[\\"numberProp\\"] != null) { value.NumberProp = jo[\\"numberProp\\"].ToObject(serializer); } From b6a4f2f8e55b4236c5c9b23b65890d2676172c07 Mon Sep 17 00:00:00 2001 From: Moritz Kalwa Date: Sun, 18 Feb 2024 15:57:03 +0100 Subject: [PATCH 8/8] feat: migration guide --- docs/migrations/version-3-to-4.md | 32 ++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/migrations/version-3-to-4.md b/docs/migrations/version-3-to-4.md index 8bdafbb228..2d98d6aa64 100644 --- a/docs/migrations/version-3-to-4.md +++ b/docs/migrations/version-3-to-4.md @@ -28,4 +28,34 @@ but will now generate: interface AnonymousSchema_1 { aa_00_testAttribute?: string; } -``` \ No newline at end of file +``` + +## C# + +### Constant values are now properly rendered as const properties + +This example used to generate a `string` with a getter and setter, but will now generate a const string that is initialized to the const value provided. + +```yaml +type: object +properties: + property: + type: string + const: 'abc' +``` + +will generate + +```csharp +public class TestClass { + private const string property = "test"; + + public string Property + { + get { return property; } + } + ... +} +``` + +Notice that `Property` no longer has a `set` method. This might break existing models. \ No newline at end of file