Skip to content

Commit

Permalink
Fixed nested options where not being merged together with default opt…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
jonaslagoni committed Jul 28, 2022
1 parent c17b77c commit 27ab4dc
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 25 deletions.
9 changes: 4 additions & 5 deletions src/generators/csharp/CSharpGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import { ClassRenderer } from './renderers/ClassRenderer';
import { isReservedCSharpKeyword } from './Constants';
import { Logger } from '../../index';
import { CSharpDefaultConstraints, CSharpDefaultTypeMapping } from './CSharpConstrainer';

import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';
export interface CSharpOptions extends CommonGeneratorOptions<CSharpPreset> {
collectionType?: 'List' | 'Array';
collectionType: 'List' | 'Array';
typeMapping: TypeMapping<CSharpOptions>;
constraints: Constraints;
autoImplementedProperties: boolean;
Expand All @@ -37,10 +37,9 @@ export class CSharpGenerator extends AbstractGenerator<CSharpOptions, CSharpRend
};

constructor(
options: Partial<CSharpOptions> = CSharpGenerator.defaultOptions,
options?: DeepPartial<CSharpOptions>
) {
const realizedOptions = {...CSharpGenerator.defaultOptions, ...options};

const realizedOptions = mergePartialAndDefault(CSharpGenerator.defaultOptions, options) as CSharpOptions;
super('CSharp', realizedOptions);
}

Expand Down
5 changes: 3 additions & 2 deletions src/generators/dart/DartGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {isReservedDartKeyword} from './Constants';
import {Logger} from '../../';
import {FormatHelpers} from '../../helpers/FormatHelpers';
import { DartDefaultConstraints, DartDefaultTypeMapping } from './DartConstrainer';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';

export interface DartOptions extends CommonGeneratorOptions<DartPreset> {
collectionType?: 'List';
Expand All @@ -33,9 +34,9 @@ export class DartGenerator extends AbstractGenerator<DartOptions, DartRenderComp
};

constructor(
options: Partial<DartOptions> = DartGenerator.defaultOptions,
options?: DeepPartial<DartOptions>,
) {
const realizedOptions = {...DartGenerator.defaultOptions, ...options};
const realizedOptions = mergePartialAndDefault(DartGenerator.defaultOptions, options) as DartOptions;
super('Dart', realizedOptions);
}

Expand Down
7 changes: 4 additions & 3 deletions src/generators/go/GoGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { StructRenderer } from './renderers/StructRenderer';
import { EnumRenderer } from './renderers/EnumRenderer';
import { Logger } from '../../utils/LoggingInterface';
import { GoDefaultConstraints, GoDefaultTypeMapping } from './GoConstrainer';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';

export interface GoOptions extends CommonGeneratorOptions<GoPreset> {
typeMapping: TypeMapping<GoOptions>;
Expand All @@ -30,11 +31,11 @@ export class GoGenerator extends AbstractGenerator<GoOptions, GoRenderCompleteMo
typeMapping: GoDefaultTypeMapping,
constraints: GoDefaultConstraints
};

constructor(
options: Partial<GoOptions> = GoGenerator.defaultOptions,
options?: DeepPartial<GoOptions>,
) {
const realizedOptions = {...GoGenerator.defaultOptions, ...options};

const realizedOptions = mergePartialAndDefault(GoGenerator.defaultOptions, options) as GoOptions;
super('Go', realizedOptions);
}

Expand Down
8 changes: 4 additions & 4 deletions src/generators/java/JavaGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { isReservedJavaKeyword } from './Constants';
import { Logger } from '../../';
import { constrainMetaModel, Constraints } from '../../helpers/ConstrainHelpers';
import { JavaDefaultConstraints, JavaDefaultTypeMapping } from './JavaConstrainer';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';

export interface JavaOptions extends CommonGeneratorOptions<JavaPreset> {
collectionType: 'List' | 'Array';
Expand All @@ -31,13 +32,12 @@ export class JavaGenerator extends AbstractGenerator<JavaOptions, JavaRenderComp
};

constructor(
options: Partial<JavaOptions> = JavaGenerator.defaultOptions,
options?: DeepPartial<JavaOptions>,
) {
const realizedOptions = {...JavaGenerator.defaultOptions, ...options};

const realizedOptions = mergePartialAndDefault(JavaGenerator.defaultOptions, options) as JavaOptions;
super('Java', realizedOptions);
}

