Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: csharp generate not null properties #969

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/presets.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ This preset is a generator for the meta model `ConstrainedObjectModel` and [can
| `accessor` | A method to extend rendered given property accessor. | `property` object as a [`ConstrainedObjectPropertyModel`](./internal-model.md#the-constrained-meta-model) instance. |
| `setter` | A method to extend setter for a given property. | `property` object as a [`ConstrainedObjectPropertyModel`](./internal-model.md#the-constrained-meta-model) instance. |
| `getter` | A method to extend getter for a given property. | `property` object as a [`ConstrainedObjectPropertyModel`](./internal-model.md#the-constrained-meta-model) instance. |
| `propertyType` | A method to extend type definition of a given property. | `property` object as a [`ConstrainedObjectPropertyModel`](./internal-model.md#the-constrained-meta-model) instance. |

#### **Enum**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ exports[`Should be able to render auto-implemented properties in CSharp and shou
Array [
"public class Root
{
public dynamic[]? Emails { get; set; }
public string? StringProp { get; set; }
public double? NumberProp { get; set; }
public dynamic[]? NullArray { get; set; }
public string? NullString { get; set; }
public double? NullNumber { get; set; }
public dynamic[] NonNullArray { get; set; }
public string NonNullString { get; set; }
public double NonNullNumber { get; set; }
}",
]
`;
20 changes: 17 additions & 3 deletions examples/csharp-auto-implemented-properties/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,34 @@ const jsonSchemaDraft7 = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
additionalProperties: false,
required: ['nonNullNumber', 'nonNullString', 'nonNullArray'],
properties: {
emails: {
nullArray: {
type: 'array',
items: {
type: 'string',
format: 'email'
}
},
stringProp: {
nullString: {
type: 'string'
},
numberProp: {
nullNumber: {
type: 'number'
},
nonNullArray: {
type: 'array',
items: {
type: 'string',
format: 'email'
}
},
nonNullString: {
type: 'string'
},
nonNullNumber: {
type: 'number'
}
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ Array [
"public class Root
{
private bool requiredBoolean;
private bool notRequiredBoolean;
private bool? notRequiredBoolean;
private string requiredString;
private string notRequiredString;
private string? notRequiredString;

public bool RequiredBoolean
{
get { return requiredBoolean; }
set { requiredBoolean = value; }
}

public bool NotRequiredBoolean
public bool? NotRequiredBoolean
{
get { return notRequiredBoolean; }
set { notRequiredBoolean = value; }
Expand All @@ -27,7 +27,7 @@ Array [
set { requiredString = value; }
}

public string NotRequiredString
public string? NotRequiredString
{
get { return notRequiredString; }
set { notRequiredString = value; }
Expand Down
1 change: 1 addition & 0 deletions src/generators/csharp/CSharpPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CSHARP_DEFAULT_ENUM_PRESET, EnumRenderer } from './renderers/EnumRender
// Our class preset uses custom `accessor` hook to craft getter and setters.
export interface CsharpClassPreset<O> extends ClassPreset<ClassRenderer, O> {
accessor?: (args: PresetArgs<ClassRenderer, O, ConstrainedObjectModel> & PropertyArgs) => Promise<string> | string;
propertyType?: (args: PresetArgs<ClassRenderer, O, ConstrainedObjectModel> & PropertyArgs) => Promise<string> | string;
}

export type ClassPresetType<O> = CsharpClassPreset<O>;
Expand Down
24 changes: 19 additions & 5 deletions src/generators/csharp/renderers/ClassRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CSharpRenderer } from '../CSharpRenderer';
import { ConstrainedDictionaryModel, ConstrainedObjectModel, ConstrainedObjectPropertyModel} from '../../../models';
import { ConstrainedDictionaryModel, ConstrainedObjectModel, ConstrainedObjectPropertyModel } from '../../../models';
import { pascalCase } from 'change-case';
import { CsharpClassPreset } from '../CSharpPreset';
import { CSharpOptions } from '../CSharpGenerator';
Expand Down Expand Up @@ -71,27 +71,36 @@ ${this.indent(this.renderBlock(content, 2))}
runSetterPreset(property: ConstrainedObjectPropertyModel): Promise<string> {
return this.runPreset('setter', { property, options: this.options, renderer: this });
}

runPropertyTypePreset(property: ConstrainedObjectPropertyModel): Promise<string> {
return this.runPreset('propertyType', { property, options: this.options, renderer: this });
}
}

export const CSHARP_DEFAULT_CLASS_PRESET: CsharpClassPreset<CSharpOptions> = {
self({ renderer }) {
return renderer.defaultSelf();
},
async property({ renderer, property, options }) {
const type = await renderer.runPropertyTypePreset(property);

if (options?.autoImplementedProperties) {
const getter = await renderer.runGetterPreset(property);
const setter = await renderer.runSetterPreset(property);
return `public ${property.property.type}${property.required === false && '?'} ${pascalCase(property.propertyName)} { ${getter} ${setter} }`;
return `public ${type} ${pascalCase(property.propertyName)} { ${getter} ${setter} }`;
}
return `private ${property.property.type} ${property.propertyName};`;
return `private ${type} ${property.propertyName};`;
},
async accessor({ renderer, options, property }) {
const formattedAccessorName = pascalCase(property.propertyName);
const type = await renderer.runPropertyTypePreset(property);

if (options?.autoImplementedProperties) {
return '';
}

return `public ${property.property.type} ${formattedAccessorName}
const formattedAccessorName = pascalCase(property.propertyName);

return `public ${type} ${formattedAccessorName}
{
${await renderer.runGetterPreset(property)}
${await renderer.runSetterPreset(property)}
Expand All @@ -108,5 +117,10 @@ export const CSHARP_DEFAULT_CLASS_PRESET: CsharpClassPreset<CSharpOptions> = {
return 'set;';
}
return `set { ${property.propertyName} = value; }`;
},
propertyType({ property }) {
const isNullable = property.required === false;

return `${property.property.type}${isNullable ? '?' : ''}`;
}
};
48 changes: 24 additions & 24 deletions test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
exports[`CSharpGenerator class renderer should be able to overwrite accessor preset hook 1`] = `
"public class CustomClass
{
private string property;
private Dictionary<string, string> additionalProperties;
private string? property;
private Dictionary<string, string>? additionalProperties;

my own custom factory

Expand All @@ -18,13 +18,13 @@ exports[`CSharpGenerator class renderer should be able to overwrite property pre
my own property
my own property

public string Property
public string? Property
{
get { return property; }
set { property = value; }
}

public Dictionary<string, string> AdditionalProperties
public Dictionary<string, string>? AdditionalProperties
{
get { return additionalProperties; }
set { additionalProperties = value; }
Expand All @@ -39,11 +39,11 @@ exports[`CSharpGenerator should render \`class\` type 1`] = `
private string city;
private string state;
private double houseNumber;
private bool marriage;
private dynamic members;
private dynamic[] tupleType;
private bool? marriage;
private dynamic? members;
private dynamic[]? tupleType;
private dynamic[] arrayType;
private Dictionary<string, string> additionalProperties;
private Dictionary<string, string>? additionalProperties;

public string StreetName
{
Expand All @@ -69,19 +69,19 @@ exports[`CSharpGenerator should render \`class\` type 1`] = `
set { houseNumber = value; }
}

public bool Marriage
public bool? Marriage
{
get { return marriage; }
set { marriage = value; }
}

public dynamic Members
public dynamic? Members
{
get { return members; }
set { members = value; }
}

public dynamic[] TupleType
public dynamic[]? TupleType
{
get { return tupleType; }
set { tupleType = value; }
Expand All @@ -93,7 +93,7 @@ exports[`CSharpGenerator should render \`class\` type 1`] = `
set { arrayType = value; }
}

public Dictionary<string, string> AdditionalProperties
public Dictionary<string, string>? AdditionalProperties
{
get { return additionalProperties; }
set { additionalProperties = value; }
Expand Down Expand Up @@ -194,11 +194,11 @@ exports[`CSharpGenerator should render models and their dependencies 1`] = `
private string city;
private string state;
private double houseNumber;
private bool marriage;
private dynamic members;
private bool? marriage;
private dynamic? members;
private dynamic[] arrayType;
private OtherModel otherModel;
private Dictionary<string, dynamic> additionalProperties;
private OtherModel? otherModel;
private Dictionary<string, dynamic>? additionalProperties;

public string StreetName
{
Expand All @@ -224,13 +224,13 @@ exports[`CSharpGenerator should render models and their dependencies 1`] = `
set { houseNumber = value; }
}

public bool Marriage
public bool? Marriage
{
get { return marriage; }
set { marriage = value; }
}

public dynamic Members
public dynamic? Members
{
get { return members; }
set { members = value; }
Expand All @@ -242,13 +242,13 @@ exports[`CSharpGenerator should render models and their dependencies 1`] = `
set { arrayType = value; }
}

public OtherModel OtherModel
public OtherModel? OtherModel
{
get { return otherModel; }
set { otherModel = value; }
}

public Dictionary<string, dynamic> AdditionalProperties
public Dictionary<string, dynamic>? AdditionalProperties
{
get { return additionalProperties; }
set { additionalProperties = value; }
Expand All @@ -264,16 +264,16 @@ exports[`CSharpGenerator should render models and their dependencies 2`] = `

public class OtherModel
{
private string streetName;
private Dictionary<string, dynamic> additionalProperties;
private string? streetName;
private Dictionary<string, dynamic>? additionalProperties;

public string StreetName
public string? StreetName
{
get { return streetName; }
set { streetName = value; }
}

public Dictionary<string, dynamic> AdditionalProperties
public Dictionary<string, dynamic>? AdditionalProperties
{
get { return additionalProperties; }
set { additionalProperties = value; }
Expand Down
Loading