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

refactor: add object property model #758

Merged
Merged
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
4 changes: 2 additions & 2 deletions src/generators/csharp/constrainer/PropertyKeyConstrainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};

return ({propertyKey, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = propertyKey;
return ({objectPropertyModel, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = objectPropertyModel.propertyName;

constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
Expand Down
4 changes: 2 additions & 2 deletions src/generators/go/constrainer/PropertyKeyConstrainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};

return ({propertyKey, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = propertyKey;
return ({objectPropertyModel, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = objectPropertyModel.propertyName;

constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
Expand Down
4 changes: 2 additions & 2 deletions src/generators/java/constrainer/PropertyKeyConstrainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};

return ({propertyKey, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = propertyKey;
return ({objectPropertyModel, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = objectPropertyModel.propertyName;

constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};

return ({propertyKey, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = propertyKey;
return ({objectPropertyModel, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = objectPropertyModel.propertyName;

constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};

return ({propertyKey, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = propertyKey;
return ({objectPropertyModel, constrainedObjectModel, objectModel}) => {
let constrainedPropertyKey = objectPropertyModel.propertyName;

constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
Expand Down
12 changes: 8 additions & 4 deletions src/helpers/CommonModelToMetaModel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { CommonModel, MetaModel, UnionModel, ObjectModel, DictionaryModel, StringModel, TupleModel, TupleValueModel, ArrayModel, BooleanModel, IntegerModel, FloatModel, EnumModel, EnumValueModel} from '../models';
import { CommonModel, MetaModel, UnionModel, ObjectModel, DictionaryModel, StringModel, TupleModel, TupleValueModel, ArrayModel, BooleanModel, IntegerModel, FloatModel, EnumModel, EnumValueModel, ObjectPropertyModel} from '../models';

export function convertToMetaModel(jsonSchemaModel: CommonModel): MetaModel {
const modelName = jsonSchemaModel.$id || 'undefined';
Expand Down Expand Up @@ -123,7 +123,9 @@ export function convertToObjectModel(jsonSchemaModel: CommonModel, name: string)
}
const metaModel = new ObjectModel(name, jsonSchemaModel.originalInput, {});
for (const [propertyName, prop] of Object.entries(jsonSchemaModel.properties || {})) {
metaModel.properties[String(propertyName)] = convertToMetaModel(prop);
const isRequired = jsonSchemaModel.isRequired(propertyName);
const propertyModel = new ObjectPropertyModel(propertyName, isRequired, convertToMetaModel(prop));
metaModel.properties[String(propertyName)] = propertyModel;
}

if (jsonSchemaModel.additionalProperties !== undefined) {
Expand All @@ -132,7 +134,8 @@ export function convertToObjectModel(jsonSchemaModel: CommonModel, name: string)
const keyModel = new StringModel(propertyName, jsonSchemaModel.additionalProperties.originalInput);
const valueModel = convertToMetaModel(jsonSchemaModel.additionalProperties);
const dictionaryModel = new DictionaryModel(propertyName, jsonSchemaModel.additionalProperties.originalInput, keyModel, valueModel, 'unwrap');
metaModel.properties[String(propertyName)] = dictionaryModel;
const propertyModel = new ObjectPropertyModel(propertyName, false, dictionaryModel);
metaModel.properties[String(propertyName)] = propertyModel;
} else {
throw new Error('Property already exists');
}
Expand All @@ -145,7 +148,8 @@ export function convertToObjectModel(jsonSchemaModel: CommonModel, name: string)
const keyModel = new StringModel(propertyName, pattern);
const valueModel = convertToMetaModel(patternModel);
const dictionaryModel = new DictionaryModel(propertyName, patternModel.originalInput, keyModel, valueModel, 'unwrap');
metaModel.properties[String(propertyName)] = dictionaryModel;
const propertyModel = new ObjectPropertyModel(propertyName, false, dictionaryModel);
metaModel.properties[String(propertyName)] = propertyModel;
} else {
throw new Error('Property already exists');
}
Expand Down
18 changes: 11 additions & 7 deletions src/helpers/ConstrainHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AbstractRenderer } from '../generators';
import { ConstrainedAnyModel, ConstrainedBooleanModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedArrayModel, ConstrainedUnionModel, ConstrainedEnumModel, ConstrainedDictionaryModel, ConstrainedEnumValueModel } from '../models/ConstrainedMetaModel';
import { AnyModel, BooleanModel, FloatModel, IntegerModel, ObjectModel, ReferenceModel, StringModel, TupleModel, ArrayModel, UnionModel, EnumModel, DictionaryModel, MetaModel } from '../models/MetaModel';
import { ConstrainedAnyModel, ConstrainedBooleanModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedArrayModel, ConstrainedUnionModel, ConstrainedEnumModel, ConstrainedDictionaryModel, ConstrainedEnumValueModel, ConstrainedObjectPropertyModel } from '../models/ConstrainedMetaModel';
import { AnyModel, BooleanModel, FloatModel, IntegerModel, ObjectModel, ReferenceModel, StringModel, TupleModel, ArrayModel, UnionModel, EnumModel, DictionaryModel, MetaModel, ObjectPropertyModel } from '../models/MetaModel';
import { getTypeFromMapping, TypeMapping } from './TypeHelpers';

export type ConstrainContext<R extends AbstractRenderer, M extends MetaModel> = {
Expand Down Expand Up @@ -30,7 +30,8 @@ export type ModelNameContext = {
export type ModelNameConstraint = (context: ModelNameContext) => string;

export type PropertyKeyContext = {
propertyKey: string,
constrainedObjectPropertyModel: ConstrainedObjectPropertyModel,
objectPropertyModel: ObjectPropertyModel,
constrainedObjectModel: ConstrainedObjectModel,
objectModel: ObjectModel
}
Expand Down Expand Up @@ -148,10 +149,13 @@ function constrainDictionaryModel<R extends AbstractRenderer>(typeMapping: TypeM

function constrainObjectModel<R extends AbstractRenderer>(typeMapping: TypeMapping<R>, constrainRules: Constraints, context: ConstrainContext<R, ObjectModel>): ConstrainedObjectModel {
const constrainedModel = new ConstrainedObjectModel(context.constrainedName, context.metaModel.originalInput, '', {});
for (const [propertyKey, propertyMetaModel] of Object.entries(context.metaModel.properties)) {
const constrainedPropertyName = constrainRules.propertyKey({propertyKey, constrainedObjectModel: constrainedModel, objectModel: context.metaModel});
const constrainedProperty = constrainMetaModel(typeMapping, constrainRules, {...context, metaModel: propertyMetaModel, propertyKey: constrainedPropertyName});
constrainedModel.properties[String(constrainedPropertyName)] = constrainedProperty;
for (const propertyMetaModel of Object.values(context.metaModel.properties)) {
const constrainedPropertyModel = new ConstrainedObjectPropertyModel('', propertyMetaModel.required, constrainedModel);
const constrainedPropertyName = constrainRules.propertyKey({objectPropertyModel: propertyMetaModel, constrainedObjectPropertyModel: constrainedPropertyModel, constrainedObjectModel: constrainedModel, objectModel: context.metaModel});
constrainedPropertyModel.propertyName = constrainedPropertyName;
const constrainedProperty = constrainMetaModel(typeMapping, constrainRules, {...context, metaModel: context.metaModel, propertyKey: constrainedPropertyName});
constrainedPropertyModel.property = constrainedProperty;
constrainedModel.properties[String(constrainedPropertyName)] = constrainedPropertyModel;
}
constrainedModel.type = getTypeFromMapping(typeMapping, {
constrainedModel,
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/Splitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const trySplitModel = (model: MetaModel, options: SplitOptions, models: MetaMode
export const split = (model: MetaModel, options: SplitOptions, models: MetaModel[] = [model]): MetaModel[] => {
if (model instanceof ObjectModel) {
for (const [prop, propModel] of Object.entries(model.properties)) {
model.properties[String(prop)] = trySplitModel(propModel, options, models);
split(propModel, options, models);
model.properties[String(prop)].property = trySplitModel(propModel.property, options, models);
split(propModel.property, options, models);
}
} else if (model instanceof UnionModel) {
for (let index = 0; index < model.union.length; index++) {
Expand Down
9 changes: 8 additions & 1 deletion src/models/ConstrainedMetaModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,19 @@ export class ConstrainedTupleModel extends ConstrainedMetaModel {
super(name, originalInput, type);
}
}
export class ConstrainedObjectPropertyModel {
constructor(
public propertyName: string,
public required: boolean,
public property: ConstrainedMetaModel) {
}
}
export class ConstrainedObjectModel extends ConstrainedMetaModel {
constructor(
name: string,
originalInput: any,
type: string,
public properties: { [key: string]: ConstrainedMetaModel; }) {
public properties: { [key: string]: ConstrainedObjectPropertyModel; }) {
super(name, originalInput, type);
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/models/MetaModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@ export class TupleModel extends MetaModel {
super(name, originalInput);
}
}
export class ObjectPropertyModel {
constructor(
public propertyName: string,
public required: boolean,
public property: MetaModel) {
}
}
export class ObjectModel extends MetaModel {
constructor(
name: string,
originalInput: any,
public properties: { [key: string]: MetaModel; }) {
public properties: { [key: string]: ObjectPropertyModel; }) {
super(name, originalInput);
}
}
Expand Down
34 changes: 23 additions & 11 deletions test/generators/csharp/constrainer/PropertyKeyConstrainer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
import { CSharpDefaultConstraints } from '../../../../src/generators/csharp/CSharpConstrainer';
import { ConstrainedObjectModel, ObjectModel } from '../../../../src';
import { ConstrainedObjectModel, ConstrainedObjectPropertyModel, ObjectModel, ObjectPropertyModel } from '../../../../src';
import { DefaultPropertyKeyConstraints, defaultPropertyKeyConstraints, PropertyKeyConstraintOptions } from '../../../../src/generators/csharp/constrainer/PropertyKeyConstrainer';
describe('PropertyKeyConstrainer', () => {
const objectModel = new ObjectModel('test', undefined, {});
const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});

const constrainPropertyName = (propertyName: string) => {
const objectPropertyModel = new ObjectPropertyModel(propertyName, false, objectModel);
const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
return CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel });
};

test('should never render special chars', () => {
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '%'});
const constrainedKey = constrainPropertyName('%');
expect(constrainedKey).toEqual('Percent');
});
test('should not render number as start char', () => {
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '1'});
const constrainedKey = constrainPropertyName('1');
expect(constrainedKey).toEqual('Number_1');
});
test('should never contain empty name', () => {
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: ''});
const constrainedKey = constrainPropertyName('');
expect(constrainedKey).toEqual('Empty');
});
test('should use constant naming format', () => {
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'some weird_value!"#2'});
const constrainedKey = constrainPropertyName('some weird_value!"#2');
expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
});
test('should not contain duplicate properties', () => {
const objectModel = new ObjectModel('test', undefined, {});
const propertyModel = new ConstrainedObjectModel('SomeProperty', undefined, '', {});
const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {SomeProperty: propertyModel});
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'SomeProperty'});
const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});
const objectPropertyModel = new ObjectPropertyModel('SomeProperty', false, objectModel);
const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('SomeProperty', objectPropertyModel.required, constrainedObjectModel);
constrainedObjectModel.properties['SomeProperty'] = constrainedObjectPropertyModel;
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
expect(constrainedKey).toEqual('ReservedSomeProperty');
});
test('should never render reserved keywords', () => {
const constrainedKey = CSharpDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'return'});
const constrainedKey = constrainPropertyName('return');
expect(constrainedKey).toEqual('ReservedReturn');
});
describe('custom constraints', () => {
Expand All @@ -43,7 +51,9 @@ describe('PropertyKeyConstrainer', () => {
NO_DUPLICATE_PROPERTIES: jest.fn().mockReturnValue('')
};
const constrainFunction = defaultPropertyKeyConstraints(mockedConstraintCallbacks);
constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
const objectPropertyModel = new ObjectPropertyModel('', false, objectModel);
const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
constrainFunction({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
//Expect all callbacks to be called
for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
expect(jestMockCallback).toHaveBeenCalled();
Expand All @@ -60,7 +70,9 @@ describe('PropertyKeyConstrainer', () => {
];
const jestCallback = jest.fn().mockReturnValue('');
const constrainFunction = defaultPropertyKeyConstraints({NAMING_FORMATTER: jestCallback});
const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
const objectPropertyModel = new ObjectPropertyModel('', false, objectModel);
const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
expect(constrainedValue).toEqual('');
for (const jestMockCallback of spies) {
expect(jestMockCallback).toHaveBeenCalled();
Expand Down
Loading