splitMetaModel(model: MetaModel): MetaModel[] {
//These are the models that we have separate renderers for
const metaModelsToSplit = {
Expand Down
10 changes: 5 additions & 5 deletions src/generators/javascript/JavaScriptGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { JavaScriptPreset, JS_DEFAULT_PRESET } from './JavaScriptPreset';
import { ClassRenderer } from './renderers/ClassRenderer';
import { Logger } from '../../';
import { JavaScriptDefaultConstraints, JavaScriptDefaultTypeMapping } from './JavaScriptConstrainer';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';
export interface JavaScriptOptions extends CommonGeneratorOptions<JavaScriptPreset> {
typeMapping: TypeMapping<JavaScriptOptions>;
constraints: Constraints;
Expand All @@ -28,15 +29,14 @@ export class JavaScriptGenerator extends AbstractGenerator<JavaScriptOptions, Ja
typeMapping: JavaScriptDefaultTypeMapping,
constraints: JavaScriptDefaultConstraints
};

constructor(
options: Partial<JavaScriptOptions> = JavaScriptGenerator.defaultOptions,
options?: DeepPartial<JavaScriptOptions>,
) {
const realizedOptions = {...JavaScriptGenerator.defaultOptions, ...options};

const realizedOptions = mergePartialAndDefault(JavaScriptGenerator.defaultOptions, options) as JavaScriptOptions;
super('JavaScript', realizedOptions);
}

/**
* Render a complete model result where the model code, library and model dependencies are all bundled appropriately.
*
Expand Down
10 changes: 4 additions & 6 deletions src/generators/typescript/TypeScriptGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { EnumRenderer } from './renderers/EnumRenderer';
import { TypeRenderer } from './renderers/TypeRenderer';
import { TypeScriptDefaultConstraints, TypeScriptDefaultTypeMapping } from './TypeScriptConstrainer';
import { TS_EXPORT_KEYWORD_PRESET } from './presets';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';

export interface TypeScriptOptions extends CommonGeneratorOptions<TypeScriptPreset> {
renderTypes: boolean;
Expand Down Expand Up @@ -43,12 +44,12 @@ export class TypeScriptGenerator extends AbstractGenerator<TypeScriptOptions,Typ
};

constructor(
options: Partial<TypeScriptOptions> = TypeScriptGenerator.defaultOptions,
options?: DeepPartial<TypeScriptOptions>,
) {
const realizedOptions = {...TypeScriptGenerator.defaultOptions, ...options};
const realizedOptions = mergePartialAndDefault(TypeScriptGenerator.defaultOptions, options) as TypeScriptOptions;
super('TypeScript', realizedOptions);
}

splitMetaModel(model: MetaModel): MetaModel[] {
//These are the models that we have separate renderers for
const metaModelsToSplit = {
Expand Down Expand Up @@ -129,9 +130,6 @@ ${modelCode}`;
}
return this.renderClass(model, inputModel);
} else if (model instanceof ConstrainedEnumModel) {
if (this.options.enumType === 'union') {
return this.renderType(model, inputModel);
}
return this.renderEnum(model, inputModel);
}
return this.renderType(model, inputModel);
Expand Down
32 changes: 32 additions & 0 deletions src/utils/Partials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable security/detect-object-injection */

/**
* Deep partial type that does NOT partial function arguments.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export type DeepPartial<T> = T extends Function ? T : (T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T);

export function mergePartialAndDefault<T extends Record<string, any>>(defaultNonOptional: T, customOptional?: DeepPartial<T>): T {
if (customOptional === undefined) {
return defaultNonOptional;
}
// create a new object
const target = {...defaultNonOptional} as Record<string, any>;

// deep merge the object into the target object
const merger = (obj: Record<string, any>) => {
for (const [propName, prop] of Object.entries(obj)) {
if (typeof prop === 'object') {
if (target[propName] === undefined) {
target[propName] = prop;
} else {
target[propName] = mergePartialAndDefault(target[propName], prop);
}
} else if (prop) {
target[propName] = prop;
}
}
};
merger(customOptional);
return target as T;
}
68 changes: 68 additions & 0 deletions test/utils/Partials.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {DeepPartial, mergePartialAndDefault} from '../../src/utils';

describe('mergePartialAndDefault', () => {
test('should handle default objects', () => {
interface TestType {
nestedObject: {
nested: string
},
testProp: string
}
const defaultOptions: TestType = {
nestedObject: {
nested: 'test'
},
testProp: 'test'
};
const partialOptions: DeepPartial<TestType> = {
testProp: 'test2'
};
const realizedOptions = mergePartialAndDefault(defaultOptions, partialOptions) as TestType;
expect(realizedOptions.testProp).toEqual('test2');
expect(realizedOptions.nestedObject.nested).toEqual('test');
});
test('should handle overwriting nested objects', () => {
interface TestType {
nestedObject: {
nested: string
}
}
const defaultOptions: TestType = {
nestedObject: {
nested: 'test'
}
};
const partialOptions: DeepPartial<TestType> = {
nestedObject: {
nested: 'test2'
}
};
const realizedOptions = mergePartialAndDefault(defaultOptions, partialOptions) as TestType;
expect(realizedOptions.nestedObject.nested).toEqual('test2');
});
test('should not overwrite old realized options ', () => {
interface TestType {
nestedObject: {
nested: string
}
}
const defaultOptions: TestType = {
nestedObject: {
nested: 'test'
}
};
const partialOptions: DeepPartial<TestType> = {
nestedObject: {
nested: 'test2'
}
};
const partialOptions2: DeepPartial<TestType> = {
nestedObject: {
nested: 'test3'
}
};
const realizedOptions = mergePartialAndDefault(defaultOptions, partialOptions) as TestType;
mergePartialAndDefault(defaultOptions, partialOptions2) as TestType;
expect(realizedOptions.nestedObject.nested).toEqual('test2');
});
});

0 comments on commit 27ab4dc

Please sign in to comment.